Compare commits
127 commits
Author | SHA1 | Date | |
---|---|---|---|
72ea4ff8b3 | |||
991124c9e4 | |||
47b5386c0c | |||
5381486c25 | |||
375ce4c798 | |||
d2c6148662 | |||
84101ab821 | |||
bd0db76e31 | |||
8743c2329e | |||
46244e8e84 | |||
8afac77841 | |||
6452369351 | |||
641d838140 | |||
2d5276f742 | |||
0dae5d0402 | |||
022dde4754 | |||
0aaf00dc5e | |||
dfb5736ac0 | |||
04a72ed947 | |||
105f94690d | |||
36bbce78d7 | |||
5a9f52fb11 | |||
5a4822f89e | |||
c934127d84 | |||
2128b88571 | |||
84d361e8a9 | |||
c7381cf1d5 | |||
11354a45ce | |||
7703991f4c | |||
9bb6d57515 | |||
0aa213a31d | |||
bef119b03b | |||
d036740c8b | |||
2c9b86d873 | |||
fb97ce040b | |||
c2adab0716 | |||
06882b4fbd | |||
079a3b49de | |||
c9dca6802e | |||
019c05c8e4 | |||
159629372d | |||
3a6dd45741 | |||
e19ecd2ba1 | |||
3ead98a770 | |||
9ca32aa3ea | |||
9d9df949ef | |||
cd5c22aaa1 | |||
39a03d876e | |||
992833bdc9 | |||
e2c8880363 | |||
e6a7f9193b | |||
3dc85595b1 | |||
cb4f4ff89c | |||
fe85ee5307 | |||
fa3a5f80a1 | |||
a881e6b3d5 | |||
e62df46c61 | |||
24d853966f | |||
b87e51567e | |||
3a48fa03a5 | |||
ebad5364b9 | |||
3720d559a3 | |||
522e6b8001 | |||
32a8936fc6 | |||
fe8dfc7da3 | |||
4dc0a4c8c6 | |||
df8aa42ee4 | |||
c4951dc605 | |||
a5edc29be7 | |||
2c608c5a92 | |||
8e0af3fc27 | |||
af8366f0fe | |||
db90802e6e | |||
59108365f1 | |||
092ee49139 | |||
c324cd5953 | |||
5cfbd72fa8 | |||
ce942b0585 | |||
91ed50d993 | |||
a93dc423f0 | |||
399df8ab68 | |||
8d383cba9d | |||
dadb12a6e5 | |||
d7cecc1d8c | |||
5b76668cbe | |||
64cc6b7af7 | |||
15f3c2ff66 | |||
0e5c654d5b | |||
de446c4240 | |||
4f335b9471 | |||
6269aa6398 | |||
da0b96a5ad | |||
db1318fed1 | |||
a0cacb5553 | |||
6cc8da120f | |||
35ca90b8f2 | |||
65e5b40223 | |||
4803180bcf | |||
7e8e954de7 | |||
0ca9b1be48 | |||
85eddfc536 | |||
0ab0fb5dd4 | |||
6705fb453e | |||
2c58475d61 | |||
a381a64b31 | |||
68c199aa64 | |||
805d8d81c5 | |||
063beddb01 | |||
59aa9c5474 | |||
a32206a6fb | |||
bec0dc3c0b | |||
cf2ec690db | |||
7daf35d898 | |||
9d3c5e50d6 | |||
9cc0c4f874 | |||
fe1ee08df4 | |||
84b2ae3e8f | |||
55054f1fa6 | |||
8aae821e59 | |||
d646edee08 | |||
b0d35f5ef8 | |||
34e81fdf87 | |||
5696f22951 | |||
8853adda62 | |||
1984b3747e | |||
c85fa98bcc | |||
7874b77104 |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
@ -39,6 +39,7 @@ body:
|
|||
- Image Resizer
|
||||
- Keyboard Manager
|
||||
- MD Preview
|
||||
- Mouse Utilities
|
||||
- PDF Preview
|
||||
- PDF Thumbnail
|
||||
- PowerRename
|
||||
|
@ -47,6 +48,7 @@ body:
|
|||
- SVG Preview
|
||||
- SVG Thumbnail
|
||||
- Settings
|
||||
- Video Conference Mute
|
||||
- Welcome / PowerToys Tour window
|
||||
- System tray interaction
|
||||
- Installer
|
||||
|
|
7
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,8 +1,5 @@
|
|||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: "\U0001F4F7 Video Conference Mute Issue"
|
||||
url: https://github.com/microsoft/PowerToys/issues/6246
|
||||
about: Report Bug for the Video Conference Mute utility
|
||||
- name: "\U0001F6A8 Microsoft Security Response Center (MSRC)"
|
||||
url: https://msrc.microsoft.com/create-report
|
||||
about: Report security bugs
|
||||
|
@ -10,6 +7,6 @@ contact_links:
|
|||
url: https://github.com/microsoft/PowerToys/wiki
|
||||
about: Documentation for users of PowerToys utilities
|
||||
- name: "\U0001F4DA PowerToys dev documentation"
|
||||
url: https://github.com/microsoft/PowerToys/tree/master/doc/devdocs
|
||||
url: https://github.com/microsoft/PowerToys/tree/main/doc/devdocs
|
||||
about: Documentation for people interested in developing and contributing for PowerToys
|
||||
|
||||
|
|
51
.github/actions/spell-check/expect.txt
vendored
|
@ -5,7 +5,9 @@ abcdef
|
|||
abcdefgh
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
abgr
|
||||
abi
|
||||
ABlocked
|
||||
ABOUTBOX
|
||||
Abug
|
||||
accctrl
|
||||
Acceleratorkeys
|
||||
|
@ -128,6 +130,7 @@ AUTOSIZECOLUMNS
|
|||
AUTOUPDATE
|
||||
available
|
||||
AValid
|
||||
awakeness
|
||||
awakeversion
|
||||
AWAYMODE
|
||||
AYUV
|
||||
|
@ -183,6 +186,7 @@ Browsable
|
|||
bsd
|
||||
bstr
|
||||
bti
|
||||
btn
|
||||
BTNFACE
|
||||
Bto
|
||||
buf
|
||||
|
@ -202,6 +206,7 @@ CANRENAME
|
|||
Captureascreenshot
|
||||
CAPTURECHANGED
|
||||
CASESENSITIVE
|
||||
cassert
|
||||
CAtl
|
||||
CCDDEE
|
||||
ccf
|
||||
|
@ -380,6 +385,7 @@ CXVIRTUALSCREEN
|
|||
cxx
|
||||
cxxopts
|
||||
CYSMICON
|
||||
CYVIRTUALSCREEN
|
||||
cziplib
|
||||
Dac
|
||||
dacl
|
||||
|
@ -429,6 +435,7 @@ Delimarsky
|
|||
delims
|
||||
dend
|
||||
DENORMAL
|
||||
Deondre
|
||||
depersist
|
||||
deprioritized
|
||||
deps
|
||||
|
@ -490,6 +497,8 @@ DPICHANGED
|
|||
DPolicy
|
||||
DPopup
|
||||
DPSAPI
|
||||
DQTAT
|
||||
DQTYPE
|
||||
DRAWFRAME
|
||||
drawingcolor
|
||||
dreamsofameaningfullife
|
||||
|
@ -569,6 +578,7 @@ errc
|
|||
errorlevel
|
||||
ERRORMESSAGE
|
||||
ERRORTITLE
|
||||
ESettings
|
||||
esize
|
||||
estdir
|
||||
etcore
|
||||
|
@ -621,6 +631,7 @@ Farbraum
|
|||
FARPROC
|
||||
fdw
|
||||
feimage
|
||||
FFAA
|
||||
ffcd
|
||||
FFDDDDDD
|
||||
fff
|
||||
|
@ -666,6 +677,7 @@ FRAMEDOWNLOAD
|
|||
franky
|
||||
Froml
|
||||
fstream
|
||||
ftp
|
||||
ftps
|
||||
FTYPE
|
||||
FULLNAME
|
||||
|
@ -687,6 +699,7 @@ gdi
|
|||
gdiplus
|
||||
GDISCALED
|
||||
generatesqlfromuserquery
|
||||
GETDESKWALLPAPER
|
||||
GETDISPINFO
|
||||
GETDLGCODE
|
||||
GETDPISCALEDSIZE
|
||||
|
@ -721,6 +734,7 @@ Hardlines
|
|||
HARDWAREINPUT
|
||||
hashcode
|
||||
Hashset
|
||||
Hashtable
|
||||
HASHVAL
|
||||
hbitmap
|
||||
hbmp
|
||||
|
@ -749,8 +763,10 @@ hglobal
|
|||
hhk
|
||||
HHmmss
|
||||
HHOOK
|
||||
hhx
|
||||
HICON
|
||||
HIDEWINDOW
|
||||
highlighter
|
||||
HIMAGELIST
|
||||
himl
|
||||
hinst
|
||||
|
@ -774,6 +790,7 @@ hmonitor
|
|||
HOLDENTER
|
||||
HOLDESC
|
||||
homljgmgpmcbpjbnjpfijnhipfkiclkd
|
||||
homepage
|
||||
HOOKPROC
|
||||
hostname
|
||||
hotkeycontrol
|
||||
|
@ -783,6 +800,7 @@ hotspot
|
|||
HPAINTBUFFER
|
||||
hpj
|
||||
hpp
|
||||
HRAWINPUT
|
||||
hread
|
||||
HREDRAW
|
||||
href
|
||||
|
@ -802,6 +820,7 @@ Htmdid
|
|||
html
|
||||
htt
|
||||
http
|
||||
HTTRANSPARENT
|
||||
hwb
|
||||
HWINEVENTHOOK
|
||||
hwnd
|
||||
|
@ -835,6 +854,7 @@ ICollection
|
|||
IColor
|
||||
ICommand
|
||||
IComparer
|
||||
ICompositor
|
||||
ICONERROR
|
||||
ICONINFORMATION
|
||||
IContext
|
||||
|
@ -849,6 +869,7 @@ IDesktop
|
|||
IDictionary
|
||||
IDirectory
|
||||
IDispatch
|
||||
IDispatcher
|
||||
IDisposable
|
||||
idl
|
||||
IDLIST
|
||||
|
@ -863,6 +884,7 @@ IEasing
|
|||
IEnum
|
||||
IEnumerable
|
||||
IEnumerator
|
||||
IEnvironment
|
||||
IEquality
|
||||
IEquatable
|
||||
IEvent
|
||||
|
@ -935,6 +957,7 @@ INPUTHARDWARE
|
|||
INPUTKEYBOARD
|
||||
INPUTLANGCHANGED
|
||||
INPUTMOUSE
|
||||
INPUTSINK
|
||||
INPUTTYPE
|
||||
INSTALLDESKTOPSHORTCUT
|
||||
INSTALLDIR
|
||||
|
@ -1002,6 +1025,7 @@ IShell
|
|||
ISingle
|
||||
ISmart
|
||||
isocpp
|
||||
iss
|
||||
IStorage
|
||||
IStream
|
||||
istreambuf
|
||||
|
@ -1012,6 +1036,7 @@ ITab
|
|||
ITask
|
||||
ITemplate
|
||||
ITEMSTATEICONCLICK
|
||||
ITerminal
|
||||
ITest
|
||||
ith
|
||||
IThrottled
|
||||
|
@ -1031,6 +1056,7 @@ IWeb
|
|||
IWIC
|
||||
IWindows
|
||||
IWork
|
||||
IXaml
|
||||
IXml
|
||||
ixx
|
||||
IYUV
|
||||
|
@ -1063,6 +1089,7 @@ KBDLLHOOKSTRUCT
|
|||
kbm
|
||||
KERNELBASE
|
||||
KEYBDINPUT
|
||||
keybindings
|
||||
keyboardeventhandlers
|
||||
keyboardmanager
|
||||
keyboardmanagercommon
|
||||
|
@ -1139,6 +1166,7 @@ lmcons
|
|||
LMEM
|
||||
LMENU
|
||||
lnk
|
||||
LOADSTRING
|
||||
LOCALAPPDATA
|
||||
LOCALDISPLAY
|
||||
localhost
|
||||
|
@ -1160,6 +1188,7 @@ lowlevel
|
|||
LOWORD
|
||||
lparam
|
||||
LPBYTE
|
||||
LPCITEMIDLIST
|
||||
LPCMINVOKECOMMANDINFO
|
||||
LPCREATESTRUCT
|
||||
LPCTSTR
|
||||
|
@ -1206,6 +1235,7 @@ LVS
|
|||
LVSIL
|
||||
LWA
|
||||
lwin
|
||||
LZero
|
||||
lzw
|
||||
mailto
|
||||
MAINICON
|
||||
|
@ -1319,6 +1349,7 @@ msedge
|
|||
MSGFLT
|
||||
mshtmdid
|
||||
msi
|
||||
msiexec
|
||||
MSIFASTINSTALL
|
||||
MSIHANDLE
|
||||
MSIINSTALLER
|
||||
|
@ -1561,6 +1592,7 @@ phwnd
|
|||
pici
|
||||
pid
|
||||
pidl
|
||||
PIDLIST
|
||||
PINDIR
|
||||
pinfo
|
||||
pinvoke
|
||||
|
@ -1593,6 +1625,7 @@ powerlauncher
|
|||
powerpreview
|
||||
powerrename
|
||||
POWERRENAMETEST
|
||||
POWERRENAMEUIHOST
|
||||
powershell
|
||||
powertoy
|
||||
powertoysinterop
|
||||
|
@ -1632,7 +1665,9 @@ prgms
|
|||
pri
|
||||
PRINTCLIENT
|
||||
printf
|
||||
pritudev
|
||||
prm
|
||||
proactively
|
||||
PROCESSKEY
|
||||
PRODUCTVERSION
|
||||
PROGDLG
|
||||
|
@ -1685,6 +1720,7 @@ QUERYOPEN
|
|||
QUEUESYNC
|
||||
Quickime
|
||||
QUICKLAYOUTSWITCH
|
||||
QUNS
|
||||
qwertyuiopasdfghjklzxcvbnm
|
||||
qword
|
||||
qwrtyuiopsghjklzxvnm
|
||||
|
@ -1692,6 +1728,9 @@ Radiobuttons
|
|||
RAII
|
||||
RAlt
|
||||
randyrants
|
||||
RAWINPUT
|
||||
RAWINPUTDEVICE
|
||||
RAWINPUTHEADER
|
||||
RAWPATH
|
||||
rbegin
|
||||
Rbp
|
||||
|
@ -1702,6 +1741,7 @@ RBUTTONUP
|
|||
rclsid
|
||||
RCONTROL
|
||||
RCtrl
|
||||
rdeveen
|
||||
RDW
|
||||
readme
|
||||
READMODE
|
||||
|
@ -1775,6 +1815,7 @@ rgs
|
|||
rhs
|
||||
ricardosantos
|
||||
Richtext
|
||||
RIDEV
|
||||
RIGHTSCROLLBAR
|
||||
riid
|
||||
riverar
|
||||
|
@ -1821,6 +1862,7 @@ scancode
|
|||
scanled
|
||||
schedtasks
|
||||
Scn
|
||||
SCOOBE
|
||||
SCOPEID
|
||||
screenshot
|
||||
scrollable
|
||||
|
@ -1998,6 +2040,7 @@ stdlib
|
|||
STDMETHODCALLTYPE
|
||||
STDMETHODIMP
|
||||
stdout
|
||||
stefan
|
||||
STEPIT
|
||||
stgm
|
||||
STGMEDIUM
|
||||
|
@ -2043,6 +2086,7 @@ Switchbetweenvirtualdesktops
|
|||
SWP
|
||||
swprintf
|
||||
SWRESTORE
|
||||
swscanf
|
||||
SYMED
|
||||
SYMOPT
|
||||
SYNCMFT
|
||||
|
@ -2152,7 +2196,9 @@ tsx
|
|||
TYMED
|
||||
typedef
|
||||
TYPEKEY
|
||||
TYPEKEYBOARD
|
||||
TYPELIB
|
||||
TYPEMOUSE
|
||||
typename
|
||||
typeof
|
||||
typeparam
|
||||
|
@ -2292,7 +2338,7 @@ VTABLE
|
|||
Vtbl
|
||||
wav
|
||||
WBounds
|
||||
Wca
|
||||
wca
|
||||
wcautil
|
||||
WCE
|
||||
wcex
|
||||
|
@ -2397,6 +2443,7 @@ workaround
|
|||
Workflow
|
||||
workspaces
|
||||
wostream
|
||||
wostringstream
|
||||
wox
|
||||
wparam
|
||||
wpf
|
||||
|
@ -2455,6 +2502,7 @@ XSmall
|
|||
XStr
|
||||
XToolset
|
||||
xunit
|
||||
XVIRTUALSCREEN
|
||||
Yaml
|
||||
YDiff
|
||||
YIncrement
|
||||
|
@ -2465,6 +2513,7 @@ YStr
|
|||
YUY
|
||||
yuyoyuppe
|
||||
YUYV
|
||||
YVIRTUALSCREEN
|
||||
YVU
|
||||
YVYU
|
||||
ZEROINIT
|
||||
|
|
4
.github/pull_request_template.md
vendored
|
@ -16,8 +16,8 @@
|
|||
- [ ] **Docs:** Added/ updated
|
||||
- [ ] **Binaries:** Any new files are added to WXS / YML
|
||||
- [ ] No new binaries
|
||||
- [ ] [YML for signing](https://github.com/microsoft/PowerToys/blob/master/.pipelines/pipeline.user.windows.yml#L68) for new binaries
|
||||
- [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/master/installer/PowerToysSetup/Product.wxs) for new binaries
|
||||
- [ ] [YML for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/pipeline.user.windows.yml#L68) for new binaries
|
||||
- [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries
|
||||
|
||||
## Contributor License Agreement (CLA)
|
||||
A CLA must be signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/PowerToys) and sign the CLA.
|
||||
|
|
|
@ -2,7 +2,7 @@ trigger:
|
|||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- main
|
||||
- stable
|
||||
paths:
|
||||
exclude:
|
||||
|
@ -13,7 +13,7 @@ trigger:
|
|||
pr:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- main
|
||||
- stable
|
||||
|
||||
# 0.0.yyMM.dd##
|
||||
|
|
|
@ -138,7 +138,8 @@ steps:
|
|||
**\Microsoft.PowerToys.Run.Plugin.Calculator.UnitTest.dll
|
||||
**\Microsoft.Plugin.Uri.UnitTests.dll
|
||||
**\Wox.Test.dll
|
||||
**\Microsoft.PowerToys.Run.Plugin.System.UnitTests.dll
|
||||
**\Microsoft.PowerToys.Run.Plugin.System.UnitTests.dll
|
||||
**\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests.dll
|
||||
!**\obj\**
|
||||
|
||||
# Native dlls
|
||||
|
|
|
@ -62,11 +62,12 @@ build:
|
|||
- 'x64/**/*.pdb'
|
||||
exclude:
|
||||
- 'x64/Release/obj/**/*.pdb'
|
||||
# TODO(yuyoyuppe): uncomment when VCM should be enabled
|
||||
#- from: 'x86/Release'
|
||||
# to: 'Build_Output'
|
||||
# include:
|
||||
# - 'modules\VideoConference\VideoConferenceProxyFilter_x86.dll'
|
||||
- from: 'x86/Release'
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
- 'modules\VideoConference\VideoConferenceProxyFilter_x86.dll'
|
||||
signing_options:
|
||||
sign_inline: true # This does signing as soon as this command completes
|
||||
- from: 'x64/Release'
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
|
@ -137,27 +138,29 @@ build:
|
|||
- 'modules\launcher\Microsoft.Launcher.dll'
|
||||
- 'modules\launcher\Plugins\Calculator\Microsoft.PowerToys.Run.Plugin.Calculator.dll'
|
||||
- 'modules\launcher\Plugins\Calculator\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Folder\Microsoft.Plugin.Folder.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Folder\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Indexer\Microsoft.Plugin.Indexer.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Indexer\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Program\Microsoft.Plugin.Program.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Program\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\Microsoft.PowerToys.Run.Plugin.Registry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\WindowsSettings.json'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Shell\Microsoft.Plugin.Shell.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Shell\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Uri\Microsoft.Plugin.Uri.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.Uri\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Microsoft.Plugin.WindowWalker.dll'
|
||||
- 'modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Community.UnitConverter\Community.PowerToys.Run.Plugin.UnitConverter.dll'
|
||||
- 'modules\launcher\Plugins\Folder\Microsoft.Plugin.Folder.dll'
|
||||
- 'modules\launcher\Plugins\Folder\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Indexer\Microsoft.Plugin.Indexer.dll'
|
||||
- 'modules\launcher\Plugins\Indexer\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Program\Microsoft.Plugin.Program.dll'
|
||||
- 'modules\launcher\Plugins\Program\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Registry\Microsoft.PowerToys.Run.Plugin.Registry.dll'
|
||||
- 'modules\launcher\Plugins\Registry\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\WindowsSettings\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.dll'
|
||||
- 'modules\launcher\Plugins\WindowsSettings\WindowsSettings.json'
|
||||
- 'modules\launcher\Plugins\Shell\Microsoft.Plugin.Shell.dll'
|
||||
- 'modules\launcher\Plugins\Shell\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\Uri\Microsoft.Plugin.Uri.dll'
|
||||
- 'modules\launcher\Plugins\Uri\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\WindowWalker\Microsoft.Plugin.WindowWalker.dll'
|
||||
- 'modules\launcher\Plugins\WindowWalker\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\Plugins\UnitConverter\Community.PowerToys.Run.Plugin.UnitConverter.dll'
|
||||
- 'modules\launcher\Plugins\VSCodeWorkspaces\Community.PowerToys.Run.Plugin.VSCodeWorkspaces.dll'
|
||||
- 'modules\launcher\Plugins\Service\Microsoft.PowerToys.Run.Plugin.Service.dll'
|
||||
- 'modules\launcher\Plugins\System\Microsoft.PowerToys.Run.Plugin.System.dll'
|
||||
- 'modules\launcher\Plugins\WindowsTerminal\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.dll'
|
||||
- 'modules\launcher\Plugins\WindowsTerminal\ManagedTelemetry.dll'
|
||||
- 'modules\launcher\PowerLauncher.dll'
|
||||
- 'modules\launcher\PowerLauncher.exe'
|
||||
- 'modules\launcher\PowerLauncher.Telemetry.dll'
|
||||
|
@ -167,13 +170,15 @@ build:
|
|||
- 'modules\launcher\Wox.dll'
|
||||
- 'modules\launcher\Wox.Infrastructure.dll'
|
||||
- 'modules\launcher\Wox.Plugin.dll'
|
||||
- 'modules\MouseUtils\FindMyMouse.dll'
|
||||
- 'modules\MouseUtils\MouseHighlighter.dll'
|
||||
- 'modules\PowerRename\PowerRenameExt.dll'
|
||||
- 'modules\PowerRename\PowerRenameUILib.dll'
|
||||
- 'modules\PowerRename\PowerRename.exe'
|
||||
- 'modules\ShortcutGuide\ShortcutGuide\PowerToys.ShortcutGuide.exe'
|
||||
- 'modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.dll'
|
||||
# TODO(yuyoyuppe): uncomment when VCM should be enabled
|
||||
#- 'modules\VideoConference\VideoConferenceModule.dll'
|
||||
#- 'modules\VideoConference\VideoConferenceProxyFilter_x64.dll'
|
||||
#- 'modules\VideoConference\VideoConferenceProxyFilter_x86.dll'
|
||||
- 'modules\VideoConference\VideoConferenceModule.dll'
|
||||
- 'modules\VideoConference\VideoConferenceProxyFilter_x64.dll'
|
||||
- 'Settings\ManagedTelemetry.dll'
|
||||
- 'Settings\Microsoft.PowerToys.Settings.UI.exe'
|
||||
- 'Settings\Microsoft.PowerToys.Settings.UI.Lib.dll'
|
||||
|
@ -250,6 +255,7 @@ static_analysis_options:
|
|||
exclude:
|
||||
- 'WiX.*/**/*.dll'
|
||||
- 'Wix.*/**/*.exe'
|
||||
- 'Microsoft.Windows.CppWinRT.*/**/*.exe'
|
||||
moderncop_options:
|
||||
files_to_scan:
|
||||
- from: 'src'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# not using this but keeping around in case we need it in the future.
|
||||
# good use case here could be to set up a new machine, we just point people at it.
|
||||
# https://github.com/microsoft/PowerToys/tree/master/doc/devdocs#prerequisites-for-compiling-powertoys
|
||||
# https://github.com/microsoft/PowerToys/tree/main/doc/devdocs#prerequisites-for-compiling-powertoys
|
||||
|
||||
# improvements if this script is used to replace the snippet
|
||||
# Add in a param for passive versus quiet. Could be a IsSettingUpDevComputer true/false flag
|
||||
|
|
|
@ -72,6 +72,10 @@ PowerToys Awake is a tool to keep your computer awake.
|
|||
|
||||
Color Picker is from Martin.
|
||||
|
||||
### [@oldnewthing](https://github.com/oldnewthing) - Raymond Chen
|
||||
|
||||
Find My Mouse is based on Raymond Chen's SuperSonar.
|
||||
|
||||
### Microsoft InVEST team
|
||||
|
||||
This amazing team helped PowerToys develop PowerToys Run and Keyboard manager as well as update our Settings to v2. @alekhyareddy28, @arjunbalgovind, @jyuwono @laviusmotileng-ms, @ryanbodrug-microsoft, @saahmedm, @somil55, @traies, @udit3333
|
||||
|
|
|
@ -49,7 +49,7 @@ Once the team has approved an issue/spec approach to solving, development can pr
|
|||
|
||||
## Development
|
||||
|
||||
Follow the [development guidelines](https://github.com/microsoft/PowerToys/blob/master/doc/devdocs/readme.md).
|
||||
Follow the [development guidelines](https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md).
|
||||
|
||||
### Naming of features and functionality
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
|
||||
<!-- Global props -->
|
||||
<PropertyGroup Label="Globals" Condition="'$(OverrideWindowsTargetPlatformVersion)'!='True'">
|
||||
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Props that are constant for both Debug and Release configurations -->
|
||||
|
@ -84,7 +84,6 @@
|
|||
<PlatformToolset Condition="'$(OverridePlatformToolset)'!='True'">v142</PlatformToolset>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Debug/Release props -->
|
||||
|
|
103
PowerToys.sln
|
@ -5,7 +5,6 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
|||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner.vcxproj", "{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA} = {217DF501-135C-4E38-BFC8-99D4821032EA}
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227} = {48804216-2A0E-4168-A6D8-9CD068D14227}
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB} = {6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}
|
||||
|
@ -57,26 +56,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "powerrename", "powerrename"
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameExt", "src\modules\powerrename\dll\PowerRenameExt.vcxproj", "{B25AC7A5-FB9F-4789-B392-D5C85E948670}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameLib", "src\modules\powerrename\lib\PowerRenameLib.vcxproj", "{51920F1F-C28C-4ADF-8660-4238766796C2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUI", "src\modules\powerrename\ui\PowerRenameUI.vcxproj", "{0E072714-D127-460B-AFAD-B4C40B412798}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameTest", "src\modules\powerrename\testapp\PowerRenameTest.vcxproj", "{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUnitTests", "src\modules\powerrename\unittests\PowerRenameLibUnitTests.vcxproj", "{2151F984-E006-4A9F-92EF-C6DDE3DC8413}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {B25AC7A5-FB9F-4789-B392-D5C85E948670}
|
||||
EndProjectSection
|
||||
|
@ -84,9 +75,6 @@ EndProject
|
|||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModuleTemplateCompileTest", "tools\project_template\ModuleTemplate\ModuleTemplateCompileTest.vcxproj", "{64A80062-4D8B-4229-8A38-DFA1D7497749}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUWPUI", "src\modules\powerrename\UWPui\PowerRenameUWPUI.vcxproj", "{0485F45C-EA7A-4BB5-804B-3E8D14699387}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {0E072714-D127-460B-AFAD-B4C40B412798}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManager", "src\modules\keyboardmanager\dll\KeyboardManager.vcxproj", "{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}"
|
||||
EndProject
|
||||
|
@ -153,6 +141,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerLauncher", "src\module
|
|||
{5043CECE-E6A7-4867-9CBE-02D27D83747A} = {5043CECE-E6A7-4867-9CBE-02D27D83747A}
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820} = {F8B870EB-D5F5-45BA-9CF7-A5C459818820}
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E} = {74F1B9ED-F59C-4FE7-B473-7B453E30837E}
|
||||
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85} = {A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF} = {4BABF3FE-3451-42FD-873F-3C332E18DCEF}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
|
@ -180,11 +169,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "powerpreview", "src\modules
|
|||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF} = {CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "powerpreviewTest", "src\modules\previewpane\powerpreviewTest\powerpreviewTest.vcxproj", "{47310AB4-9034-4BD1-8D8B-E88AD21A171B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA} = {217DF501-135C-4E38-BFC8-99D4821032EA}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "settings-ui", "settings-ui", "{C3081D9A-1586-441A-B5F4-ED815B3719C1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerToys.Settings.UI", "src\settings-ui\Microsoft.PowerToys.Settings.UI\Microsoft.PowerToys.Settings.UI.csproj", "{A7D5099E-F0FD-4BF3-8522-5A682759F915}"
|
||||
|
@ -193,6 +177,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
ProjectSection(SolutionItems) = preProject
|
||||
src\.editorconfig = src\.editorconfig
|
||||
src\tests\win-app-driver\packages.config = src\tests\win-app-driver\packages.config
|
||||
Solution.props = Solution.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Settings.UI.Library", "src\settings-ui\Microsoft.PowerToys.Settings.UI.Library\Microsoft.PowerToys.Settings.UI.Library.csproj", "{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}"
|
||||
|
@ -277,18 +262,23 @@ EndProject
|
|||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{B39DC643-4663-475E-B329-03F0C9918D48}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
src\common\utils\appMutex.h = src\common\utils\appMutex.h
|
||||
src\common\utils\color.h = src\common\utils\color.h
|
||||
src\common\utils\com_object_factory.h = src\common\utils\com_object_factory.h
|
||||
src\common\utils\elevation.h = src\common\utils\elevation.h
|
||||
src\common\utils\EventLocker.h = src\common\utils\EventLocker.h
|
||||
src\common\utils\EventWaiter.h = src\common\utils\EventWaiter.h
|
||||
src\common\utils\exec.h = src\common\utils\exec.h
|
||||
src\common\utils\game_mode.h = src\common\utils\game_mode.h
|
||||
src\common\utils\HDropIterator.h = src\common\utils\HDropIterator.h
|
||||
src\common\utils\HttpClient.h = src\common\utils\HttpClient.h
|
||||
src\common\utils\json.h = src\common\utils\json.h
|
||||
src\common\utils\logger_helper.h = src\common\utils\logger_helper.h
|
||||
src\common\utils\modulesRegistry.h = src\common\utils\modulesRegistry.h
|
||||
src\common\utils\MsiUtils.h = src\common\utils\MsiUtils.h
|
||||
src\common\utils\os-detect.h = src\common\utils\os-detect.h
|
||||
src\common\utils\process_path.h = src\common\utils\process_path.h
|
||||
src\common\utils\ProcessWaiter.h = src\common\utils\ProcessWaiter.h
|
||||
src\common\utils\registry.h = src\common\utils\registry.h
|
||||
src\common\utils\resources.h = src\common\utils\resources.h
|
||||
src\common\utils\string_utils.h = src\common\utils\string_utils.h
|
||||
src\common\utils\timeutil.h = src\common\utils\timeutil.h
|
||||
|
@ -367,6 +357,23 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfThumbnailProvider", "src
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-PdfThumbnailProvider", "src\modules\previewpane\UnitTests-PdfThumbnailProvider\UnitTests-PdfThumbnailProvider.csproj", "{F40C3397-1834-4530-B2D9-8F8B8456BCDF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsTerminal", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsTerminal\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.csproj", "{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.UnitTests.csproj", "{4ED320BC-BA04-4D42-8D15-CBE62151F08B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUIHost", "src\modules\powerrename\PowerRenameUIHost\PowerRenameUIHost.vcxproj", "{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{4642D596-723F-4BFC-894C-46811219AC4A} = {4642D596-723F-4BFC-894C-46811219AC4A}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRenameUILib", "src\modules\powerrename\PowerRenameUILib\PowerRenameUILib.vcxproj", "{4642D596-723F-4BFC-894C-46811219AC4A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MouseUtils", "MouseUtils", "{322566EF-20DC-43A6-B9F8-616AF942579A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FindMyMouse", "src\modules\MouseUtils\FindMyMouse\FindMyMouse.vcxproj", "{E94FD11C-0591-456F-899F-EFC0CA548336}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MouseHighlighter", "src\modules\MouseUtils\MouseHighlighter\MouseHighlighter.vcxproj", "{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -417,12 +424,6 @@ Global
|
|||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.ActiveCfg = Release|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.Build.0 = Release|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x86.ActiveCfg = Release|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.Build.0 = Debug|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.ActiveCfg = Release|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.Build.0 = Release|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x86.ActiveCfg = Release|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.Build.0 = Debug|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x86.ActiveCfg = Debug|x64
|
||||
|
@ -597,17 +598,9 @@ Global
|
|||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.ActiveCfg = Release|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.Build.0 = Release|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x86.ActiveCfg = Release|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.Build.0 = Debug|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.ActiveCfg = Release|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.Build.0 = Release|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x86.ActiveCfg = Release|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.Build.0 = Debug|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.Build.0 = Debug|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.Deploy.0 = Debug|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.ActiveCfg = Release|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.Build.0 = Release|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.ActiveCfg = Release|Win32
|
||||
|
@ -965,6 +958,43 @@ Global
|
|||
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x64.ActiveCfg = Release|x64
|
||||
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x64.Build.0 = Release|x64
|
||||
{F40C3397-1834-4530-B2D9-8F8B8456BCDF}.Release|x86.ActiveCfg = Release|x64
|
||||
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Debug|x64.Build.0 = Debug|x64
|
||||
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Release|x64.ActiveCfg = Release|x64
|
||||
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Release|x64.Build.0 = Release|x64
|
||||
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85}.Release|x86.ActiveCfg = Release|x64
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Debug|x64.Build.0 = Debug|x64
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x64.ActiveCfg = Release|x64
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x64.Build.0 = Release|x64
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Debug|x64.Build.0 = Debug|x64
|
||||
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Release|x64.ActiveCfg = Release|x64
|
||||
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Release|x64.Build.0 = Release|x64
|
||||
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63}.Release|x86.ActiveCfg = Release|x64
|
||||
{4642D596-723F-4BFC-894C-46811219AC4A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4642D596-723F-4BFC-894C-46811219AC4A}.Debug|x64.Build.0 = Debug|x64
|
||||
{4642D596-723F-4BFC-894C-46811219AC4A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4642D596-723F-4BFC-894C-46811219AC4A}.Release|x64.ActiveCfg = Release|x64
|
||||
{4642D596-723F-4BFC-894C-46811219AC4A}.Release|x64.Build.0 = Release|x64
|
||||
{4642D596-723F-4BFC-894C-46811219AC4A}.Release|x86.ActiveCfg = Release|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Debug|x64.Build.0 = Debug|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Release|x64.ActiveCfg = Release|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Release|x64.Build.0 = Release|x64
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336}.Release|x86.ActiveCfg = Release|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Debug|x64.Build.0 = Debug|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Release|x64.ActiveCfg = Release|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Release|x64.Build.0 = Release|x64
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88}.Release|x86.ActiveCfg = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -979,7 +1009,6 @@ Global
|
|||
{89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
|
@ -1012,7 +1041,6 @@ Global
|
|||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033} = {5A7818A8-109C-4E1C-850D-1A654E234B0E}
|
||||
|
@ -1080,6 +1108,13 @@ Global
|
|||
{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{11491FD8-F921-48BF-880C-7FEA185B80A1} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{F40C3397-1834-4530-B2D9-8F8B8456BCDF} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{A2D583F0-B70C-4462-B1F0-8E81AFB7BA85} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{4ED320BC-BA04-4D42-8D15-CBE62151F08B} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{F7EC4E6C-19CA-4FBD-9918-B8AC5FEF4F63} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{4642D596-723F-4BFC-894C-46811219AC4A} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
{322566EF-20DC-43A6-B9F8-616AF942579A} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{E94FD11C-0591-456F-899F-EFC0CA548336} = {322566EF-20DC-43A6-B9F8-616AF942579A}
|
||||
{782A61BE-9D85-4081-B35C-1CCC9DCC1E88} = {322566EF-20DC-43A6-B9F8-616AF942579A}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
|
174
README.md
|
@ -1,53 +1,50 @@
|
|||
# Microsoft PowerToys
|
||||
|
||||
<img src="./doc/images/overview/PT%20hero%20image.png"/>
|
||||
![Hero image for Microsoft PowerToys](doc/images/overview/PT_hero_image.png)
|
||||
|
||||
[Downloads & Release notes][github-release-link] | [Contributing to PowerToys](#contributing) | [What's Happening](#whats-happening) | [Roadmap](#powertoys-roadmap)
|
||||
[How to use PowerToys][usingPowerToys-docs-link] | [Downloads & Release notes][github-release-link] | [Contributing to PowerToys](#contributing) | [What's Happening](#whats-happening) | [Roadmap](#powertoys-roadmap)
|
||||
|
||||
## Build status
|
||||
|
||||
| Architecture | Master | Stable | Installer |
|
||||
|--------------|--------|--------|-----------|
|
||||
| x64 | [![Build Status for Master](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=master)](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=master) | [![Build Status for Stable](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=stable)](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=stable) | [![Build Status for Installer](https://github-private.visualstudio.com/microsoft/_apis/build/status/CDPX/powertoys/powertoys-Windows-Official-master-Test?branchName=master)](https://github-private.visualstudio.com/microsoft/_build/latest?definitionId=61&branchName=master) |
|
||||
| Architecture | Main | Stable | Installer |
|
||||
|--------------|------|--------|-----------|
|
||||
| x64 | [![Build Status for Main](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=main)](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=main) | [![Build Status for Stable](https://dev.azure.com/ms/PowerToys/_apis/build/status/microsoft.PowerToys?branchName=stable)](https://dev.azure.com/ms/PowerToys/_build/latest?definitionId=219&branchName=stable) | [![Build Status for Installer](https://github-private.visualstudio.com/microsoft/_apis/build/status/CDPX/powertoys/powertoys-Windows-Official-master-Test?branchName=main)](https://github-private.visualstudio.com/microsoft/_build/latest?definitionId=61&branchName=main) |
|
||||
|
||||
## About
|
||||
|
||||
Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows 10 experience for greater productivity. For more info on [PowerToys overviews and guides][usingPowerToys-docs-link], or any other tools and resources for [Windows development environments](https://docs.microsoft.com/windows/dev-environment/overview), head over to [docs.microsoft.com][usingPowerToys-docs-link]!
|
||||
Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity. For more info on [PowerToys overviews and how to use the utilities][usingPowerToys-docs-link], or any other tools and resources for [Windows development environments](https://docs.microsoft.com/windows/dev-environment/overview), head over to [docs.microsoft.com][usingPowerToys-docs-link]!
|
||||
|
||||
| | Current utilities: | |
|
||||
|--------------|--------------------|--------------|
|
||||
| [Awake](https://aka.ms/PowerToysOverview_Awake) | [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) | [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) |
|
||||
| [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) |
|
||||
| [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
|
||||
| [Video Conference Mute (Experimental)](https://aka.ms/PowerToysOverview_VideoConference) | | |
|
||||
| [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
|
||||
|
||||
- ⚠️ PowerToys (v0.37.0 and newer) requires Windows 10 v1903 (18362) or newer.
|
||||
|
||||
- Have [.NET Core 3.1.15 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-desktop-3.1.15-windows-x64-installer). The installer should handle this but we want to directly make people aware.
|
||||
- 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.
|
||||
|
||||
### Via GitHub with EXE [Recommended]
|
||||
|
||||
#### Stable version
|
||||
|
||||
Install from the [Microsoft Store's PowerToys page][microsoft-store-link] or use [Microsoft PowerToys GitHub releases page][github-release-link].
|
||||
|
||||
- For GitHub, click on `Assets` to show the files available in the release and then click on `PowerToysSetup-0.45.0-x64.exe` to download the PowerToys installer.
|
||||
- For Microsoft Store, you must be using the [new Microsoft Store](https://blogs.windows.com/windowsExperience/2021/06/24/building-a-new-open-microsoft-store-on-windows-11/) which will be available for both Windows 11 and Windows 10.
|
||||
[Microsoft PowerToys GitHub releases page][github-release-link], click on `Assets` at the bottom to show the files available in the release and then click on `PowerToysSetup-0.49.0-x64.exe` to download the PowerToys installer.
|
||||
|
||||
This is our preferred method.
|
||||
|
||||
#### Experimental version
|
||||
To install the Video Conference mute, please use the [v0.46 experimental version of PowerToys][github-prerelease-link] to try out this version. It includes all improvements from v0.45 in addition to the Video conference utility. Click on `Assets` to show the files available in the release and then download the .exe installer.
|
||||
### Via Microsoft Store
|
||||
|
||||
Install from the [Microsoft Store's PowerToys page][microsoft-store-link]. You must be using the [new Microsoft Store](https://blogs.windows.com/windowsExperience/2021/06/24/building-a-new-open-microsoft-store-on-windows-11/) which will be available for both Windows 11 and Windows 10.
|
||||
|
||||
### Via WinGet (Preview)
|
||||
Download PowerToys from [WinGet](https://github.com/microsoft/winget-cli#installing-the-client). To install PowerToys, run the following command from the command line / PowerShell:
|
||||
|
||||
```powershell
|
||||
WinGet install powertoys
|
||||
winget install Microsoft.PowerToys -s winget
|
||||
```
|
||||
|
||||
### Other install methods
|
||||
|
@ -78,114 +75,74 @@ 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.45 - August 2021 Update
|
||||
### 0.49 - October 2021 Update
|
||||
|
||||
Our goals for the [v0.45 release cycle](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F23) primarily centered around stability updates and optimizations, installer updates, general bug fixes, and accessibility improvements.
|
||||
The [v0.49 release cycle](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F25) introduces exciting new updates primarily centered around modernizing PowerRename's UI, adding a brand new mouse utility, and merging Video Conference Mute into the stable releases!
|
||||
|
||||
We also worked extensively with the community to build an updated settings menu UI. This UI update takes advantage of the latest styling elements to provide users with a refreshed, modern experience navigating the various utilities and their settings.
|
||||
PowerRename's new UI brings a refreshed experience that reflects the modern UI theming of Windows 11, along with helpful regular expression guidance and file formatting tips.
|
||||
|
||||
An experimental version of [PowerToys (v0.46)][github-prerelease-link] was released the week of September 13th. Download and install it to try out the latest improvements to our Video Conference Mute utility! All updates from the v0.45.0 release will still apply in v0.46.0.
|
||||
With the new mouse utility, PowerToys introduces functionality to quickly find your mouse position by double pressing the left <kbd>ctrl</kbd> key. This is ideal for large, high-resolution displays and low-vision users, with additional features and enhancements planned for future releases. Special thanks to [Raymond Chen](https://github.com/oldnewthing) for providing the base code PowerToys used to develop this feature. To learn more, check out our [Mouse Utilities documentation](https://aka.ms/PowerToysOverview_MouseUtilities) on Microsoft Docs!
|
||||
|
||||
#### Highlights from v0.45
|
||||
As Video Conference Mute becomes available in the stable releases, there are still known quirks that we are actively working to address. These bugs are [tracked on our GitHub](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+label%3A%22Product-Video+Conference+Mute%22), and we welcome any and all feedback as we work to isolate and resolve the cause.
|
||||
|
||||
Color Picker's HEX format will no longer have the `#` character. This addresses issues with various color inputs that only accept six characters cutting off the last value. We apologize for any inconvenience this causes as we understand it impacts users who may prefer having `#` included. However, we believe this is the best solution while the custom string functionality ([#8305](https://github.com/microsoft/PowerToys/issues/8305)) is in development.
|
||||
|
||||
Additional work in this release include stability updates and optimizations, installer updates, general bug fixes, and accessibility improvements.
|
||||
|
||||
#### Highlights from v0.49
|
||||
|
||||
**General**
|
||||
- **Change of Behavior:** Color Picker's HEX format will no longer have the `#` character. Custom string functionality for color picker ([#8305](https://github.com/microsoft/PowerToys/issues/8305)) is in development and will allow someone to use this again.
|
||||
- Find My Mouse utility added! Utilize the functionality to quickly locate the cursor on your displays! Learn more on our [Mouse Utility docs](https://aka.ms/PowerToysOverview_MouseUtilities).
|
||||
- Accessibility and minor UI improvements to the settings page. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- Added deep links to the Settings menus for various utilities within their respective editors. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- Settings improvements to improve clarity for various options. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- Improved settings window to adjust size and position as needed when multi-monitor conditions change. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
|
||||
- Settings and OOBE windows updated with Fluent UX! We hope you enjoy the new modern feel of the application menus as we align our product with upcoming Windows 11 interfaces. Special thanks to @niels9001 for driving the development of this UI, along with many thanks to the various community members who offered constant feedback and adjustments to make this a truly spectacular update!
|
||||
- Added button to settings which displays version history. Thanks @niels9001!
|
||||
- Signed PowerToysSetupCustomActions.dll.
|
||||
- Improved auto-update experience. Thanks @niels9001!
|
||||
- Aligned OOBE theme color with Settings theme color. Thanks @niels9001!
|
||||
- Adjusted labeling of "Restart as Administrator" button to "Restart PowerToys as Administrator" to avoid ambiguity in meaning. Thanks @niels9001!
|
||||
- Added colored icons to settings sidebar. Thanks @niels9001!
|
||||
- Fixed accessibility issue in OOBE where Microsoft Docs and PowerToys release notes links could not be navigated to via keyboard. Thanks @niels9001!
|
||||
- Fixed settings header alignment. Thanks @niels9001!
|
||||
- Fixed text under updates section to be visible when in light mode. Thanks @niels9001!
|
||||
- Updated "Learn More" text to be more descriptive. Thanks @niels9001!
|
||||
- Updated "Read more" text on updates to be more descriptive. Thanks @niels9001!
|
||||
- Added link to documentation in system tray. Thanks @BenConstable9!
|
||||
- Fixed error caused by file in use issues when installing PowerToys.
|
||||
- Fixed issue where opening settings from start menu didn't work when PowerToys was run as admin. Thanks @davidegiacometti!
|
||||
|
||||
### Awake
|
||||
**PowerToys Awake**
|
||||
- Screen reader improvements for accessibility.
|
||||
|
||||
- Added PowerToys Awake as option in translation bug template. Thanks @Aaron-Junker!
|
||||
- Adjusted description of inactive setting to improve distinguishing between the utility being disabled vs inactive. Thanks @niels9001!
|
||||
**Color Picker**
|
||||
- Color Picker's HEX format was changed to remove the `#` character. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
- Accessibility improvements for screen reader and UI to distinguish colors from the border when matching. Thanks [@niels9001](https://github.com/niels9001)!
|
||||
|
||||
### Color Picker
|
||||
**FancyZones**
|
||||
- Fixed Color Picker and OOBE windows from being snapped by FancyZones. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Fixed regression with layouts not being changed via shortcuts.
|
||||
- Fixed crashing issue with FancyZones editor.
|
||||
- Fixed zone layouts resetting after screen locking.
|
||||
- Accessibility improvements for screen reader in editor.
|
||||
|
||||
- Fixed bug where changing RGB values doesn't update color's HEX value. Thanks @martinchrzan!
|
||||
- Fixed accessibility issue with screen reader not announcing when "Copied to Clipboard" is activated.
|
||||
- Fixed accessibility issue where user could not hover the content of the info icon using a mouse. Thanks @niels9001!
|
||||
- Fixed color picker format order not being accessible via keyboard. Thanks @niels9001!
|
||||
- Fixed accessibility issue where screen reader announces incorrect name for "Editor color format" button and not announcing "Toggle switch" button at all. Thanks @niels9001!
|
||||
**Keyboard Manager**
|
||||
- Fixed crashing issue when the editor is opened at high zoom on 4k monitors.
|
||||
|
||||
### FancyZones
|
||||
**PowerRename**
|
||||
- New UI update! We hope you enjoy the modern experience and take advantage of new tool-tips to describe common regular expressions and text/file formatting. Thanks to [@niels9001](https://github.com/niels9001) for all the support on this redesign!
|
||||
|
||||
- Adjusted "Save and apply" editor button to adjust with text size for localizations. Thanks @niels9001!
|
||||
- Fixed "Create new layout" button visibility when in high contrast mode. Thanks @niels9001!
|
||||
- Fixed scaling quirks related to editor UI. Thanks @niels9001!
|
||||
- Fixed editor crashing when double clicking the "edit layout" button.
|
||||
- Fixed issue with editor crashing immediately after displaying zones.
|
||||
- Fixed bug when navigating editor options via keyboard where pressing enter on unselected Canvas option launches Grid editor instead.
|
||||
- Fixed issue where FancyZones would not restore Console Applications.
|
||||
- Fixed Canvas editor and Grid editor window heights. Thanks @niels9001!
|
||||
- Fixed crash due to KERNELBASE.dll.
|
||||
- Fixed FancyZone icons to be smoother at higher DPI settings. Thanks @niels9001!
|
||||
- Fixed crash when changing between zone layouts.
|
||||
- Fixed regression where FancyZones does not resize windows on layout change.
|
||||
- Adjusted layout settings to reset shortcut key after canceling changes on a particular layout.
|
||||
**PowerToys Run**
|
||||
- Windows Terminal Plugin added. Open shells through Windows Terminal via `_` activation command by default. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Added environment variables to Folder plugin search. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Fixed certain schemas that were overwritten with HTTPS. Thanks [@franky920920](https://github.com/franky920920)!
|
||||
- Fixed issue with program plugin getting caught in infinite loops as certain file paths are recursively searched.
|
||||
|
||||
### File Explorer add-ons
|
||||
|
||||
- Fixed issue where markdown files were still previewed even when "Enable Markdown" was turned off.
|
||||
|
||||
### Image Resizer
|
||||
|
||||
- Added warning that GIF files with animations may not correctly resize if the encoding used for the files is incompatible.
|
||||
|
||||
### Keyboard Manager
|
||||
|
||||
- Improved UI for KBM re-mappings list. Thanks @niels9001!
|
||||
|
||||
### PowerRename
|
||||
|
||||
- Expanding a plugin option in settings can now be toggled. Thanks @niels9001!
|
||||
- Fixed race condition causing PowerRename to crash File Explorer. Thanks @ianjoneill!
|
||||
|
||||
### PowerToys Run
|
||||
|
||||
- Fixed lag caused from PowerToys running in background and invoking Alt-Tab.
|
||||
- Resolved file not found exception when loading "System.Windows.Controls.Ribbon".
|
||||
- Fixed null reference exception crash.
|
||||
- Fixed registry plugin load crash.
|
||||
- Fixed unauthorized access exception crash when setting registry keys for the utility.
|
||||
- Added search for Plugin Manager. Thanks @davidegiacometti!
|
||||
- Fixed VSCode workspace plugin not working. Thanks @BenConstable9!
|
||||
|
||||
### Video Conference Mute
|
||||
|
||||
- Fixed toolbar top right vertical offset to allow users to close other app windows.
|
||||
- Fixed compatibility issues for certain systems when compiling from source.
|
||||
- Fixed toolbox from persisting on screen.
|
||||
- Fixed microphone un-muting when changing Video Conference Mute toolbar position.
|
||||
- Added Video Conference Mute to OOBE.
|
||||
**Video Conference Mute**
|
||||
- VCM added to stable releases of PowerToys!
|
||||
|
||||
## Community contributions
|
||||
|
||||
We'd like to directly mention certain contributors (in alphabetical order) for their continued community support this month and helping directly make PowerToys a better piece of software.
|
||||
|
||||
[@Aaron-Junker](https://github.com/Aaron-Junker), [@BenConstable9](https://github.com/BenConstable9), [@davidegiacometti](https://github.com/davidegiacometti), [@dchristensen](https://github.com/dchristensen), [@dend](https://github.com/dend), [@franky920920](https://github.com/franky920920), [@htcfreek](https://github.com/htcfreek), [@ianjoneill](https://github.com/ianjoneill), [@jakeoeding](https://github.com/jakeoeding), [@Jay-o-Way](https://github.com/Jay-o-Way), [@jsoref](https://github.com/jsoref), [@martinchrzan](https://github.com/martinchrzan), [@niels9001](https://github.com/niels9001) and [@royvou](https://github.com/royvou)
|
||||
[@Aaron-Junker](https://github.com/Aaron-Junker), [@davidegiacometti](https://github.com/davidegiacometti), [@franky920920](https://github.com/franky920920), [@htcfreek](https://github.com/htcfreek), [@Jay-o-Way](https://github.com/Jay-o-Way), [@martinchrzan](https://github.com/martinchrzan), [@niels9001](https://github.com/niels9001), [@pritudev](https://github.com/pritudev), and [@TobiasSekan](https://github.com/TobiasSekan)
|
||||
|
||||
#### What is being planned for v0.47
|
||||
#### What is being planned for v0.51
|
||||
|
||||
For [v0.47][github-next-release-work], we are planning to work on:
|
||||
For [v0.51][github-next-release-work], we are planning to work on:
|
||||
|
||||
- Initial development of Always on Top utility to allow users to persist desired windows in the foreground of their displays
|
||||
- We are working to heavily reduce / remove the UAC prompt over the next few releases on install. This is a big shift so it is spanning multiple releases so we can isolate issues if they do occur. Work is tracked in [#10126](https://github.com/microsoft/PowerToys/issues/10126)
|
||||
- UI/UX investigations to adopt WinUI and improve accessibility
|
||||
- Stability and bug fixes
|
||||
- Upgrading PowerToys Run to .NET 5
|
||||
- Preliminary UI/UX investigations to adopt WinUI and improve accessibility
|
||||
- Configuring Shortcut guide to re-enable long `Win` key press to activate
|
||||
- Testing PDF preview functionality for File Explorer add-ons
|
||||
- Planning for new utilities and enhancements
|
||||
- Update the PowerToys Build Pipeline to allow .NET 5 integration
|
||||
|
||||
## PowerToys Community
|
||||
|
||||
|
@ -208,8 +165,7 @@ The application logs basic telemetry. Our Telemetry Data page (Coming Soon) has
|
|||
[privacy-link]: http://go.microsoft.com/fwlink/?LinkId=521839
|
||||
[vidConfOverview]: https://aka.ms/PowerToysOverview_VideoConference
|
||||
[loc-bug]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=translation_issue.md&title=
|
||||
[usingPowerToys-docs-link]: https://docs.microsoft.com/windows/powertoys/
|
||||
[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%2F21
|
||||
[github-prerelease-link]: https://github.com/microsoft/PowerToys/releases/tag/v0.46.0
|
||||
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F26
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
# Support
|
||||
|
||||
|
||||
## How to use Microsoft PowerToys
|
||||
|
||||
For more info on [PowerToys overviews and how to use the utilities][usingPowerToys-docs-link], or any other tools and resources for [Windows development environments](https://docs.microsoft.com/windows/dev-environment/overview), head over to [docs.microsoft.com][usingPowerToys-docs-link]!
|
||||
|
||||
## How to file issues and get help
|
||||
|
||||
This project uses [GitHub Issues][gh-issue] to [track bugs][gh-bug] and [feature requests][gh-feature]. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or
|
||||
|
@ -15,4 +20,5 @@ Support for PowerToys is limited to the resources listed above.
|
|||
[gh-bug]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=Issue-Bug&template=bug_report.md&title=
|
||||
[gh-feature]: https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=feature_request.md&title=
|
||||
[wiki]: https://github.com/microsoft/PowerToys/wiki
|
||||
[contributor]: https://github.com/microsoft/PowerToys/blob/master/CONTRIBUTING.md
|
||||
[contributor]: https://github.com/microsoft/PowerToys/blob/main/CONTRIBUTING.md
|
||||
[usingPowerToys-docs-link]: https://aka.ms/powertoys-docs
|
||||
|
|
6
Solution.props
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<GeneratedFilesDir>$(IntDir)Generated Files\</GeneratedFilesDir>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -4,43 +4,44 @@
|
|||
|----------|----------|
|
||||
| getpowertoys | ms-windows-store://pdp/?productid=XP89DCGQ3K6VLD |
|
||||
| installpowertoys | https://github.com/microsoft/PowerToys/releases/latest |
|
||||
| powertoys-license | https://github.com/microsoft/PowerToys/blob/master/LICENSE |
|
||||
| powertoys-license | https://github.com/microsoft/PowerToys/blob/main/LICENSE |
|
||||
| powertoys | https://github.com/microsoft/PowerToys |
|
||||
| PowerToysAppCompat | https://github.com/microsoft/PowerToys/wiki/Application-Compatibility |
|
||||
| powerToysCannotRemapKeys | https://docs.microsoft.com/windows/powertoys/keyboard-manager#keys-that-cannot-be-remapped |
|
||||
| powerToysColorPickerImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/ColorPicker_small.png |
|
||||
| powerToysColorPickerSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/ColorPicker_large.png |
|
||||
| powerToysColorPickerSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/ColorPicker_large.png |
|
||||
| powertoysDetectedElevatedHelp | https://docs.microsoft.com/windows/powertoys/administrator |
|
||||
| powertoys-docs | https://docs.microsoft.com/windows/powertoys/?WT.mc_id=twitter-0000-docsmsft |
|
||||
| powerToysFancyZoneImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/FancyZones_small.png |
|
||||
| powerToysFancyZoneSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/FancyZones_large.png |
|
||||
| powerToysFancyZoneSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/FancyZones_large.png |
|
||||
| powerToysGiveFeedback | https://github.com/microsoft/PowerToys/issues |
|
||||
| powerToysImageResizerImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/ImageResizer_small.png |
|
||||
| powerToysImageResizerSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/ImageResizer_large.png |
|
||||
| powerToysImageResizerSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/ImageResizer_large.png |
|
||||
| powerToysKBMImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/KBM_small.png |
|
||||
| powerToysKBMSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/KBM_large.png |
|
||||
| powerToysKBMSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/KBM_large.png |
|
||||
| PowerToysOverview | https://docs.microsoft.com/windows/powertoys/ |
|
||||
| PowerToysOverview_ColorPicker | https://docs.microsoft.com/windows/powertoys/color-picker |
|
||||
| PowerToysOverview_FancyZones | https://docs.microsoft.com/windows/powertoys/fancyzones |
|
||||
| PowerToysOverview_FileExplorerAddOns | https://docs.microsoft.com/windows/powertoys/file-explorer |
|
||||
| PowerToysOverview_ImageResizer | https://docs.microsoft.com/windows/powertoys/image-resizer |
|
||||
| PowerToysOverview_KeyboardManager | https://docs.microsoft.com/windows/powertoys/keyboard-manager |
|
||||
| PowerToysOverview_MouseUtilities | https://docs.microsoft.com/windows/powertoys/mouse-utilities |
|
||||
| PowerToysOverview_PowerRename | https://docs.microsoft.com/windows/powertoys/powerrename |
|
||||
| PowerToysOverview_PowerToysRun | https://docs.microsoft.com/windows/powertoys/run |
|
||||
| PowerToysOverview_ShortcutGuide | https://docs.microsoft.com/windows/powertoys/shortcut-guide |
|
||||
| PowerToysOverview_VideoConference | https://docs.microsoft.com/windows/powertoys/video-conference-mute |
|
||||
| powerToysPowerLauncherImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerLauncher_small.png |
|
||||
| powerToysPowerLauncherSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/PowerLauncher_large.png |
|
||||
| powerToysPowerLauncherSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PowerLauncher_large.png |
|
||||
| powerToysPowerPreviewImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerPreview_small.png |
|
||||
| powerToysPowerPreviewSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/PowerPreview_large.png |
|
||||
| powerToysPowerPreviewSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PowerPreview_large.png |
|
||||
| powerToysPowerRenameImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PowerRename_small.png |
|
||||
| powerToysPowerRenameSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/PowerRename_large.png |
|
||||
| powerToysPowerRenameSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PowerRename_large.png |
|
||||
| powerToysPTImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/PT_small.png |
|
||||
| powerToysPTSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/PT_large.png |
|
||||
| powerToysPTSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/PT_large.png |
|
||||
| powerToysReportBug | https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=Issue-Bug%2CTriage-Needed&template=bug_report.yml&title= |
|
||||
| powerToysRequestFeature | https://github.com/microsoft/PowerToys/issues/new?assignees=&labels=&template=feature_request.md&title= |
|
||||
| powerToysShortcutGuideImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/ShortcutGuide_small.png |
|
||||
| powerToysShortcutGuideSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/master/doc/images/overview/ShortcutGuide_large.png |
|
||||
| powerToysShortcutGuideSettingImage | https://raw.githubusercontent.com/microsoft/PowerToys/main/doc/images/overview/ShortcutGuide_large.png |
|
||||
| powerToysVideoConferenceImageSmall | https://github.com/microsoft/PowerToys/wiki/images/overview/VideoConference_small.png |
|
||||
| powerToysVideoConferenceSettingImage | https://github.com/microsoft/PowerToys/wiki/images/overview/VideoConference_large.png |
|
||||
| powertoyswiki | https://github.com/microsoft/PowerToys/wiki |
|
||||
|
|
30
doc/devdocs/embedded-msix.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
# How to integrate new MSIX module with PowerToys Settings and WiX installer
|
||||
[`issue_11705_with_example` branch](https://github.com/microsoft/PowerToys/tree/issue_11705_with_example) contains HelloWorld UWP C# MSIX application which reads its module settings and is installed along PowerToys.
|
||||
|
||||
## Steps
|
||||
- uncomment everything near "TODO: Use to activate embedded MSIX" comments
|
||||
- build PowerToys solution
|
||||
- deploy HelloModule module and sign it with a self-signed certificate (don't forget to put it into a trusted store)
|
||||
- build PowerToysSetup solution and install it
|
||||
|
||||
Type HelloModule into start search and observe that it was installed:
|
||||
|
||||
<img src="../images/msix/hello-module-start.png">
|
||||
|
||||
Open PowerToys settings and change the stub setting to something:
|
||||
|
||||
<img src="../images/msix/hello-module-settings-page.png">
|
||||
|
||||
Open HelloModule:
|
||||
|
||||
<img src="../images/msix/hello-module-screen.png">
|
||||
|
||||
First time you press "Load Settings", it'll detect that it doesn't have permissions to access local file system and open its system settings window, toggle it there:
|
||||
|
||||
<img src="../images/msix/hello-module-app-permissions.png">
|
||||
|
||||
(it's a known uwp limitation, see https://stackoverflow.com/a/53533414/657390)
|
||||
|
||||
HelloModule will close then, restart it, press "Load Settings" and you should see that the application was able to load the setting string which was set by the settings app:
|
||||
|
||||
<img src="../images/msix/hello-module-loaded-settings.png">
|
|
@ -12,11 +12,11 @@
|
|||
5. [Enabling localized MSI for a new project](#enabling-localized-msi-for-a-new-project)
|
||||
|
||||
## Localization on the pipeline (CDPX)
|
||||
[The localization step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L45-L52) is run on the pipeline before the solution is built. This step runs the [build-localization](https://github.com/microsoft/PowerToys/blob/master/.pipelines/build-localization.cmd) script, which generates resx files for all the projects with localization enabled using the `Localization.XLoc` package.
|
||||
[The localization step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L45-L52) is run on the pipeline before the solution is built. This step runs the [build-localization](https://github.com/microsoft/PowerToys/blob/main/.pipelines/build-localization.cmd) script, which generates resx files for all the projects with localization enabled using the `Localization.XLoc` package.
|
||||
|
||||
The [`Localization.XLoc`](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L24-L25) tool is run on the repo root, and it checks for all occurrences of `LocProject.json`. Each localized project has a `LocProject.json` file in the project root, which contains the location of the English resx file, list of languages for localization, and the output path where the localized resx files are to be copied to. In addition to this, some other parameters can be set, such as whether the language ID should be added as a folder in the file path or in the file name. When the CDPX pipeline is run, the localization team is notified of changes in the English resx files. For each project with localization enabled, a `loc` folder (see [this](https://github.com/microsoft/PowerToys/tree/master/src/modules/launcher/Microsoft.Launcher/loc) for example) is created in the same directory as the `LocProject.json` file. The folder contains language specific folders which in turn have a nested folder path equivalent to `OutputPath` in the `LocProject.json`. Each of these folders contain one `lcl` file. The `lcl` files contain the English resources along with their translation for that language. These are described in more detail [here](#lcl-files). Once the `.resx` files are generated, they will be used during the `Build PowerToys` step for localized versions of the modules.
|
||||
The [`Localization.XLoc`](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L24-L25) tool is run on the repo root, and it checks for all occurrences of `LocProject.json`. Each localized project has a `LocProject.json` file in the project root, which contains the location of the English resx file, list of languages for localization, and the output path where the localized resx files are to be copied to. In addition to this, some other parameters can be set, such as whether the language ID should be added as a folder in the file path or in the file name. When the CDPX pipeline is run, the localization team is notified of changes in the English resx files. For each project with localization enabled, a `loc` folder (see [this](https://github.com/microsoft/PowerToys/tree/main/src/modules/launcher/Microsoft.Launcher/loc) for example) is created in the same directory as the `LocProject.json` file. The folder contains language specific folders which in turn have a nested folder path equivalent to `OutputPath` in the `LocProject.json`. Each of these folders contain one `lcl` file. The `lcl` files contain the English resources along with their translation for that language. These are described in more detail [here](#lcl-files). Once the `.resx` files are generated, they will be used during the `Build PowerToys` step for localized versions of the modules.
|
||||
|
||||
Since the localization script requires certain nuget packages, the [`restore-localization`](https://github.com/microsoft/PowerToys/blob/master/.pipelines/restore-localization.cmd) script is run before running `build-localization` to install all the required packages. This script must [run in the `restore` step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L37-L39) of pipeline because [the host is network isolated](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipelinhttps://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipeline?anchor=overview) at the `build` step. The [Toolset package source](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L23) is used for this.
|
||||
Since the localization script requires certain nuget packages, the [`restore-localization`](https://github.com/microsoft/PowerToys/blob/main/.pipelines/restore-localization.cmd) script is run before running `build-localization` to install all the required packages. This script must [run in the `restore` step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L37-L39) of pipeline because [the host is network isolated](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipelinhttps://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipeline?anchor=overview) at the `build` step. The [Toolset package source](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L23) is used for this.
|
||||
|
||||
The process and variables that can be tweaked on the pipeline are described in more detail [here](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/290/Localization).
|
||||
|
||||
|
@ -31,7 +31,7 @@ UWP differs from this as it expects the resources to have the same Resources.res
|
|||
|
||||
For example, `path\en-us\Resources.resw` for English and `path\fr-fr\Resources.resw` for French.
|
||||
|
||||
Since the pipeline generates it in this format, [a script is run](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L29-L31) to move these resw files to the correct format expected by all UWP projects. Currently the only UWP project is [Microsoft.PowerToys.Settings.UI](https://github.com/microsoft/PowerToys/tree/master/src/core/Microsoft.PowerToys.Settings.UI). The script used for moving the resources can be [found here](https://github.com/microsoft/PowerToys/blob/master/tools/localization/move_uwp_resources.ps1). The equivalent full language IDs for each shortened language ID obtained from the pipeline has been hardcoded in the script.
|
||||
Since the pipeline generates it in this format, [a script is run](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L29-L31) to move these resw files to the correct format expected by all UWP projects. Currently the only UWP project is [Microsoft.PowerToys.Settings.UI](https://github.com/microsoft/PowerToys/tree/main/src/core/Microsoft.PowerToys.Settings.UI). The script used for moving the resources can be [found here](https://github.com/microsoft/PowerToys/blob/main/tools/localization/move_uwp_resources.ps1). The equivalent full language IDs for each shortened language ID obtained from the pipeline has been hardcoded in the script.
|
||||
|
||||
## Enabling localization on a new project
|
||||
To enable localization on a new project, the first step is to create a file `LocProject.json` in the project root.
|
||||
|
@ -58,7 +58,7 @@ The rest of the steps depend on the project type and are covered in the sections
|
|||
### C++
|
||||
C++ projects do not support `resx` files, and instead use `rc` files along with `resource.h` files. The CDPX pipeline however doesn't support localizing `rc` files and the other alternative they support is directly translating the resources from the binary which makes it harder to maintain resources. To avoid this, a custom script has been added which expects a resx file and converts the entries to an rc file with a string table and adds resource declarations to a resource.h file so that the resources can be compiled with the C++ project.
|
||||
|
||||
If you already have a .rc file, copy the string table to a separate txt file and run the [convert-stringtable-to-resx.ps1](https://github.com/microsoft/PowerToys/blob/master/tools/build/convert-stringtable-to-resx.ps1) script on it. This script is not very robust to input, and requires the data in a specific format, where `IDS_ResName L"ResourceValue"` and any number of spaces can be present in between. The script converts this file to the format expected by [`resgen`](https://docs.microsoft.com/en-us/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert), which will convert it to resx. The resource names are changed from all uppercase to title case, and the `IDS_` prefix is removed. Escape characters might have to be manually replaced, for example .rc files would have escaped double quotes as `""`, so this should be replaced with just `"` before converting to the resx files.
|
||||
If you already have a .rc file, copy the string table to a separate txt file and run the [convert-stringtable-to-resx.ps1](https://github.com/microsoft/PowerToys/blob/main/tools/build/convert-stringtable-to-resx.ps1) script on it. This script is not very robust to input, and requires the data in a specific format, where `IDS_ResName L"ResourceValue"` and any number of spaces can be present in between. The script converts this file to the format expected by [`resgen`](https://docs.microsoft.com/en-us/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert), which will convert it to resx. The resource names are changed from all uppercase to title case, and the `IDS_` prefix is removed. Escape characters might have to be manually replaced, for example .rc files would have escaped double quotes as `""`, so this should be replaced with just `"` before converting to the resx files.
|
||||
|
||||
After generating the resx file, rename the existing rc and h files to ProjName.base.rc and resource.base.h. In the rc file remove the string table which is to be localized and in the .h file remove all `#define`s corresponding to localized resources. In the vcxproj of the C++ project, add the following build event:
|
||||
```
|
||||
|
@ -67,7 +67,7 @@ After generating the resx file, rename the existing rc and h files to ProjName.b
|
|||
</Target>
|
||||
```
|
||||
|
||||
This event runs a script which generates a resource.h and ProjName.rc in the `Generated Files` folder using the strings in all the resx files along with the existing information in resource.base.h and ProjName.base.rc. The script can be found [here](https://github.com/microsoft/PowerToys/blob/master/tools/build/convert-resx-to-rc.ps1). The script uses [`resgen`](https://docs.microsoft.com/en-us/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert) to convert the resx file to a string table expected in the .rc file format. When the resources are added to the rc file the `IDS_` prefix is added and resource names are in upper case (as it was originally). Any occurrences of `"` in the string resource is escaped as `""` to prevent build errors. The string tables are added to the rc file in the following format:
|
||||
This event runs a script which generates a resource.h and ProjName.rc in the `Generated Files` folder using the strings in all the resx files along with the existing information in resource.base.h and ProjName.base.rc. The script can be found [here](https://github.com/microsoft/PowerToys/blob/main/tools/build/convert-resx-to-rc.ps1). The script uses [`resgen`](https://docs.microsoft.com/en-us/dotnet/framework/tools/resgen-exe-resource-file-generator#Convert) to convert the resx file to a string table expected in the .rc file format. When the resources are added to the rc file the `IDS_` prefix is added and resource names are in upper case (as it was originally). Any occurrences of `"` in the string resource is escaped as `""` to prevent build errors. The string tables are added to the rc file in the following format:
|
||||
```
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
@ -84,7 +84,7 @@ Since there is no API to identify the `AFX_TARG_*`, `LANG_*` or `SUBLANG_*` valu
|
|||
<None Include="Resources.resx" />
|
||||
```
|
||||
|
||||
Some rc/resource.h files might be used in multiple projects (for example, KBM). To ensure the projects build for these cases, the build event can be added to the entire directory so that the rc files are generated before any project is built. See [Directory.Build.targets](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/Directory.Build.targets) for an example.
|
||||
Some rc/resource.h files might be used in multiple projects (for example, KBM). To ensure the projects build for these cases, the build event can be added to the entire directory so that the rc files are generated before any project is built. See [Directory.Build.targets](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/Directory.Build.targets) for an example.
|
||||
|
||||
Check [this PR](https://github.com/microsoft/PowerToys/pull/6104) for an example for making these changes for a C++ project.
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ TODO
|
|||
#### [`ZoneSet.cpp`](/src/modules/fancyzones/lib/ZoneSet.cpp)
|
||||
TODO
|
||||
|
||||
#### [`ZoneWindow.cpp`](/src/modules/fancyzones/lib/ZoneWindow.cpp)
|
||||
#### [`WorkArea.cpp`](/src/modules/fancyzones/lib/WorkArea.cpp)
|
||||
TODO
|
||||
|
||||
## FancyZones Editor
|
||||
|
|
|
@ -66,10 +66,10 @@ This file contains documentation for all the methods involved in key/shortcut re
|
|||
[This method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp#L126-L176) was added to support a feature for converting the behavior of a key from behaving like a toggle (like Caps Lock/Num Lock) to a modifier (like Ctrl), such that when you hold Caps Lock it would behave as if Caps Lock was active, and when it was not pressed Caps Lock would be off. For Caps Lock this would be similar to behaving like Shift, but for Num Lock there is no existing key which can substitute for this. This was added while testing out remapping for the KBM PoC, but wasn't added as a feature since it wasn't a priority.
|
||||
|
||||
## Tests
|
||||
In order to test the remapping logic, a mocked keyboard input handler had to be created because otherwise the tests would process and send actual key events. For this the [`InputInterface`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/InputInterface.h) was made, and in production code the methods are implemented using [`SendInput`](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput) and [`GetAsyncKeyState`](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate). In addition to this, [`GetCurrentApplication`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L226-L268) had to be mocked so that app-specific remapping can be tested.
|
||||
In order to test the remapping logic, a mocked keyboard input handler had to be created because otherwise the tests would process and send actual key events. For this the [`InputInterface`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/InputInterface.h) was made, and in production code the methods are implemented using [`SendInput`](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput) and [`GetAsyncKeyState`](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate). In addition to this, [`GetCurrentApplication`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L226-L268) had to be mocked so that app-specific remapping can be tested.
|
||||
|
||||
### MockedInput
|
||||
The [`MockedInput`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/MockedInput.h) class uses a 256 size `bool` vector to store the key state for each key code. Identifying the foreground process is mocked by simply setting and getting a string value for the name of the current process.
|
||||
The [`MockedInput`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/MockedInput.h) class uses a 256 size `bool` vector to store the key state for each key code. Identifying the foreground process is mocked by simply setting and getting a string value for the name of the current process.
|
||||
|
||||
[To mock the `SendInput` method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/test/MockedInput.cpp#L10-L110), the steps for processing the input are as follows. This implementation is based on public documentation for SendInput and the behavior of key messages and keyboard hooks:
|
||||
- Iterate over all the inputs in the INPUT array argument
|
||||
|
@ -81,4 +81,4 @@ The [`MockedInput`](https://github.com/microsoft/PowerToys/blob/master/src/modul
|
|||
- For modifiers the behavior is slightly different as if the key state of the L/R version is modified, it should also modify the common version, and if a common version is released, it should release both the L and R versions.
|
||||
|
||||
### Tests for single key remaps and shortcut remaps
|
||||
Using the MockedInput handler, all the expected (and known) key scenarios that can occur for while pressing a [remapped key](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/SingleKeyRemappingTests.cpp) or [remapped shortcut](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/OSLevelShortcutRemappingTests.cpp) are tested. The foreground app behavior which is specific to app-specific shortcuts is tested [here](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/AppSpecificShortcutRemappingTests.cpp).
|
||||
Using the MockedInput handler, all the expected (and known) key scenarios that can occur for while pressing a [remapped key](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/SingleKeyRemappingTests.cpp) or [remapped shortcut](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/OSLevelShortcutRemappingTests.cpp) are tested. The foreground app behavior which is specific to app-specific shortcuts is tested [here](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/AppSpecificShortcutRemappingTests.cpp).
|
||||
|
|
|
@ -185,7 +185,7 @@ This method is used by [SharpKeys](https://github.com/randyrants/sharpkeys) and
|
|||
Using a driver approach has the benefit of not depending on precedence orders as KBM could always run before low level hooks, and it also has the benefit of differentiating between different keyboards, allowing [multi keyboard-specific remaps](https://github.com/microsoft/PowerToys/issues/1460). The disadvantages are however that any bug or crash could have system level consequences. [Interception](https://github.com/oblitum/Interception) is an open source driver that could be used for implementing this. The approach was deprioritized due to the potential side effects.
|
||||
|
||||
## Telemetry
|
||||
Keyboard Manager emits the following telemetry events (implemented in [trace.h](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/trace.h) and [trace.cpp](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/trace.cpp)):
|
||||
Keyboard Manager emits the following telemetry events (implemented in [trace.h](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/trace.h) and [trace.cpp](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/trace.cpp)):
|
||||
- **`KeyboardManager_EnableKeyboardManager`:** Logs a `boolean` value storing the KBM toggle state. It is logged whenever KBM is enabled or disabled (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/dllmain.cpp#L305-L316)).
|
||||
- **`KeyboardManager_KeyRemapCount`:** Logs the number of key to key and key to shortcut remaps (i.e. all the remaps on the Remap a key window). This gets logged on saving new settings in the Remap a key window (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L159-L163)).
|
||||
- **`KeyboardManager_OSLevelShortcutRemapCount`:** Logs the number of global shortcut to shortcut and shortcut to key remaps. This gets logged on saving new settings in the Remap a shortcut window (emitted [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/LoadingAndSavingRemappingHelper.cpp#L220)).
|
||||
|
|
|
@ -17,7 +17,7 @@ This project contains any code that is to be shared between the backend and UI p
|
|||
1. [Foreground App Detection](#Foreground-App-Detection)
|
||||
|
||||
## KeyboardManagerState
|
||||
[This class](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/KeyboardManagerState.cpp) stores all the data related to remappings and is also used in the sense of a View Model as it used to communicate common data that is shared between the KBM UI and the backend. They are accessed on the UI controls using static class members of `SingleKeyRemapControl` and `ShortcutControl`.
|
||||
[This class](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/KeyboardManagerState.cpp) stores all the data related to remappings and is also used in the sense of a View Model as it used to communicate common data that is shared between the KBM UI and the backend. They are accessed on the UI controls using static class members of `SingleKeyRemapControl` and `ShortcutControl`.
|
||||
|
||||
### UI States
|
||||
[UI states](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyboardManagerState.h#L27-L42) are used to keep track in which step of the UI flow is the user at, such as which Remap window they are on, or if they have one of the Type windows open. This is required because the hook needs to suppress input and update UI in some cases, and in some cases remappings have to be disabled altogether.
|
||||
|
@ -37,12 +37,12 @@ The [`SaveConfigToFile`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a
|
|||
To prevent the UI thread and low level hook thread from concurrently accessing the remap tables we use an [`atomic bool` variable](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyboardManagerState.h#L91-L92), which is set to `true` while the tables are getting updated. When this is `true` the hook will skip all remappings. Use of mutexes in the hook were removed to prevent re-entrant mutex bugs.
|
||||
|
||||
## KeyDelay
|
||||
[This class](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/KeyDelay.cpp) implements a queue based approach for processing key events and based on the time difference between key down and key up events [executes separate methods for `ShortPress`, `LongPress` or `LongPressReleased`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.h#L69-L72). The class is used for the hold Enter/Esc functionality required for making the Type window accessible and prevent keyboard traps (see [this](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp#L273-L292) for an example of it's usage). The `KeyEvents` are added to the queue from the hook thread of KBM, and a separate [`DelayThread`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.cpp#L142-L166) is used to process the key events by checking the `time` member in the key event. The thresholds for short vs long press and hold wait timeouts are `static` constants, but if the module is extended for other purposes these could be made into arguments.
|
||||
[This class](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/KeyDelay.cpp) implements a queue based approach for processing key events and based on the time difference between key down and key up events [executes separate methods for `ShortPress`, `LongPress` or `LongPressReleased`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.h#L69-L72). The class is used for the hold Enter/Esc functionality required for making the Type window accessible and prevent keyboard traps (see [this](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp#L273-L292) for an example of it's usage). The `KeyEvents` are added to the queue from the hook thread of KBM, and a separate [`DelayThread`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.cpp#L142-L166) is used to process the key events by checking the `time` member in the key event. The thresholds for short vs long press and hold wait timeouts are `static` constants, but if the module is extended for other purposes these could be made into arguments.
|
||||
|
||||
**Note:** [Deletion of the `KeyDelay`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/KeyDelay.cpp#L4-L12) object should never be called from the `DelayThread` i.e. from within one of the 3 handlers, as it can re-enter the mutex and would lead to a deadlock. This can be avoided by either deleting it on a separate thread or as done in the KBM UI, on the dispatcher thread. See [this PR](https://github.com/microsoft/PowerToys/pull/6959#issue-496583547) for more details on this issue.
|
||||
|
||||
## Shortcut and RemapShortcut classes
|
||||
The [`Shortcut` class](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/Shortcut.h) is a data structure for storing key combinations which are valid shortcuts and it contains several methods which are used for shortcut specific operations. [`RemapShortcut`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/RemapShortcut.h) consists of a shortcut/key union (`std::variant`), along with other boolean flags which are required on the hook side for storing any relevant keyboard states mid-execution.
|
||||
The [`Shortcut` class](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/Shortcut.h) is a data structure for storing key combinations which are valid shortcuts and it contains several methods which are used for shortcut specific operations. [`RemapShortcut`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/RemapShortcut.h) consists of a shortcut/key union (`std::variant`), along with other boolean flags which are required on the hook side for storing any relevant keyboard states mid-execution.
|
||||
|
||||
### IsKeyboardStateClearExceptShortcut
|
||||
[This method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L665-L813) is used by the `HandleShortcutRemapEvent` to check if any other keys on the keyboard have been pressed apart from the keys in the shortcut. This is required because shortcut to shortcut remaps should not be applied if the shortcut is pressed with other keys. The method iterates over all the possible key codes, except any keys that are considered reserved, unassigned, OEM-specific or undefined, as well as mouse buttons (see list [here](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L628-L663)).
|
||||
|
@ -51,13 +51,13 @@ The [`Shortcut` class](https://github.com/microsoft/PowerToys/blob/master/src/mo
|
|||
[This method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Shortcut.cpp#L517-L614) uses `GetVirtualKeyState` (internally calls `GetAsyncKeyState` in production code), to check if all the modifiers of the current shortcut are being pressed. Since Win doesn't have a non-L/R key code we check this by checking both LWIN and RWIN.
|
||||
|
||||
### Tests
|
||||
Tests for some methods in the `Shortcut` class can be found [here](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/ShortcutTests.cpp).
|
||||
Tests for some methods in the `Shortcut` class can be found [here](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/ShortcutTests.cpp).
|
||||
|
||||
## Helpers
|
||||
[This namespace](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/common/Helpers.cpp) has any methods which are used across either UI or the backend which aren't specific to either. Some of these methods have tests [here](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/SetKeyEventTests.cpp).
|
||||
[This namespace](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/common/Helpers.cpp) has any methods which are used across either UI or the backend which aren't specific to either. Some of these methods have tests [here](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/SetKeyEventTests.cpp).
|
||||
|
||||
### Foreground App Detection
|
||||
[`GetCurrentApplication`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L226-L268) is used for detecting the foreground process for App-specific shortcuts. The logic is very similar to that used for FZ's app exception feature, involving `GetForegroundWindow` and `get_process_path`. The one additional case which has been added is for full-screen UWP apps, where the above method fails and returns `ApplicationFrameHost.exe`. The [`GetFullscreenUWPWindowHandle`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/common/Helpers.cpp#L210-L224) uses `GetGUIThreadInfo` API to find the window linked to the GUI thread. This logic is based on [this stackoverflow answer](https://stackoverflow.com/questions/39702704/connecting-uwp-apps-hosted-by-applicationframehost-to-their-real-processes/55353165#55353165).
|
||||
|
||||
**Note:** The [`GetForegroundProcess` method](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/dll/Input.cpp#L17-L21) performs string allocation in a weird way because of exceptions that were occurring while running tests as a result of memory being allocated or deallocated across dll boundaries. Here's the comment from the PR where this was added
|
||||
> To make app-specific logic test-able, a GetForegroundProcess was added to the input interface which internally calls GetCurrentApplication. This allows us to mock this method in the test project by just setting some process name as the foreground process for that function. When I set this to just return the string name, it would goes runtime errors on the test project in debug_heap with `__acrt_first_block == header`. Based on [this stackoverflow answer](https://stackoverflow.com/a/35311928), this would happen if allocation happens in one dll's code space and deallocation happens in another. One way to avoid this is to change both the projects to MD (multi threaded dll) instead of MT(multi threaded), however that results in many compile-time errors since all the PT projects are configured as MT. To solve this, the GetForegroundProcess was rewritten such that its argument is the output variable, and we allocate memory for that string within the AppSpecificHandler method rather than in that function.
|
||||
> To make app-specific logic test-able, a GetForegroundProcess was added to the input interface which internally calls GetCurrentApplication. This allows us to mock this method in the test project by just setting some process name as the foreground process for that function. When I set this to just return the string name, it would goes runtime errors on the test project in debug_heap with `__acrt_first_block == header`. Based on [this stackoverflow answer](https://stackoverflow.com/a/35311928), this would happen if allocation happens in one dll's code space and deallocation happens in another. One way to avoid this is to change both the projects to MD (multi threaded dll) instead of MT(multi threaded), however that results in many compile-time errors since all the PT projects are configured as MT. To solve this, the GetForegroundProcess was rewritten such that its argument is the output variable, and we allocate memory for that string within the AppSpecificHandler method rather than in that function.
|
||||
|
|
|
@ -24,7 +24,7 @@ The KBM UI is implemented as a C++ XAML Island, but all the controls are impleme
|
|||
|
||||
The windows are [created as C++ windows](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L128-L140) and the window sizes are set to default by [scaling them as per DPI](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L120-L126) using the `DPIAware::Convert` API from common lib. Since the UI is launched on a new thread, the window may not be in the foreground, so [we call `SetForegroundWindow`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L146-L150).
|
||||
|
||||
`DesktopWindowXamlSource` has to be declared and [it is initialized](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L159-L162) using the [`XamlBridge`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/ui/XamlBridge.cpp), and [a second window handle](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L161-L162) is generated for the internal Xaml Island window. Most of the code was based on the [Xaml Island Sample](https://github.com/microsoft/Xaml-Islands-Samples/blob/master/Samples/Win32/SampleCppApp/XamlBridge.cpp). The `XamlBridge` class contains code which handles initializing the Xaml Island containers as well as handling special messages like keyboard navigation, and focus between islands and between the C++ window and the island. It also has methods for clearing the xaml islands and closing the window.
|
||||
`DesktopWindowXamlSource` has to be declared and [it is initialized](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L159-L162) using the [`XamlBridge`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/XamlBridge.cpp), and [a second window handle](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L161-L162) is generated for the internal Xaml Island window. Most of the code was based on the [Xaml Island Sample](https://github.com/microsoft/Xaml-Islands-Samples/blob/master/Samples/Win32/SampleCppApp/XamlBridge.cpp). The `XamlBridge` class contains code which handles initializing the Xaml Island containers as well as handling special messages like keyboard navigation, and focus between islands and between the C++ window and the island. It also has methods for clearing the xaml islands and closing the window.
|
||||
|
||||
Once the UI controls are created, the parent container is set as the content for the `DesktopWindowXamlSource` and the `XamlBridge.MessageLoop` is executed. Messages are processed by the C++ window handler like [`EditKeyboardWindowProc`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L364-L404). The general structure we use for this is, for any `WM_PAINT` or `WM_SIZE` message we resize the Xaml Island window. For `WM_GETMINMAXINFO` we set minimum widths so that the window cannot be resized beyond a minimum height and width. This is done to prevent the WinUI elements from overlapping and getting cropped. If it is neither of these cases we send the message to the [`XamlBridge.MessageHandler`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/XamlBridge.cpp#L291-L301) which handles Destroy, Activation and Focus. If `WM_NCDESTROY` is received when the `XamlBridge` is `nullptr`, the window thread is terminated.
|
||||
|
||||
|
@ -41,7 +41,7 @@ To access the brushes available on C# Xaml, it has to be done with the `Resource
|
|||
`primaryButton.Background(Windows::UI::Xaml::Application::Current().Resources().Lookup(box_value(L"SystemControlBackgroundBaseMediumLowBrush")).as<Windows::UI::Xaml::Media::SolidColorBrush>());`
|
||||
|
||||
## UI Structure
|
||||
The KBM UI consists of a [`Grid` with several columns](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L200-L218). Rows are added dynamically when [the add button is pressed](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L305-L309). [A vector of vector of unique pointers to `SingleKeyRemapControl`/`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L248-L249) is created so that references to the UI components and their data are not lost until the window is closed. [`SingleKeyRemapControl`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp) is the UI class for each row of the Remap keys table, and [`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/ui/ShortcutControl.cpp) is the UI class for each row of the Remap shortcuts table. [`KeyDropDownControl`](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp) is used for handling the ComboBox operations. Each of these two classes [have vectors of unique pointers to the `KeyDropDownControl` objects](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.h#L44-L45) so that references to the objects are active until the control is deleted.
|
||||
The KBM UI consists of a [`Grid` with several columns](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L200-L218). Rows are added dynamically when [the add button is pressed](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L305-L309). [A vector of vector of unique pointers to `SingleKeyRemapControl`/`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L248-L249) is created so that references to the UI components and their data are not lost until the window is closed. [`SingleKeyRemapControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp) is the UI class for each row of the Remap keys table, and [`ShortcutControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/ShortcutControl.cpp) is the UI class for each row of the Remap shortcuts table. [`KeyDropDownControl`](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp) is used for handling the ComboBox operations. Each of these two classes [have vectors of unique pointers to the `KeyDropDownControl` objects](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/ShortcutControl.h#L44-L45) so that references to the objects are active until the control is deleted.
|
||||
|
||||
When the UI windows are activated the `KeyboardManagerState` object [sets the `UIState` variable](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp#L251-L252) which is used for distinguishing if the UI is up from the keyboard hook thread. The [states are also updated](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp#L53) on opening and closing the Type window.
|
||||
|
||||
|
@ -89,7 +89,7 @@ On making a selection in the drop down, [the selection handler](https://github.c
|
|||
- Conflicting modifier previously remapped (Ctrl->A and Ctrl(left)->B, since Ctrl also includes Ctrl(left))
|
||||
If the selection is found to be valid, the `singleKeyRemapBuffer` is updated accordingly.
|
||||
For handling `Shortcut` and key in the remap buffer for the right column, we use `std::variant`, which allows us to store either of the two types and check which one of them is present in the buffer by using the `index` method.
|
||||
[`ValidateAndUpdateKeyBufferElement`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/BufferValidationHelpers.cpp#L8-L66) does not reference any UI components and instead takes all the relevant data as arguments. This method [has tests](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/BufferValidationTests.cpp) which covers all the cases that could arise from making selections on the UI.
|
||||
[`ValidateAndUpdateKeyBufferElement`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/BufferValidationHelpers.cpp#L8-L66) does not reference any UI components and instead takes all the relevant data as arguments. This method [has tests](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/BufferValidationTests.cpp) which covers all the cases that could arise from making selections on the UI.
|
||||
|
||||
### Shortcut ComboBox Selection Handler
|
||||
On making a selection in the drop down, [the selection handler](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp#L215-L295) validates the input with the buffer from the other column and other rows. Error messages are shown using flyouts if the selection is not considered valid and the drop down and buffer for that entry are reset to empty selection.
|
||||
|
@ -115,7 +115,7 @@ Unlike the Single Key handler, there is a different set of errors that can occur
|
|||
- Conflicting shortcut previously remapped for same target app (Ctrl+A->B and Ctrl(left)+A->C, since Ctrl also includes Ctrl(left))
|
||||
- Illegal shortcut remaps like Win+L or Ctrl+Alt+Del (since these cannot be remapped using LL hooks)
|
||||
|
||||
[`ValidateShortcutBufferElement`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/BufferValidationHelpers.cpp#L68-L304) does not reference any UI components and instead takes all the relevant data as arguments. This method [has tests](https://github.com/microsoft/PowerToys/blob/master/src/modules/keyboardmanager/test/BufferValidationTests.cpp) which covers all the cases that could arise from making selections on the UI.
|
||||
[`ValidateShortcutBufferElement`](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/BufferValidationHelpers.cpp#L68-L304) does not reference any UI components and instead takes all the relevant data as arguments. This method [has tests](https://github.com/microsoft/PowerToys/blob/main/src/modules/keyboardmanager/test/BufferValidationTests.cpp) which covers all the cases that could arise from making selections on the UI.
|
||||
|
||||
**Note:** After updating the buffer we have [code to handle a special case](https://github.com/microsoft/PowerToys/blob/b80578b1b9a4b24c9945bddac33c771204280107/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp#L269-L279), which was required to prevent scenarios where a drop down can get deleted but the corresponding `KeyDropDownControl` object isn't deleted. The code checks if the drop down is still linked to the parent and accordingly deletes the `KeyDropDownControl` object from the vector.
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
|
||||
## Debugging Prerequisite
|
||||
Setup development environment for PowerToys by following instruction [here.](https://github.com/microsoft/PowerToys/tree/master/doc/devdocs#prerequisites-for-compiling-powertoys)
|
||||
Setup development environment for PowerToys by following instruction [here.](https://github.com/microsoft/PowerToys/tree/main/doc/devdocs#prerequisites-for-compiling-powertoys)
|
||||
|
||||
## Direct debugging
|
||||
This approach is used to test UI, plugins, and core `PowerToys Run` functionality. This **cannot** be used to test `PowerToys Run` settings. The approach is significantly faster compared to `Debugging with runner`, as it requires compiling projects relevant to `PowerToys Run`. Please follow the steps below for direct debugging.
|
||||
|
|
161
doc/devdocs/modules/launcher/plugins/windowssettings.md
Normal file
|
@ -0,0 +1,161 @@
|
|||
# Windows Settings Plugin
|
||||
|
||||
The Windows settings Plugin allows users to search the Windows settings.
|
||||
|
||||
## Special functions (differ from the regular functions)
|
||||
|
||||
* Support modern Windows settings (Windows 10+)
|
||||
* Support legacy Windows settings (Windows 7, 8.1)
|
||||
* Support extra programs for setting (like ODBC)
|
||||
|
||||
* Support search by the area of the setting (like `Privacy`)
|
||||
* Support search for alternative names of a setting
|
||||
|
||||
## How to add a new Windows Setting or change one
|
||||
|
||||
All Windows settings are located in `WindowsSettings.json` in root folder of the project.
|
||||
The `WindowsSettings.json` use a JSON schema file that make it easier to edit it.
|
||||
|
||||
| Key | Optional | Value type | String prefix |
|
||||
| ------------------- | -------- | ----------------- | ------------- |
|
||||
| `Name` | **No** | String | |
|
||||
| `Type` | **No** | String | `App` |
|
||||
| `Command` | **No** | String | |
|
||||
| `Areas` | Yes | List with strings | `Area` |
|
||||
| `AltNames` | Yes | List with strings | |
|
||||
| `Note` | Yes | String | `Note` |
|
||||
| `IntroducedInBuild` | Yes | Integer | |
|
||||
| `DeprecatedInBuild` | Yes | Integer | |
|
||||
| `ShowAsFirstResult` | Yes | Boolean | |
|
||||
|
||||
A minimum entry for the `WindowsSettings.json` looks like:
|
||||
|
||||
```json
|
||||
{
|
||||
"Name": "mySetting",
|
||||
"Type": "AppSettingsApp",
|
||||
"Command": "ms-settings:mySetting"
|
||||
}
|
||||
```
|
||||
|
||||
A full entry for the `WindowsSettings.json` looks like:
|
||||
|
||||
```json
|
||||
{
|
||||
"Name": "mySetting",
|
||||
"Type": "AppSettingsApp",
|
||||
"Command": "ms-settings:mySetting",
|
||||
"Areas": [ "AreaMySettingArea" ],
|
||||
"AltNames": [ "NiceSetting" ],
|
||||
"Note": "NoteMySettingNote",
|
||||
"IntroducedInBuild" : 1903,
|
||||
"DeprecatedInBuild" : 2004,
|
||||
"ShowAsFirstResult" : true
|
||||
}
|
||||
```
|
||||
|
||||
### Remarks
|
||||
|
||||
* The `Command` for modern Windows settings should start with `ms-settings:`
|
||||
* The `Command` for legacy Windows settings should start with `control`
|
||||
* The integer value for `IntroducedInBuild` and `DeprecatedInBuild` must be in range of `0` to `4294967295`
|
||||
* The strings for `Name`, `AltNames`, `Areas`, `Type` and `Note` must not contain whitespace(s) or special characters (#, €, $, etc.)
|
||||
* The strings for `Name`, `AltNames`, `Areas`, `Type` and `Note` are used as ids for the resource file under `Properties\Resources.resx`
|
||||
* When you add new strings make sure you have add add all translations for it.
|
||||
|
||||
## Scores
|
||||
|
||||
There are three different score types with different start values.
|
||||
|
||||
| Score type | Start value |
|
||||
| ------------------ | ------------ |
|
||||
| First result score | 10500 |
|
||||
| High score | 10000 |
|
||||
| Medium score | 5000 |
|
||||
| Low score | 1000 |
|
||||
|
||||
Each score will decreased by one when a condition match.
|
||||
|
||||
| Priority | Condition | Score type |
|
||||
| -------- | ----------------------------------------------------------------- | ------------ |
|
||||
| 1. | Settings name starts with the search value | High score |
|
||||
| 2. | Settings name contain the search value | Medium score |
|
||||
| 3. | Setting has no area | Low score |
|
||||
| 4. | One area of the settings starts with the search value | Low score |
|
||||
| 5. | Setting has no alternative name | Low score |
|
||||
| 6. | One alternative name of the settings starts with the search value | Medium score |
|
||||
| x. | no condition match | Low score |
|
||||
|
||||
### Remarks
|
||||
* For each score condition we check if the property "ShowAsFirstResult" of the setting is true. If yes we use the firstResultScore instead of condition`s score.
|
||||
|
||||
## Important for developers
|
||||
|
||||
### General
|
||||
|
||||
* The assembly name is cached into `_assemblyName` (to avoid to many calls of `Assembly.GetExecutingAssembly()`)
|
||||
|
||||
## Microsoft.PowerToys.Run.Plugin.WindowsSettings project
|
||||
|
||||
### Important plugin values (meta-data)
|
||||
|
||||
| Name | Value |
|
||||
| --------------- | ---------------------------------------------------- |
|
||||
| ActionKeyword | `$` |
|
||||
| ExecuteFileName | `Microsoft.PowerToys.Run.Plugin.WindowsSettings.dll` |
|
||||
| ID | `5043CECEE6A748679CBE02D27D83747A` |
|
||||
|
||||
### Interfaces used by this plugin
|
||||
|
||||
The plugin use only these interfaces (all inside the `Main.cs`):
|
||||
|
||||
* `Wox.Plugin.IPlugin`
|
||||
* `Wox.Plugin.IContextMenu`
|
||||
* `Wox.Plugin.IPluginI18n`
|
||||
|
||||
### Program files
|
||||
|
||||
| File | Content |
|
||||
| ------------------------------------- | ----------------------------------------------------------------------- |
|
||||
| `Classes\WindowsSetting.cs` | A class that represent one Windows setting |
|
||||
| `Classes\WindowsSettings.cs` | A wrapper class that only contains a list with Windows settings (see 1) |
|
||||
| `Helper\ContextMenuHelper.cs` | All functions to build the context menu (for each result entry) |
|
||||
| `Helper\JsonSettingsListHelper.cs` | All functions to load the windows settings from a JSON file |
|
||||
| `Helper\ResultHelper.cs` | All functions to convert internal results into WOX results |
|
||||
| `Helper\TranslationHelper.cs` | All functions to translate the result in the surface language |
|
||||
| `Helper\UnsupportedSettingsHelper.cs` | All functions to filter not supported Windows settings out |
|
||||
| `Helper\WindowsSettingsPathHelper.cs` | All functions to build the area paths |
|
||||
| `Images\WindowsSettings.dark.png` | Symbol for the results for the dark theme |
|
||||
| `Images\WindowsSettings.light.png` | Symbol for the results for the light theme |
|
||||
| `Properties\Resources.Designer.resx` | File that contain all translatable keys |
|
||||
| `Properties\Resources.resx` | File that contain all translatable strings in the neutral language |
|
||||
| `GlobalSuppressions.cs` | Code suppressions (no real file, linked via *.csproj) |
|
||||
| `Main.cs` | Main class, the only place that implement the WOX interfaces |
|
||||
| `plugin.json` | All meta-data for this plugin |
|
||||
| `StyleCop.json` | Code style (no real file, linked via *.csproj) |
|
||||
|
||||
1. We need this extra wrapper class to make it possible that the JSON file can have and use a JSON schema file.
|
||||
Because the JSON file must have a object as root type, instead of a array.
|
||||
|
||||
### Important project values (*.csproj)
|
||||
|
||||
| Name | Value |
|
||||
| --------------- | --------------------------------------------------------------------------------------------------- |
|
||||
| TargetFramework | `netcoreapp3.1` (means .NET Core 3.1) |
|
||||
| Platforms | `x64` |
|
||||
| Output | `..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\` |
|
||||
| RootNamespace | `Microsoft.PowerToys.Run.Plugin.WindowsSettings` |
|
||||
| AssemblyName | `Microsoft.PowerToys.Run.Plugin.WindowsSettings` |
|
||||
|
||||
### Project dependencies
|
||||
|
||||
#### Packages
|
||||
|
||||
| Package | Version |
|
||||
| ------------------------------------------------------------------------------------- | ------- |
|
||||
| [`StyleCop.Analyzers`](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) | 1.1.118 |
|
||||
|
||||
#### Projects
|
||||
|
||||
* `Wox.Infrastructure`
|
||||
* `Wox.Plugin`
|
|
@ -21,6 +21,3 @@ TODO
|
|||
|
||||
#### [`trace.cpp`](/src/modules/powerrename/lib/trace.cpp)
|
||||
TODO
|
||||
|
||||
#### [`PowerRenameUI.cpp`](/src/modules/powerrename/ui/PowerRenameUI.cpp)
|
||||
TODO
|
|
@ -53,7 +53,7 @@ bool ExamplePowertoy::get_config(wchar_t* buffer, int* buffer_size)
|
|||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
```
|
||||
The list of all the available settings elements and their description is [further in this doc](#available-settings-elements). New PowerToy icons need to be [added to the `settings-web` project](https://github.com/microsoft/PowerToys/blob/master/doc/devdocs/settings-web.md#updating-the-icons).
|
||||
The list of all the available settings elements and their description is [further in this doc](#available-settings-elements). New PowerToy icons need to be [added to the `settings-web` project](https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/settings-web.md#updating-the-icons).
|
||||
|
||||
## User changes settings
|
||||
When user closes the settings screen, the runner will call the [`get_config()`](modules/interface.md) method. Use [`PowerToyValues`](/src/common/settings_objects.h) class static `from_json_string` method to parse the settings. After that, the code is similar to loading the settings from disk:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
## Formatting
|
||||
|
||||
- We use [`.clang-format`](https://github.com/microsoft/PowerToys/blob/master/src/.clang-format) style file to enable automatic code formatting. You can [easily format source files from Visual Studio](https://devblogs.microsoft.com/cppblog/clangformat-support-in-visual-studio-2017-15-7-preview-1/). For example, `CTRL+K CTRL+D` formats the current document.
|
||||
- If you prefer another text editor or have ClangFormat disabled in Visual Studio, you could invoke [`format_sources`](https://github.com/microsoft/PowerToys/blob/master/src/codeAnalysis/format_sources.ps1) powershell script from command line. It gets a list of all currently modified files from `git` and invokes clang-format on them.
|
||||
- We use [`.clang-format`](https://github.com/microsoft/PowerToys/blob/main/src/.clang-format) style file to enable automatic code formatting. You can [easily format source files from Visual Studio](https://devblogs.microsoft.com/cppblog/clangformat-support-in-visual-studio-2017-15-7-preview-1/). For example, `CTRL+K CTRL+D` formats the current document.
|
||||
- If you prefer another text editor or have ClangFormat disabled in Visual Studio, you could invoke [`format_sources`](https://github.com/microsoft/PowerToys/blob/main/src/codeAnalysis/format_sources.ps1) powershell script from command line. It gets a list of all currently modified files from `git` and invokes clang-format on them.
|
||||
Please note that you should also have `clang-format.exe` in `%PATH%` for it to work. The script can infer the path of `clang-format.exe` version which is shipped with Visual Studio at `%VCINSTALLDIR%\Tools\Llvm\bin\`, if you launch it from the *Native Tools Command Prompt for VS*.
|
||||
- CI doesn't enforce code formatting yet, since we're gradually applying code formatting to the codebase, but please adhere to our formatting style for any new code.
|
||||
|
|
BIN
doc/images/SCOOBE/SCOOBE.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
doc/images/SCOOBE/Welcome_SCOOBE.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
doc/images/icons/Find My Mouse.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
doc/images/icons/Mouse Highlighter.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
doc/images/icons/MouseUtils.png
Normal file
After Width: | Height: | Size: 8 KiB |
BIN
doc/images/msix/hello-module-app-permissions.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
doc/images/msix/hello-module-loaded-settings.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
doc/images/msix/hello-module-screen.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
doc/images/msix/hello-module-settings-page.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
doc/images/msix/hello-module-start.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
doc/images/overview/MouseUtils_large.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
doc/images/overview/MouseUtils_small.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
doc/images/overview/Original/MouseUtils.png
Normal file
After Width: | Height: | Size: 114 KiB |
Before Width: | Height: | Size: 447 KiB After Width: | Height: | Size: 447 KiB |
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 72 KiB |
|
@ -2,17 +2,17 @@
|
|||
---
|
||||
|
||||
1. `Zone` - Class which is basically wrapper around rectangle structure, representing one zone inside applied zone layout. ZoneSet is holding array of these which represent zone layout.
|
||||
2. `ZoneSet` - Class implementing actual zone layout applied. What this means is that ZoneSet is responsible for actual calculation of rectangle coordinates (whether is grid or canvas layout) and moving window through them. ZoneWindow holds ZoneSet structure which represents currently active zone set.
|
||||
3. `ZoneWindow` - Class representing work area, which is defined by monitor and current virtual desktop. For an example, if You have two monitors connected and two virtual desktops, You have 4 work areas available, and each of them can have separate zone layout. ZoneWindow is describing single work area. As mentioned before it holds active ZoneSet.
|
||||
2. `ZoneSet` - Class implementing actual zone layout applied. What this means is that ZoneSet is responsible for actual calculation of rectangle coordinates (whether is grid or canvas layout) and moving window through them. WorkArea holds ZoneSet structure which represents currently active zone set.
|
||||
3. `WorkArea` - Class representing work area, which is defined by monitor and current virtual desktop. For an example, if You have two monitors connected and two virtual desktops, You have 4 work areas available, and each of them can have separate zone layout. WorkArea is describing single work area. As mentioned before it holds active ZoneSet.
|
||||
4. `FancyZones` - Top level entity and entry point for all user actions (which goes through actual module interface). Some of the main responsibilities of FancyZones class:
|
||||
|
||||
1. Starting FancyZones Editor (C#) with appropriate command line arguments on user request.
|
||||
2. Keeping track of ZoneWindow per monitor (currently active work area on each connected monitor).
|
||||
2. Keeping track of WorkArea per monitor (currently active work area on each connected monitor).
|
||||
3. Keeping track of active virtual desktops. This is performed in separate thread by polling VirtualDesktopIDs registry key and parsing its content.
|
||||
4. Detecting every change in work environment, such as creating / destroying / switching between virtual desktops, closing FancyZones Editor, changing display settings and handling those changes.
|
||||
|
||||
### Proposal for modifications of handling described in 4.4:
|
||||
|
||||
Currently after each of the mentioned changes in work environment we are calling EnumDisplayMonitors windows API, and passing callback function to it. EnumDisplayMonitors works asynchronous and triggers that callback for each work area available (as mentioned in previous example, for two monitors and two virtual desktops, we have this callback triggered four times). As mentioned previously, we have ZoneWindow class as our representation of this work area. And what we do, every time this callback is triggered we destroy previous ZoneWindow object for that work area and create new one, even though that it is most likely that nothing has changed (e.g. just switching back and forth between virtual desktops). This constant creation and deletion of ZoneWindow has caused some problems in the past and it's not ideal for some other fixes we would like to make in the multi-monitor/multi-desktop scenario.
|
||||
Currently after each of the mentioned changes in work environment we are calling EnumDisplayMonitors windows API, and passing callback function to it. EnumDisplayMonitors works asynchronous and triggers that callback for each work area available (as mentioned in previous example, for two monitors and two virtual desktops, we have this callback triggered four times). As mentioned previously, we have WorkArea class as our representation of this work area. And what we do, every time this callback is triggered we destroy previous WorkArea object for that work area and create new one, even though that it is most likely that nothing has changed (e.g. just switching back and forth between virtual desktops). This constant creation and deletion of WorkArea has caused some problems in the past and it's not ideal for some other fixes we would like to make in the multi-monitor/multi-desktop scenario.
|
||||
|
||||
As mentioned in 4.3 we already have tracker of virtual desktops implemented. Idea is to use this functionality and to extend it bit more, so we can track if work area (ZoneWindow) is new one, or already processed and skip creating new ZoneWindow objects and deleting old ones every time, even if nothing changed in it. We will keep map, where virtual desktop id is the key, and values are already processed monitors (virtual desktop exists across all monitors). Once we receive callback from EnumDisplayMonitors, indicating work area (defined by virtual desktop id and monitor) we can check if it’s new or not, and act accordingly (create new ZoneWindow for it or not). Deleting virtual desktop (which is also registered in 4.3), will trigger updates in this map, and also updates in our JSON storage.
|
||||
As mentioned in 4.3 we already have tracker of virtual desktops implemented. Idea is to use this functionality and to extend it bit more, so we can track if work area (WorkArea) is new one, or already processed and skip creating new WorkArea objects and deleting old ones every time, even if nothing changed in it. We will keep map, where virtual desktop id is the key, and values are already processed monitors (virtual desktop exists across all monitors). Once we receive callback from EnumDisplayMonitors, indicating work area (defined by virtual desktop id and monitor) we can check if it’s new or not, and act accordingly (create new WorkArea for it or not). Deleting virtual desktop (which is also registered in 4.3), will trigger updates in this map, and also updates in our JSON storage.
|
||||
|
|
143
doc/specs/SCOOBE.md
Normal file
|
@ -0,0 +1,143 @@
|
|||
# PowerToys SCOOBE Dialog
|
||||
|
||||
- **What is it:** Post-upgrade prompted dialog that walks users through the latest additions to PowerToys utilities and functionalities
|
||||
- **Author:** Deondre Davis
|
||||
- **Spec Status:** Draft
|
||||
|
||||
## 1. Overview
|
||||
|
||||
### 1.1. Executive Summary
|
||||
|
||||
To expand on our end-user on-boarding efforts, we seek to resolve the critical issue of informing users of new additions and improvements to PowerToys during upgrade scenarios. We currently list release notes on the main repository, in addition to affiliated information on Microsoft Docs. However, neither of these mediums are internal to the application, and thus requires users to proactively seek out information on what's been updated, or merely notice by chance what's been changed from their regular usage. As these are not ideal experiences, this document describes the inclusion of a post-upgrade 'SCOOBE' prompt that launches the previously developed OOBE dialog loaded with new information related to upgrade improvements and additions.
|
||||
|
||||
### 1.2. Key-Definitions/Concepts
|
||||
|
||||
Here are definitions for words and acronyms found throughout this document to ensure clarity:
|
||||
|
||||
- **OOBE:** Out of box experience – The users' initial interactions with the product immediately after installing the product and/or launching the product for the first time.
|
||||
- **SCOOBE:** Second chance out of box experience - The users' initial interactions with the product immediately after upgrading the product and/or launching the product for the first time after upgrading.
|
||||
|
||||
### 1.3. Goals and Non-Goals
|
||||
|
||||
Goals:
|
||||
|
||||
- Create a guided prompt that exposes the user to a brief overview of the new features and/or improvements included with the latest version of PowerToys.
|
||||
|
||||
Non-Goals:
|
||||
|
||||
- Present a copy-and-paste replica of the repository release notes. This information needs to be readily consumable, often requiring visual demonstrations of the new behavior and/or functionality that's either not possible or not necessary to depict on the repository release notes.
|
||||
|
||||
## 2. Definition of Success
|
||||
|
||||
**2.1. Customers**
|
||||
|
||||
The PowerToys SCOOBE is for existing and new power users and developers who are looking to tune and streamline their Windows experience for greater productivity and enhanced user experience. As the PowerToys customer base tends to be particularly biased against SCOOBE prompts in general, we need to present the PowerToys SCOOBE dialog in such a way that it provides immediate value to end-users to improve the likelihood of users discovering all the additions to PowerToys by making their way through the prompt.
|
||||
|
||||
**2.2. Expected Impact: Customer, and Technology Outcomes**
|
||||
|
||||
- **High Reliability** : Less than 0.1% crash rate.
|
||||
- **Increased Activation** : 50% or more adoption rate of new feature/utilities among PowerToys users who already utilize associated tools.
|
||||
- **High User Retention:** 25% or more active PowerToys users after 28 days of upgrade.
|
||||
|
||||
## 3. Requirements
|
||||
|
||||
The SCOOBE dialog builds off the currently implemented OOBE dialog originally drafted by [Niels's mock-up.](https://github.com/microsoft/PowerToys/issues/1285)
|
||||
|
||||
**3.1. Functional Requirements**
|
||||
|
||||
**3.1.1. Functional Requirements** **Overview**
|
||||
|
||||
| **No.** | **Requirement** | **Pri** |
|
||||
| --- | --- | --- |
|
||||
|1. | The SCOOBE dialog should launch immediately when PowerToys runs after having been updated. | P0 |
|
||||
|2. | The SCOOBE dialog should be contained inside the existing OOBE Dialog under its own "What's New" page of the dialog window. See figure 5.1.1. | P0 |
|
||||
|3. | The content for the SCOOBE dialog should be stored externally from the PowerToys application on the PowerToys Github in distinct wiki pages on for each release. **\*** | P0 |
|
||||
|4. | When the "What's New" page is opened, the content displayed should be loaded from the information contained in the relevant wiki pages discussed in 3.1.1.3 above. Assumes the user's device is connected to the internet. | P0 |
|
||||
|6. | The SCOOBE dialog should display information on updates that have occurred on the version of PowerToys the user has installed/updated to. | P0 |
|
||||
|7. | If PowerToys was installed for the first time, the OOBE's "Welcome to PowerToys" page should display first, not the SCOOBE's "What's New" page. See figure 5.1.2. | P0 |
|
||||
|8. | The structure of the SCOOBE dialog page's content should follow the guidelines described in section 3.1.2. | P0 |
|
||||
|9. | After SCOOBE is initially viewed, the user should be able to re-access the SCOOBE dialog at any time by opening the OOBE window again and selecting the "What's New" page. | P1 |
|
||||
|
||||
**\*** - By storing the content for SCOOBE externally from the application, the PowerToys team can update/adjust information without being constrained to PowerToys' release cycles. This is critical in the event of errors or miscommunications that would otherwise be difficult, if not impossible, to correct if stored locally to the app and shipped with the version of PowerToys being released. The content will likely be stored in an archive maintained in the PowerToys Github Wiki.
|
||||
|
||||
**3.1.2. Page Content**
|
||||
|
||||
| **No.** | **Requirement** | **Pri** |
|
||||
| --- | --- | --- |
|
||||
|1. | The SCOOBE dialog should display the version of PowerToys the user has installed, as shown in figures 5.1.1. | P0 |
|
||||
|2. | The SCOOBE dialog information should be grouped into two sections: "New Features & Improvements" and "Bug fixes Highlights". | P0 |
|
||||
|3. | The "New Features & Improvements" section should contain information related to end user functionality that has been added or updated. | P0 |
|
||||
|4. | The "New Features & Improvements" section should be subdivided by the relevant utilities updated (i.e. Color Picker, FancyZones, etc.). See figure 5.1.1 and section 5.1.3 for examples. | P1 |
|
||||
|5. | The "Bug fixes Highlights" section should contain information related to noteworthy issues/errors that were corrected. | P0 |
|
||||
|6. | If there are relevant visuals, they should be included with the information text. See figure 5.1.1. | P1 |
|
||||
|8. | The SCOOBE dialog should be scrollable if needed to fit all the content. | P0 |
|
||||
|10. | The bottom of the SCOOBE dialog should include a link to the PowerToys releases page for a complete list of versions and their release notes ([Releases · microsoft/PowerToys (github.com)](https://github.com/microsoft/PowerToys/releases)). | P1 |
|
||||
|
||||
|
||||
## 4. Measure Requirements
|
||||
|
||||
| **No.** | **Requirement** | **Implication** | **Pri** |
|
||||
| --- | --- | --- | --- |
|
||||
|1. | Date/Time of first-run following upgrade | Helps to categorize usage and retention trends across users who've been exposed to SCOOBE. | P0 |
|
||||
|2. | SCOOBE section viewed | Used to measure activation of the SCOOBE dialog. Should be 100% for the current version of PowerToys following SCOOBE's inclusion. | P0 |
|
||||
|3. | Accesses to linked documentation | Used to gauge interest in user's desire to learn more about the PowerToys described. | P1 |
|
||||
|4. | Access to linked settings pages | Used to gauge whether the settings presented to users in the dialog are sufficient for user needs. | P1 |
|
||||
|5. | PowerToys launched while SCOOBE window is active | Used to track user engagement with the various PowerToys while exploring the content in the SCOOBE. | P1 |
|
||||
|6. | Screen size | Gives crucial information for considerations related to minimal/maximum window size needed for displaying content. | P2 |
|
||||
|
||||
## 5. Appendix
|
||||
|
||||
### 5.1. Mock-ups
|
||||
|
||||
**5.1.1. SCOOBE Dialog Layout**
|
||||
|
||||
![](../images/SCOOBE/SCOOBE.png)
|
||||
|
||||
**5.1.2. OOBE Welcome Page**
|
||||
|
||||
![](../images/SCOOBE/Welcome_SCOOBE.png)
|
||||
|
||||
**5.1.3. Example Textual Descriptions for Updates**
|
||||
|
||||
**v0.29 -> v0.31:**
|
||||
|
||||
- New Features & Improvements
|
||||
- FancyZones
|
||||
- Dark mode for the editor
|
||||
- Certain settings (e.g. number of zones, spacing settings) can now be set on individual layouts.
|
||||
- PowerToys Run
|
||||
- Service management plugin (Start, stop, …)
|
||||
- Registry key plugin
|
||||
- System action plugin (Reboot, lock, ...)
|
||||
- Bug fixes Highlights
|
||||
- Fixed OneDrive SVG Bug (#9999)
|
||||
- SVG are scaled appropriately when view box is provided (#9999)
|
||||
|
||||
**v0.31 -> v0.33:**
|
||||
|
||||
- New Features & Improvements
|
||||
- General
|
||||
- Added a 'First time load' experience. The hope is a quick, light way to learn about basic functionality
|
||||
- FancyZones
|
||||
- New options to change zone activation algorithm
|
||||
- PowerToys Run
|
||||
- Plugin Manager now is in settings. You can directly turn on / off, include items in general search, and change the action key
|
||||
- Improved support for additional window managers by abstracting out shell process calls
|
||||
- ~ will now act as the user home directory in Folder plugin
|
||||
- Bug fixes Highlights
|
||||
- Fix for PT Run registering the hotkey on non-supported OS versions (#9999)
|
||||
|
||||
**v0.33 -> v0.35:**
|
||||
|
||||
- New Features & Improvements
|
||||
- Color Picker
|
||||
- Esc can now be used to exit the editor
|
||||
- FancyZones
|
||||
- Added hotkeys and quick swap functionality for custom layouts! Users can now assign a hotkey in the editor and use it to quickly set a desktop's zones with Ctrl + Win + Alt + NUMBER key binding, or by pressing the hotkey while dragging a window.
|
||||
- PowerToys Run
|
||||
- Users can specify where to show the launcher window
|
||||
- New plugin added to support opening previously used Visual Studio Code workspaces, remote machines (SSH or Codespaces), and containers! When enabled, use { to query for available workspaces. Please note, this plugin is off by default.
|
||||
- Shell history now saves the raw command instead of the resolved command. A command like %appdata% would now save in the Shell history as is instead of C:\Users\YourUserName\AppData\Roaming.
|
||||
- Bug fixes Highlights
|
||||
- PowerToys will start requiring Windows 10 v1903 or greater after 0.35.x release. (#9999)
|
||||
- Fixed FancyZones placement algorithm for when the Taskbar is vertical (#9999)
|
|
@ -9,7 +9,7 @@ namespace fs = std::filesystem;
|
|||
|
||||
namespace updating
|
||||
{
|
||||
constexpr size_t REQUIRED_MINIMAL_PATCH = 15;
|
||||
constexpr size_t REQUIRED_MINIMAL_PATCH = 20;
|
||||
|
||||
bool dotnet_is_installed()
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ namespace updating
|
|||
|
||||
std::optional<fs::path> download_dotnet()
|
||||
{
|
||||
const wchar_t DOTNET_DESKTOP_DOWNLOAD_LINK[] = L"https://download.visualstudio.microsoft.com/download/pr/d30352fe-d4f3-4203-91b9-01a3b66a802e/bb416e6573fa278fec92113abefc58b3/windowsdesktop-runtime-3.1.15-win-x64.exe";
|
||||
const wchar_t DOTNET_DESKTOP_DOWNLOAD_LINK[] = L"https://download.visualstudio.microsoft.com/download/pr/93c69a29-d379-4a5d-bb9e-3116cc14de41/907bbc52446d8bb7baa0c6faebde1d44/windowsdesktop-runtime-3.1.20-win-x64.exe";
|
||||
const wchar_t DOTNET_DESKTOP_FILENAME[] = L"windowsdesktop-runtime.exe";
|
||||
|
||||
auto dotnet_download_path = fs::temp_directory_path() / DOTNET_DESKTOP_FILENAME;
|
||||
|
|
|
@ -42,7 +42,9 @@ std::optional<fs::path> ExtractEmbeddedInstaller(const fs::path extractPath)
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto installerPath = extractPath / L"PowerToysBootstrappedInstaller-" PRODUCT_VERSION_STRING L".msi";
|
||||
std::wstring msiName(L"PowerToysSetup-" STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "." STRINGIZE(VERSION_REVISION) L"-");
|
||||
msiName += get_architecture_string(get_current_architecture()) + std::wstring(L".msi");
|
||||
auto installerPath = extractPath / msiName;
|
||||
return executableRes->saveAsFile(installerPath) ? std::make_optional(std::move(installerPath)) : std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -163,6 +165,51 @@ std::optional<InstalledVersionInfo> get_installed_powertoys_version()
|
|||
};
|
||||
}
|
||||
|
||||
void ReLaunchElevatedAndExit()
|
||||
{
|
||||
std::wstring params;
|
||||
int nCmdArgs = 0;
|
||||
LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs);
|
||||
for (int i = 1; i < nCmdArgs; ++i)
|
||||
{
|
||||
if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos)
|
||||
{
|
||||
params += L'"';
|
||||
params += argList[i];
|
||||
params += L'"';
|
||||
}
|
||||
else
|
||||
{
|
||||
params += argList[i];
|
||||
}
|
||||
|
||||
if (i != nCmdArgs - 1)
|
||||
{
|
||||
params += L' ';
|
||||
}
|
||||
}
|
||||
|
||||
const auto processHandle = run_elevated(argList[0], params.c_str());
|
||||
if (!processHandle)
|
||||
{
|
||||
spdlog::error("Couldn't restart elevated: ({})", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0)
|
||||
{
|
||||
DWORD exitCode = 0;
|
||||
GetExitCodeProcess(processHandle, &exitCode);
|
||||
std::exit(exitCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::error("Elevated setup process timed out after 60m: ({})", GetLastError());
|
||||
TerminateProcess(processHandle, 0);
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int Bootstrapper(HINSTANCE hInstance)
|
||||
{
|
||||
winrt::init_apartment();
|
||||
|
@ -297,7 +344,14 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||
}
|
||||
}
|
||||
|
||||
// Setup MSI UI visibility and restart as elevated if required
|
||||
// Always elevate bootstrapper process since it invokes msiexec multiple times,
|
||||
// so we can avoid multiple UAC confirmations
|
||||
if (!is_process_elevated())
|
||||
{
|
||||
ReLaunchElevatedAndExit();
|
||||
}
|
||||
|
||||
// Setup MSI UI visibility
|
||||
if (!noFullUI)
|
||||
{
|
||||
MsiSetInternalUI(INSTALLUILEVEL_FULL, nullptr);
|
||||
|
@ -305,58 +359,7 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||
|
||||
if (g_Silent)
|
||||
{
|
||||
if (is_process_elevated())
|
||||
{
|
||||
MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::debug("MSI doesn't support silent mode without elevation => restarting elevated");
|
||||
// MSI fails to run in silent mode due to a suppressed UAC w/o elevation,
|
||||
// so we restart ourselves elevated with the same args
|
||||
std::wstring params;
|
||||
int nCmdArgs = 0;
|
||||
LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs);
|
||||
for (int i = 1; i < nCmdArgs; ++i)
|
||||
{
|
||||
if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos)
|
||||
{
|
||||
params += L'"';
|
||||
params += argList[i];
|
||||
params += L'"';
|
||||
}
|
||||
else
|
||||
{
|
||||
params += argList[i];
|
||||
}
|
||||
|
||||
if (i != nCmdArgs - 1)
|
||||
{
|
||||
params += L' ';
|
||||
}
|
||||
}
|
||||
|
||||
const auto processHandle = run_elevated(argList[0], params.c_str());
|
||||
if (!processHandle)
|
||||
{
|
||||
spdlog::error("Couldn't restart elevated to enable silent mode! ({})", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0)
|
||||
{
|
||||
DWORD exitCode = 0;
|
||||
GetExitCodeProcess(processHandle, &exitCode);
|
||||
return exitCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::error("Elevated setup process timed out after 60m => using basic MSI UI ({})", GetLastError());
|
||||
// Couldn't install using the completely silent mode in an hour, use basic UI.
|
||||
TerminateProcess(processHandle, 0);
|
||||
MsiSetInternalUI(INSTALLUILEVEL_BASIC, nullptr);
|
||||
}
|
||||
}
|
||||
MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr);
|
||||
}
|
||||
|
||||
// Try killing PowerToys and prevent future processes launch by acquiring app mutex
|
||||
|
|
|
@ -7,6 +7,10 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "PowerToysSetup", "PowerToys
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToysSetupCustomActions", "PowerToysSetupCustomActions\PowerToysSetupCustomActions.vcxproj", "{32F3882B-F2D6-4586-B5ED-11E39E522BD3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spdlog", "..\src\logging\logging.vcxproj", "{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logger", "..\src\common\logger\logger.vcxproj", "{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -21,6 +25,14 @@ Global
|
|||
{32F3882B-F2D6-4586-B5ED-11E39E522BD3}.Debug|x64.Build.0 = Debug|x64
|
||||
{32F3882B-F2D6-4586-B5ED-11E39E522BD3}.Release|x64.ActiveCfg = Release|x64
|
||||
{32F3882B-F2D6-4586-B5ED-11E39E522BD3}.Release|x64.Build.0 = Release|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.Build.0 = Debug|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.ActiveCfg = Release|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.Build.0 = Release|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.Build.0 = Debug|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.ActiveCfg = Release|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<?define ColorPickerProjectName="ColorPicker"?>
|
||||
<?define VideoConferenceProjectName="VideoConference"?>
|
||||
<?define AwakeProjectName="Awake"?>
|
||||
<?define MouseUtilsProjectName="MouseUtils"?>
|
||||
|
||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||
<?define BinX32Dir="$(var.RepoDir)x86\$(var.Configuration)\" ?>
|
||||
|
@ -77,21 +78,19 @@
|
|||
<Property Id="CREATESCHEDULEDTASK" Value="1"/>
|
||||
<Property Id="WixShellExecTarget" Value="[#PowerToys_ActionRunner.exe]" />
|
||||
|
||||
<Property Id ="EXISTINGPOWERRENAMEEXTPATH">
|
||||
<RegistrySearch Id="ExistingExtPath" Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}\InprocServer32" Type="raw"/>
|
||||
</Property>
|
||||
<Property Id ="EXISTINGIMAGERESIZERPATH">
|
||||
<RegistrySearch Id="ExistingImageResizerPath" Root="HKCR" Key="CLSID\{51B4D7E5-7568-4234-B4BB-47FB3C016A69}\InprocServer32" Type="raw"/>
|
||||
</Property>
|
||||
|
||||
<InstallUISequence>
|
||||
<Custom Action="DetectPrevInstallPath" After="CostFinalize" />
|
||||
</InstallUISequence>
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="SetRegisterPowerToysSchTaskParam" Before="RegisterPowerToysSchTask" />
|
||||
<Custom Action="SetApplyModulesRegistryChangeSetsParam" Before="ApplyModulesRegistryChangeSets" />
|
||||
<Custom Action="SetUnApplyModulesRegistryChangeSetsParam" Before="UnApplyModulesRegistryChangeSets" />
|
||||
<Custom Action="RegisterPowerToysSchTask" After="InstallFiles">
|
||||
NOT Installed and CREATESCHEDULEDTASK = 1
|
||||
</Custom>
|
||||
<Custom Action="ApplyModulesRegistryChangeSets" After="InstallFiles">
|
||||
NOT Installed
|
||||
</Custom>
|
||||
<Custom Action="WixCloseApplications" Before="RemoveFiles" />
|
||||
<Custom Action="RemovePowerToysSchTasks" After="RemoveFiles" />
|
||||
<!-- TODO: Use to activate embedded MSIX -->
|
||||
|
@ -104,6 +103,10 @@
|
|||
<Custom Action="TelemetryLogUninstallSuccess" After="InstallFinalize">
|
||||
Installed and (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
<Custom Action="UnApplyModulesRegistryChangeSets" Before="InstallFinalize">
|
||||
Installed AND (REMOVE="ALL")
|
||||
</Custom>
|
||||
|
||||
<!-- TODO: Use to activate embedded MSIX -->
|
||||
<!--<Custom Action="UninstallEmbeddedMSIXTask" After="InstallFinalize">
|
||||
Installed AND (REMOVE="ALL")
|
||||
|
@ -123,7 +126,15 @@
|
|||
Property="RegisterPowerToysSchTask"
|
||||
Value="[#PowerToys.exe]" />
|
||||
|
||||
<!-- Needs to Impersonate="no" and Execute="deferred" in order to run elevated. -->
|
||||
<CustomAction Id="SetApplyModulesRegistryChangeSetsParam"
|
||||
Property="ApplyModulesRegistryChangeSets"
|
||||
Value="[INSTALLFOLDER]" />
|
||||
|
||||
<CustomAction Id="SetUnApplyModulesRegistryChangeSetsParam"
|
||||
Property="UnApplyModulesRegistryChangeSets"
|
||||
Value="[INSTALLFOLDER]" />
|
||||
|
||||
<!-- Needs to Impersonate="no" and Execute="deferred" in order to run elevated. -->
|
||||
<CustomAction Id="RegisterPowerToysSchTask"
|
||||
Return="ignore"
|
||||
Impersonate="no"
|
||||
|
@ -217,6 +228,23 @@
|
|||
DllEntry="DetectPrevInstallPathCA"
|
||||
/>
|
||||
|
||||
<CustomAction Id="ApplyModulesRegistryChangeSets"
|
||||
Return="check"
|
||||
Impersonate="no"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="ApplyModulesRegistryChangeSetsCA"
|
||||
/>
|
||||
|
||||
<CustomAction Id="UnApplyModulesRegistryChangeSets"
|
||||
Return="check"
|
||||
Impersonate="no"
|
||||
Execute="deferred"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="UnApplyModulesRegistryChangeSetsCA"
|
||||
/>
|
||||
|
||||
|
||||
<!-- Close 'PowerToys.exe' before uninstall-->
|
||||
<Property Id="MSIRESTARTMANAGERCONTROL" Value="DisableShutdown" />
|
||||
<Property Id="MSIFASTINSTALL" Value="DisableShutdown" />
|
||||
|
@ -235,17 +263,18 @@
|
|||
<Directory Id="ToolsFolder" Name="Tools"/>
|
||||
<Directory Id="ModulesInstallFolder" Name="modules">
|
||||
<Directory Id="ImageResizerInstallFolder" Name="$(var.ImageResizerProjectName)" />
|
||||
<Directory Id="PowerRenameInstallFolder" Name="$(var.PowerRenameProjectName)"/>
|
||||
<Directory Id="PowerRenameInstallFolder" Name="$(var.PowerRenameProjectName)">
|
||||
<Directory Id="PowerRenameAssetsFolder" Name="Assets" />
|
||||
</Directory>
|
||||
<Directory Id="ShortcutGuideInstallFolder" Name="ShortcutGuide">
|
||||
<Directory Id="ShortcutGuideExecutableInstallFolder" Name="ShortcutGuide">
|
||||
<Directory Id="ShortcutGuideSvgsInstallFolder" Name="svgs"/>
|
||||
</Directory>
|
||||
<Directory Id="ShortcutGuideModuleInterfaceInstallFolder" Name="ShortcutGuideModuleInterface"/>
|
||||
</Directory>
|
||||
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
|
||||
<!-- <Directory Id="VideoConferenceInstallFolder" Name="$(var.VideoConferenceProjectName)">
|
||||
<Directory Id="VideoConferenceInstallFolder" Name="$(var.VideoConferenceProjectName)">
|
||||
<Directory Id="VideoConferenceIconsFolder" Name="Icons" />
|
||||
</Directory> -->
|
||||
</Directory>
|
||||
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
|
||||
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
|
||||
<Directory Id="AwakeInstallFolder" Name="$(var.AwakeProjectName)">
|
||||
|
@ -271,6 +300,10 @@
|
|||
<Directory Id="ColorPickerResourcesFolder" Name="Resources"/>
|
||||
</Directory>
|
||||
|
||||
<!-- Mouse Utils -->
|
||||
<Directory Id="MouseUtilsInstallFolder" Name="$(var.MouseUtilsProjectName)">
|
||||
</Directory>
|
||||
|
||||
<!-- Launcher -->
|
||||
<Directory Id="LauncherInstallFolder" Name="launcher">
|
||||
<Directory Id="AssetsFolder" Name="Assets" />
|
||||
|
@ -283,27 +316,27 @@
|
|||
<Directory Id="CalculatorImagesFolder" Name="Images" />
|
||||
<Directory Id="CalculatorLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="FolderPluginFolder" Name="Microsoft.Plugin.Folder">
|
||||
<Directory Id="FolderPluginFolder" Name="Folder">
|
||||
<Directory Id="FolderPluginImagesFolder" Name="Images" />
|
||||
<Directory Id="FolderPluginLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="ProgramPluginFolder" Name="Microsoft.Plugin.Program">
|
||||
<Directory Id="ProgramPluginFolder" Name="Program">
|
||||
<Directory Id="ProgramImagesFolder" Name="Images" />
|
||||
<Directory Id="ProgramLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="ShellPluginFolder" Name="Microsoft.Plugin.Shell">
|
||||
<Directory Id="ShellPluginFolder" Name="Shell">
|
||||
<Directory Id="ShellImagesFolder" Name="Images" />
|
||||
<Directory Id="ShellLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="IndexerPluginFolder" Name="Microsoft.Plugin.Indexer">
|
||||
<Directory Id="IndexerPluginFolder" Name="Indexer">
|
||||
<Directory Id="IndexerImagesFolder" Name="Images" />
|
||||
<Directory Id="IndexerLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="UriPluginFolder" Name="Microsoft.Plugin.Uri">
|
||||
<Directory Id="UriPluginFolder" Name="Uri">
|
||||
<Directory Id="UriImagesFolder" Name="Images" />
|
||||
<Directory Id="UriLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="UnitConverterPluginFolder" Name="Community.UnitConverter">
|
||||
<Directory Id="UnitConverterPluginFolder" Name="UnitConverter">
|
||||
<Directory Id="UnitConverterImagesFolder" Name="Images" />
|
||||
<Directory Id="UnitConverterLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
|
@ -311,21 +344,24 @@
|
|||
<Directory Id="VSCodeWorkspaceImagesFolder" Name="Images" />
|
||||
<Directory Id="VSCodeWorkspaceLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="WindowWalkerPluginFolder" Name="Microsoft.Plugin.WindowWalker">
|
||||
<Directory Id="WindowWalkerPluginFolder" Name="WindowWalker">
|
||||
<Directory Id="WindowWalkerImagesFolder" Name="Images" />
|
||||
<Directory Id="WindowWalkerLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="RegistryPluginFolder" Name="Microsoft.PowerToys.Run.Plugin.Registry">
|
||||
<Directory Id="RegistryPluginFolder" Name="Registry">
|
||||
<Directory Id="RegistryImagesFolder" Name="Images" />
|
||||
<Directory Id="RegistryLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
<Directory Id="ServicePluginFolder" Name="Service">
|
||||
<Directory Id="ServiceImagesFolder" Name="Images" />
|
||||
</Directory>
|
||||
<Directory Id="WindowsTerminalPluginFolder" Name="WindowsTerminal">
|
||||
<Directory Id="WindowsTerminalImagesFolder" Name="Images" />
|
||||
</Directory>
|
||||
<Directory Id="SystemPluginFolder" Name="System">
|
||||
<Directory Id="SystemImagesFolder" Name="Images" />
|
||||
</Directory>
|
||||
<Directory Id="WindowsSettingsPluginFolder" Name="Microsoft.PowerToys.Run.Plugin.WindowsSettings">
|
||||
<Directory Id="WindowsSettingsPluginFolder" Name="WindowsSettings">
|
||||
<Directory Id="WindowsSettingsImagesFolder" Name="Images" />
|
||||
<Directory Id="WindowsSettingsLanguagesFolder" Name="Languages" />
|
||||
</Directory>
|
||||
|
@ -478,109 +514,7 @@
|
|||
|
||||
<DirectoryRef Id="ModulesInstallFolder" FileSource="$(var.BinX64Dir)modules\">
|
||||
|
||||
<Component Id="Module_PowerPreview_PerUserRegistry" Guid="CD90ADC0-7CD5-4A62-B0AF-23545C1E6DD3" Win64="yes">
|
||||
<!-- Added a separate component for Per-User registry changes -->
|
||||
<!-- Registry Key for Class Registration of Svg Preview Handler -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{ddee2b8a-6807-48a6-bb20-2338174ff779}">
|
||||
<RegistryValue Type="string" Value="Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler" />
|
||||
<RegistryValue Type="string" Name="DisplayName" Value="Svg Preview Handler" />
|
||||
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
|
||||
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value=""/>
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]SvgPreviewHandler.comhost.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="SvgPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
|
||||
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="SvgPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
|
||||
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler" />
|
||||
</RegistryKey>
|
||||
<!-- Registry Key for Class Registration of Svg Thumbnail Provider -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{36B27788-A8BB-4698-A756-DF9F11F64F84}">
|
||||
<RegistryValue Type="string" Value="Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider" />
|
||||
<RegistryValue Type="string" Name="DisplayName" Value="Svg Thumbnail Provider" />
|
||||
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
|
||||
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value=""/>
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]SvgThumbnailProvider.comhost.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="SvgThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
|
||||
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="SvgThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
|
||||
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider" />
|
||||
</RegistryKey>
|
||||
<!-- Registry Key for Class Registration of Markdown Preview Handler -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{45769bcc-e8fd-42d0-947e-02beef77a1f5}">
|
||||
<RegistryValue Type="string" Value="Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler" />
|
||||
<RegistryValue Type="string" Name="DisplayName" Value="Markdown Preview Handler" />
|
||||
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
|
||||
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value="" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]MarkdownPreviewHandler.comhost.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="MarkdownPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
|
||||
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="MarkdownPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
|
||||
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler" />
|
||||
</RegistryKey>
|
||||
<!-- Registry Key for Class Registration of Pdf Preview Handler -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{07665729-6243-4746-95b7-79579308d1b2}">
|
||||
<RegistryValue Type="string" Value="Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler" />
|
||||
<RegistryValue Type="string" Name="DisplayName" Value="Pdf Preview Handler" />
|
||||
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
|
||||
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value="" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]PdfPreviewHandler.comhost.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="PdfPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
|
||||
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="PdfPreviewHandler, Version=$(var.Version).0, Culture=neutral" />
|
||||
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler" />
|
||||
</RegistryKey>
|
||||
<!-- Registry Key for Class Registration of Pdf Thumbnail Provider -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{BCC13D15-9720-4CC4-8371-EA74A274741E}">
|
||||
<RegistryValue Type="string" Value="Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider" />
|
||||
<RegistryValue Type="string" Name="DisplayName" Value="Pdf Thumbnail Provider" />
|
||||
<RegistryValue Type="string" Name="AppID" Value="{CF142243-F059-45AF-8842-DBBE9783DB14}" />
|
||||
<RegistryValue Type="string" Key="Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value=""/>
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[FileExplorerPreviewInstallFolder]PdfThumbnailProvider.comhost.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="Assembly" Value="PdfThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Both" />
|
||||
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Assembly" Value="PdfThumbnailProvider, Version=$(var.Version).0, Culture=neutral" />
|
||||
<RegistryValue Type="string" Key="InprocServer32\$(var.Version).0" Name="Class" Value="Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider" />
|
||||
</RegistryKey>
|
||||
<!-- Registry Key for AppID registration -->
|
||||
<RegistryKey Root="HKCR" Key="AppID\{CF142243-F059-45AF-8842-DBBE9783DB14}">
|
||||
<RegistryValue Type="expandable" Name="DllSurrogate" Value="%SystemRoot%\system32\prevhost.exe" />
|
||||
</RegistryKey>
|
||||
<!-- Add Svg preview handler to preview handlers list -->
|
||||
<RegistryKey Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\PreviewHandlers">
|
||||
<RegistryValue Type="string" Name="{ddee2b8a-6807-48a6-bb20-2338174ff779}" Value="Svg Preview Handler" />
|
||||
</RegistryKey>
|
||||
<!-- Add Markdown preview handler to preview handlers list -->
|
||||
<RegistryKey Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\PreviewHandlers">
|
||||
<RegistryValue Type="string" Name="{45769bcc-e8fd-42d0-947e-02beef77a1f5}" Value="Markdown Preview Handler" />
|
||||
</RegistryKey>
|
||||
<!-- Add Pdf preview handler to preview handlers list -->
|
||||
<RegistryKey Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\PreviewHandlers">
|
||||
<RegistryValue Type="string" Name="{07665729-6243-4746-95b7-79579308d1b2}" Value="Pdf Preview Handler" />
|
||||
</RegistryKey>
|
||||
<!-- Add file type association for Svg Preview Handler -->
|
||||
<RegistryKey Root="HKCR" Key=".svg\shellex">
|
||||
<RegistryValue Type="string" Key="{8895b1c6-b41f-4c1c-a562-0d564250836f}" Value="{ddee2b8a-6807-48a6-bb20-2338174ff779}" />
|
||||
</RegistryKey>
|
||||
<!-- Add file type association for Svg Thumbnail Provider -->
|
||||
<RegistryKey Root="HKCR" Key=".svg\shellex">
|
||||
<RegistryValue Type="string" Key="{E357FCCD-A995-4576-B01F-234630154E96}" Value="{36B27788-A8BB-4698-A756-DF9F11F64F84}" />
|
||||
</RegistryKey>
|
||||
<!-- Add file type association for Markdown Preview Handler -->
|
||||
<RegistryKey Root="HKCR" Key=".md\shellex">
|
||||
<RegistryValue Type="string" Key="{8895b1c6-b41f-4c1c-a562-0d564250836f}" Value="{45769bcc-e8fd-42d0-947e-02beef77a1f5}" />
|
||||
</RegistryKey>
|
||||
<!-- Add file type association for Pdf Preview Handler -->
|
||||
<RegistryKey Root="HKCR" Key=".pdf\shellex">
|
||||
<RegistryValue Type="string" Key="{8895b1c6-b41f-4c1c-a562-0d564250836f}" Value="{07665729-6243-4746-95b7-79579308d1b2}" />
|
||||
</RegistryKey>
|
||||
<!-- Add file type association for Pdf Thumbnail Provider -->
|
||||
<RegistryKey Root="HKCR" Key=".pdf\shellex">
|
||||
<RegistryValue Type="string" Key="{E357FCCD-A995-4576-B01F-234630154E96}" Value="{BCC13D15-9720-4CC4-8371-EA74A274741E}" />
|
||||
</RegistryKey>
|
||||
<Component Id="Module_PowerPreview_Registry" Guid="CD90ADC0-7CD5-4A62-B0AF-23545C1E6DD3" Win64="yes">
|
||||
<!-- Update Key to use IE11 for prevhost.exe -->
|
||||
<RegistryKey Root="HKLM" Key="Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION">
|
||||
<RegistryValue Type="integer" Name="prevhost.exe" Value="11000" />
|
||||
|
@ -687,7 +621,19 @@
|
|||
<!-- PowerRename -->
|
||||
<DirectoryRef Id="PowerRenameInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)">
|
||||
<Component Id="Module_PowerRename" Guid="E4401D08-27FE-4F96-BA17-0C61FD79E684" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\PowerRenameExt.dll" KeyPath="yes" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\Microsoft.Toolkit.Win32.UI.XamlHost.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\Microsoft.UI.Xaml.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\msvcp140_app.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\PowerRenameUILib.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\PowerRename.exe" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\resources.pri" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\vcruntime140_1_app.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\vcruntime140_app.dll" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\PowerRenameExt.dll" KeyPath="yes" />
|
||||
<!-- VCRuntime -->
|
||||
<?foreach File in vcruntime140.dll;vcruntime140_1.dll;concrt140.dll;msvcp140.dll;msvcp140_1.dll;msvcp140_2.dll;msvcp140_codecvt_ids.dll;vccorlib140.dll?>
|
||||
<File Id="PowerRename_$(var.File)" Source="$(var.RepoDir)installer\VCRuntime\$(var.File)" />
|
||||
<?endforeach?>
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}">
|
||||
<RegistryValue Type="string" Value="PowerRename Shell Extension" />
|
||||
<RegistryValue Type="string" Name="ContextMenuOptIn" Value="" />
|
||||
|
@ -700,6 +646,22 @@
|
|||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="PowerRenameAssetsFolder" FileSource="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)">
|
||||
<Component Id="Module_PowerRename_Assets" Guid="5976BEDF-64F5-4836-8674-EE7577C77508" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\Assets\file.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PowerRenameProjectName)\Assets\folder.png" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<!-- MouseUtils -->
|
||||
<DirectoryRef Id="MouseUtilsInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.MouseUtilsProjectName)">
|
||||
<Component Id="Module_FindMyMouse" Guid="60D0E4AE-188F-4403-BF06-1465AACC1BC5" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.MouseUtilsProjectName)\FindMyMouse.dll" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="Module_MouseHighlighter" Guid="3BAEA39F-A73D-48D2-9616-BBED5B8C86D3" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.MouseUtilsProjectName)\MouseHighlighter.dll" KeyPath="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Shortcut guide -->
|
||||
<DirectoryRef Id="ShortcutGuideModuleInterfaceInstallFolder" FileSource="$(var.ShortcutGuideModuleInterface)">
|
||||
<Component Id="Module_ShortcutGuideModuleInterface" Guid="CBD0AC09-91D3-428E-B2B3-05745ADF3473" Win64="yes">
|
||||
|
@ -707,8 +669,7 @@
|
|||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
|
||||
<!-- <DirectoryRef Id="VideoConferenceInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\">
|
||||
<DirectoryRef Id="VideoConferenceInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\">
|
||||
<Component Id="Module_VideoConference" Guid="5996527a-40fc-432e-b3ac-abc0b4bd3887" Win64="yes">
|
||||
<Condition>WINDOWSBUILDNUMBER >= 18362</Condition>
|
||||
<File SelfRegCost="1" Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\VideoConferenceProxyFilter_x64.dll" KeyPath="yes">
|
||||
|
@ -736,7 +697,7 @@
|
|||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-On Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-On Light.png" />
|
||||
</Component>
|
||||
</DirectoryRef> -->
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="ShortcutGuideExecutableInstallFolder" FileSource="$(var.ShortcutGuideExecutable)">
|
||||
<Component Id="Module_ShortcutGuideExecutable" Guid="DA6E5710-F1DF-44EB-A316-300FA39544E9" Win64="yes">
|
||||
|
@ -902,21 +863,21 @@
|
|||
</DirectoryRef>
|
||||
<DirectoryRef Id="SettingsV2AssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules">
|
||||
<Component Id="SettingsV2AssetsModules" Guid="A0B961A9-77D0-4223-88A9-E3B41BD9C329" Win64="yes">
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;MouseUtils.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<File Id="SettingsV2AssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SettingsV2OOBEAssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules\OOBE">
|
||||
<Component Id="SettingsV2OOBEAssetsModules" Guid="E2360A83-6694-4B33-B5F6-641A906359EE" Win64="yes">
|
||||
<?foreach File in ColorPicker.gif;Awake.png;FancyZones.gif;FileExplorer.png;ImageResizer.gif;KBM.gif;PowerRename.gif;Run.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
|
||||
<?foreach File in ColorPicker.gif;Awake.png;FancyZones.gif;FileExplorer.png;ImageResizer.gif;KBM.gif;MouseUtils.gif;PowerRename.gif;Run.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
|
||||
<File Id="SettingsV2OOBEAssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\OOBE\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SettingsV2OOBEAssetsFluentIconsInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\FluentIcons">
|
||||
<Component Id="SettingsV2OOBEAssetsFluentIcons" Guid="6A380D5A-DA63-45B5-B68F-06D57CDD1B9C" Win64="yes">
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;FileExplorerPreview.png;ImageResizer.png;KeyboardManager.png;PowerRename.png;PowerToys.png;PowerToysRun.png;Settings.png;ShortcutGuide.png;VideoConferenceMute.png ?>
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;FileExplorerPreview.png;ImageResizer.png;KeyboardManager.png;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>
|
||||
|
@ -993,16 +954,16 @@
|
|||
<ComponentRef Id="ShortcutGuideSvgs" />
|
||||
<ComponentRef Id="Module_ShortcutGuideModuleInterface" />
|
||||
<ComponentRef Id="Module_ShortcutGuideExecutable" />
|
||||
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
|
||||
<!-- <ComponentRef Id="Module_VideoConference" />
|
||||
<ComponentRef Id="Module_VideoConferenceIcons" /> -->
|
||||
<ComponentRef Id="Module_VideoConference" />
|
||||
<ComponentRef Id="Module_VideoConferenceIcons" />
|
||||
<ComponentRef Id="Module_FancyZones" />
|
||||
<ComponentRef Id="DesktopShortcut" />
|
||||
<ComponentRef Id="Module_PowerRename" />
|
||||
<ComponentRef Id="Module_PowerRename_Assets" />
|
||||
<ComponentRef Id="Module_ImageResizer" />
|
||||
<ComponentRef Id="Module_ImageResizer_Registry" />
|
||||
<ComponentRef Id="Module_PowerPreview" />
|
||||
<ComponentRef Id="Module_PowerPreview_PerUserRegistry" />
|
||||
<ComponentRef Id="Module_PowerPreview_Registry" />
|
||||
<ComponentRef Id="Module_KeyboardManager" />
|
||||
<ComponentRef Id="Module_KeyboardManager_Editor" />
|
||||
<ComponentRef Id="Module_KeyboardManager_Engine" />
|
||||
|
@ -1012,6 +973,8 @@
|
|||
<ComponentRef Id="Module_Awake_runtime_netstandard20"/>
|
||||
<ComponentRef Id="Module_Awake_runtime_netcoreapp30"/>
|
||||
<ComponentRef Id="Module_Awake_runtime_netcoreapp21"/>
|
||||
<ComponentRef Id="Module_FindMyMouse"/>
|
||||
<ComponentRef Id="Module_MouseHighlighter"/>
|
||||
<ComponentRef Id="SettingsV2" />
|
||||
<ComponentRef Id="SettingsV2Assets" />
|
||||
<ComponentRef Id="SettingsV2AssetsModules" />
|
||||
|
@ -1035,7 +998,7 @@
|
|||
<Fragment>
|
||||
<!-- Resource directories should be added only if the installer is built on the build farm -->
|
||||
<?ifdef env.IsPipeline?>
|
||||
<?foreach ParentDirectory in LauncherInstallFolder;FancyZonesInstallFolder;ImageResizerInstallFolder;ColorPickerInstallFolder;FileExplorerPreviewInstallFolder;CalculatorPluginFolder;FolderPluginFolder;ProgramPluginFolder;ShellPluginFolder;IndexerPluginFolder;UnitConverterPluginFolder;UriPluginFolder;WindowWalkerPluginFolder;RegistryPluginFolder;VSCodeWorkspacesPluginFolder;ServicePluginFolder;SystemPluginFolder;WindowsSettingsPluginFolder?>
|
||||
<?foreach ParentDirectory in LauncherInstallFolder;FancyZonesInstallFolder;ImageResizerInstallFolder;ColorPickerInstallFolder;FileExplorerPreviewInstallFolder;CalculatorPluginFolder;FolderPluginFolder;ProgramPluginFolder;ShellPluginFolder;IndexerPluginFolder;UnitConverterPluginFolder;UriPluginFolder;WindowWalkerPluginFolder;RegistryPluginFolder;VSCodeWorkspacesPluginFolder;ServicePluginFolder;SystemPluginFolder;WindowsSettingsPluginFolder;WindowsTerminalPluginFolder?>
|
||||
<DirectoryRef Id="$(var.ParentDirectory)">
|
||||
<!-- Resource file directories -->
|
||||
<?foreach Language in $(var.LocLanguageList)?>
|
||||
|
@ -1100,28 +1063,28 @@
|
|||
<File Id="Launcher_Calculator_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Calculator\$(var.Language)\Microsoft.PowerToys.Run.Plugin.Calculator.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Folder_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)FolderPluginFolder">
|
||||
<File Id="Launcher_Folder_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Folder\$(var.Language)\Microsoft.Plugin.Folder.resources.dll" />
|
||||
<File Id="Launcher_Folder_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Folder\$(var.Language)\Microsoft.Plugin.Folder.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Program_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)ProgramPluginFolder">
|
||||
<File Id="Launcher_Program_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Program\$(var.Language)\Microsoft.Plugin.Program.resources.dll" />
|
||||
<File Id="Launcher_Program_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Program\$(var.Language)\Microsoft.Plugin.Program.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Shell_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)ShellPluginFolder">
|
||||
<File Id="Launcher_Shell_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Shell\$(var.Language)\Microsoft.Plugin.Shell.resources.dll" />
|
||||
<File Id="Launcher_Shell_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Shell\$(var.Language)\Microsoft.Plugin.Shell.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Indexer_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)IndexerPluginFolder">
|
||||
<File Id="Launcher_Indexer_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Indexer\$(var.Language)\Microsoft.Plugin.Indexer.resources.dll" />
|
||||
<File Id="Launcher_Indexer_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Indexer\$(var.Language)\Microsoft.Plugin.Indexer.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Uri_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)UriPluginFolder">
|
||||
<File Id="Launcher_Uri_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\$(var.Language)\Microsoft.Plugin.Uri.resources.dll" />
|
||||
<File Id="Launcher_Uri_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Uri\$(var.Language)\Microsoft.Plugin.Uri.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_VSCodeWorkspaces_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)VSCodeWorkspacesPluginFolder">
|
||||
<File Id="Launcher_VSCodeWorkspaces_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\VSCodeWorkspaces\$(var.Language)\Community.PowerToys.Run.Plugin.VSCodeWorkspaces.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_WindowWalker_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)WindowWalkerPluginFolder">
|
||||
<File Id="Launcher_WindowWalker_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\$(var.Language)\Microsoft.Plugin.WindowWalker.resources.dll" />
|
||||
<File Id="Launcher_WindowWalker_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowWalker\$(var.Language)\Microsoft.Plugin.WindowWalker.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Registry_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)RegistryPluginFolder">
|
||||
<File Id="Launcher_Registry_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\$(var.Language)\Microsoft.PowerToys.Run.Plugin.Registry.resources.dll" />
|
||||
<File Id="Launcher_Registry_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Registry\$(var.Language)\Microsoft.PowerToys.Run.Plugin.Registry.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_Service_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)ServicePluginFolder">
|
||||
<File Id="Launcher_Service_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Service\$(var.Language)\Microsoft.PowerToys.Run.Plugin.Service.resources.dll" />
|
||||
|
@ -1130,8 +1093,13 @@
|
|||
<File Id="Launcher_System_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\System\$(var.Language)\Microsoft.PowerToys.Run.Plugin.System.resources.dll" />
|
||||
</Component>
|
||||
<Component Id="Launcher_WindowsSettings_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)WindowsSettingsPluginFolder">
|
||||
<File Id="Launcher_WindowsSettings_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\$(var.Language)\Microsoft.PowerToys.Run.Plugin.WindowsSettings.resources.dll" />
|
||||
<File Id="Launcher_WindowsSettings_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsSettings\$(var.Language)\Microsoft.PowerToys.Run.Plugin.WindowsSettings.resources.dll" />
|
||||
</Component>
|
||||
<!-- Uncomment after Plugin receives the localization files.
|
||||
<Component Id="Launcher_WindowsTerminal_$(var.IdSafeLanguage)_Component" Directory="Resource$(var.IdSafeLanguage)WindowsTerminalFolder">
|
||||
<File Id="Launcher_WindowsTerminal_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsTerminal\$(var.Language)\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.resources.dll" />
|
||||
</Component>
|
||||
-->
|
||||
<?undef IdSafeLanguage?>
|
||||
<?endforeach?>
|
||||
<?endif?>
|
||||
|
@ -1179,71 +1147,71 @@
|
|||
<!-- Folder Plugin -->
|
||||
<Component Id="FolderComponent" Directory="FolderPluginFolder" Guid="453D6C29-8F0D-46EC-B210-82E6AF547039">
|
||||
<?foreach File in plugin.json;Microsoft.Plugin.Folder.deps.json;Microsoft.Plugin.Folder.dll;ManagedTelemetry.dll?>
|
||||
<File Id="Folder_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Folder\$(var.File)" />
|
||||
<File Id="Folder_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Folder\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="FolderImagesComponent" Directory="FolderPluginImagesFolder" Guid="6C5226EB-E312-4768-B4D1-B1D3ACFCCBDF">
|
||||
<?foreach File in copy.dark.png;copy.light.png;delete.dark.png;delete.light.png;file.dark.png;file.light.png;folder.dark.png;folder.light.png;user.dark.png;user.light.png;Warning.dark.png;Warning.light.png?>
|
||||
<File Id="FolderPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Folder\Images\$(var.File)" />
|
||||
<File Id="FolderPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Folder\Images\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
|
||||
<!-- Program Plugin -->
|
||||
<Component Id="ProgramComponent" Directory="ProgramPluginFolder" Guid="3C5CA6E6-3D36-4F4E-B40E-38AA5E5CB799">
|
||||
<?foreach File in plugin.json;Microsoft.Plugin.Program.deps.json;Microsoft.Plugin.Program.dll;ManagedTelemetry.dll?>
|
||||
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Program\$(var.File)" />
|
||||
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Program\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="ProgramImagesComponent" Directory="ProgramImagesFolder" Guid="30D357F5-406F-47D1-BEFE-6022746469B4">
|
||||
<?foreach File in app.dark.png;app.light.png;disable.light.png;disable.dark.png;folder.light.png;folder.dark.png;shell.light.png;shell.dark.png;user.light.png;user.dark.png?>
|
||||
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Program\Images\$(var.File)" />
|
||||
<File Id="Program_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Program\Images\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
|
||||
<!-- Shell Plugin -->
|
||||
<Component Id="ShellComponent" Directory="ShellPluginFolder" Guid="6D3D7294-1804-47C9-83E5-47A8867F3801">
|
||||
<?foreach File in plugin.json;Microsoft.Plugin.Shell.deps.json;Microsoft.Plugin.Shell.dll;ManagedTelemetry.dll?>
|
||||
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Shell\$(var.File)" />
|
||||
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Shell\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="ShellImagesComponent" Directory="ShellImagesFolder" Guid="15B5DBAE-E7C1-4BF7-A29E-6CE76242F8F4">
|
||||
<?foreach File in shell.light.png;shell.dark.png;user.light.png;user.dark.png?>
|
||||
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Shell\Images\$(var.File)" />
|
||||
<File Id="Shell_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Shell\Images\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
|
||||
<!-- Indexer Plugin -->
|
||||
<Component Id="IndexerComponent" Directory="IndexerPluginFolder" Guid="FEA9816A-B4F7-42CC-99AF-B05F3E7F7EBF">
|
||||
<?foreach File in Microsoft.Plugin.Indexer.deps.json;Microsoft.Plugin.Indexer.dll;plugin.json;ManagedTelemetry.dll?>
|
||||
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Indexer\$(var.File)" />
|
||||
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Indexer\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="IndexerImagesComponent" Directory="IndexerImagesFolder" Guid="DB2E8D49-D104-425B-9616-952AC8CAB676">
|
||||
<?foreach File in indexer.dark.png;indexer.light.png;Warning.light.png;Warning.dark.png?>
|
||||
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Indexer\Images\$(var.File)" />
|
||||
<File Id="Indexer_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Indexer\Images\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
|
||||
<!-- UnitConverter Plugin -->
|
||||
<Component Id="UnitConverterComponent" Directory="UnitConverterPluginFolder" Guid="D4F429E3-C619-49D6-9416-88A757D18E02">
|
||||
<?foreach File in plugin.json;Community.PowerToys.Run.Plugin.UnitConverter.deps.json;Community.PowerToys.Run.Plugin.UnitConverter.dll?>
|
||||
<File Id="UnitConverter_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Community.UnitConverter\$(var.File)" />
|
||||
<File Id="UnitConverter_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\UnitConverter\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="UnitConverterImagesComponent" Directory="UnitConverterImagesFolder" Guid="16ABD217-0898-47B2-89D9-AF1ABF00F543">
|
||||
<File Id="UnitConverterLight" Source="$(var.BinX64Dir)modules\launcher\Plugins\Community.UnitConverter\Images\unitconverter.light.png" />
|
||||
<File Id="UnitConverterDark" Source="$(var.BinX64Dir)modules\launcher\Plugins\Community.UnitConverter\Images\unitconverter.dark.png" />
|
||||
<File Id="UnitConverterLight" Source="$(var.BinX64Dir)modules\launcher\Plugins\UnitConverter\Images\unitconverter.light.png" />
|
||||
<File Id="UnitConverterDark" Source="$(var.BinX64Dir)modules\launcher\Plugins\UnitConverter\Images\unitconverter.dark.png" />
|
||||
</Component>
|
||||
|
||||
<!-- Uri Plugin -->
|
||||
<Component Id="UriComponent" Directory="UriPluginFolder" Guid="C7DC8F88-554C-4375-9510-9435399B5D3D">
|
||||
<?foreach File in plugin.json;Microsoft.Plugin.Uri.deps.json;Microsoft.Plugin.Uri.dll;ManagedTelemetry.dll?>
|
||||
<File Id="Uri_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\$(var.File)" />
|
||||
<File Id="Uri_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Uri\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="UriImagesComponent" Directory="UriImagesFolder" Guid="8C9C1634-28C8-45C4-A8EA-8D4C9B4810D0">
|
||||
<File Id="UriDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\Images\Uri.dark.png" />
|
||||
<File Id="UriLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\Images\Uri.light.png" />
|
||||
<File Id="UriDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Uri\Images\Uri.dark.png" />
|
||||
<File Id="UriLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Uri\Images\Uri.light.png" />
|
||||
</Component>
|
||||
|
||||
<!-- VSCodeWorkspaces Plugin -->
|
||||
|
@ -1263,23 +1231,23 @@
|
|||
<!-- WindowWalker Plugin -->
|
||||
<Component Id="WindowWalkerComponent" Directory="WindowWalkerPluginFolder" Guid="EB1391C9-B701-421F-80FC-ABB2FEDFAD19">
|
||||
<?foreach File in plugin.json;Microsoft.Plugin.WindowWalker.deps.json;Microsoft.Plugin.WindowWalker.dll;ManagedTelemetry.dll?>
|
||||
<File Id="WindowWalker_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\$(var.File)" />
|
||||
<File Id="WindowWalker_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowWalker\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="WindowWalkerImagesComponent" Directory="WindowWalkerImagesFolder" Guid="3944A7F5-77F4-4979-9911-EDE709B2F509">
|
||||
<File Id="WindowWalkerDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Images\windowwalker.dark.png" />
|
||||
<File Id="WindowWalkerLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.WindowWalker\Images\windowwalker.light.png" />
|
||||
<File Id="WindowWalkerDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowWalker\Images\windowwalker.dark.png" />
|
||||
<File Id="WindowWalkerLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowWalker\Images\windowwalker.light.png" />
|
||||
</Component>
|
||||
|
||||
<!-- Registry Plugin -->
|
||||
<Component Id="RegistryComponent" Directory="RegistryPluginFolder" Guid="186FDFDC-12F1-4221-BEF6-DE6763F54B18">
|
||||
<?foreach File in plugin.json;Microsoft.PowerToys.Run.Plugin.Registry.deps.json;Microsoft.PowerToys.Run.Plugin.Registry.dll;ManagedTelemetry.dll?>
|
||||
<File Id="Registry_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\$(var.File)" />
|
||||
<File Id="Registry_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Registry\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="RegistryImagesComponent" Directory="RegistryImagesFolder" Guid="2E2C91A2-9F53-40C6-BBE9-E6FD6D6E94EB">
|
||||
<File Id="RegistryDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\Images\reg.dark.png" />
|
||||
<File Id="RegistryLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Registry\Images\reg.light.png" />
|
||||
<File Id="RegistryDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Registry\Images\reg.dark.png" />
|
||||
<File Id="RegistryLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Registry\Images\reg.light.png" />
|
||||
</Component>
|
||||
|
||||
<!-- Service Plugin -->
|
||||
|
@ -1317,14 +1285,25 @@
|
|||
<!-- WindowsSettings Plugin -->
|
||||
<Component Id="WindowsSettingsComponent" Directory="WindowsSettingsPluginFolder" Guid="ACEC2B6D-8E95-43BF-A1E4-137E95F07C96">
|
||||
<?foreach File in plugin.json;Microsoft.PowerToys.Run.Plugin.WindowsSettings.deps.json;Microsoft.PowerToys.Run.Plugin.WindowsSettings.dll;ManagedTelemetry.dll?>
|
||||
<File Id="WindowsSettings_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\$(var.File)" />
|
||||
<File Id="WindowsSettings_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsSettings\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="WindowsSettingsImagesComponent" Directory="WindowsSettingsImagesFolder" Guid="E1CE33A7-6318-4FA6-A46B-9302A00BD6AA">
|
||||
<File Id="WindowsSettingsDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Images\WindowsSettings.dark.png" />
|
||||
<File Id="WindowsSettingsLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Images\WindowsSettings.light.png" />
|
||||
<File Id="WindowsSettingsDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsSettings\Images\WindowsSettings.dark.png" />
|
||||
<File Id="WindowsSettingsLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsSettings\Images\WindowsSettings.light.png" />
|
||||
</Component>
|
||||
|
||||
<!-- WindowsTerminal Plugin -->
|
||||
<Component Id="WindowsTerminalComponent" Directory="WindowsTerminalPluginFolder" Guid="5392FD11-9A69-4409-A711-748C225F1A18">
|
||||
<?foreach File in plugin.json;Microsoft.PowerToys.Run.Plugin.WindowsTerminal.deps.json;Microsoft.PowerToys.Run.Plugin.WindowsTerminal.dll;ManagedTelemetry.dll?>
|
||||
<File Id="WindowsTerminal_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsTerminal\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
<Component Id="WindowsTerminalImagesComponent" Directory="WindowsTerminalImagesFolder" Guid="CDD21BEB-E2F3-4138-A1F8-72FD3B52706A">
|
||||
<File Id="WindowsTerminalDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsTerminal\Images\WindowsTerminal.dark.png" />
|
||||
<File Id="WindowsTerminalLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\WindowsTerminal\Images\WindowsTerminal.light.png" />
|
||||
</Component>
|
||||
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
#include "resource.h"
|
||||
#include <ProjectTelemetry.h>
|
||||
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
|
||||
#include "../../src/common/logger/logger.h"
|
||||
#include "../../src/common/utils/MsiUtils.h"
|
||||
#include "../../src/common/utils/modulesRegistry.h"
|
||||
#include "../../src/common/updating/installer.h"
|
||||
#include "../../src/common/version/version.h"
|
||||
|
||||
|
@ -25,6 +29,94 @@ const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
|
|||
static const wchar_t* POWERTOYS_EXE_COMPONENT = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
|
||||
static const wchar_t* POWERTOYS_UPGRADE_CODE = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
|
||||
|
||||
struct WcaSink : spdlog::sinks::base_sink<std::mutex>
|
||||
{
|
||||
virtual void sink_it_(const spdlog::details::log_msg& msg) override
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, msg.payload.data());
|
||||
}
|
||||
virtual void flush_() override
|
||||
{
|
||||
// we don't need to flush wca log manually
|
||||
}
|
||||
};
|
||||
|
||||
void initSystemLogger()
|
||||
{
|
||||
static std::once_flag initLoggerFlag;
|
||||
std::call_once(initLoggerFlag, []() { Logger::init(std::vector<spdlog::sink_ptr>{ std::make_shared<WcaSink>() }); });
|
||||
}
|
||||
|
||||
HRESULT getInstallFolder(MSIHANDLE hInstall, std::wstring& installationDir)
|
||||
{
|
||||
DWORD len = 0;
|
||||
wchar_t _[1];
|
||||
MsiGetPropertyW(hInstall, L"CustomActionData", _, &len);
|
||||
len += 1;
|
||||
installationDir.resize(len);
|
||||
HRESULT hr = MsiGetPropertyW(hInstall, L"CustomActionData", installationDir.data(), &len);
|
||||
if (installationDir.length())
|
||||
{
|
||||
installationDir.resize(installationDir.length() - 1);
|
||||
}
|
||||
ExitOnFailure(hr, "Failed to get INSTALLFOLDER property.");
|
||||
LExit:
|
||||
return hr;
|
||||
}
|
||||
UINT __stdcall ApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
|
||||
{
|
||||
initSystemLogger();
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
std::wstring installationFolder;
|
||||
bool failedToApply = false;
|
||||
|
||||
hr = WcaInitialize(hInstall, "ApplyModulesRegistryChangeSets");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
hr = getInstallFolder(hInstall, installationFolder);
|
||||
ExitOnFailure(hr, "Failed to get installFolder.");
|
||||
|
||||
for (const auto& changeSet : getAllModulesChangeSets(installationFolder, false))
|
||||
{
|
||||
if (!changeSet.apply())
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "Couldn't apply registry changeSet");
|
||||
failedToApply = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!failedToApply)
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "All registry changeSets applied successfully");
|
||||
}
|
||||
LExit:
|
||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall UnApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
|
||||
{
|
||||
initSystemLogger();
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
std::wstring installationFolder;
|
||||
|
||||
hr = WcaInitialize(hInstall, "UndoModulesRegistryChangeSets"); // original func name is too long
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
hr = getInstallFolder(hInstall, installationFolder);
|
||||
ExitOnFailure(hr, "Failed to get installFolder.");
|
||||
for (const auto& changeSet : getAllModulesChangeSets(installationFolder, false))
|
||||
{
|
||||
changeSet.unApply();
|
||||
}
|
||||
|
||||
ExitOnFailure(hr, "Failed to extract msix");
|
||||
|
||||
LExit:
|
||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall InstallEmbeddedMSIXCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
LIBRARY "PowerToysSetupCustomActions"
|
||||
|
||||
EXPORTS
|
||||
ApplyModulesRegistryChangeSetsCA
|
||||
CreateScheduledTaskCA
|
||||
DetectPrevInstallPathCA
|
||||
RemoveScheduledTasksCA
|
||||
|
@ -17,5 +18,6 @@ EXPORTS
|
|||
CertifyVirtualCameraDriverCA
|
||||
InstallVirtualCameraDriverCA
|
||||
InstallEmbeddedMSIXCA
|
||||
UnApplyModulesRegistryChangeSetsCA
|
||||
UninstallVirtualCameraDriverCA
|
||||
UninstallEmbeddedMSIXCA
|
|
@ -30,6 +30,7 @@
|
|||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<Import Project="..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
|
@ -122,6 +123,11 @@
|
|||
<ItemGroup>
|
||||
<ResourceCompile Include="Resource.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <psapi.h>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# PowerToys installer instructions
|
||||
|
||||
Please go to https://github.com/microsoft/PowerToys/tree/master/doc/devdocs#compile-the-installer for instructions
|
||||
Please go to https://github.com/microsoft/PowerToys/tree/main/doc/devdocs#compile-the-installer for instructions
|
||||
|
|
80
src/common/Microsoft.PowerToys.Common.UI/SettingsDeepLink.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.PowerToys.Common.UI
|
||||
{
|
||||
public static class SettingsDeepLink
|
||||
{
|
||||
public enum SettingsWindow
|
||||
{
|
||||
Overview = 0,
|
||||
Awake,
|
||||
ColorPicker,
|
||||
FancyZones,
|
||||
Run,
|
||||
ImageResizer,
|
||||
KBM,
|
||||
MouseUtils,
|
||||
PowerRename,
|
||||
FileExplorer,
|
||||
ShortcutGuide,
|
||||
VideoConference,
|
||||
}
|
||||
|
||||
private static string SettingsWindowNameToString(SettingsWindow value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SettingsWindow.Overview:
|
||||
return "Overview";
|
||||
case SettingsWindow.Awake:
|
||||
return "Awake";
|
||||
case SettingsWindow.ColorPicker:
|
||||
return "ColorPicker";
|
||||
case SettingsWindow.FancyZones:
|
||||
return "FancyZones";
|
||||
case SettingsWindow.Run:
|
||||
return "Run";
|
||||
case SettingsWindow.ImageResizer:
|
||||
return "ImageResizer";
|
||||
case SettingsWindow.KBM:
|
||||
return "KBM";
|
||||
case SettingsWindow.MouseUtils:
|
||||
return "MouseUtils";
|
||||
case SettingsWindow.PowerRename:
|
||||
return "PowerRename";
|
||||
case SettingsWindow.FileExplorer:
|
||||
return "FileExplorer";
|
||||
case SettingsWindow.ShortcutGuide:
|
||||
return "ShortcutGuide";
|
||||
case SettingsWindow.VideoConference:
|
||||
return "VideoConference";
|
||||
default:
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void OpenSettings(SettingsWindow window)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assemblyPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
|
||||
var fullPath = Directory.GetParent(assemblyPath).FullName;
|
||||
Process.Start(new ProcessStartInfo(fullPath + "\\..\\PowerToys.exe") { Arguments = "--open-settings=" + SettingsWindowNameToString(window) });
|
||||
}
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
catch
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
// TODO(stefan): Log exception once unified logging is implemented
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -313,7 +313,7 @@ namespace PowerToysSettings
|
|||
return json::has(props, name) && json::has(props.GetNamedObject(name), L"value", type);
|
||||
}
|
||||
|
||||
std::optional<bool> PowerToyValues::get_bool_value(std::wstring_view property_name)
|
||||
std::optional<bool> PowerToyValues::get_bool_value(std::wstring_view property_name) const
|
||||
{
|
||||
if (!has_property(m_json, property_name, json::JsonValueType::Boolean))
|
||||
{
|
||||
|
@ -322,7 +322,7 @@ namespace PowerToysSettings
|
|||
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedBoolean(L"value");
|
||||
}
|
||||
|
||||
std::optional<int> PowerToyValues::get_int_value(std::wstring_view property_name)
|
||||
std::optional<int> PowerToyValues::get_int_value(std::wstring_view property_name) const
|
||||
{
|
||||
if (!has_property(m_json, property_name, json::JsonValueType::Number))
|
||||
{
|
||||
|
@ -331,7 +331,7 @@ namespace PowerToysSettings
|
|||
return static_cast<int>(m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedNumber(L"value"));
|
||||
}
|
||||
|
||||
std::optional<std::wstring> PowerToyValues::get_string_value(std::wstring_view property_name)
|
||||
std::optional<std::wstring> PowerToyValues::get_string_value(std::wstring_view property_name) const
|
||||
{
|
||||
if (!has_property(m_json, property_name, json::JsonValueType::String))
|
||||
{
|
||||
|
@ -340,7 +340,7 @@ namespace PowerToysSettings
|
|||
return m_json.GetNamedObject(L"properties").GetNamedObject(property_name).GetNamedString(L"value").c_str();
|
||||
}
|
||||
|
||||
std::optional<json::JsonObject> PowerToyValues::get_json(std::wstring_view property_name)
|
||||
std::optional<json::JsonObject> PowerToyValues::get_json(std::wstring_view property_name) const
|
||||
{
|
||||
if (!has_property(m_json, property_name, json::JsonValueType::Object))
|
||||
{
|
||||
|
|
|
@ -79,10 +79,10 @@ namespace PowerToysSettings
|
|||
m_json.GetNamedObject(L"properties").SetNamedValue(name, prop_value);
|
||||
}
|
||||
|
||||
std::optional<bool> get_bool_value(std::wstring_view property_name);
|
||||
std::optional<int> get_int_value(std::wstring_view property_name);
|
||||
std::optional<std::wstring> get_string_value(std::wstring_view property_name);
|
||||
std::optional<json::JsonObject> get_json(std::wstring_view property_name);
|
||||
std::optional<bool> get_bool_value(std::wstring_view property_name) const;
|
||||
std::optional<int> get_int_value(std::wstring_view property_name) const;
|
||||
std::optional<std::wstring> get_string_value(std::wstring_view property_name) const;
|
||||
std::optional<json::JsonObject> get_json(std::wstring_view property_name) const;
|
||||
json::JsonObject get_raw_json();
|
||||
|
||||
std::wstring serialize();
|
||||
|
|
|
@ -171,6 +171,10 @@ public
|
|||
return gcnew String(CommonSharedConstants::POWER_LAUNCHER_SHARED_EVENT);
|
||||
}
|
||||
|
||||
static String ^ PowerLauncherCentralizedHookSharedEvent() {
|
||||
return gcnew String(CommonSharedConstants::POWER_LAUNCHER_CENTRALIZED_HOOK_SHARED_EVENT);
|
||||
}
|
||||
|
||||
static String ^ RunSendSettingsTelemetryEvent() {
|
||||
return gcnew String(CommonSharedConstants::RUN_SEND_SETTINGS_TELEMETRY_EVENT);
|
||||
}
|
||||
|
|
|
@ -10,5 +10,6 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
// add headers that you want to pre-compile here
|
||||
#include <Windows.h>
|
||||
#include <Endpointvolume.h>
|
||||
|
||||
#endif //PCH_H
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace CommonSharedConstants
|
|||
// Path to the event used by PowerLauncher
|
||||
const wchar_t POWER_LAUNCHER_SHARED_EVENT[] = L"Local\\PowerToysRunInvokeEvent-30f26ad7-d36d-4c0e-ab02-68bb5ff3c4ab";
|
||||
|
||||
const wchar_t POWER_LAUNCHER_CENTRALIZED_HOOK_SHARED_EVENT[] = L"Local\\PowerToysRunCentralizedHookInvokeEvent-30f26ad7-d36d-4c0e-ab02-68bb5ff3c4ab";
|
||||
|
||||
const wchar_t RUN_SEND_SETTINGS_TELEMETRY_EVENT[] = L"Local\\PowerToysRunInvokeEvent-638ec522-0018-4b96-837d-6bd88e06f0d6";
|
||||
|
||||
const wchar_t RUN_EXIT_EVENT[] = L"Local\\PowerToysRunExitEvent-3e38e49d-a762-4ef1-88f2-fd4bc7481516";
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "pch.h"
|
||||
#include "CallTracer.h"
|
||||
#include "call_tracer.h"
|
||||
|
||||
#include <map>
|
||||
#include <thread>
|
||||
|
||||
namespace
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/logger/logger.h"
|
||||
#include <string>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#define _TRACER_ CallTracer callTracer(__FUNCTION__)
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
#include "pch.h"
|
||||
#include "framework.h"
|
||||
#include "logger.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <spdlog/sinks/daily_file_sink.h>
|
||||
#include <spdlog/sinks/msvc_sink.h>
|
||||
#include <spdlog/sinks/null_sink.h>
|
||||
|
@ -16,26 +16,32 @@ using spdlog::sinks::daily_file_sink_mt;
|
|||
using spdlog::sinks::msvc_sink_mt;
|
||||
using std::make_shared;
|
||||
|
||||
std::map<std::wstring, level_enum> logLevelMapping = {
|
||||
{ L"trace", level_enum::trace },
|
||||
{ L"debug", level_enum::debug },
|
||||
{ L"info", level_enum::info },
|
||||
{ L"warn", level_enum::warn },
|
||||
{ L"err", level_enum::err },
|
||||
{ L"critical", level_enum::critical },
|
||||
{ L"off", level_enum::off },
|
||||
};
|
||||
namespace
|
||||
{
|
||||
const std::unordered_map<std::wstring, level_enum> logLevelMapping = {
|
||||
{ L"trace", level_enum::trace },
|
||||
{ L"debug", level_enum::debug },
|
||||
{ L"info", level_enum::info },
|
||||
{ L"warn", level_enum::warn },
|
||||
{ L"err", level_enum::err },
|
||||
{ L"critical", level_enum::critical },
|
||||
{ L"off", level_enum::off },
|
||||
};
|
||||
}
|
||||
|
||||
level_enum getLogLevel(std::wstring_view logSettingsPath)
|
||||
{
|
||||
auto logLevel = get_log_settings(logSettingsPath).logLevel;
|
||||
level_enum result = logLevelMapping[LogSettings::defaultLogLevel];
|
||||
if (logLevelMapping.find(logLevel) != logLevelMapping.end())
|
||||
if (auto it = logLevelMapping.find(logLevel); it != logLevelMapping.end())
|
||||
{
|
||||
result = logLevelMapping[logLevel];
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return result;
|
||||
if (auto it = logLevelMapping.find(LogSettings::defaultLogLevel); it != logLevelMapping.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return level_enum::trace;
|
||||
}
|
||||
|
||||
std::shared_ptr<spdlog::logger> Logger::logger = spdlog::null_logger_mt("null");
|
||||
|
@ -89,3 +95,14 @@ void Logger::init(std::string loggerName, std::wstring logFilePath, std::wstring
|
|||
spdlog::flush_every(std::chrono::seconds(3));
|
||||
logger->info("{} logger is initialized", loggerName);
|
||||
}
|
||||
|
||||
void Logger::init(std::vector<spdlog::sink_ptr> sinks)
|
||||
{
|
||||
auto logger = std::make_shared<spdlog::logger>("", begin(sinks), end(sinks));
|
||||
if (!logger)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::logger = logger;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ public:
|
|||
Logger() = delete;
|
||||
|
||||
static void init(std::string loggerName, std::wstring logFilePath, std::wstring_view logSettingsPath);
|
||||
static void init(std::vector<spdlog::sink_ptr> sinks);
|
||||
|
||||
// log message should not be localized
|
||||
template<typename FormatString, typename... Args>
|
||||
|
|
|
@ -31,12 +31,14 @@
|
|||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="call_tracer.h" />
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="logger.h" />
|
||||
<ClInclude Include="logger_settings.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="call_tracer.cpp" />
|
||||
<ClCompile Include="logger.cpp" />
|
||||
<ClCompile Include="logger_settings.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
|
@ -50,9 +52,6 @@
|
|||
<ProjectReference Include="..\..\logging\logging.vcxproj">
|
||||
<Project>{7e1e3f13-2bd6-3f75-a6a7-873a2b55c60f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
<ClInclude Include="logger_settings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="call_tracer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="logger.cpp">
|
||||
|
@ -38,6 +41,9 @@
|
|||
<ClCompile Include="logger_settings.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="call_tracer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
|
|
@ -9,7 +9,7 @@ using namespace winrt::Windows::Data::Json;
|
|||
|
||||
LogSettings::LogSettings()
|
||||
{
|
||||
this->logLevel = LogSettings::defaultLogLevel;
|
||||
logLevel = defaultLogLevel;
|
||||
}
|
||||
|
||||
std::optional<JsonObject> from_file(std::wstring_view file_name)
|
||||
|
|
|
@ -13,6 +13,8 @@ struct LogSettings
|
|||
inline const static std::wstring actionRunnerLogPath = L"RunnerLogs\\action-runner-log.txt";
|
||||
inline const static std::string updateLoggerName = "update";
|
||||
inline const static std::wstring updateLogPath = L"UpdateLogs\\update-log.txt";
|
||||
inline const static std::string fileExplorerLoggerName = "FileExplorer";
|
||||
inline const static std::wstring fileExplorerLogPath = L"Logs\\file-explorer-log.txt";
|
||||
inline const static std::string launcherLoggerName = "launcher";
|
||||
inline const static std::wstring launcherLogPath = L"LogsModuleInterface\\launcher-log.txt";
|
||||
inline const static std::wstring awakeLogPath = L"Logs\\awake-log.txt";
|
||||
|
@ -23,6 +25,9 @@ struct LogSettings
|
|||
inline const static std::wstring shortcutGuideLogPath = L"ShortcutGuideLogs\\shortcut-guide-log.txt";
|
||||
inline const static std::string keyboardManagerLoggerName = "keyboard-manager";
|
||||
inline const static std::wstring keyboardManagerLogPath = L"Logs\\keyboard-manager-log.txt";
|
||||
inline const static std::string findMyMouseLoggerName = "find-my-mouse";
|
||||
inline const static std::string mouseHighlighterLoggerName = "mouse-highlighter";
|
||||
inline const static std::string powerRenameLoggerName = "powerrename";
|
||||
inline const static int retention = 30;
|
||||
std::wstring logLevel;
|
||||
LogSettings();
|
||||
|
|
58
src/common/utils/HDropIterator.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
#include <shellapi.h>
|
||||
|
||||
class HDropIterator
|
||||
{
|
||||
public:
|
||||
HDropIterator(IDataObject* pDataObject)
|
||||
{
|
||||
_current = 0;
|
||||
|
||||
FORMATETC formatetc = {
|
||||
CF_HDROP,
|
||||
NULL,
|
||||
DVASPECT_CONTENT,
|
||||
-1,
|
||||
TYMED_HGLOBAL
|
||||
};
|
||||
|
||||
pDataObject->GetData(&formatetc, &m_medium);
|
||||
|
||||
_listCount = DragQueryFile((HDROP)m_medium.hGlobal, 0xFFFFFFFF, NULL, 0);
|
||||
}
|
||||
|
||||
~HDropIterator()
|
||||
{
|
||||
ReleaseStgMedium(&m_medium);
|
||||
}
|
||||
|
||||
void First()
|
||||
{
|
||||
_current = 0;
|
||||
}
|
||||
|
||||
void Next()
|
||||
{
|
||||
_current++;
|
||||
}
|
||||
|
||||
bool IsDone() const
|
||||
{
|
||||
return _current >= _listCount;
|
||||
}
|
||||
|
||||
LPTSTR CurrentItem() const
|
||||
{
|
||||
UINT cch = DragQueryFile((HDROP)m_medium.hGlobal, _current, NULL, 0) + 1;
|
||||
LPTSTR pszPath = (LPTSTR)malloc(sizeof(TCHAR) * cch);
|
||||
|
||||
DragQueryFile((HDROP)m_medium.hGlobal, _current, pszPath, cch);
|
||||
|
||||
return pszPath;
|
||||
}
|
||||
|
||||
private:
|
||||
UINT _listCount;
|
||||
STGMEDIUM m_medium;
|
||||
UINT _current;
|
||||
};
|
|
@ -9,10 +9,7 @@
|
|||
#include "winapi_error.h"
|
||||
#include "../logger/logger.h"
|
||||
|
||||
static IMAGEHLP_SYMBOL64* pSymbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH * sizeof(TCHAR));
|
||||
static IMAGEHLP_LINE64 line;
|
||||
static BOOLEAN processingException = FALSE;
|
||||
static CHAR modulePath[MAX_PATH];
|
||||
|
||||
static inline const char* exceptionDescription(const DWORD& code)
|
||||
{
|
||||
|
@ -64,15 +61,15 @@ static inline const char* exceptionDescription(const DWORD& code)
|
|||
}
|
||||
|
||||
/* Returns the index of the last backslash in the file path */
|
||||
inline int GetFilenameStart(CHAR* path)
|
||||
inline int GetFilenameStart(wchar_t* path)
|
||||
{
|
||||
int pos = 0;
|
||||
int found = 0;
|
||||
if (path != NULL)
|
||||
{
|
||||
while (path[pos] != '\0' && pos < MAX_PATH)
|
||||
while (path[pos] != L'\0' && pos < MAX_PATH)
|
||||
{
|
||||
if (path[pos] == '\\')
|
||||
if (path[pos] == L'\\')
|
||||
{
|
||||
found = pos + 1;
|
||||
}
|
||||
|
@ -83,22 +80,73 @@ inline int GetFilenameStart(CHAR* path)
|
|||
return found;
|
||||
}
|
||||
|
||||
inline void LogStackTrace()
|
||||
inline std::wstring GetModuleName(HANDLE process, const STACKFRAME64& stack)
|
||||
{
|
||||
BOOL result;
|
||||
HANDLE thread;
|
||||
HANDLE process;
|
||||
CONTEXT context;
|
||||
STACKFRAME64 stack;
|
||||
ULONG frame;
|
||||
DWORD64 dw64Displacement;
|
||||
DWORD dwDisplacement;
|
||||
static wchar_t modulePath[MAX_PATH]{};
|
||||
const size_t size = sizeof(modulePath);
|
||||
memset(&modulePath[0], '\0', size);
|
||||
|
||||
DWORD64 moduleBase = SymGetModuleBase64(process, stack.AddrPC.Offset);
|
||||
if (!moduleBase)
|
||||
{
|
||||
Logger::error(L"Failed to get a module. {}", get_last_error_or_default(GetLastError()));
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
if (!GetModuleFileNameW((HINSTANCE)moduleBase, modulePath, MAX_PATH))
|
||||
{
|
||||
Logger::error(L"Failed to get a module path. {}", get_last_error_or_default(GetLastError()));
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
const int start = GetFilenameStart(modulePath);
|
||||
return std::wstring(modulePath, start);
|
||||
}
|
||||
|
||||
inline std::wstring GetName(HANDLE process, const STACKFRAME64& stack)
|
||||
{
|
||||
static IMAGEHLP_SYMBOL64* pSymbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH * sizeof(TCHAR));
|
||||
if (!pSymbol)
|
||||
{
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
memset(&stack, 0, sizeof(STACKFRAME64));
|
||||
memset(pSymbol, '\0', sizeof(*pSymbol) + MAX_PATH);
|
||||
memset(&modulePath[0], '\0', sizeof(modulePath));
|
||||
pSymbol->MaxNameLength = MAX_PATH;
|
||||
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
|
||||
DWORD64 dw64Displacement = 0;
|
||||
if (!SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, pSymbol))
|
||||
{
|
||||
Logger::error(L"Failed to get a symbol. {}", get_last_error_or_default(GetLastError()));
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
std::string str = pSymbol->Name;
|
||||
return std::wstring(str.begin(), str.end());
|
||||
}
|
||||
|
||||
inline std::wstring GetLine(HANDLE process, const STACKFRAME64& stack)
|
||||
{
|
||||
static IMAGEHLP_LINE64 line{};
|
||||
|
||||
memset(&line, '\0', sizeof(IMAGEHLP_LINE64));
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
line.LineNumber = 0;
|
||||
|
||||
DWORD dwDisplacement = 0;
|
||||
if (!SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line))
|
||||
{
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
std::string fileName(line.FileName);
|
||||
return L"(" + std::wstring(fileName.begin(), fileName.end()) + L":" + std::to_wstring(line.LineNumber) + L")";
|
||||
}
|
||||
|
||||
inline void LogStackTrace()
|
||||
{
|
||||
CONTEXT context;
|
||||
try
|
||||
{
|
||||
RtlCaptureContext(&context);
|
||||
|
@ -109,9 +157,11 @@ inline void LogStackTrace()
|
|||
return;
|
||||
}
|
||||
|
||||
process = GetCurrentProcess();
|
||||
thread = GetCurrentThread();
|
||||
dw64Displacement = 0;
|
||||
STACKFRAME64 stack;
|
||||
memset(&stack, 0, sizeof(STACKFRAME64));
|
||||
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
stack.AddrPC.Offset = context.Rip;
|
||||
stack.AddrPC.Mode = AddrModeFlat;
|
||||
stack.AddrStack.Offset = context.Rsp;
|
||||
|
@ -119,8 +169,9 @@ inline void LogStackTrace()
|
|||
stack.AddrFrame.Offset = context.Rbp;
|
||||
stack.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
std::stringstream ss;
|
||||
for (frame = 0;; frame++)
|
||||
BOOL result = false;
|
||||
std::wstringstream ss;
|
||||
for (;;)
|
||||
{
|
||||
result = StackWalk64(
|
||||
IMAGE_FILE_MACHINE_AMD64,
|
||||
|
@ -138,34 +189,10 @@ inline void LogStackTrace()
|
|||
break;
|
||||
}
|
||||
|
||||
pSymbol->MaxNameLength = MAX_PATH;
|
||||
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
|
||||
if (!SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, pSymbol))
|
||||
{
|
||||
Logger::error(L"Failed to get a symbol. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
|
||||
line.LineNumber = 0;
|
||||
SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line);
|
||||
|
||||
DWORD64 moduleBase = SymGetModuleBase64(process, stack.AddrPC.Offset);
|
||||
if (moduleBase)
|
||||
{
|
||||
if (!GetModuleFileNameA((HINSTANCE)moduleBase, modulePath, MAX_PATH))
|
||||
{
|
||||
Logger::error(L"Failed to get a module path. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Failed to get a module. {}", get_last_error_or_default(GetLastError()));
|
||||
}
|
||||
|
||||
ss << std::string(modulePath).substr(GetFilenameStart(modulePath)) << "!" << pSymbol->Name << "(" << line.FileName << ":" << line.LineNumber << std::endl;
|
||||
ss << GetModuleName(process, stack) << "!" << GetName(process, stack) << GetLine(process, stack) << std::endl;
|
||||
}
|
||||
|
||||
Logger::error("STACK TRACE\r\n{}", ss.str());
|
||||
Logger::error(L"STACK TRACE\r\n{}", ss.str());
|
||||
Logger::flush();
|
||||
}
|
||||
|
||||
|
@ -218,7 +245,6 @@ inline void InitSymbols()
|
|||
{
|
||||
// Preload symbols so they will be available in case of out-of-memory exception
|
||||
SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
HANDLE process = GetCurrentProcess();
|
||||
if (!SymInitialize(process, NULL, TRUE))
|
||||
{
|
||||
|
|
21
src/common/utils/color.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
// helper function to get the RGB from a #FFFFFF string.
|
||||
inline bool checkValidRGB(std::wstring_view hex, uint8_t* R, uint8_t* G, uint8_t* B)
|
||||
{
|
||||
if (hex.length() != 7)
|
||||
return false;
|
||||
hex = hex.substr(1, 6); // remove #
|
||||
for (auto& c : hex)
|
||||
{
|
||||
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (swscanf_s(hex.data(), L"%2hhx%2hhx%2hhx", R, G, B) != 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
12
src/common/utils/game_mode.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include <shellapi.h>
|
||||
|
||||
inline bool detect_game_mode()
|
||||
{
|
||||
QUERY_USER_NOTIFICATION_STATE notification_state;
|
||||
if (SHQueryUserNotificationState(¬ification_state) != S_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (notification_state == QUNS_RUNNING_D3D_FULL_SCREEN);
|
||||
}
|
88
src/common/utils/modulesRegistry.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
|
||||
#include "registry.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
inline registry::ChangeSet getSvgPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
return generatePreviewHandler(PreviewHandlerType::preview,
|
||||
perUser,
|
||||
L"{ddee2b8a-6807-48a6-bb20-2338174ff779}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } /
|
||||
LR"d(modules\FileExplorerPreview\SvgPreviewHandler.comhost.dll)d")
|
||||
.wstring(),
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.PreviewHandler.Svg.SvgPreviewHandler",
|
||||
L"Svg Preview Handler",
|
||||
L".svg");
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getMdPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
return generatePreviewHandler(PreviewHandlerType::preview,
|
||||
perUser,
|
||||
L"{45769bcc-e8fd-42d0-947e-02beef77a1f5}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\MarkdownPreviewHandler.comhost.dll)d").wstring(),
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.PreviewHandler.Markdown.MarkdownPreviewHandler",
|
||||
L"Markdown Preview Handler",
|
||||
L".md");
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getPdfPreviewHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
return generatePreviewHandler(PreviewHandlerType::preview,
|
||||
perUser,
|
||||
L"{07665729-6243-4746-95b7-79579308d1b2}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PdfPreviewHandler.comhost.dll)d").wstring(),
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.PreviewHandler.Pdf.PdfPreviewHandler",
|
||||
L"Pdf Preview Handler",
|
||||
L".pdf");
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getSvgThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
return generatePreviewHandler(PreviewHandlerType::thumbnail,
|
||||
perUser,
|
||||
L"{36B27788-A8BB-4698-A756-DF9F11F64F84}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\SvgThumbnailProvider.comhost.dll)d").wstring(),
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.ThumbnailHandler.Svg.SvgThumbnailProvider",
|
||||
L"Svg Thumbnail Provider",
|
||||
L".svg");
|
||||
}
|
||||
|
||||
inline registry::ChangeSet getPdfThumbnailHandlerChangeSet(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
using namespace registry::shellex;
|
||||
return generatePreviewHandler(PreviewHandlerType::thumbnail,
|
||||
perUser,
|
||||
L"{BCC13D15-9720-4CC4-8371-EA74A274741E}",
|
||||
get_std_product_version(),
|
||||
(fs::path{ installationDir } / LR"d(modules\FileExplorerPreview\PdfThumbnailProvider.comhost.dll)d").wstring(),
|
||||
registry::DOTNET_COMPONENT_CATEGORY_CLSID,
|
||||
L"Microsoft.PowerToys.ThumbnailHandler.Pdf.PdfThumbnailProvider",
|
||||
L"Pdf Thumbnail Provider",
|
||||
L".pdf");
|
||||
}
|
||||
|
||||
inline std::vector<registry::ChangeSet> getAllModulesChangeSets(const std::wstring installationDir, const bool perUser)
|
||||
{
|
||||
return { getSvgPreviewHandlerChangeSet(installationDir, perUser),
|
||||
getMdPreviewHandlerChangeSet(installationDir, perUser),
|
||||
getPdfPreviewHandlerChangeSet(installationDir, perUser),
|
||||
getSvgThumbnailHandlerChangeSet(installationDir, perUser),
|
||||
getPdfThumbnailHandlerChangeSet(installationDir, perUser) };
|
||||
}
|
382
src/common/utils/registry.h
Normal file
|
@ -0,0 +1,382 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
|
||||
#include "../logger/logger.h"
|
||||
#include "../utils/winapi_error.h"
|
||||
#include "../version/version.h"
|
||||
|
||||
namespace registry
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct on_exit
|
||||
{
|
||||
std::function<void()> f;
|
||||
|
||||
on_exit(std::function<void()> f) :
|
||||
f{ std::move(f) } {}
|
||||
~on_exit() { f(); }
|
||||
};
|
||||
|
||||
template<class>
|
||||
inline constexpr bool always_false_v = false;
|
||||
|
||||
template<class... Ts>
|
||||
struct overloaded : Ts...
|
||||
{
|
||||
using Ts::operator()...;
|
||||
};
|
||||
|
||||
template<class... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
inline const wchar_t* getScopeName(HKEY scope)
|
||||
{
|
||||
if (scope == HKEY_LOCAL_MACHINE)
|
||||
{
|
||||
return L"HKLM";
|
||||
}
|
||||
else if (scope == HKEY_CURRENT_USER)
|
||||
{
|
||||
return L"HKCU";
|
||||
}
|
||||
else if (scope == HKEY_CLASSES_ROOT)
|
||||
{
|
||||
return L"HKCR";
|
||||
}
|
||||
else
|
||||
{
|
||||
return L"HK??";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ValueChange
|
||||
{
|
||||
using value_t = std::variant<DWORD, std::wstring>;
|
||||
static constexpr size_t VALUE_BUFFER_SIZE = 512;
|
||||
|
||||
HKEY scope{};
|
||||
std::wstring path;
|
||||
std::optional<std::wstring> name; // none == default
|
||||
value_t value;
|
||||
|
||||
ValueChange(const HKEY scope, std::wstring path, std::optional<std::wstring> name, value_t value) :
|
||||
scope{ scope }, path{ std::move(path) }, name{ std::move(name) }, value{ std::move(value) }
|
||||
{
|
||||
}
|
||||
|
||||
std::wstring toString() const
|
||||
{
|
||||
using namespace detail;
|
||||
|
||||
std::wstring value_str;
|
||||
std::visit(overloaded{ [&](DWORD value) {
|
||||
std::wostringstream oss;
|
||||
oss << value;
|
||||
value_str = oss.str();
|
||||
},
|
||||
[&](const std::wstring& value) { value_str = value; } },
|
||||
value);
|
||||
|
||||
return fmt::format(L"{}\\{}\\{}:{}", detail::getScopeName(scope), path, name ? *name : L"Default", value_str);
|
||||
}
|
||||
|
||||
bool isApplied() const
|
||||
{
|
||||
HKEY key{};
|
||||
if (auto res = RegOpenKeyExW(scope, path.c_str(), 0, KEY_READ, &key); res != ERROR_SUCCESS)
|
||||
{
|
||||
Logger::info(L"isApplied of {}: RegOpenKeyExW failed: {}", toString(), get_last_error_or_default(res));
|
||||
return false;
|
||||
}
|
||||
detail::on_exit closeKey{ [key] { RegCloseKey(key); } };
|
||||
|
||||
const DWORD expectedType = valueTypeToWinapiType(value);
|
||||
|
||||
DWORD retrievedType{};
|
||||
wchar_t buffer[VALUE_BUFFER_SIZE];
|
||||
DWORD valueSize = sizeof(buffer);
|
||||
if (auto res = RegQueryValueExW(key,
|
||||
name.has_value() ? name->c_str() : nullptr,
|
||||
0,
|
||||
&retrievedType,
|
||||
reinterpret_cast<LPBYTE>(&buffer),
|
||||
&valueSize);
|
||||
res != ERROR_SUCCESS)
|
||||
{
|
||||
Logger::info(L"isApplied of {}: RegQueryValueExW failed: {}", toString(), get_last_error_or_default(res));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expectedType != retrievedType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const auto retrievedValue = bufferToValue(buffer, valueSize, retrievedType))
|
||||
{
|
||||
return value == retrievedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool apply() const
|
||||
{
|
||||
HKEY key{};
|
||||
|
||||
if (auto res = RegCreateKeyExW(scope, path.c_str(), 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &key, nullptr); res !=
|
||||
ERROR_SUCCESS)
|
||||
{
|
||||
Logger::error(L"apply of {}: RegCreateKeyExW failed: {}", toString(), get_last_error_or_default(res));
|
||||
return false;
|
||||
}
|
||||
detail::on_exit closeKey{ [key] { RegCloseKey(key); } };
|
||||
|
||||
wchar_t buffer[VALUE_BUFFER_SIZE];
|
||||
DWORD valueSize;
|
||||
DWORD valueType;
|
||||
|
||||
valueToBuffer(value, buffer, valueSize, valueType);
|
||||
if (auto res = RegSetValueExW(key,
|
||||
name.has_value() ? name->c_str() : nullptr,
|
||||
0,
|
||||
valueType,
|
||||
reinterpret_cast<BYTE*>(buffer),
|
||||
valueSize);
|
||||
res != ERROR_SUCCESS)
|
||||
{
|
||||
Logger::error(L"apply of {}: RegSetValueExW failed: {}", toString(), get_last_error_or_default(res));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unApply() const
|
||||
{
|
||||
HKEY key{};
|
||||
if (auto res = RegOpenKeyExW(scope, path.c_str(), 0, KEY_ALL_ACCESS, &key); res != ERROR_SUCCESS)
|
||||
{
|
||||
Logger::error(L"unApply of {}: RegOpenKeyExW failed: {}", toString(), get_last_error_or_default(res));
|
||||
return false;
|
||||
}
|
||||
detail::on_exit closeKey{ [key] { RegCloseKey(key); } };
|
||||
|
||||
// delete the value itself
|
||||
if (auto res = RegDeleteKeyValueW(scope, path.c_str(), name.has_value() ? name->c_str() : nullptr); res != ERROR_SUCCESS)
|
||||
{
|
||||
Logger::error(L"unApply of {}: RegDeleteKeyValueW failed: {}", toString(), get_last_error_or_default(res));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the path doesn't contain anything and delete it if so
|
||||
DWORD nValues = 0;
|
||||
DWORD maxValueLen = 0;
|
||||
const auto ok =
|
||||
RegQueryInfoKeyW(
|
||||
key, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &nValues, nullptr, &maxValueLen, nullptr, nullptr) ==
|
||||
ERROR_SUCCESS;
|
||||
|
||||
if (ok && (!nValues || !maxValueLen))
|
||||
{
|
||||
RegDeleteTreeW(scope, path.c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool requiresElevation() const { return scope == HKEY_LOCAL_MACHINE; }
|
||||
|
||||
private:
|
||||
static DWORD valueTypeToWinapiType(const value_t& v)
|
||||
{
|
||||
return std::visit(
|
||||
[](auto&& arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, DWORD>)
|
||||
return REG_DWORD;
|
||||
else if constexpr (std::is_same_v<T, std::wstring>)
|
||||
return REG_SZ;
|
||||
else
|
||||
static_assert(always_false_v<T>, "support for this registry type is not implemented");
|
||||
},
|
||||
v);
|
||||
}
|
||||
|
||||
static void valueToBuffer(const value_t& value, wchar_t buffer[VALUE_BUFFER_SIZE], DWORD& valueSize, DWORD& type)
|
||||
{
|
||||
using detail::overloaded;
|
||||
|
||||
std::visit(overloaded{ [&](DWORD value) {
|
||||
*reinterpret_cast<DWORD*>(buffer) = value;
|
||||
type = REG_DWORD;
|
||||
valueSize = sizeof(value);
|
||||
},
|
||||
[&](const std::wstring& value) {
|
||||
assert(value.size() < VALUE_BUFFER_SIZE);
|
||||
value.copy(buffer, value.size());
|
||||
type = REG_SZ;
|
||||
valueSize = static_cast<DWORD>(sizeof(wchar_t) * value.size());
|
||||
} },
|
||||
value);
|
||||
}
|
||||
|
||||
static std::optional<value_t> bufferToValue(const wchar_t buffer[VALUE_BUFFER_SIZE],
|
||||
const DWORD valueSize,
|
||||
const DWORD type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case REG_DWORD:
|
||||
return *(DWORD*)buffer;
|
||||
case REG_SZ:
|
||||
{
|
||||
if (!valueSize)
|
||||
{
|
||||
return std::wstring{};
|
||||
}
|
||||
std::wstring result{ buffer, valueSize / sizeof(wchar_t) };
|
||||
while (result[result.size() - 1] == L'\0')
|
||||
{
|
||||
result.resize(result.size() - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ChangeSet
|
||||
{
|
||||
std::vector<ValueChange> changes;
|
||||
|
||||
bool isApplied() const
|
||||
{
|
||||
for (const auto& c : changes)
|
||||
{
|
||||
if (!c.isApplied())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool apply() const
|
||||
{
|
||||
bool ok = true;
|
||||
for (const auto& c : changes)
|
||||
{
|
||||
ok = c.apply() && ok;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool unApply() const
|
||||
{
|
||||
bool ok = true;
|
||||
for (const auto& c : changes)
|
||||
{
|
||||
ok = c.unApply() && ok;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
};
|
||||
|
||||
const inline std::wstring DOTNET_COMPONENT_CATEGORY_CLSID = L"{62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}";
|
||||
const inline std::wstring ITHUMBNAIL_PROVIDER_CLSID = L"{E357FCCD-A995-4576-B01F-234630154E96}";
|
||||
const inline std::wstring IPREVIEW_HANDLER_CLSID = L"{8895b1c6-b41f-4c1c-a562-0d564250836f}";
|
||||
|
||||
namespace shellex
|
||||
{
|
||||
enum PreviewHandlerType
|
||||
{
|
||||
preview,
|
||||
thumbnail
|
||||
};
|
||||
|
||||
inline registry::ChangeSet generatePreviewHandler(const PreviewHandlerType handlerType,
|
||||
const bool perUser,
|
||||
std::wstring handlerClsid,
|
||||
std::wstring powertoysVersion,
|
||||
std::wstring fullPathToHandler,
|
||||
std::wstring handlerCategory,
|
||||
std::wstring className,
|
||||
std::wstring displayName,
|
||||
std::wstring fileType)
|
||||
{
|
||||
const HKEY scope = perUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
|
||||
|
||||
std::wstring clsidPath = L"Software\\Classes\\CLSID";
|
||||
clsidPath += L'\\';
|
||||
clsidPath += handlerClsid;
|
||||
|
||||
std::wstring inprocServerPath = clsidPath;
|
||||
inprocServerPath += L'\\';
|
||||
inprocServerPath += L"InprocServer32";
|
||||
|
||||
std::wstring implementedCategoriesPath = clsidPath + LR"d(\Implemented Categories\)d";
|
||||
implementedCategoriesPath += handlerCategory;
|
||||
|
||||
std::wstring assemblyKeyValue;
|
||||
if (const auto lastDotPos = className.rfind(L'.'); lastDotPos != std::wstring::npos)
|
||||
{
|
||||
assemblyKeyValue = className.substr(lastDotPos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
assemblyKeyValue = className;
|
||||
}
|
||||
|
||||
assemblyKeyValue += L", Version=";
|
||||
assemblyKeyValue += powertoysVersion;
|
||||
assemblyKeyValue += L", Culture=neutral";
|
||||
|
||||
std::wstring versionPath = inprocServerPath;
|
||||
versionPath += L'\\';
|
||||
versionPath += powertoysVersion;
|
||||
|
||||
std::wstring fileAssociationPath = L"Software\\Classes\\";
|
||||
fileAssociationPath += fileType;
|
||||
fileAssociationPath += L"\\shellex\\";
|
||||
fileAssociationPath += handlerType == PreviewHandlerType::preview ? IPREVIEW_HANDLER_CLSID : ITHUMBNAIL_PROVIDER_CLSID;
|
||||
|
||||
using vec_t = std::vector<registry::ValueChange>;
|
||||
// TODO: verify that we actually need all of those
|
||||
vec_t changes = { { scope, clsidPath, L"DisplayName", displayName },
|
||||
{ scope, clsidPath, std::nullopt, className },
|
||||
{ scope, implementedCategoriesPath, std::nullopt, L"" },
|
||||
{ scope, inprocServerPath, std::nullopt, fullPathToHandler },
|
||||
{ scope, inprocServerPath, L"Assembly", assemblyKeyValue },
|
||||
{ scope, inprocServerPath, L"Class", className },
|
||||
{ scope, inprocServerPath, L"ThreadingModel", L"Both" },
|
||||
{ scope, versionPath, L"Assembly", assemblyKeyValue },
|
||||
{ scope, versionPath, L"Class", className },
|
||||
{ scope, fileAssociationPath, std::nullopt, handlerClsid } };
|
||||
if (handlerType == PreviewHandlerType::preview)
|
||||
{
|
||||
const std::wstring previewHostClsid = L"{6d2b5079-2f0b-48dd-ab7f-97cec514d30b}";
|
||||
const std::wstring previewHandlerListPath = LR"(Software\Microsoft\Windows\CurrentVersion\PreviewHandlers)";
|
||||
|
||||
changes.push_back({ scope, clsidPath, L"AppID", previewHostClsid });
|
||||
changes.push_back({ scope, previewHandlerListPath, handlerClsid, displayName });
|
||||
}
|
||||
|
||||
return registry::ChangeSet{ .changes = std::move(changes) };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,5 +33,14 @@ inline std::wstring get_product_version()
|
|||
L"." + std::to_wstring(VERSION_MINOR) +
|
||||
L"." + std::to_wstring(VERSION_REVISION);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
inline std::wstring get_std_product_version()
|
||||
{
|
||||
static std::wstring version = L"v" + std::to_wstring(VERSION_MAJOR) +
|
||||
L"." + std::to_wstring(VERSION_MINOR) +
|
||||
L"." + std::to_wstring(VERSION_REVISION) + L".0";
|
||||
|
||||
return version;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
|
||||
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 .\ resource.base.h resource.h FindMyMouse.base.rc FindMyMouse.rc" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -1,6 +1,10 @@
|
|||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../common/version/version.h"
|
||||
#include "../../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
|
@ -13,7 +17,7 @@ FILEFLAGS 0x0L
|
|||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
915
src/modules/MouseUtils/FindMyMouse/FindMyMouse.cpp
Normal file
|
@ -0,0 +1,915 @@
|
|||
// FindMyMouse.cpp : Based on Raymond Chen's SuperSonar.cpp
|
||||
//
|
||||
#include "pch.h"
|
||||
#include "FindMyMouse.h"
|
||||
#include "trace.h"
|
||||
#include "common/utils/game_mode.h"
|
||||
|
||||
#ifdef COMPOSITION
|
||||
namespace winrt
|
||||
{
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Composition;
|
||||
}
|
||||
|
||||
namespace ABI
|
||||
{
|
||||
using namespace ABI::Windows::System;
|
||||
using namespace ABI::Windows::UI::Composition::Desktop;
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma region Super_Sonar_Base_Code
|
||||
|
||||
template<typename D>
|
||||
struct SuperSonar
|
||||
{
|
||||
bool Initialize(HINSTANCE hinst);
|
||||
void Terminate();
|
||||
|
||||
protected:
|
||||
// You are expected to override these, as appropriate.
|
||||
|
||||
DWORD GetExtendedStyle()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
return BaseWndProc(message, wParam, lParam);
|
||||
}
|
||||
|
||||
void BeforeMoveSonar() {}
|
||||
void AfterMoveSonar() {}
|
||||
void SetSonarVisibility(bool visible) = delete;
|
||||
|
||||
protected:
|
||||
// Base class members you can access.
|
||||
D* Shim() { return static_cast<D*>(this); }
|
||||
LRESULT BaseWndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
|
||||
HWND m_hwnd;
|
||||
POINT m_sonarPos = ptNowhere;
|
||||
|
||||
// Only consider double left control click if at least 100ms passed between the clicks, to avoid keyboards that might be sending rapid clicks.
|
||||
// At actual check, time a fifth of the current double click setting might be used instead to take into account users who might have low values.
|
||||
static const int MIN_DOUBLE_CLICK_TIME = 100;
|
||||
|
||||
bool m_destroyed = false;
|
||||
bool m_doNotActivateOnGameMode = true;
|
||||
int m_sonarRadius = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS;
|
||||
int m_sonarZoomFactor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM;
|
||||
DWORD m_fadeDuration = FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS;
|
||||
int m_finalAlphaNumerator = FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY;
|
||||
static constexpr int FinalAlphaDenominator = 100;
|
||||
winrt::DispatcherQueueController m_dispatcherQueueController{ nullptr };
|
||||
|
||||
private:
|
||||
static bool IsEqual(POINT const& p1, POINT const& p2)
|
||||
{
|
||||
return p1.x == p2.x && p1.y == p2.y;
|
||||
}
|
||||
|
||||
static constexpr POINT ptNowhere = { -1, -1 };
|
||||
|
||||
static constexpr DWORD TIMER_ID_TRACK = 100;
|
||||
static constexpr DWORD IdlePeriod = 1000;
|
||||
|
||||
// Activate sonar: Hit LeftControl twice.
|
||||
enum class SonarState
|
||||
{
|
||||
Idle,
|
||||
ControlDown1,
|
||||
ControlUp1,
|
||||
ControlDown2,
|
||||
ControlUp2,
|
||||
};
|
||||
|
||||
HWND m_hwndOwner;
|
||||
SonarState m_sonarState = SonarState::Idle;
|
||||
POINT m_lastKeyPos{};
|
||||
DWORD m_lastKeyTime{};
|
||||
|
||||
static constexpr DWORD NoSonar = 0;
|
||||
static constexpr DWORD SonarWaitingForMouseMove = 1;
|
||||
DWORD m_sonarStart = NoSonar;
|
||||
bool m_isSnoopingMouse = false;
|
||||
|
||||
private:
|
||||
static constexpr auto className = L"FindMyMouse";
|
||||
|
||||
// Use the runner name for the Window title. Otherwise, since Find My Mouse has an actual visual, its Window name will be the one shown in Task Manager after being shown.
|
||||
static constexpr auto windowTitle = L"PowerToys Runner";
|
||||
|
||||
static LRESULT CALLBACK s_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
BOOL OnSonarCreate();
|
||||
void OnSonarDestroy();
|
||||
void OnSonarInput(WPARAM flags, HRAWINPUT hInput);
|
||||
void OnSonarKeyboardInput(RAWINPUT const& input);
|
||||
void OnSonarMouseInput(RAWINPUT const& input);
|
||||
void OnMouseTimer();
|
||||
|
||||
void StartSonar();
|
||||
void StopSonar();
|
||||
|
||||
void UpdateMouseSnooping();
|
||||
};
|
||||
|
||||
template<typename D>
|
||||
bool SuperSonar<D>::Initialize(HINSTANCE hinst)
|
||||
{
|
||||
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
|
||||
WNDCLASS wc{};
|
||||
|
||||
if (!GetClassInfoW(hinst, className, &wc))
|
||||
{
|
||||
wc.lpfnWndProc = s_WndProc;
|
||||
wc.hInstance = hinst;
|
||||
wc.hIcon = LoadIcon(hinst, IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
|
||||
wc.lpszClassName = className;
|
||||
|
||||
if (!RegisterClassW(&wc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hinst, nullptr);
|
||||
|
||||
DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW | Shim()->GetExtendedStyle();
|
||||
return CreateWindowExW(exStyle, className, windowTitle, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hinst, this) != nullptr;
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::Terminate()
|
||||
{
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
m_destroyed = true;
|
||||
DestroyWindow(m_hwndOwner);
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to destroy the sonar Window.");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
LRESULT SuperSonar<D>::s_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
SuperSonar* self;
|
||||
if (message == WM_NCCREATE)
|
||||
{
|
||||
auto info = (LPCREATESTRUCT)lParam;
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)info->lpCreateParams);
|
||||
self = (SuperSonar*)info->lpCreateParams;
|
||||
self->m_hwnd = hwnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
self = (SuperSonar*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
}
|
||||
if (self)
|
||||
{
|
||||
return self->Shim()->WndProc(message, wParam, lParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DefWindowProc(hwnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
LRESULT SuperSonar<D>::BaseWndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
return OnSonarCreate() ? 0 : -1;
|
||||
|
||||
case WM_DESTROY:
|
||||
OnSonarDestroy();
|
||||
break;
|
||||
|
||||
case WM_INPUT:
|
||||
OnSonarInput(wParam, (HRAWINPUT)lParam);
|
||||
break;
|
||||
|
||||
case WM_TIMER:
|
||||
switch (wParam)
|
||||
{
|
||||
case TIMER_ID_TRACK:
|
||||
OnMouseTimer();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_NCHITTEST:
|
||||
return HTTRANSPARENT;
|
||||
}
|
||||
|
||||
return DefWindowProc(m_hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
BOOL SuperSonar<D>::OnSonarCreate()
|
||||
{
|
||||
RAWINPUTDEVICE keyboard{};
|
||||
keyboard.usUsagePage = HID_USAGE_PAGE_GENERIC;
|
||||
keyboard.usUsage = HID_USAGE_GENERIC_KEYBOARD;
|
||||
keyboard.dwFlags = RIDEV_INPUTSINK;
|
||||
keyboard.hwndTarget = m_hwnd;
|
||||
return RegisterRawInputDevices(&keyboard, 1, sizeof(keyboard));
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::OnSonarDestroy()
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::OnSonarInput(WPARAM flags, HRAWINPUT hInput)
|
||||
{
|
||||
RAWINPUT input;
|
||||
UINT size = sizeof(input);
|
||||
auto result = GetRawInputData(hInput, RID_INPUT, &input, &size, sizeof(RAWINPUTHEADER));
|
||||
if ((int)result < sizeof(RAWINPUTHEADER))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (input.header.dwType)
|
||||
{
|
||||
case RIM_TYPEKEYBOARD:
|
||||
OnSonarKeyboardInput(input);
|
||||
break;
|
||||
case RIM_TYPEMOUSE:
|
||||
OnSonarMouseInput(input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::OnSonarKeyboardInput(RAWINPUT const& input)
|
||||
{
|
||||
// Don't activate if game mode is on.
|
||||
if (m_doNotActivateOnGameMode && detect_game_mode())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (input.data.keyboard.VKey != VK_CONTROL)
|
||||
{
|
||||
StopSonar();
|
||||
return;
|
||||
}
|
||||
|
||||
bool pressed = (input.data.keyboard.Flags & RI_KEY_BREAK) == 0;
|
||||
bool rightCtrl = (input.data.keyboard.Flags & RI_KEY_E0) != 0;
|
||||
|
||||
// Deal with rightCtrl first.
|
||||
if (rightCtrl)
|
||||
{
|
||||
/*
|
||||
* SuperSonar originally exited when pressing right control after pressing left control twice.
|
||||
* We take care of exiting FindMyMouse through module disabling in PowerToys settings instead.
|
||||
if (m_sonarState == SonarState::ControlUp2)
|
||||
{
|
||||
Terminate();
|
||||
}
|
||||
*/
|
||||
StopSonar();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_sonarState)
|
||||
{
|
||||
case SonarState::Idle:
|
||||
if (pressed)
|
||||
{
|
||||
m_sonarState = SonarState::ControlDown1;
|
||||
m_lastKeyTime = GetTickCount();
|
||||
m_lastKeyPos = {};
|
||||
GetCursorPos(&m_lastKeyPos);
|
||||
UpdateMouseSnooping();
|
||||
}
|
||||
break;
|
||||
|
||||
case SonarState::ControlDown1:
|
||||
if (!pressed)
|
||||
{
|
||||
m_sonarState = SonarState::ControlUp1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SonarState::ControlUp1:
|
||||
if (pressed)
|
||||
{
|
||||
auto now = GetTickCount();
|
||||
auto doubleClickInterval = now - m_lastKeyTime;
|
||||
POINT ptCursor{};
|
||||
auto doubleClickTimeSetting = GetDoubleClickTime();
|
||||
if (GetCursorPos(&ptCursor) &&
|
||||
doubleClickInterval >= min(MIN_DOUBLE_CLICK_TIME, doubleClickTimeSetting / 5) &&
|
||||
doubleClickInterval <= doubleClickTimeSetting &&
|
||||
IsEqual(m_lastKeyPos, ptCursor))
|
||||
{
|
||||
m_sonarState = SonarState::ControlDown2;
|
||||
StartSonar();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sonarState = SonarState::ControlDown1;
|
||||
m_lastKeyTime = GetTickCount();
|
||||
m_lastKeyPos = {};
|
||||
GetCursorPos(&m_lastKeyPos);
|
||||
UpdateMouseSnooping();
|
||||
}
|
||||
Logger::info("Detecting double left control click with {} ms interval.", doubleClickInterval);
|
||||
m_lastKeyTime = now;
|
||||
m_lastKeyPos = ptCursor;
|
||||
}
|
||||
break;
|
||||
case SonarState::ControlUp2:
|
||||
// Also deactivate sonar with left control.
|
||||
if (pressed)
|
||||
{
|
||||
StopSonar();
|
||||
}
|
||||
break;
|
||||
case SonarState::ControlDown2:
|
||||
if (!pressed)
|
||||
{
|
||||
m_sonarState = SonarState::ControlUp2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::OnSonarMouseInput(RAWINPUT const& input)
|
||||
{
|
||||
if (input.data.mouse.usButtonFlags)
|
||||
{
|
||||
StopSonar();
|
||||
}
|
||||
else if (m_sonarStart != NoSonar)
|
||||
{
|
||||
OnMouseTimer();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::StartSonar()
|
||||
{
|
||||
Logger::info("Focusing the sonar on the mouse cursor.");
|
||||
Trace::MousePointerFocused();
|
||||
// Cover the entire virtual screen.
|
||||
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), 0);
|
||||
m_sonarPos = ptNowhere;
|
||||
OnMouseTimer();
|
||||
UpdateMouseSnooping();
|
||||
Shim()->SetSonarVisibility(true);
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::StopSonar()
|
||||
{
|
||||
if (m_sonarStart != NoSonar)
|
||||
{
|
||||
m_sonarStart = NoSonar;
|
||||
Shim()->SetSonarVisibility(false);
|
||||
KillTimer(m_hwnd, TIMER_ID_TRACK);
|
||||
}
|
||||
m_sonarState = SonarState::Idle;
|
||||
UpdateMouseSnooping();
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::OnMouseTimer()
|
||||
{
|
||||
auto now = GetTickCount();
|
||||
|
||||
// If mouse has moved, then reset the sonar timer.
|
||||
POINT ptCursor{};
|
||||
if (!GetCursorPos(&ptCursor))
|
||||
{
|
||||
// We are no longer the active desktop - done.
|
||||
StopSonar();
|
||||
return;
|
||||
}
|
||||
ScreenToClient(m_hwnd, &ptCursor);
|
||||
|
||||
if (IsEqual(m_sonarPos, ptCursor))
|
||||
{
|
||||
// Mouse is stationary.
|
||||
if (m_sonarStart != SonarWaitingForMouseMove && now - m_sonarStart >= IdlePeriod)
|
||||
{
|
||||
StopSonar();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mouse has moved.
|
||||
if (IsEqual(m_sonarPos, ptNowhere))
|
||||
{
|
||||
// Initial call, mark sonar as active but waiting for first mouse-move.
|
||||
now = SonarWaitingForMouseMove;
|
||||
}
|
||||
SetTimer(m_hwnd, TIMER_ID_TRACK, IdlePeriod, nullptr);
|
||||
Shim()->BeforeMoveSonar();
|
||||
m_sonarPos = ptCursor;
|
||||
m_sonarStart = now;
|
||||
Shim()->AfterMoveSonar();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::UpdateMouseSnooping()
|
||||
{
|
||||
bool wantSnoopingMouse = m_sonarStart != NoSonar || m_sonarState != SonarState::Idle;
|
||||
if (m_isSnoopingMouse != wantSnoopingMouse)
|
||||
{
|
||||
m_isSnoopingMouse = wantSnoopingMouse;
|
||||
RAWINPUTDEVICE mouse{};
|
||||
mouse.usUsagePage = HID_USAGE_PAGE_GENERIC;
|
||||
mouse.usUsage = HID_USAGE_GENERIC_MOUSE;
|
||||
if (wantSnoopingMouse)
|
||||
{
|
||||
mouse.dwFlags = RIDEV_INPUTSINK;
|
||||
mouse.hwndTarget = m_hwnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse.dwFlags = RIDEV_REMOVE;
|
||||
mouse.hwndTarget = nullptr;
|
||||
}
|
||||
RegisterRawInputDevices(&mouse, 1, sizeof(mouse));
|
||||
}
|
||||
}
|
||||
|
||||
struct CompositionSpotlight : SuperSonar<CompositionSpotlight>
|
||||
{
|
||||
static constexpr UINT WM_OPACITY_ANIMATION_COMPLETED = WM_APP;
|
||||
float m_sonarRadiusFloat = static_cast<float>(m_sonarRadius);
|
||||
|
||||
DWORD GetExtendedStyle()
|
||||
{
|
||||
return WS_EX_NOREDIRECTIONBITMAP;
|
||||
}
|
||||
|
||||
void AfterMoveSonar()
|
||||
{
|
||||
m_spotlight.Offset({ (float)m_sonarPos.x, (float)m_sonarPos.y, 0.0f });
|
||||
}
|
||||
|
||||
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
return OnCompositionCreate() && BaseWndProc(message, wParam, lParam);
|
||||
|
||||
case WM_OPACITY_ANIMATION_COMPLETED:
|
||||
OnOpacityAnimationCompleted();
|
||||
break;
|
||||
}
|
||||
return BaseWndProc(message, wParam, lParam);
|
||||
}
|
||||
|
||||
void SetSonarVisibility(bool visible)
|
||||
{
|
||||
m_batch = m_compositor.GetCommitBatch(winrt::CompositionBatchTypes::Animation);
|
||||
m_batch.Completed([hwnd = m_hwnd](auto&&, auto&&) {
|
||||
PostMessage(hwnd, WM_OPACITY_ANIMATION_COMPLETED, 0, 0);
|
||||
});
|
||||
m_root.Opacity(visible ? static_cast<float>(m_finalAlphaNumerator) / FinalAlphaDenominator : 0.0f);
|
||||
if (visible)
|
||||
{
|
||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool OnCompositionCreate()
|
||||
try
|
||||
{
|
||||
// We need a dispatcher queue.
|
||||
DispatcherQueueOptions options = {
|
||||
sizeof(options),
|
||||
DQTYPE_THREAD_CURRENT,
|
||||
DQTAT_COM_ASTA,
|
||||
};
|
||||
ABI::IDispatcherQueueController* controller;
|
||||
winrt::check_hresult(CreateDispatcherQueueController(options, &controller));
|
||||
*winrt::put_abi(m_dispatcherQueueController) = controller;
|
||||
|
||||
// Create the compositor for our window.
|
||||
m_compositor = winrt::Compositor();
|
||||
ABI::IDesktopWindowTarget* target;
|
||||
winrt::check_hresult(m_compositor.as<ABI::ICompositorDesktopInterop>()->CreateDesktopWindowTarget(m_hwnd, false, &target));
|
||||
*winrt::put_abi(m_target) = target;
|
||||
|
||||
// Our composition tree:
|
||||
//
|
||||
// [root] ContainerVisual
|
||||
// \ LayerVisual
|
||||
// \[gray backdrop]
|
||||
// [spotlight]
|
||||
m_root = m_compositor.CreateContainerVisual();
|
||||
m_root.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
m_root.Opacity(0.0f);
|
||||
m_target.Root(m_root);
|
||||
|
||||
auto layer = m_compositor.CreateLayerVisual();
|
||||
layer.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
m_root.Children().InsertAtTop(layer);
|
||||
|
||||
m_backdrop = m_compositor.CreateSpriteVisual();
|
||||
m_backdrop.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
|
||||
m_backdrop.Brush(m_compositor.CreateColorBrush(m_backgroundColor));
|
||||
layer.Children().InsertAtTop(m_backdrop);
|
||||
|
||||
m_circleGeometry = m_compositor.CreateEllipseGeometry(); // radius set via expression animation
|
||||
m_circleShape = m_compositor.CreateSpriteShape(m_circleGeometry);
|
||||
m_circleShape.FillBrush(m_compositor.CreateColorBrush(m_spotlightColor));
|
||||
m_circleShape.Offset({ m_sonarRadiusFloat * m_sonarZoomFactor, m_sonarRadiusFloat * m_sonarZoomFactor });
|
||||
m_spotlight = m_compositor.CreateShapeVisual();
|
||||
m_spotlight.Size({ m_sonarRadiusFloat * 2 * m_sonarZoomFactor, m_sonarRadiusFloat * 2 * m_sonarZoomFactor });
|
||||
m_spotlight.AnchorPoint({ 0.5f, 0.5f });
|
||||
m_spotlight.Shapes().Append(m_circleShape);
|
||||
|
||||
layer.Children().InsertAtTop(m_spotlight);
|
||||
|
||||
// Implicitly animate the alpha.
|
||||
m_animation = m_compositor.CreateScalarKeyFrameAnimation();
|
||||
m_animation.Target(L"Opacity");
|
||||
m_animation.InsertExpressionKeyFrame(1.0f, L"this.FinalValue");
|
||||
m_animation.Duration(std::chrono::milliseconds{ m_fadeDuration });
|
||||
auto collection = m_compositor.CreateImplicitAnimationCollection();
|
||||
collection.Insert(L"Opacity", m_animation);
|
||||
m_root.ImplicitAnimations(collection);
|
||||
|
||||
// Radius of spotlight shrinks as opacity increases.
|
||||
// At opacity zero, it is m_sonarRadius * SonarZoomFactor.
|
||||
// At maximum opacity, it is m_sonarRadius.
|
||||
auto radiusExpression = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression.SetReferenceParameter(L"Root", m_root);
|
||||
wchar_t expressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius, FinalAlphaDenominator, m_finalAlphaNumerator));
|
||||
radiusExpression.Expression(expressionText);
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnOpacityAnimationCompleted()
|
||||
{
|
||||
if (m_root.Opacity() < 0.01f)
|
||||
{
|
||||
ShowWindow(m_hwnd, SW_HIDE);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void ApplySettings(const FindMyMouseSettings& settings, bool applyToRuntimeObjects) {
|
||||
if (!applyToRuntimeObjects)
|
||||
{
|
||||
// Runtime objects not created yet. Just update fields.
|
||||
m_sonarRadius = settings.spotlightRadius;
|
||||
m_sonarRadiusFloat = static_cast<float>(m_sonarRadius);
|
||||
m_backgroundColor = settings.backgroundColor;
|
||||
m_spotlightColor = settings.spotlightColor;
|
||||
m_doNotActivateOnGameMode = settings.doNotActivateOnGameMode;
|
||||
m_fadeDuration = settings.animationDurationMs > 0 ? settings.animationDurationMs : 1;
|
||||
m_finalAlphaNumerator = settings.overlayOpacity;
|
||||
m_sonarZoomFactor = settings.spotlightInitialZoom;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Runtime objects already created. Should update in the owner thread.
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
FindMyMouseSettings localSettings = settings;
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
if (!m_destroyed)
|
||||
{
|
||||
// Runtime objects not created yet. Just update fields.
|
||||
m_sonarRadius = localSettings.spotlightRadius;
|
||||
m_sonarRadiusFloat = static_cast<float>(m_sonarRadius);
|
||||
m_backgroundColor = localSettings.backgroundColor;
|
||||
m_spotlightColor = localSettings.spotlightColor;
|
||||
m_doNotActivateOnGameMode = localSettings.doNotActivateOnGameMode;
|
||||
m_fadeDuration = localSettings.animationDurationMs > 0 ? localSettings.animationDurationMs : 1;
|
||||
m_finalAlphaNumerator = localSettings.overlayOpacity;
|
||||
m_sonarZoomFactor = localSettings.spotlightInitialZoom;
|
||||
|
||||
// Apply new settings to runtime composition objects.
|
||||
m_backdrop.Brush().as<winrt::CompositionColorBrush>().Color(m_backgroundColor);
|
||||
m_circleShape.FillBrush().as<winrt::CompositionColorBrush>().Color(m_spotlightColor);
|
||||
m_circleShape.Offset({ m_sonarRadiusFloat * m_sonarZoomFactor, m_sonarRadiusFloat * m_sonarZoomFactor });
|
||||
m_spotlight.Size({ m_sonarRadiusFloat * 2 * m_sonarZoomFactor, m_sonarRadiusFloat * 2 * m_sonarZoomFactor });
|
||||
m_animation.Duration(std::chrono::milliseconds{ m_fadeDuration });
|
||||
m_circleGeometry.StopAnimation(L"Radius");
|
||||
|
||||
// Update animation
|
||||
auto radiusExpression = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression.SetReferenceParameter(L"Root", m_root);
|
||||
wchar_t expressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius, FinalAlphaDenominator, m_finalAlphaNumerator));
|
||||
radiusExpression.Expression(expressionText);
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression);
|
||||
}
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to update the sonar settings.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
winrt::Compositor m_compositor{ nullptr };
|
||||
winrt::Desktop::DesktopWindowTarget m_target{ nullptr };
|
||||
winrt::ContainerVisual m_root{ nullptr };
|
||||
winrt::CompositionEllipseGeometry m_circleGeometry{ nullptr };
|
||||
winrt::ShapeVisual m_spotlight{ nullptr };
|
||||
winrt::CompositionCommitBatch m_batch{ nullptr };
|
||||
winrt::SpriteVisual m_backdrop{ nullptr };
|
||||
winrt::CompositionSpriteShape m_circleShape{ nullptr };
|
||||
winrt::Windows::UI::Color m_backgroundColor = FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR;
|
||||
winrt::Windows::UI::Color m_spotlightColor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR;
|
||||
winrt::ScalarKeyFrameAnimation m_animation{ nullptr };
|
||||
};
|
||||
|
||||
template<typename D>
|
||||
struct GdiSonar : SuperSonar<D>
|
||||
{
|
||||
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
SetLayeredWindowAttributes(this->m_hwnd, 0, 0, LWA_ALPHA);
|
||||
break;
|
||||
|
||||
case WM_TIMER:
|
||||
switch (wParam)
|
||||
{
|
||||
case TIMER_ID_FADE:
|
||||
OnFadeTimer();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
this->Shim()->OnPaint();
|
||||
break;
|
||||
}
|
||||
return this->BaseWndProc(message, wParam, lParam);
|
||||
}
|
||||
|
||||
void BeforeMoveSonar() { this->Shim()->InvalidateSonar(); }
|
||||
void AfterMoveSonar() { this->Shim()->InvalidateSonar(); }
|
||||
|
||||
void SetSonarVisibility(bool visible)
|
||||
{
|
||||
m_alphaTarget = visible ? MaxAlpha : 0;
|
||||
m_fadeStart = GetTickCount() - FadeFramePeriod;
|
||||
SetTimer(this->m_hwnd, TIMER_ID_FADE, FadeFramePeriod, nullptr);
|
||||
OnFadeTimer();
|
||||
}
|
||||
|
||||
void OnFadeTimer()
|
||||
{
|
||||
auto now = GetTickCount();
|
||||
auto step = (int)((now - m_fadeStart) * MaxAlpha / this->m_fadeDuration);
|
||||
|
||||
this->Shim()->InvalidateSonar();
|
||||
if (m_alpha < m_alphaTarget)
|
||||
{
|
||||
m_alpha += step;
|
||||
if (m_alpha > m_alphaTarget)
|
||||
m_alpha = m_alphaTarget;
|
||||
}
|
||||
else if (m_alpha > m_alphaTarget)
|
||||
{
|
||||
m_alpha -= step;
|
||||
if (m_alpha < m_alphaTarget)
|
||||
m_alpha = m_alphaTarget;
|
||||
}
|
||||
SetLayeredWindowAttributes(this->m_hwnd, 0, (BYTE)m_alpha, LWA_ALPHA);
|
||||
this->Shim()->InvalidateSonar();
|
||||
if (m_alpha == m_alphaTarget)
|
||||
{
|
||||
KillTimer(this->m_hwnd, TIMER_ID_FADE);
|
||||
if (m_alpha == 0)
|
||||
{
|
||||
ShowWindow(this->m_hwnd, SW_HIDE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowWindow(this->m_hwnd, SW_SHOWNOACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
int CurrentSonarRadius()
|
||||
{
|
||||
int range = MaxAlpha - m_alpha;
|
||||
int radius = this->m_sonarRadius + this->m_sonarRadius * range * (this->m_sonarZoomFactor - 1) / MaxAlpha;
|
||||
return radius;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr DWORD FadeFramePeriod = 10;
|
||||
int MaxAlpha = SuperSonar<D>::m_finalAlphaNumerator * 255 / SuperSonar<D>::FinalAlphaDenominator;
|
||||
static constexpr DWORD TIMER_ID_FADE = 101;
|
||||
|
||||
private:
|
||||
int m_alpha = 0;
|
||||
int m_alphaTarget = 0;
|
||||
DWORD m_fadeStart = 0;
|
||||
};
|
||||
|
||||
struct GdiSpotlight : GdiSonar<GdiSpotlight>
|
||||
{
|
||||
void InvalidateSonar()
|
||||
{
|
||||
RECT rc;
|
||||
auto radius = CurrentSonarRadius();
|
||||
rc.left = this->m_sonarPos.x - radius;
|
||||
rc.top = this->m_sonarPos.y - radius;
|
||||
rc.right = this->m_sonarPos.x + radius;
|
||||
rc.bottom = this->m_sonarPos.y + radius;
|
||||
InvalidateRect(this->m_hwnd, &rc, FALSE);
|
||||
}
|
||||
|
||||
void OnPaint()
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(this->m_hwnd, &ps);
|
||||
|
||||
auto radius = CurrentSonarRadius();
|
||||
auto spotlight = CreateRoundRectRgn(
|
||||
this->m_sonarPos.x - radius, this->m_sonarPos.y - radius, this->m_sonarPos.x + radius, this->m_sonarPos.y + radius, radius * 2, radius * 2);
|
||||
|
||||
FillRgn(ps.hdc, spotlight, (HBRUSH)GetStockObject(WHITE_BRUSH));
|
||||
Sleep(1000 / 60);
|
||||
ExtSelectClipRgn(ps.hdc, spotlight, RGN_DIFF);
|
||||
FillRect(ps.hdc, &ps.rcPaint, (HBRUSH)GetStockObject(BLACK_BRUSH));
|
||||
DeleteObject(spotlight);
|
||||
|
||||
EndPaint(this->m_hwnd, &ps);
|
||||
}
|
||||
};
|
||||
|
||||
struct GdiCrosshairs : GdiSonar<GdiCrosshairs>
|
||||
{
|
||||
void InvalidateSonar()
|
||||
{
|
||||
RECT rc;
|
||||
auto radius = CurrentSonarRadius();
|
||||
GetClientRect(m_hwnd, &rc);
|
||||
rc.left = m_sonarPos.x - radius;
|
||||
rc.right = m_sonarPos.x + radius;
|
||||
InvalidateRect(m_hwnd, &rc, FALSE);
|
||||
|
||||
GetClientRect(m_hwnd, &rc);
|
||||
rc.top = m_sonarPos.y - radius;
|
||||
rc.bottom = m_sonarPos.y + radius;
|
||||
InvalidateRect(m_hwnd, &rc, FALSE);
|
||||
}
|
||||
|
||||
void OnPaint()
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(this->m_hwnd, &ps);
|
||||
|
||||
auto radius = CurrentSonarRadius();
|
||||
RECT rc;
|
||||
|
||||
HBRUSH white = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
||||
|
||||
rc.left = m_sonarPos.x - radius;
|
||||
rc.top = ps.rcPaint.top;
|
||||
rc.right = m_sonarPos.x + radius;
|
||||
rc.bottom = ps.rcPaint.bottom;
|
||||
FillRect(ps.hdc, &rc, white);
|
||||
|
||||
rc.left = ps.rcPaint.left;
|
||||
rc.top = m_sonarPos.y - radius;
|
||||
rc.right = ps.rcPaint.right;
|
||||
rc.bottom = m_sonarPos.y + radius;
|
||||
FillRect(ps.hdc, &rc, white);
|
||||
|
||||
HBRUSH black = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
|
||||
// Top left
|
||||
rc.left = ps.rcPaint.left;
|
||||
rc.top = ps.rcPaint.top;
|
||||
rc.right = m_sonarPos.x - radius;
|
||||
rc.bottom = m_sonarPos.y - radius;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
// Top right
|
||||
rc.left = m_sonarPos.x + radius;
|
||||
rc.top = ps.rcPaint.top;
|
||||
rc.right = ps.rcPaint.right;
|
||||
rc.bottom = m_sonarPos.y - radius;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
// Bottom left
|
||||
rc.left = ps.rcPaint.left;
|
||||
rc.top = m_sonarPos.y + radius;
|
||||
rc.right = m_sonarPos.x - radius;
|
||||
rc.bottom = ps.rcPaint.bottom;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
// Bottom right
|
||||
rc.left = m_sonarPos.x + radius;
|
||||
rc.top = m_sonarPos.y + radius;
|
||||
rc.right = ps.rcPaint.right;
|
||||
rc.bottom = ps.rcPaint.bottom;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
EndPaint(this->m_hwnd, &ps);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma endregion Super_Sonar_Base_Code
|
||||
|
||||
|
||||
#pragma region Super_Sonar_API
|
||||
|
||||
CompositionSpotlight* m_sonar = nullptr;
|
||||
void FindMyMouseApplySettings(const FindMyMouseSettings& settings)
|
||||
{
|
||||
if (m_sonar != nullptr)
|
||||
{
|
||||
Logger::info("Applying settings.");
|
||||
m_sonar->ApplySettings(settings, true);
|
||||
}
|
||||
}
|
||||
|
||||
void FindMyMouseDisable()
|
||||
{
|
||||
if (m_sonar != nullptr)
|
||||
{
|
||||
Logger::info("Terminating a sonar instance.");
|
||||
m_sonar->Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
bool FindMyMouseIsEnabled()
|
||||
{
|
||||
return (m_sonar != nullptr);
|
||||
}
|
||||
|
||||
// Based on SuperSonar's original wWinMain.
|
||||
int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings)
|
||||
{
|
||||
Logger::info("Starting a sonar instance.");
|
||||
if (m_sonar != nullptr)
|
||||
{
|
||||
Logger::error("A sonar instance was still working when trying to start a new one.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
CompositionSpotlight sonar;
|
||||
sonar.ApplySettings(settings, false);
|
||||
if (!sonar.Initialize(hinst))
|
||||
{
|
||||
Logger::error("Couldn't initialize a sonar instance.");
|
||||
return 0;
|
||||
}
|
||||
m_sonar = &sonar;
|
||||
Logger::info("Initialized the sonar instance.");
|
||||
|
||||
MSG msg;
|
||||
|
||||
// Main message loop:
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
Logger::info("Sonar message loop ended.");
|
||||
m_sonar = nullptr;
|
||||
|
||||
return (int)msg.wParam;
|
||||
}
|
||||
|
||||
#pragma endregion Super_Sonar_API
|
26
src/modules/MouseUtils/FindMyMouse/FindMyMouse.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
constexpr bool FIND_MY_MOUSE_DEFAULT_DO_NOT_ACTIVATE_ON_GAME_MODE = true;
|
||||
const winrt::Windows::UI::Color FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 0, 0, 0);
|
||||
const winrt::Windows::UI::Color FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 255, 255);
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY = 50;
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS = 100;
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS = 500;
|
||||
constexpr int FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM = 9;
|
||||
|
||||
struct FindMyMouseSettings
|
||||
{
|
||||
bool doNotActivateOnGameMode = FIND_MY_MOUSE_DEFAULT_DO_NOT_ACTIVATE_ON_GAME_MODE;
|
||||
winrt::Windows::UI::Color backgroundColor = FIND_MY_MOUSE_DEFAULT_BACKGROUND_COLOR;
|
||||
winrt::Windows::UI::Color spotlightColor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_COLOR;
|
||||
int overlayOpacity = FIND_MY_MOUSE_DEFAULT_OVERLAY_OPACITY;
|
||||
int spotlightRadius = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS;
|
||||
int animationDurationMs = FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS;
|
||||
int spotlightInitialZoom = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM;
|
||||
};
|
||||
|
||||
int FindMyMouseMain(HINSTANCE hinst, const FindMyMouseSettings& settings);
|
||||
void FindMyMouseDisable();
|
||||
bool FindMyMouseIsEnabled();
|
||||
void FindMyMouseApplySettings(const FindMyMouseSettings& settings);
|
146
src/modules/MouseUtils/FindMyMouse/FindMyMouse.vcxproj
Normal file
|
@ -0,0 +1,146 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{e94fd11c-0591-456f-899f-efc0ca548336}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>FindMyMouse</RootNamespace>
|
||||
<OverrideWindowsTargetPlatformVersion>true</OverrideWindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>FindMyMouse</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(CIBuild)'!='true'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="FindMyMouse.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="Generated Files\resource.h" />
|
||||
<None Include="resource.base.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="FindMyMouse.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<None Include="FindMyMouse.base.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\FindMyMouse.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -3,22 +3,31 @@
|
|||
<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>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{875a08c6-f610-4667-bd0f-80171ed96072}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FileExplorerPreviewSettingsTest.cpp">
|
||||
<ClCompile Include="FindMyMouse.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
@ -26,16 +35,28 @@
|
|||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FindMyMouse.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Generated Files\resource.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="powerpreviewTest.rc">
|
||||
<None Include="packages.config" />
|
||||
<None Include="resource.base.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</None>
|
||||
<None Include="FindMyMouse.base.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<ResourceCompile Include="Generated Files\FindMyMouse.rc">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
273
src/modules/MouseUtils/FindMyMouse/dllmain.cpp
Normal file
|
@ -0,0 +1,273 @@
|
|||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include "trace.h"
|
||||
#include "FindMyMouse.h"
|
||||
#include <thread>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/color.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
|
||||
const wchar_t JSON_KEY_VALUE[] = L"value";
|
||||
const wchar_t JSON_KEY_DO_NOT_ACTIVATE_ON_GAME_MODE[] = L"do_not_activate_on_game_mode";
|
||||
const wchar_t JSON_KEY_BACKGROUND_COLOR[] = L"background_color";
|
||||
const wchar_t JSON_KEY_SPOTLIGHT_COLOR[] = L"spotlight_color";
|
||||
const wchar_t JSON_KEY_OVERLAY_OPACITY[] = L"overlay_opacity";
|
||||
const wchar_t JSON_KEY_SPOTLIGHT_RADIUS[] = L"spotlight_radius";
|
||||
const wchar_t JSON_KEY_ANIMATION_DURATION_MS[] = L"animation_duration_ms";
|
||||
const wchar_t JSON_KEY_SPOTLIGHT_INITIAL_ZOOM[] = L"spotlight_initial_zoom";
|
||||
}
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
HMODULE m_hModule;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
m_hModule = hModule;
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The PowerToy name that will be shown in the settings.
|
||||
const static wchar_t* MODULE_NAME = L"FindMyMouse";
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"Focus the mouse pointer";
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class FindMyMouse : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
// Find My Mouse specific settings
|
||||
FindMyMouseSettings m_findMyMouseSettings;
|
||||
|
||||
// Load initial settings from the persisted values.
|
||||
void init_settings();
|
||||
|
||||
// Helper function to extract the settings
|
||||
void parse_settings(PowerToysSettings::PowerToyValues& settings);
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
FindMyMouse()
|
||||
{
|
||||
LoggerHelpers::init_logger(MODULE_NAME, L"ModuleInterface", LogSettings::findMyMouseLoggerName);
|
||||
init_settings();
|
||||
};
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the localized display name of the powertoy
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return the non localized key of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
|
||||
// Create a Settings object.
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
settings.set_description(MODULE_DESC);
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Signal from the Settings editor to call a custom action.
|
||||
// This can be used to spawn more complex editors.
|
||||
virtual void call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the input JSON string.
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
parse_settings(values);
|
||||
|
||||
FindMyMouseApplySettings(m_findMyMouseSettings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Improper JSON.
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
Trace::EnableFindMyMouse(true);
|
||||
std::thread([=]() { FindMyMouseMain(m_hModule, m_findMyMouseSettings); }).detach();
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
Trace::EnableFindMyMouse(false);
|
||||
FindMyMouseDisable();
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
};
|
||||
|
||||
// Load the settings file.
|
||||
void FindMyMouse::init_settings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load and parse the settings file for this PowerToy.
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(FindMyMouse::get_key());
|
||||
parse_settings(settings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Error while loading from the settings file. Let default values stay as they are.
|
||||
}
|
||||
}
|
||||
|
||||
void FindMyMouse::parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
FindMyMouseSettings findMyMouseSettings;
|
||||
if (settingsObject.GetView().Size())
|
||||
{
|
||||
try
|
||||
{
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_DO_NOT_ACTIVATE_ON_GAME_MODE);
|
||||
findMyMouseSettings.doNotActivateOnGameMode = (bool)jsonPropertiesObject.GetNamedBoolean(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to get 'do not activate on game mode' setting");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse background color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_BACKGROUND_COLOR);
|
||||
auto backgroundColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(backgroundColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Background color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
findMyMouseSettings.backgroundColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize background color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse spotlight color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_COLOR);
|
||||
auto spotlightColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(spotlightColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Spotlight color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
findMyMouseSettings.spotlightColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize spotlight color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Overlay Opacity
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_OVERLAY_OPACITY);
|
||||
findMyMouseSettings.overlayOpacity = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Overlay Opacity from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Spotlight Radius
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_RADIUS);
|
||||
findMyMouseSettings.spotlightRadius = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Spotlight Radius from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Animation Duration
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ANIMATION_DURATION_MS);
|
||||
findMyMouseSettings.animationDurationMs = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Animation Duration from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Spotlight Initial Zoom
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SPOTLIGHT_INITIAL_ZOOM);
|
||||
findMyMouseSettings.spotlightInitialZoom = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Spotlight Initial Zoom from settings. Will use default value");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("Find My Mouse settings are empty");
|
||||
}
|
||||
m_findMyMouseSettings = findMyMouseSettings;
|
||||
}
|
||||
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new FindMyMouse();
|
||||
}
|
20
src/modules/MouseUtils/FindMyMouse/pch.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#define COMPOSITION
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <windows.h>
|
||||
#include <strsafe.h>
|
||||
#include <hIdUsage.h>
|
||||
|
||||
#ifdef COMPOSITION
|
||||
#include <windows.ui.composition.interop.h>
|
||||
#include <DispatcherQueue.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.UI.Composition.Desktop.h>
|
||||
#endif
|
||||
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger.h>
|
14
src/modules/MouseUtils/FindMyMouse/resource.base.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by FindMyMouse.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys FindMyMouse"
|
||||
#define INTERNAL_NAME "FindMyMouse"
|
||||
#define ORIGINAL_FILENAME "FindMyMouse.dll"
|
||||
#define IDS_KEYBOARDMANAGER_ICON 1001
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
40
src/modules/MouseUtils/FindMyMouse/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 FindMyMouse enabled or disabled
|
||||
void Trace::EnableFindMyMouse(const bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"FindMyMouse_EnableFindMyMouse",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
|
||||
// Log that the user activated the module by focusing the mouse pointer
|
||||
void Trace::MousePointerFocused() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"FindMyMouse_MousePointerFocused",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
14
src/modules/MouseUtils/FindMyMouse/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 FindMyMouse enabled or disabled
|
||||
static void EnableFindMyMouse(const bool enabled) noexcept;
|
||||
|
||||
// Log that the user activated the module by focusing the mouse pointer
|
||||
static void MousePointerFocused() noexcept;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
|
||||
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 .\ resource.base.h resource.h MouseHighlighter.base.rc MouseHighlighter.rc" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -0,0 +1,40 @@
|
|||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
PRODUCTVERSION PRODUCT_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
|
||||
BEGIN
|
||||
VALUE "CompanyName", COMPANY_NAME
|
||||
VALUE "FileDescription", FILE_DESCRIPTION
|
||||
VALUE "FileVersion", FILE_VERSION_STRING
|
||||
VALUE "InternalName", INTERNAL_NAME
|
||||
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||
VALUE "ProductName", PRODUCT_NAME
|
||||
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
443
src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.cpp
Normal file
|
@ -0,0 +1,443 @@
|
|||
// MouseHighlighter.cpp : Defines the entry point for the application.
|
||||
//
|
||||
|
||||
#include "pch.h"
|
||||
#include "MouseHighlighter.h"
|
||||
#include "trace.h"
|
||||
|
||||
#ifdef COMPOSITION
|
||||
namespace winrt
|
||||
{
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Composition;
|
||||
}
|
||||
|
||||
namespace ABI
|
||||
{
|
||||
using namespace ABI::Windows::System;
|
||||
using namespace ABI::Windows::UI::Composition::Desktop;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Highlighter
|
||||
{
|
||||
bool MyRegisterClass(HINSTANCE hInstance);
|
||||
static Highlighter* instance;
|
||||
void Terminate();
|
||||
void SwitchActivationMode();
|
||||
void ApplySettings(MouseHighlighterSettings settings);
|
||||
|
||||
private:
|
||||
enum class MouseButton
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
void DestroyHighlighter();
|
||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
void StartDrawing();
|
||||
void StopDrawing();
|
||||
bool CreateHighlighter();
|
||||
void AddDrawingPoint(MouseButton button);
|
||||
void UpdateDrawingPointPosition(MouseButton button);
|
||||
void StartDrawingPointFading(MouseButton button);
|
||||
void ClearDrawing();
|
||||
HHOOK m_mouseHook = NULL;
|
||||
static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
|
||||
static constexpr auto m_className = L"MouseHighlighter";
|
||||
static constexpr auto m_windowTitle = L"MouseHighlighter";
|
||||
HWND m_hwndOwner = NULL;
|
||||
HWND m_hwnd = NULL;
|
||||
HINSTANCE m_hinstance = NULL;
|
||||
static constexpr DWORD WM_SWITCH_ACTIVATION_MODE = WM_APP;
|
||||
|
||||
winrt::DispatcherQueueController m_dispatcherQueueController{ nullptr };
|
||||
winrt::Compositor m_compositor{ nullptr };
|
||||
winrt::Desktop::DesktopWindowTarget m_target{ nullptr };
|
||||
winrt::ContainerVisual m_root{ nullptr };
|
||||
winrt::LayerVisual m_layer{ nullptr };
|
||||
winrt::ShapeVisual m_shape{ nullptr };
|
||||
|
||||
winrt::CompositionSpriteShape m_leftPointer{ nullptr };
|
||||
winrt::CompositionSpriteShape m_rightPointer{ nullptr };
|
||||
bool m_leftButtonPressed = false;
|
||||
bool m_rightButtonPressed = false;
|
||||
|
||||
bool m_visible = false;
|
||||
|
||||
// Possible configurable settings
|
||||
float m_radius = MOUSE_HIGHLIGHTER_DEFAULT_RADIUS;
|
||||
|
||||
int m_fadeDelay_ms = MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS;
|
||||
int m_fadeDuration_ms = MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS;
|
||||
|
||||
winrt::Windows::UI::Color m_leftClickColor = MOUSE_HIGHLIGHTER_DEFAULT_LEFT_BUTTON_COLOR;
|
||||
winrt::Windows::UI::Color m_rightClickColor = MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR;
|
||||
};
|
||||
|
||||
Highlighter* Highlighter::instance = nullptr;
|
||||
|
||||
bool Highlighter::CreateHighlighter()
|
||||
{
|
||||
try
|
||||
{
|
||||
// We need a dispatcher queue.
|
||||
DispatcherQueueOptions options =
|
||||
{
|
||||
sizeof(options),
|
||||
DQTYPE_THREAD_CURRENT,
|
||||
DQTAT_COM_ASTA,
|
||||
};
|
||||
ABI::IDispatcherQueueController* controller;
|
||||
winrt::check_hresult(CreateDispatcherQueueController(options, &controller));
|
||||
*winrt::put_abi(m_dispatcherQueueController) = controller;
|
||||
|
||||
// Create the compositor for our window.
|
||||
m_compositor = winrt::Compositor();
|
||||
ABI::IDesktopWindowTarget* target;
|
||||
winrt::check_hresult(m_compositor.as<ABI::ICompositorDesktopInterop>()->CreateDesktopWindowTarget(m_hwnd, false, &target));
|
||||
*winrt::put_abi(m_target) = target;
|
||||
|
||||
// Create visual root
|
||||
m_root = m_compositor.CreateContainerVisual();
|
||||
m_root.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
m_target.Root(m_root);
|
||||
|
||||
// Create the shapes container visual and add it to root.
|
||||
m_shape = m_compositor.CreateShapeVisual();
|
||||
m_shape.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
m_root.Children().InsertAtTop(m_shape);
|
||||
|
||||
return true;
|
||||
} catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Highlighter::AddDrawingPoint(MouseButton button)
|
||||
{
|
||||
POINT pt;
|
||||
|
||||
// Applies DPIs.
|
||||
GetCursorPos(&pt);
|
||||
|
||||
// Converts to client area of the Windows.
|
||||
ScreenToClient(m_hwnd, &pt);
|
||||
|
||||
// Create circle and add it.
|
||||
auto circleGeometry = m_compositor.CreateEllipseGeometry();
|
||||
circleGeometry.Radius({ m_radius, m_radius });
|
||||
auto circleShape = m_compositor.CreateSpriteShape(circleGeometry);
|
||||
circleShape.Offset({ (float)pt.x, (float)pt.y });
|
||||
if (button == MouseButton::Left)
|
||||
{
|
||||
circleShape.FillBrush(m_compositor.CreateColorBrush(m_leftClickColor));
|
||||
m_leftPointer = circleShape;
|
||||
}
|
||||
else
|
||||
{
|
||||
//right
|
||||
circleShape.FillBrush(m_compositor.CreateColorBrush(m_rightClickColor));
|
||||
m_rightPointer = circleShape;
|
||||
}
|
||||
m_shape.Shapes().Append(circleShape);
|
||||
|
||||
// TODO: We're leaking shapes for long drawing sessions.
|
||||
// Perhaps add a task to the Dispatcher every X circles to clean up.
|
||||
|
||||
// Get back on top in case other Window is now the topmost.
|
||||
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN),
|
||||
GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), 0);
|
||||
}
|
||||
|
||||
void Highlighter::UpdateDrawingPointPosition(MouseButton button)
|
||||
{
|
||||
POINT pt;
|
||||
|
||||
// Applies DPIs.
|
||||
GetCursorPos(&pt);
|
||||
|
||||
// Converts to client area of the Windows.
|
||||
ScreenToClient(m_hwnd, &pt);
|
||||
|
||||
if (button == MouseButton::Left)
|
||||
{
|
||||
m_leftPointer.Offset({ (float)pt.x, (float)pt.y });
|
||||
}
|
||||
else
|
||||
{
|
||||
//right
|
||||
m_rightPointer.Offset({ (float)pt.x, (float)pt.y });
|
||||
}
|
||||
}
|
||||
void Highlighter::StartDrawingPointFading(MouseButton button)
|
||||
{
|
||||
winrt::Windows::UI::Composition::CompositionSpriteShape circleShape{ nullptr };
|
||||
if (button == MouseButton::Left)
|
||||
{
|
||||
circleShape = m_leftPointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
//right
|
||||
circleShape = m_rightPointer;
|
||||
}
|
||||
|
||||
auto brushColor = circleShape.FillBrush().as<winrt::Windows::UI::Composition::CompositionColorBrush>().Color();
|
||||
|
||||
// Animate opacity to simulate a fade away effect.
|
||||
auto animation = m_compositor.CreateColorKeyFrameAnimation();
|
||||
animation.InsertKeyFrame(1, winrt::Windows::UI::ColorHelper::FromArgb(0, brushColor.R, brushColor.G, brushColor.B));
|
||||
using timeSpan = std::chrono::duration<int, std::ratio<1, 1000>>;
|
||||
std::chrono::milliseconds duration(m_fadeDuration_ms);
|
||||
std::chrono::milliseconds delay(m_fadeDelay_ms);
|
||||
animation.Duration(timeSpan(duration));
|
||||
animation.DelayTime(timeSpan(delay));
|
||||
|
||||
circleShape.FillBrush().StartAnimation(L"Color", animation);
|
||||
}
|
||||
|
||||
|
||||
void Highlighter::ClearDrawing()
|
||||
{
|
||||
m_shape.Shapes().Clear();
|
||||
}
|
||||
|
||||
LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
if (nCode >= 0)
|
||||
{
|
||||
MSLLHOOKSTRUCT* hookData = (MSLLHOOKSTRUCT*)lParam;
|
||||
switch (wParam)
|
||||
{
|
||||
case WM_LBUTTONDOWN:
|
||||
instance->AddDrawingPoint(MouseButton::Left);
|
||||
instance->m_leftButtonPressed = true;
|
||||
break;
|
||||
case WM_RBUTTONDOWN:
|
||||
instance->AddDrawingPoint(MouseButton::Right);
|
||||
instance->m_rightButtonPressed = true;
|
||||
break;
|
||||
case WM_MOUSEMOVE:
|
||||
if (instance->m_leftButtonPressed)
|
||||
{
|
||||
instance->UpdateDrawingPointPosition(MouseButton::Left);
|
||||
}
|
||||
if (instance->m_rightButtonPressed)
|
||||
{
|
||||
instance->UpdateDrawingPointPosition(MouseButton::Right);
|
||||
}
|
||||
break;
|
||||
case WM_LBUTTONUP:
|
||||
if (instance->m_leftButtonPressed)
|
||||
{
|
||||
instance->StartDrawingPointFading(MouseButton::Left);
|
||||
instance->m_leftButtonPressed = false;
|
||||
}
|
||||
break;
|
||||
case WM_RBUTTONUP:
|
||||
if (instance->m_rightButtonPressed)
|
||||
{
|
||||
instance->StartDrawingPointFading(MouseButton::Right);
|
||||
instance->m_rightButtonPressed = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return CallNextHookEx(0, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
void Highlighter::StartDrawing()
|
||||
{
|
||||
Logger::info("Starting draw mode.");
|
||||
Trace::StartHighlightingSession();
|
||||
m_visible = true;
|
||||
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN),
|
||||
GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), 0);
|
||||
ClearDrawing();
|
||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||
m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, m_hinstance, 0);
|
||||
}
|
||||
|
||||
void Highlighter::StopDrawing()
|
||||
{
|
||||
Logger::info("Stopping draw mode.");
|
||||
m_visible = false;
|
||||
m_leftButtonPressed = false;
|
||||
m_rightButtonPressed = false;
|
||||
m_leftPointer = nullptr;
|
||||
m_rightPointer = nullptr;
|
||||
ShowWindow(m_hwnd, SW_HIDE);
|
||||
UnhookWindowsHookEx(m_mouseHook);
|
||||
ClearDrawing();
|
||||
m_mouseHook = NULL;
|
||||
}
|
||||
|
||||
void Highlighter::SwitchActivationMode()
|
||||
{
|
||||
PostMessage(m_hwnd, WM_SWITCH_ACTIVATION_MODE, 0, 0);
|
||||
}
|
||||
|
||||
void Highlighter::ApplySettings(MouseHighlighterSettings settings) {
|
||||
m_radius = (float)settings.radius;
|
||||
m_fadeDelay_ms = settings.fadeDelayMs;
|
||||
m_fadeDuration_ms = settings.fadeDurationMs;
|
||||
m_leftClickColor = settings.leftButtonColor;
|
||||
m_rightClickColor = settings.rightButtonColor;
|
||||
}
|
||||
|
||||
void Highlighter::DestroyHighlighter()
|
||||
{
|
||||
StopDrawing();
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK Highlighter::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_NCCREATE:
|
||||
instance->m_hwnd = hWnd;
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
case WM_CREATE:
|
||||
return instance->CreateHighlighter() ? 0 : -1;
|
||||
case WM_NCHITTEST:
|
||||
return HTTRANSPARENT;
|
||||
case WM_SWITCH_ACTIVATION_MODE:
|
||||
if (instance->m_visible)
|
||||
{
|
||||
instance->StopDrawing();
|
||||
}
|
||||
else
|
||||
{
|
||||
instance->StartDrawing();
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
instance->DestroyHighlighter();
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Highlighter::MyRegisterClass(HINSTANCE hInstance)
|
||||
{
|
||||
WNDCLASS wc{};
|
||||
|
||||
m_hinstance = hInstance;
|
||||
|
||||
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
if (!GetClassInfoW(hInstance, m_className, &wc))
|
||||
{
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
|
||||
wc.lpszClassName = m_className;
|
||||
|
||||
if (!RegisterClassW(&wc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hInstance, nullptr);
|
||||
|
||||
DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOOLWINDOW;
|
||||
return CreateWindowExW(exStyle, m_className, m_windowTitle, WS_POPUP,
|
||||
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hInstance, nullptr) != nullptr;
|
||||
}
|
||||
|
||||
void Highlighter::Terminate()
|
||||
{
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
DestroyWindow(m_hwndOwner);
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to destroy the window.");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma region MouseHighlighter_API
|
||||
|
||||
void MouseHighlighterApplySettings(MouseHighlighterSettings settings)
|
||||
{
|
||||
if (Highlighter::instance != nullptr)
|
||||
{
|
||||
Logger::info("Applying settings.");
|
||||
Highlighter::instance->ApplySettings(settings);
|
||||
}
|
||||
}
|
||||
|
||||
void MouseHighlighterSwitch()
|
||||
{
|
||||
if (Highlighter::instance != nullptr)
|
||||
{
|
||||
Logger::info("Switching activation mode.");
|
||||
Highlighter::instance->SwitchActivationMode();
|
||||
}
|
||||
}
|
||||
|
||||
void MouseHighlighterDisable()
|
||||
{
|
||||
if (Highlighter::instance != nullptr)
|
||||
{
|
||||
Logger::info("Terminating the highlighter instance.");
|
||||
Highlighter::instance->Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
bool MouseHighlighterIsEnabled()
|
||||
{
|
||||
return (Highlighter::instance != nullptr);
|
||||
}
|
||||
|
||||
int MouseHighlighterMain(HINSTANCE hInstance, MouseHighlighterSettings settings)
|
||||
{
|
||||
Logger::info("Starting a highlighter instance.");
|
||||
if (Highlighter::instance != nullptr)
|
||||
{
|
||||
Logger::error("A highlighter instance was still working when trying to start a new one.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Perform application initialization:
|
||||
Highlighter highlighter;
|
||||
Highlighter::instance = &highlighter;
|
||||
highlighter.ApplySettings(settings);
|
||||
if (!highlighter.MyRegisterClass(hInstance))
|
||||
{
|
||||
Logger::error("Couldn't initialize a highlighter instance.");
|
||||
Highlighter::instance = nullptr;
|
||||
return FALSE;
|
||||
}
|
||||
Logger::info("Initialized the highlighter instance.");
|
||||
|
||||
MSG msg;
|
||||
|
||||
// Main message loop:
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
Logger::info("Mouse highlighter message loop ended.");
|
||||
Highlighter::instance = nullptr;
|
||||
|
||||
return (int)msg.wParam;
|
||||
}
|
||||
|
||||
#pragma endregion MouseHighlighter_API
|
24
src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
constexpr int MOUSE_HIGHLIGHTER_DEFAULT_OPACITY = 160;
|
||||
const winrt::Windows::UI::Color MOUSE_HIGHLIGHTER_DEFAULT_LEFT_BUTTON_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(MOUSE_HIGHLIGHTER_DEFAULT_OPACITY, 255, 255, 0);
|
||||
const winrt::Windows::UI::Color MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(MOUSE_HIGHLIGHTER_DEFAULT_OPACITY, 0, 0, 255);
|
||||
constexpr int MOUSE_HIGHLIGHTER_DEFAULT_RADIUS = 20;
|
||||
constexpr int MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS = 500;
|
||||
constexpr int MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS = 250;
|
||||
|
||||
struct MouseHighlighterSettings
|
||||
{
|
||||
winrt::Windows::UI::Color leftButtonColor = MOUSE_HIGHLIGHTER_DEFAULT_LEFT_BUTTON_COLOR;
|
||||
winrt::Windows::UI::Color rightButtonColor = MOUSE_HIGHLIGHTER_DEFAULT_RIGHT_BUTTON_COLOR;
|
||||
int radius = MOUSE_HIGHLIGHTER_DEFAULT_RADIUS;
|
||||
int fadeDelayMs = MOUSE_HIGHLIGHTER_DEFAULT_DELAY_MS;
|
||||
int fadeDurationMs = MOUSE_HIGHLIGHTER_DEFAULT_DURATION_MS;
|
||||
};
|
||||
|
||||
int MouseHighlighterMain(HINSTANCE hinst, MouseHighlighterSettings settings);
|
||||
void MouseHighlighterDisable();
|
||||
bool MouseHighlighterIsEnabled();
|
||||
void MouseHighlighterSwitch();
|
||||
void MouseHighlighterApplySettings(MouseHighlighterSettings settings);
|
145
src/modules/MouseUtils/MouseHighlighter/MouseHighlighter.vcxproj
Normal file
|
@ -0,0 +1,145 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{782a61be-9d85-4081-b35c-1ccc9dcc1e88}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>MouseHighlighter</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>MouseHighlighter</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(CIBuild)'!='true'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MouseHighlighter.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="Generated Files\resource.h" />
|
||||
<None Include="resource.base.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="MouseHighlighter.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<None Include="MouseHighlighter.base.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\MouseHighlighter.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MouseHighlighter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Generated Files\resource.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MouseHighlighter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="MouseHighlighter.base.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="resource.base.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{b012a2c8-5ccb-47fc-9429-4ebf877928e2}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{c8345550-9836-40a0-b473-0f4bf6129568}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{7934ee5b-8427-486d-9324-73b6bcf60eed}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{e1083d6b-b856-42a6-bd1f-1710e96170ba}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files\MouseHighlighter.rc">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
304
src/modules/MouseUtils/MouseHighlighter/dllmain.cpp
Normal file
|
@ -0,0 +1,304 @@
|
|||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include "trace.h"
|
||||
#include "MouseHighlighter.h"
|
||||
#include "common/utils/color.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
|
||||
const wchar_t JSON_KEY_VALUE[] = L"value";
|
||||
const wchar_t JSON_KEY_ACTIVATION_SHORTCUT[] = L"activation_shortcut";
|
||||
const wchar_t JSON_KEY_LEFT_BUTTON_CLICK_COLOR[] = L"left_button_click_color";
|
||||
const wchar_t JSON_KEY_RIGHT_BUTTON_CLICK_COLOR[] = L"right_button_click_color";
|
||||
const wchar_t JSON_KEY_HIGHLIGHT_OPACITY[] = L"highlight_opacity";
|
||||
const wchar_t JSON_KEY_HIGHLIGHT_RADIUS[] = L"highlight_radius";
|
||||
const wchar_t JSON_KEY_HIGHLIGHT_FADE_DELAY_MS[] = L"highlight_fade_delay_ms";
|
||||
const wchar_t JSON_KEY_HIGHLIGHT_FADE_DURATION_MS[] = L"highlight_fade_duration_ms";
|
||||
}
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
HMODULE m_hModule;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
m_hModule = hModule;
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The PowerToy name that will be shown in the settings.
|
||||
const static wchar_t* MODULE_NAME = L"MouseHighlighter";
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"<no description>";
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class MouseHighlighter : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
// Hotkey to invoke the module
|
||||
HotkeyEx m_hotkey;
|
||||
|
||||
// Mouse Highlighter specific settings
|
||||
MouseHighlighterSettings m_highlightSettings;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
MouseHighlighter()
|
||||
{
|
||||
LoggerHelpers::init_logger(MODULE_NAME, L"ModuleInterface", LogSettings::mouseHighlighterLoggerName);
|
||||
init_settings();
|
||||
};
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the localized display name of the powertoy
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return the non localized key of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Signal from the Settings editor to call a custom action.
|
||||
// This can be used to spawn more complex editors.
|
||||
virtual void call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the input JSON string.
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
parse_settings(values);
|
||||
|
||||
MouseHighlighterApplySettings(m_highlightSettings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::error("Invalid json when trying to parse Mouse Highlighter settings json.");
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
Trace::EnableMouseHighlighter(true);
|
||||
std::thread([=]() { MouseHighlighterMain(m_hModule, m_highlightSettings); }).detach();
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
Trace::EnableMouseHighlighter(false);
|
||||
MouseHighlighterDisable();
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
virtual std::optional<HotkeyEx> GetHotkeyEx() override
|
||||
{
|
||||
return m_hotkey;
|
||||
}
|
||||
|
||||
virtual void OnHotkeyEx() override
|
||||
{
|
||||
MouseHighlighterSwitch();
|
||||
}
|
||||
|
||||
// Load the settings file.
|
||||
void init_settings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load and parse the settings file for this PowerToy.
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(MouseHighlighter::get_key());
|
||||
parse_settings(settings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::error("Invalid json when trying to load the Mouse Highlighter settings json from file.");
|
||||
}
|
||||
}
|
||||
|
||||
void parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
// TODO: refactor to use common/utils/json.h instead
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
MouseHighlighterSettings highlightSettings;
|
||||
if (settingsObject.GetView().Size())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse HotKey
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ACTIVATION_SHORTCUT);
|
||||
auto hotkey = PowerToysSettings::HotkeyObject::from_json(jsonPropertiesObject);
|
||||
m_hotkey = HotkeyEx();
|
||||
if (hotkey.win_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_WIN;
|
||||
}
|
||||
|
||||
if (hotkey.ctrl_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_CONTROL;
|
||||
}
|
||||
|
||||
if (hotkey.shift_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_SHIFT;
|
||||
}
|
||||
|
||||
if (hotkey.alt_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_ALT;
|
||||
}
|
||||
|
||||
m_hotkey.vkCode = hotkey.get_code();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Mouse Highlighter activation shortcut");
|
||||
}
|
||||
uint8_t opacity = MOUSE_HIGHLIGHTER_DEFAULT_OPACITY;
|
||||
try
|
||||
{
|
||||
// Parse Opacity
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_OPACITY);
|
||||
opacity = (uint8_t)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Opacity from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse left button click color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_LEFT_BUTTON_CLICK_COLOR);
|
||||
auto leftColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(leftColor,&r,&g,&b))
|
||||
{
|
||||
Logger::error("Left click color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
highlightSettings.leftButtonColor = winrt::Windows::UI::ColorHelper::FromArgb(opacity, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize left click color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse right button click color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_RIGHT_BUTTON_CLICK_COLOR);
|
||||
auto rightColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(rightColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Right click color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
highlightSettings.rightButtonColor = winrt::Windows::UI::ColorHelper::FromArgb(opacity, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize right click color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Radius
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_RADIUS);
|
||||
highlightSettings.radius = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Radius from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Fade Delay
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_FADE_DELAY_MS);
|
||||
highlightSettings.fadeDelayMs = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Fade Delay from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Fade Duration
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_HIGHLIGHT_FADE_DURATION_MS);
|
||||
highlightSettings.fadeDurationMs = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Fade Duration from settings. Will use default value");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("Mouse Highlighter settings are empty");
|
||||
}
|
||||
if (!m_hotkey.modifiersMask)
|
||||
{
|
||||
Logger::info("Mouse Highlighter is going to use default shortcut");
|
||||
m_hotkey.modifiersMask = MOD_SHIFT | MOD_WIN;
|
||||
m_hotkey.vkCode = 0x48; // H key
|
||||
}
|
||||
m_highlightSettings = highlightSettings;
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new MouseHighlighter();
|
||||
}
|
1
src/modules/MouseUtils/MouseHighlighter/pch.cpp
Normal file
|
@ -0,0 +1 @@
|
|||
#include "pch.h"
|
22
src/modules/MouseUtils/MouseHighlighter/pch.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#define COMPOSITION
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <strsafe.h>
|
||||
#include <hIdUsage.h>
|
||||
#include <thread>
|
||||
|
||||
#ifdef COMPOSITION
|
||||
#include <windows.ui.composition.interop.h>
|
||||
#include <DispatcherQueue.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.UI.Composition.Desktop.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#endif
|
||||
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
14
src/modules/MouseUtils/MouseHighlighter/resource.base.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by MouseHighlighter.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys MouseHighlighter"
|
||||
#define INTERNAL_NAME "MouseHighlighter"
|
||||
#define ORIGINAL_FILENAME "MouseHighlighter.dll"
|
||||
#define IDS_KEYBOARDMANAGER_ICON 1001
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
40
src/modules/MouseUtils/MouseHighlighter/trace.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
// Log if the user has MouseHighlighter enabled or disabled
|
||||
void Trace::EnableMouseHighlighter(const bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"MouseHighlighter_EnableMouseHighlighter",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
|
||||
// Log that the user activated the module by starting a highlighting session
|
||||
void Trace::StartHighlightingSession() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"MouseHighlighter_StartHighlightingSession",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|