Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dustin Howett 2021-10-25 13:59:01 -05:00
commit 645416229d
222 changed files with 9034 additions and 9963 deletions

View file

@ -5,7 +5,9 @@ abcdef
abcdefgh
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abgr
abi
ABlocked
ABOUTBOX
Abug
accctrl
Acceleratorkeys
@ -204,6 +206,7 @@ CANRENAME
Captureascreenshot
CAPTURECHANGED
CASESENSITIVE
cassert
CAtl
CCDDEE
ccf
@ -382,6 +385,7 @@ CXVIRTUALSCREEN
cxx
cxxopts
CYSMICON
CYVIRTUALSCREEN
cziplib
Dac
dacl
@ -493,6 +497,8 @@ DPICHANGED
DPolicy
DPopup
DPSAPI
DQTAT
DQTYPE
DRAWFRAME
drawingcolor
dreamsofameaningfullife
@ -788,6 +794,7 @@ hotspot
HPAINTBUFFER
hpj
hpp
HRAWINPUT
hread
HREDRAW
href
@ -807,6 +814,7 @@ Htmdid
html
htt
http
HTTRANSPARENT
hwb
HWINEVENTHOOK
hwnd
@ -840,6 +848,7 @@ ICollection
IColor
ICommand
IComparer
ICompositor
ICONERROR
ICONINFORMATION
IContext
@ -854,6 +863,7 @@ IDesktop
IDictionary
IDirectory
IDispatch
IDispatcher
IDisposable
idl
IDLIST
@ -941,6 +951,7 @@ INPUTHARDWARE
INPUTKEYBOARD
INPUTLANGCHANGED
INPUTMOUSE
INPUTSINK
INPUTTYPE
INSTALLDESKTOPSHORTCUT
INSTALLDIR
@ -1000,7 +1011,6 @@ IRepository
IResult
ISavable
isbi
iss
ISearch
IService
isetting
@ -1009,6 +1019,7 @@ IShell
ISingle
ISmart
isocpp
iss
IStorage
IStream
istreambuf
@ -1019,9 +1030,9 @@ ITab
ITask
ITemplate
ITEMSTATEICONCLICK
ITerminal
ITest
ith
ITerminal
IThrottled
IThumbnail
ITrigger
@ -1039,6 +1050,7 @@ IWeb
IWIC
IWindows
IWork
IXaml
IXml
ixx
IYUV
@ -1148,6 +1160,7 @@ lmcons
LMEM
LMENU
lnk
LOADSTRING
LOCALAPPDATA
LOCALDISPLAY
localhost
@ -1169,6 +1182,7 @@ lowlevel
LOWORD
lparam
LPBYTE
LPCITEMIDLIST
LPCMINVOKECOMMANDINFO
LPCREATESTRUCT
LPCTSTR
@ -1215,6 +1229,7 @@ LVS
LVSIL
LWA
lwin
LZero
lzw
mailto
MAINICON
@ -1328,6 +1343,7 @@ msedge
MSGFLT
mshtmdid
msi
msiexec
MSIFASTINSTALL
MSIHANDLE
MSIINSTALLER
@ -1570,6 +1586,7 @@ phwnd
pici
pid
pidl
PIDLIST
PINDIR
pinfo
pinvoke
@ -1602,6 +1619,7 @@ powerlauncher
powerpreview
powerrename
POWERRENAMETEST
POWERRENAMEUIHOST
powershell
powertoy
powertoysinterop
@ -1695,6 +1713,7 @@ QUERYOPEN
QUEUESYNC
Quickime
QUICKLAYOUTSWITCH
QUNS
qwertyuiopasdfghjklzxcvbnm
qword
qwrtyuiopsghjklzxvnm
@ -1702,6 +1721,9 @@ Radiobuttons
RAII
RAlt
randyrants
RAWINPUT
RAWINPUTDEVICE
RAWINPUTHEADER
RAWPATH
rbegin
Rbp
@ -1786,6 +1808,7 @@ rgs
rhs
ricardosantos
Richtext
RIDEV
RIGHTSCROLLBAR
riid
riverar
@ -2165,7 +2188,9 @@ tsx
TYMED
typedef
TYPEKEY
TYPEKEYBOARD
TYPELIB
TYPEMOUSE
typename
typeof
typeparam
@ -2468,6 +2493,7 @@ XSmall
XStr
XToolset
xunit
XVIRTUALSCREEN
Yaml
YDiff
YIncrement
@ -2478,6 +2504,7 @@ YStr
YUY
yuyoyuppe
YUYV
YVIRTUALSCREEN
YVU
YVYU
ZEROINIT

View file

@ -170,7 +170,10 @@ build:
- 'modules\launcher\Wox.dll'
- 'modules\launcher\Wox.Infrastructure.dll'
- 'modules\launcher\Wox.Plugin.dll'
- 'modules\MouseUtils\FindMyMouse.dll'
- 'modules\PowerRename\PowerRenameExt.dll'
- 'modules\PowerRename\PowerRenameUILib.dll'
- 'modules\PowerRename\PowerRename.exe'
- 'modules\ShortcutGuide\ShortcutGuide\PowerToys.ShortcutGuide.exe'
- 'modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.dll'
- 'modules\VideoConference\VideoConferenceModule.dll'

View file

@ -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

View file

@ -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 -->

View file

@ -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
@ -181,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}"
@ -194,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}"
@ -283,13 +267,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{B39DC643
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
@ -372,6 +360,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plu
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
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -422,12 +421,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
@ -602,12 +595,6 @@ Global
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.ActiveCfg = Release|x64
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.Build.0 = Release|x64
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x86.ActiveCfg = Release|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.ActiveCfg = Debug|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.Build.0 = Debug|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x86.ActiveCfg = Debug|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.ActiveCfg = Release|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.Build.0 = Release|x64
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x86.ActiveCfg = Release|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.ActiveCfg = Debug|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.Build.0 = Debug|x64
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.ActiveCfg = Debug|x64
@ -981,6 +968,24 @@ Global
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -995,7 +1000,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}
@ -1028,7 +1032,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}
@ -1098,6 +1101,10 @@ Global
{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}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View file

@ -19,7 +19,7 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
| [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) | | |
| [Video Conference Mute (Experimental)](https://aka.ms/PowerToysOverview_VideoConference) | [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | |
## Installing and running Microsoft PowerToys
@ -47,7 +47,7 @@ To install the Video Conference mute, please use the [v0.46 experimental version
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
@ -84,7 +84,7 @@ Our goals for the [v0.47 release cycle](https://github.com/microsoft/PowerToys/i
Notably, based on the community feedback received, PowerToys has re-introduced the highly-requested ability to activate Shortcut Guide via holding the <kbd>Win</kbd> key. PowerToys also now allows various commands in PowerToys Run to be used in either the universal English phrasing or system-localized translation. The great feedback the community provides is invaluable in helping PowerToys continually grow and improve as a product.
An experimental version of PowerToys (v0.48) will be released the week of October 4th, introducing improvements to our Video Conference Mute utility! All updates from the v0.47.1 release will still apply in v0.48.
An experimental version of PowerToys ([v0.48.1](https://github.com/microsoft/PowerToys/releases/tag/v0.48.1)) is also available, introducing improvements to our Video Conference Mute utility! All updates from the v0.47.1 release apply in v0.48.1.
#### Highlights from v0.47

6
Solution.props Normal file
View 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>

View file

@ -25,6 +25,7 @@
| 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 |

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View file

@ -165,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();
@ -299,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);
@ -307,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

View file

@ -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,7 +263,9 @@
<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"/>
@ -270,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" />
@ -480,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" />
@ -689,7 +621,15 @@
<!-- 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" />
<RegistryKey Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}">
<RegistryValue Type="string" Value="PowerRename Shell Extension" />
<RegistryValue Type="string" Name="ContextMenuOptIn" Value="" />
@ -702,6 +642,19 @@
</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>
</DirectoryRef>
<!-- Shortcut guide -->
<DirectoryRef Id="ShortcutGuideModuleInterfaceInstallFolder" FileSource="$(var.ShortcutGuideModuleInterface)">
<Component Id="Module_ShortcutGuideModuleInterface" Guid="CBD0AC09-91D3-428E-B2B3-05745ADF3473" Win64="yes">
@ -903,21 +856,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>
@ -999,10 +952,11 @@
<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 +966,7 @@
<ComponentRef Id="Module_Awake_runtime_netstandard20"/>
<ComponentRef Id="Module_Awake_runtime_netcoreapp30"/>
<ComponentRef Id="Module_Awake_runtime_netcoreapp21"/>
<ComponentRef Id="Module_FindMyMouse"/>
<ComponentRef Id="SettingsV2" />
<ComponentRef Id="SettingsV2Assets" />
<ComponentRef Id="SettingsV2AssetsModules" />

View file

@ -3,6 +3,7 @@
#include <ProjectTelemetry.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 +26,69 @@ 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}";
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)
{
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
std::wstring installationFolder;
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");
}
}
ExitOnFailure(hr, "Failed to extract msix");
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall UnApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
std::wstring installationFolder;
hr = WcaInitialize(hInstall, "UndoModulesRegistryChangeSets"); // original func name is too long
ExitOnFailure(hr, "Failed to initialize");
hr = getInstallFolder(hInstall, installationFolder);
ExitOnFailure(hr, "Failed to get installfolder.");
for (const auto& changeSet : getAllModulesChangeSets(installationFolder, false))
{
changeSet.unApply();
}
ExitOnFailure(hr, "Failed to extract msix");
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
UINT __stdcall InstallEmbeddedMSIXCA(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;

View file

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

View file

@ -19,6 +19,7 @@ namespace Microsoft.PowerToys.Common.UI
Run,
ImageResizer,
KBM,
MouseUtils,
PowerRename,
FileExplorer,
ShortcutGuide,
@ -43,6 +44,8 @@ namespace Microsoft.PowerToys.Common.UI
return "ImageResizer";
case SettingsWindow.KBM:
return "KBM";
case SettingsWindow.MouseUtils:
return "MouseUtils";
case SettingsWindow.PowerRename:
return "PowerRename";
case SettingsWindow.FileExplorer:

View file

@ -313,7 +313,7 @@ namespace PowerToysSettings
return json::has(props, name) && json::has(props.GetNamedObject(name), L"value", type);
}
std::optional<bool> PowerToyValues::get_bool_value(std::wstring_view property_name)
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))
{

View file

@ -79,10 +79,10 @@ namespace PowerToysSettings
m_json.GetNamedObject(L"properties").SetNamedValue(name, prop_value);
}
std::optional<bool> get_bool_value(std::wstring_view property_name);
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();

View file

@ -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

View file

@ -23,6 +23,7 @@ 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 int retention = 30;
std::wstring logLevel;
LogSettings();

View 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;
};

View file

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

View file

@ -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) };
}

329
src/common/utils/registry.h Normal file
View file

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

View file

@ -33,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;
}

View file

@ -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>

View file

@ -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

View file

@ -0,0 +1,828 @@
// 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
bool m_doNotActivateOnGameMode = true;
#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;
static constexpr int SonarRadius = 100;
static constexpr int SonarZoomFactor = 9;
static constexpr DWORD FadeDuration = 500;
static constexpr int FinalAlphaNumerator = 1;
static constexpr int FinalAlphaDenominator = 2;
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 | 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([=]() {
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:
case SonarState::ControlUp2:
if (pressed)
{
m_sonarState = SonarState::ControlDown2;
auto now = GetTickCount();
POINT ptCursor{};
if (GetCursorPos(&ptCursor) &&
now - m_lastKeyTime <= GetDoubleClickTime() &&
IsEqual(m_lastKeyPos, ptCursor))
{
StartSonar();
}
m_lastKeyTime = now;
m_lastKeyPos = ptCursor;
}
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;
static constexpr float SonarRadiusFloat = static_cast<float>(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>(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);
auto backdrop = m_compositor.CreateSpriteVisual();
backdrop.RelativeSizeAdjustment({ 1.0f, 1.0f }); // fill the parent
backdrop.Brush(m_compositor.CreateColorBrush({ 255, 0, 0, 0 }));
layer.Children().InsertAtTop(backdrop);
m_circleGeometry = m_compositor.CreateEllipseGeometry(); // radius set via expression animation
auto circleShape = m_compositor.CreateSpriteShape(m_circleGeometry);
circleShape.FillBrush(m_compositor.CreateColorBrush({ 255, 255, 255, 255 }));
circleShape.Offset({ SonarRadiusFloat * SonarZoomFactor, SonarRadiusFloat * SonarZoomFactor });
m_spotlight = m_compositor.CreateShapeVisual();
m_spotlight.Size({ SonarRadiusFloat * 2 * SonarZoomFactor, SonarRadiusFloat * 2 * SonarZoomFactor });
m_spotlight.AnchorPoint({ 0.5f, 0.5f });
m_spotlight.Shapes().Append(circleShape);
layer.Children().InsertAtTop(m_spotlight);
// Implicitly animate the alpha.
auto animation = m_compositor.CreateScalarKeyFrameAnimation();
animation.Target(L"Opacity");
animation.InsertExpressionKeyFrame(1.0f, L"this.FinalValue");
animation.Duration(std::chrono::milliseconds{ FadeDuration });
auto collection = m_compositor.CreateImplicitAnimationCollection();
collection.Insert(L"Opacity", animation);
m_root.ImplicitAnimations(collection);
// Radius of spotlight shrinks as opacity increases.
// At opacity zero, it is SonarRadius * SonarZoomFactor.
// At maximum opacity, it is SonarRadius.
auto radiusExpression = m_compositor.CreateExpressionAnimation();
radiusExpression.SetReferenceParameter(L"Root", m_root);
wchar_t expressionText[256];
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity * %d / %d)", SonarRadius * SonarZoomFactor, SonarRadius * SonarZoomFactor, SonarRadius, SonarRadius, FinalAlphaDenominator, FinalAlphaNumerator));
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);
}
}
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 };
};
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->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->SonarRadius + this->SonarRadius * range * (this->SonarZoomFactor - 1) / MaxAlpha;
return radius;
}
private:
static constexpr DWORD FadeFramePeriod = 10;
static constexpr int MaxAlpha = SuperSonar<D>::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 FindMyMouseDisable()
{
if (m_sonar != nullptr)
{
Logger::info("Terminating a sonar instance.");
m_sonar->Terminate();
}
}
bool FindMyMouseIsEnabled()
{
return (m_sonar != nullptr);
}
void FindMyMouseSetDoNotActivateOnGameMode(bool doNotActivate)
{
m_doNotActivateOnGameMode = doNotActivate;
}
// Based on SuperSonar's original wWinMain.
int FindMyMouseMain(HINSTANCE hinst)
{
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;
if (!sonar.Initialize(hinst))
{
Logger::error("Couldn't initialize a sonar instance.");
return 0;
}
m_sonar = &sonar;
Logger::info("Initialized the sonar instance.");
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Logger::info("Sonar message loop ended.");
m_sonar = nullptr;
return (int)msg.wParam;
}
#pragma endregion Super_Sonar_API

View file

@ -0,0 +1,6 @@
#pragma once
#include "pch.h"
int FindMyMouseMain(HINSTANCE hinst);
void FindMyMouseDisable();
bool FindMyMouseIsEnabled();
void FindMyMouseSetDoNotActivateOnGameMode(bool doNotActivate);

View 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>

View file

@ -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>

View file

@ -0,0 +1,186 @@
#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>
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";
}
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;
// 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);
values.save_to_settings_file();
}
catch (std::exception&)
{
// Improper JSON.
}
}
// Enable the powertoy
virtual void enable()
{
m_enabled = true;
Trace::EnableFindMyMouse(true);
std::thread([]() { FindMyMouseMain(m_hModule); }).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)
{
FindMyMouseSetDoNotActivateOnGameMode(true);
auto settingsObject = settings.get_raw_json();
if (settingsObject.GetView().Size())
{
try
{
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_DO_NOT_ACTIVATE_ON_GAME_MODE);
FindMyMouseSetDoNotActivateOnGameMode((bool)jsonPropertiesObject.GetNamedBoolean(JSON_KEY_VALUE));
}
catch (...)
{
Logger::warn("Failed to get 'do not activate on game mode' setting");
}
}
else
{
Logger::info("Find My Mouse settings are empty");
}
}
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new FindMyMouse();
}

View 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>

View 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
//////////////////////////////

View 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));
}

View 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;
};

View file

@ -175,7 +175,7 @@ namespace Awake.Core
};
// No keep-awake menu item.
ToolStripMenuItem? passiveMenuItem = new ToolStripMenuItem
CheckButtonToolStripMenuItem? passiveMenuItem = new CheckButtonToolStripMenuItem
{
Text = "Off (Passive)",
};
@ -189,7 +189,7 @@ namespace Awake.Core
};
// Indefinite keep-awake menu item.
ToolStripMenuItem? indefiniteMenuItem = new ToolStripMenuItem
CheckButtonToolStripMenuItem? indefiniteMenuItem = new CheckButtonToolStripMenuItem
{
Text = "Keep awake indefinitely",
};
@ -202,7 +202,7 @@ namespace Awake.Core
indefiniteKeepAwakeCallback();
};
ToolStripMenuItem? displayOnMenuItem = new ToolStripMenuItem
CheckButtonToolStripMenuItem? displayOnMenuItem = new CheckButtonToolStripMenuItem
{
Text = "Keep screen on",
};
@ -222,6 +222,7 @@ namespace Awake.Core
};
timedMenuItem.Checked = mode == AwakeMode.TIMED;
timedMenuItem.AccessibleName = timedMenuItem.Text + (timedMenuItem.Checked ? ". Checked. " : ". UnChecked. ");
ToolStripMenuItem? halfHourMenuItem = new ToolStripMenuItem
{
@ -284,5 +285,38 @@ namespace Awake.Core
TrayIcon.Text = text;
TrayIcon.ContextMenuStrip = contextMenuStrip;
}
private class CheckButtonToolStripMenuItemAccessibleObject : ToolStripItem.ToolStripItemAccessibleObject
{
private CheckButtonToolStripMenuItem _menuItem;
public CheckButtonToolStripMenuItemAccessibleObject(CheckButtonToolStripMenuItem menuItem)
: base(menuItem)
{
_menuItem = menuItem;
}
public override AccessibleRole Role
{
get
{
return AccessibleRole.CheckButton;
}
}
public override string Name => _menuItem.Text + ", " + Role + ", " + (_menuItem.Checked ? "Checked" : "Unchecked");
}
private class CheckButtonToolStripMenuItem : ToolStripMenuItem
{
public CheckButtonToolStripMenuItem()
{
}
protected override AccessibleObject CreateAccessibilityInstance()
{
return new CheckButtonToolStripMenuItemAccessibleObject(this);
}
}
}
}

View file

@ -3,16 +3,12 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using FancyZonesEditor.Logs;
using FancyZonesEditor.Utils;
using ManagedCommon;
using Microsoft.PowerToys.Common.UI;
@ -25,26 +21,7 @@ namespace FancyZonesEditor
public partial class App : Application, IDisposable
{
// Non-localizable strings
private const string CrashReportLogFile = "FZEditorCrashLog.txt";
private const string ErrorReportLogFile = "FZEditorErrorLog.txt";
private const string PowerToysIssuesURL = "https://aka.ms/powerToysReportBug";
private const string CrashReportExceptionTag = "Exception";
private const string CrashReportSourceTag = "Source: ";
private const string CrashReportTargetAssemblyTag = "TargetAssembly: ";
private const string CrashReportTargetModuleTag = "TargetModule: ";
private const string CrashReportTargetSiteTag = "TargetSite: ";
private const string CrashReportEnvironmentTag = "Environment";
private const string CrashReportCommandLineTag = "* Command Line: ";
private const string CrashReportTimestampTag = "* Timestamp: ";
private const string CrashReportOSVersionTag = "* OS Version: ";
private const string CrashReportIntPtrLengthTag = "* IntPtr Length: ";
private const string CrashReportx64Tag = "* x64: ";
private const string CrashReportCLRVersionTag = "* CLR Version: ";
private const string CrashReportAssembliesTag = "Assemblies - ";
private const string CrashReportDynamicAssemblyTag = "dynamic assembly doesn't have location";
private const string CrashReportLocationNullTag = "location is null or empty";
private const string ParsingErrorReportTag = "Settings parsing error";
private const string ParsingErrorDataTag = "Data: ";
@ -60,6 +37,8 @@ namespace FancyZonesEditor
private EventWaitHandle _eventHandle;
private Thread _exitWaitThread;
public static bool DebugMode
{
get
@ -84,14 +63,8 @@ namespace FancyZonesEditor
Overlay = new Overlay();
MainWindowSettings = new MainWindowSettingsModel();
new Thread(() =>
{
_eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, interop.Constants.FZEExitEvent());
if (_eventHandle.WaitOne())
{
Environment.Exit(0);
}
}).Start();
_exitWaitThread = new Thread(App_WaitExit);
_exitWaitThread.Start();
}
private void OnStartup(object sender, StartupEventArgs e)
@ -100,6 +73,7 @@ namespace FancyZonesEditor
RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>
{
Logger.LogInfo("Runner exited");
Environment.Exit(0);
});
@ -139,15 +113,7 @@ namespace FancyZonesEditor
// Error message if parsing failed
if (!parseResult.Result)
{
var sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("## " + ParsingErrorReportTag);
sb.AppendLine();
sb.AppendLine(parseResult.Message);
sb.AppendLine();
sb.AppendLine(ParsingErrorDataTag);
sb.AppendLine(parseResult.MalformedData);
Logger.LogError(ParsingErrorReportTag + ": " + parseResult.Message + "; " + ParsingErrorDataTag + ": " + parseResult.MalformedData);
MessageBox.Show(parseResult.Message, FancyZonesEditor.Properties.Resources.Error_Parsing_Zones_Settings_Title, MessageBoxButton.OK);
}
@ -159,10 +125,26 @@ namespace FancyZonesEditor
private void OnExit(object sender, ExitEventArgs e)
{
Dispose();
if (_eventHandle != null)
{
_eventHandle.Set();
}
_exitWaitThread.Join();
Logger.LogInfo("FancyZones Editor exited");
}
private void App_WaitExit()
{
_eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, interop.Constants.FZEExitEvent());
if (_eventHandle.WaitOne())
{
Logger.LogInfo("Exit event triggered");
Environment.Exit(0);
}
}
public void App_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
@ -197,126 +179,20 @@ namespace FancyZonesEditor
MessageBox.Show(fullMessage, FancyZonesEditor.Properties.Resources.Error_Exception_Message_Box_Title);
}
public static void ShowExceptionReportMessageBox(string reportData)
{
var fileStream = File.OpenWrite(ErrorReportLogFile);
using (var sw = new StreamWriter(fileStream))
{
sw.Write(reportData);
sw.Flush();
}
fileStream.Close();
ShowReportMessageBox(fileStream.Name);
}
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
var fileStream = File.OpenWrite(CrashReportLogFile);
using (var sw = new StreamWriter(fileStream))
{
sw.Write(FormatException((Exception)args.ExceptionObject));
}
fileStream.Close();
ShowReportMessageBox(fileStream.Name);
Logger.LogError("Unhandled exception", (Exception)args.ExceptionObject);
ShowReportMessageBox();
}
private static void ShowReportMessageBox(string fileName)
private static void ShowReportMessageBox()
{
MessageBox.Show(
FancyZonesEditor.Properties.Resources.Crash_Report_Message_Box_Text_Part1 +
Path.GetFullPath(fileName) +
"\n" +
FancyZonesEditor.Properties.Resources.Crash_Report_Message_Box_Text_Part2 +
FancyZonesEditor.Properties.Resources.Crash_Report_Message_Box_Text +
PowerToysIssuesURL,
FancyZonesEditor.Properties.Resources.Fancy_Zones_Editor_App_Title);
}
private static string FormatException(Exception ex)
{
var sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("## " + CrashReportExceptionTag);
sb.AppendLine();
sb.AppendLine("```");
var exlist = new List<StringBuilder>();
while (ex != null)
{
var exsb = new StringBuilder();
exsb.Append(ex.GetType().FullName);
exsb.Append(": ");
exsb.AppendLine(ex.Message);
if (ex.Source != null)
{
exsb.Append(" " + CrashReportSourceTag);
exsb.AppendLine(ex.Source);
}
if (ex.TargetSite != null)
{
exsb.Append(" " + CrashReportTargetAssemblyTag);
exsb.AppendLine(ex.TargetSite.Module.Assembly.ToString());
exsb.Append(" " + CrashReportTargetModuleTag);
exsb.AppendLine(ex.TargetSite.Module.ToString());
exsb.Append(" " + CrashReportTargetSiteTag);
exsb.AppendLine(ex.TargetSite.ToString());
}
exsb.AppendLine(ex.StackTrace);
exlist.Add(exsb);
ex = ex.InnerException;
}
foreach (var result in exlist.Select(o => o.ToString()).Reverse())
{
sb.AppendLine(result);
}
sb.AppendLine("```");
sb.AppendLine();
sb.AppendLine("## " + CrashReportEnvironmentTag);
sb.AppendLine(CrashReportCommandLineTag + Environment.CommandLine);
// Using InvariantCulture since this is used for a timestamp internally
sb.AppendLine(CrashReportTimestampTag + DateTime.Now.ToString(CultureInfo.InvariantCulture));
sb.AppendLine(CrashReportOSVersionTag + Environment.OSVersion.VersionString);
sb.AppendLine(CrashReportIntPtrLengthTag + IntPtr.Size);
sb.AppendLine(CrashReportx64Tag + Environment.Is64BitOperatingSystem);
sb.AppendLine(CrashReportCLRVersionTag + Environment.Version);
sb.AppendLine("## " + CrashReportAssembliesTag + AppDomain.CurrentDomain.FriendlyName);
sb.AppendLine();
foreach (var ass in AppDomain.CurrentDomain.GetAssemblies().OrderBy(o => o.GlobalAssemblyCache ? 50 : 0))
{
sb.Append("* ");
sb.Append(ass.FullName);
sb.Append(" (");
if (ass.IsDynamic)
{
sb.Append(CrashReportDynamicAssemblyTag);
}
else if (string.IsNullOrEmpty(ass.Location))
{
sb.Append(CrashReportLocationNullTag);
}
else
{
sb.Append(ass.Location);
}
sb.AppendLine(")");
}
return sb.ToString();
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
@ -329,6 +205,7 @@ namespace FancyZonesEditor
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
_isDisposed = true;
Logger.LogInfo("FancyZones Editor disposed");
}
}

View file

@ -4,6 +4,7 @@
using System.Windows;
using System.Windows.Input;
using FancyZonesEditor.Logs;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
@ -34,11 +35,13 @@ namespace FancyZonesEditor
private void OnAddZone(object sender, RoutedEventArgs e)
{
Logger.LogInfo("Add zone");
_model.AddZone();
}
protected new void OnCancel(object sender, RoutedEventArgs e)
{
Logger.LogInfo("Cancel changes");
base.OnCancel(sender, e);
_stashedModel.RestoreTo(_model);
}

View file

@ -4,6 +4,7 @@
using System;
using System.Windows;
using FancyZonesEditor.Logs;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
@ -12,6 +13,7 @@ namespace FancyZonesEditor
{
protected void OnSaveApplyTemplate(object sender, RoutedEventArgs e)
{
Logger.LogTrace();
var mainEditor = App.Overlay;
if (mainEditor.CurrentDataContext is LayoutModel model)
{

View file

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using FancyZonesEditor.Logs;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
@ -417,6 +418,8 @@ namespace FancyZonesEditor
public void DoMerge(List<int> indices)
{
Logger.LogTrace();
if (indices.Count == 0)
{
return;
@ -455,6 +458,7 @@ namespace FancyZonesEditor
public void Split(int zoneIndex, int position, Orientation orientation)
{
Logger.LogTrace();
if (!CanSplit(zoneIndex, position, orientation))
{
return;
@ -519,6 +523,8 @@ namespace FancyZonesEditor
public void Drag(int resizerIndex, int delta)
{
Logger.LogTrace();
if (!CanDrag(resizerIndex, delta))
{
return;

View file

@ -10,6 +10,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using FancyZonesEditor.Logs;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
@ -316,6 +317,8 @@ namespace FancyZonesEditor
private void OnSplit(object sender, SplitEventArgs args)
{
Logger.LogTrace();
MergeCancelClick(null, null);
var zonePanel = sender as GridZone;
@ -488,6 +491,7 @@ namespace FancyZonesEditor
private void OnMergeComplete(object o, MouseButtonEventArgs e)
{
Logger.LogTrace();
_inMergeDrag = false;
var selectedIndices = new List<int>();

View file

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using FancyZonesEditor.Logs;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
@ -83,6 +84,11 @@ namespace FancyZonesEditor
{
_model = (LayoutModel)DataContext;
if (_model != null)
{
Logger.LogInfo("Loaded " + _model.Name);
}
RenderPreview();
}

View file

@ -0,0 +1,101 @@
// 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.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Reflection;
using interop;
namespace FancyZonesEditor.Logs
{
public static class Logger
{
private static readonly IFileSystem _fileSystem = new FileSystem();
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
public static readonly string Version = FileVersionInfo.GetVersionInfo(Assembly.Location).ProductVersion;
private static readonly string ApplicationLogPath = Path.Combine(Constants.AppDataPath(), "FancyZones\\Editor\\Logs\\", Version);
private static readonly string Error = "Error";
private static readonly string Warning = "Warning";
private static readonly string Info = "Info";
private static readonly string Debug = "Debug";
private static readonly string TraceFlag = "Trace";
static Logger()
{
if (!_fileSystem.Directory.Exists(ApplicationLogPath))
{
_fileSystem.Directory.CreateDirectory(ApplicationLogPath);
}
// Using InvariantCulture since this is used for a log file name
var logFilePath = _fileSystem.Path.Combine(ApplicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".txt");
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));
Trace.AutoFlush = true;
}
public static void LogError(string message)
{
Log(message, Error);
}
public static void LogError(string message, Exception ex)
{
Log(
message + Environment.NewLine +
ex?.Message + Environment.NewLine +
"Inner exception: " + Environment.NewLine +
ex?.InnerException?.Message + Environment.NewLine +
"Stack trace: " + Environment.NewLine +
ex?.StackTrace,
Error);
}
public static void LogWarning(string message)
{
Log(message, Warning);
}
public static void LogInfo(string message)
{
Log(message, Info);
}
public static void LogDebug(string message)
{
Log(message, Debug);
}
public static void LogTrace()
{
Log(string.Empty, TraceFlag);
}
private static void Log(string message, string type)
{
Trace.WriteLine("[" + DateTime.Now.TimeOfDay + "] [" + type + "] " + GetCallerInfo());
Trace.Indent();
if (message != string.Empty)
{
Trace.WriteLine(message);
}
Trace.Unindent();
}
private static string GetCallerInfo()
{
StackTrace stackTrace = new StackTrace();
var methodName = stackTrace.GetFrame(3)?.GetMethod();
var className = methodName?.DeclaringType.Name;
return className + "::" + methodName?.Name;
}
}
}

View file

@ -4,13 +4,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Input;
using FancyZonesEditor.Logs;
using FancyZonesEditor.Models;
using FancyZonesEditor.Utils;
using Microsoft.PowerToys.Common.UI;
@ -42,20 +41,7 @@ namespace FancyZonesEditor
DataContext = _settings;
KeyUp += MainWindow_KeyUp;
// Prevent closing the dialog with enter
PreviewKeyDown += (object sender, KeyEventArgs e) =>
{
if (e.Key == Key.Enter && _openedDialog != null && _openedDialog.IsVisible)
{
var source = e.OriginalSource as RadioButton;
if (source != null && source.IsChecked != true)
{
source.IsChecked = true;
e.Handled = true;
}
}
};
PreviewKeyDown += MainWindow_PreviewKeyDown;
if (spanZonesAcrossMonitors)
{
@ -85,6 +71,20 @@ namespace FancyZonesEditor
}
}
// Prevent closing the dialog with enter
private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter && _openedDialog != null && _openedDialog.IsVisible)
{
var source = e.OriginalSource as RadioButton;
if (source != null && source.IsChecked != true)
{
source.IsChecked = true;
e.Handled = true;
}
}
}
private void LayoutItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
CloseDialog(sender);
@ -164,6 +164,8 @@ namespace FancyZonesEditor
private async void NewLayoutButton_Click(object sender, RoutedEventArgs e)
{
Logger.LogTrace();
if (_openedDialog != null)
{
// another dialog already opened
@ -195,6 +197,8 @@ namespace FancyZonesEditor
private void DuplicateLayout_Click(object sender, RoutedEventArgs e)
{
Logger.LogTrace();
EditLayoutDialog.Hide();
var mainEditor = App.Overlay;
@ -217,7 +221,7 @@ namespace FancyZonesEditor
name = name.TrimEnd();
}
AnnounceSuccessfulLayoutCreation(name);
Announce(name, FancyZonesEditor.Properties.Resources.Layout_Creation_Announce);
int maxCustomIndex = 0;
foreach (LayoutModel customModel in MainWindowSettingsModel.CustomModels)
{
@ -249,18 +253,19 @@ namespace FancyZonesEditor
App.FancyZonesEditorIO.SerializeZoneSettings();
}
private void AnnounceSuccessfulLayoutCreation(string name)
private void Announce(string name, string message)
{
if (AutomationPeer.ListenerExists(AutomationEvents.MenuOpened))
if (AutomationPeer.ListenerExists(AutomationEvents.MenuOpened) && _createLayoutAnnounce != null)
{
var peer = UIElementAutomationPeer.FromElement(_createLayoutAnnounce);
AutomationProperties.SetName(_createLayoutAnnounce, name + " " + FancyZonesEditor.Properties.Resources.Layout_Creation_Announce);
AutomationProperties.SetName(_createLayoutAnnounce, name + " " + message);
peer?.RaiseAutomationEvent(AutomationEvents.MenuOpened);
}
}
private void Apply()
{
Logger.LogTrace();
var mainEditor = App.Overlay;
if (mainEditor.CurrentDataContext is LayoutModel model)
{
@ -272,6 +277,7 @@ namespace FancyZonesEditor
private void OnClosing(object sender, EventArgs e)
{
Logger.LogTrace();
CancelLayoutChanges();
App.FancyZonesEditorIO.SerializeZoneSettings();
@ -281,12 +287,15 @@ namespace FancyZonesEditor
private void DeleteLayout_Click(object sender, RoutedEventArgs e)
{
Logger.LogTrace();
EditLayoutDialog.Hide();
DeleteLayout((FrameworkElement)sender);
}
private async void EditLayout_Click(object sender, RoutedEventArgs e)
{
Logger.LogTrace();
// Avoid trying to open the same dialog twice.
if (_openedDialog != null)
{
@ -310,6 +319,7 @@ namespace FancyZonesEditor
private void EditZones_Click(object sender, RoutedEventArgs e)
{
Logger.LogTrace();
var dataContext = ((FrameworkElement)sender).DataContext;
Select((LayoutModel)dataContext);
EditLayoutDialog.Hide();
@ -342,6 +352,8 @@ namespace FancyZonesEditor
private void NewLayoutDialog_PrimaryButtonClick(ModernWpf.Controls.ContentDialog sender, ModernWpf.Controls.ContentDialogButtonClickEventArgs args)
{
Logger.LogTrace();
LayoutModel selectedLayoutModel;
if (GridLayoutRadioButton.IsChecked == true)
@ -393,6 +405,8 @@ namespace FancyZonesEditor
// EditLayout: Save changes
private void EditLayoutDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
Logger.LogTrace();
var mainEditor = App.Overlay;
if (!(mainEditor.CurrentDataContext is LayoutModel model))
{
@ -415,6 +429,8 @@ namespace FancyZonesEditor
private async void DeleteLayout(FrameworkElement element)
{
Logger.LogTrace();
var dialog = new ContentDialog()
{
Title = Properties.Resources.Are_You_Sure,
@ -454,6 +470,7 @@ namespace FancyZonesEditor
private void Dialog_Opened(ContentDialog sender, ContentDialogOpenedEventArgs args)
{
Announce(sender.Name, FancyZonesEditor.Properties.Resources.Edit_Layout_Open_Announce);
_openedDialog = sender;
}
@ -498,7 +515,10 @@ namespace FancyZonesEditor
private void TextBox_GotKeyboardFocus(object sender, RoutedEventArgs e)
{
TextBox tb = sender as TextBox;
tb.SelectionStart = tb.Text.Length;
if (tb != null)
{
tb.SelectionStart = tb.Text.Length;
}
}
private void CancelLayoutChanges()

View file

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using FancyZonesEditor.Logs;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
@ -134,6 +135,8 @@ namespace FancyZonesEditor
public void Show()
{
Logger.LogTrace();
var mainWindowSettings = ((App)Application.Current).MainWindowSettings;
if (_layoutPreview != null)
{
@ -154,6 +157,8 @@ namespace FancyZonesEditor
public void ShowLayout()
{
Logger.LogTrace();
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
CurrentDataContext = settings.UpdateSelectedLayoutModel();
@ -201,6 +206,8 @@ namespace FancyZonesEditor
public void OpenEditor(LayoutModel model)
{
Logger.LogTrace();
_layoutPreview = null;
if (CurrentDataContext is GridLayoutModel)
{
@ -229,6 +236,8 @@ namespace FancyZonesEditor
public void CloseEditor()
{
Logger.LogTrace();
var mainWindowSettings = ((App)Application.Current).MainWindowSettings;
_editorLayout = null;

View file

@ -150,21 +150,12 @@ namespace FancyZonesEditor.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Error logged to .
/// </summary>
public static string Crash_Report_Message_Box_Text_Part1 {
get {
return ResourceManager.GetString("Crash_Report_Message_Box_Text_Part1", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Please report the bug to .
/// </summary>
public static string Crash_Report_Message_Box_Text_Part2 {
public static string Crash_Report_Message_Box_Text {
get {
return ResourceManager.GetString("Crash_Report_Message_Box_Text_Part2", resourceCulture);
return ResourceManager.GetString("Crash_Report_Message_Box_Text", resourceCulture);
}
}
@ -284,6 +275,15 @@ namespace FancyZonesEditor.Properties {
return ResourceManager.GetString("Edit_Layout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to opened.
/// </summary>
public static string Edit_Layout_Open_Announce {
get {
return ResourceManager.GetString("Edit_Layout_Open_Announce", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Edit zones.

View file

@ -135,10 +135,7 @@
<data name="Grid_Layout_Editor" xml:space="preserve">
<value>Grid layout editor</value>
</data>
<data name="Crash_Report_Message_Box_Text_Part1" xml:space="preserve">
<value>Error logged to </value>
</data>
<data name="Crash_Report_Message_Box_Text_Part2" xml:space="preserve">
<data name="Crash_Report_Message_Box_Text" xml:space="preserve">
<value>Please report the bug to </value>
</data>
<data name="Custom" xml:space="preserve">
@ -374,6 +371,9 @@
<data name="Edit_Layout" xml:space="preserve">
<value>Edit layout</value>
</data>
<data name="Edit_Layout_Open_Announce" xml:space="preserve">
<value>opened</value>
</data>
<data name="Layout_Creation_Announce" xml:space="preserve">
<value>custom layout was created successfully.</value>
</data>

View file

@ -11,6 +11,7 @@ using System.IO.Abstractions;
using System.Text;
using System.Text.Json;
using System.Windows;
using FancyZonesEditor.Logs;
using FancyZonesEditor.Models;
namespace FancyZonesEditor.Utils
@ -247,6 +248,8 @@ namespace FancyZonesEditor.Utils
// All strings in this function shouldn't be localized.
public static void ParseCommandLineArguments()
{
Logger.LogTrace();
string[] args = Environment.GetCommandLineArgs();
if (args.Length < 2 && !App.DebugMode)
@ -399,8 +402,9 @@ namespace FancyZonesEditor.Utils
App.Overlay.Monitors.Add(monitor);
}
}
catch (Exception)
catch (Exception ex)
{
Logger.LogError("Invalid command line arguments: " + args[1], ex);
MessageBox.Show(Properties.Resources.Error_Invalid_Arguments, Properties.Resources.Error_Message_Box_Title);
((App)Application.Current).Shutdown();
}
@ -408,6 +412,8 @@ namespace FancyZonesEditor.Utils
public ParsingResult ParseParams()
{
Logger.LogTrace();
if (_fileSystem.File.Exists(FancyZonesEditorParamsFile))
{
string data = string.Empty;
@ -471,6 +477,7 @@ namespace FancyZonesEditor.Utils
}
catch (Exception ex)
{
Logger.LogError("Editor params parsing error", ex);
return new ParsingResult(false, ex.Message, data);
}
@ -484,6 +491,8 @@ namespace FancyZonesEditor.Utils
public ParsingResult ParseZoneSettings()
{
Logger.LogTrace();
_unusedDevices.Clear();
if (_fileSystem.File.Exists(FancyZonesSettingsFile))
@ -498,6 +507,7 @@ namespace FancyZonesEditor.Utils
}
catch (Exception ex)
{
Logger.LogError("Zone settings parsing error", ex);
return new ParsingResult(false, ex.Message, settingsString);
}
@ -515,6 +525,7 @@ namespace FancyZonesEditor.Utils
}
catch (Exception ex)
{
Logger.LogError("Zone settings parsing error", ex);
return new ParsingResult(false, ex.Message, settingsString);
}
}
@ -524,6 +535,8 @@ namespace FancyZonesEditor.Utils
public void SerializeZoneSettings()
{
Logger.LogTrace();
ZoneSettingsWrapper zoneSettings = new ZoneSettingsWrapper { };
zoneSettings.Devices = new List<DeviceWrapper>();
zoneSettings.CustomZoneSets = new List<CustomLayoutWrapper>();
@ -680,8 +693,9 @@ namespace FancyZonesEditor.Utils
zoneSettings.QuickLayoutKeys.Add(wrapper);
}
catch (Exception)
catch (Exception ex)
{
Logger.LogError("Serialize quick layout keys error", ex);
}
}
}
@ -693,12 +707,15 @@ namespace FancyZonesEditor.Utils
}
catch (Exception ex)
{
Logger.LogError("Serialize zone settings error", ex);
App.ShowExceptionMessageBox(Properties.Resources.Error_Applying_Layout, ex);
}
}
private string ReadFile(string fileName)
{
Logger.LogTrace();
Stream inputStream = _fileSystem.File.Open(fileName, FileMode.Open);
using (StreamReader reader = new StreamReader(inputStream))
{
@ -710,6 +727,8 @@ namespace FancyZonesEditor.Utils
private bool SetDevices(List<DeviceWrapper> devices)
{
Logger.LogTrace();
if (devices == null)
{
return false;
@ -763,6 +782,8 @@ namespace FancyZonesEditor.Utils
private bool SetCustomLayouts(List<CustomLayoutWrapper> customLayouts)
{
Logger.LogTrace();
if (customLayouts == null)
{
return false;
@ -791,9 +812,10 @@ namespace FancyZonesEditor.Utils
layout = ParseGridInfo(zoneSet);
}
}
catch (Exception)
catch (Exception ex)
{
result = false;
Logger.LogError("Parse custom layout error", ex);
continue;
}
@ -813,6 +835,8 @@ namespace FancyZonesEditor.Utils
private bool SetTemplateLayouts(List<TemplateLayoutWrapper> templateLayouts)
{
Logger.LogTrace();
if (templateLayouts == null)
{
return false;
@ -840,6 +864,8 @@ namespace FancyZonesEditor.Utils
private bool SetQuickLayoutSwitchKeys(List<QuickLayoutKeysWrapper> quickSwitchKeys)
{
Logger.LogTrace();
if (quickSwitchKeys == null)
{
return false;
@ -971,50 +997,5 @@ namespace FancyZonesEditor.Utils
return string.Empty;
}
}
private static string ParsingCmdArgsErrorReport(string args, int count, string targetMonitorName, List<NativeMonitorData> monitorData, List<Monitor> monitors)
{
var sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("```");
sb.AppendLine(" ## Command-line arguments:");
sb.AppendLine();
sb.AppendLine(args);
sb.AppendLine();
sb.AppendLine("```");
sb.AppendLine(" ## Parsed command-line arguments:");
sb.AppendLine();
sb.Append("Span zones across monitors: ");
sb.AppendLine(App.Overlay.SpanZonesAcrossMonitors.ToString());
// using CultureInfo.InvariantCulture since this is for PowerToys team
sb.Append("Monitors count: ");
sb.AppendLine(count.ToString(CultureInfo.InvariantCulture));
sb.Append("Target monitor: ");
sb.AppendLine(targetMonitorName);
sb.AppendLine();
sb.AppendLine(" # Per monitor data:");
sb.AppendLine();
foreach (NativeMonitorData data in monitorData)
{
sb.AppendLine(data.ToString());
}
sb.AppendLine();
sb.AppendLine("```");
sb.AppendLine(" ## Monitors discovered:");
sb.AppendLine();
foreach (Monitor m in monitors)
{
sb.AppendLine(m.Device.ToString());
}
return sb.ToString();
}
}
}

View file

@ -2,11 +2,11 @@
#include "pch.h"
#include "ContextMenuHandler.h"
#include "HDropIterator.h"
#include "Settings.h"
#include <common/themes/icon_helpers.h>
#include <common/utils/process_path.h>
#include <common/utils/resources.h>
#include <common/utils/HDropIterator.h>
#include "trace.h"

View file

@ -1,49 +0,0 @@
#include "pch.h"
#include "HDropIterator.h"
HDropIterator::HDropIterator(IDataObject* pdtobj)
{
_current = 0;
FORMATETC formatetc = {
CF_HDROP,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
pdtobj->GetData(&formatetc, &m_medium);
_listCount = DragQueryFile((HDROP)m_medium.hGlobal, 0xFFFFFFFF, NULL, 0);
}
HDropIterator::~HDropIterator()
{
ReleaseStgMedium(&m_medium);
}
void HDropIterator::First()
{
_current = 0;
}
void HDropIterator::Next()
{
_current++;
}
bool HDropIterator::IsDone() const
{
return _current >= _listCount;
}
LPTSTR HDropIterator::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;
}

View file

@ -1,17 +0,0 @@
#pragma once
class HDropIterator
{
public:
HDropIterator(IDataObject *pDataObject);
~HDropIterator();
void First();
void Next();
bool IsDone() const;
LPTSTR CurrentItem() const;
private:
UINT _listCount;
STGMEDIUM m_medium;
UINT _current;
};

View file

@ -77,7 +77,6 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ContextMenuHandler.cpp" />
<ClCompile Include="HDropIterator.cpp" />
<ClCompile Include="dllmain.cpp">
<CompileAsManaged Condition="'$(CIBuild)'!='true'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">
@ -97,7 +96,6 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="ContextMenuHandler.h" />
<ClInclude Include="HDropIterator.h" />
<ClInclude Include="dllmain.h" />
<None Include="resource.base.h" />
<ClInclude Include="ImageResizerConstants.h" />

View file

@ -28,9 +28,6 @@
<ClCompile Include="ContextMenuHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="HDropIterator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Settings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -57,9 +54,6 @@
<ClInclude Include="ContextMenuHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="HDropIterator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Settings.h">
<Filter>Header Files</Filter>
</ClInclude>

View file

@ -0,0 +1,917 @@
// PowerRenameUIHost.cpp : Defines the entry point for the application.
//
#include "pch.h"
#include "PowerRenameUIHost.h"
#include <settings.h>
#include <trace.h>
#include <string>
#include <sstream>
#include <vector>
#include <common/utils/process_path.h>
#define MAX_LOADSTRING 100
const wchar_t c_WindowClass[] = L"PowerRename";
HINSTANCE g_hostHInst;
int AppWindow::Show(HINSTANCE hInstance, std::vector<std::wstring> files)
{
auto window = AppWindow(hInstance, files);
window.CreateAndShowWindow();
return window.MessageLoop(window.m_accelerators.get());
}
LRESULT AppWindow::MessageHandler(UINT message, WPARAM wParam, LPARAM lParam) noexcept
{
switch (message)
{
HANDLE_MSG(WindowHandle(), WM_CREATE, OnCreate);
HANDLE_MSG(WindowHandle(), WM_COMMAND, OnCommand);
HANDLE_MSG(WindowHandle(), WM_DESTROY, OnDestroy);
HANDLE_MSG(WindowHandle(), WM_SIZE, OnResize);
default:
return base_type::MessageHandler(message, wParam, lParam);
}
return base_type::MessageHandler(message, wParam, lParam);
}
AppWindow::AppWindow(HINSTANCE hInstance, std::vector<std::wstring> files) noexcept :
m_instance{ hInstance }, m_managerEvents{ this }
{
HRESULT hr = CPowerRenameManager::s_CreateInstance(&m_prManager);
// Create the factory for our items
CComPtr<IPowerRenameItemFactory> prItemFactory;
hr = CPowerRenameItem::s_CreateInstance(nullptr, IID_PPV_ARGS(&prItemFactory));
hr = m_prManager->PutRenameItemFactory(prItemFactory);
hr = m_prManager->Advise(&m_managerEvents, &m_cookie);
if (SUCCEEDED(hr))
{
CComPtr<IShellItemArray> shellItemArray;
// To test PowerRenameUIHost uncomment this line and update the path to
// your local (absolute or relative) path which you want to see in PowerRename
//files.push_back(L"<path>");
if (!files.empty())
{
hr = CreateShellItemArrayFromPaths(files, &shellItemArray);
if (SUCCEEDED(hr))
{
CComPtr<IEnumShellItems> enumShellItems;
hr = shellItemArray->EnumItems(&enumShellItems);
if (SUCCEEDED(hr))
{
EnumerateShellItems(enumShellItems);
}
}
}
}
}
void AppWindow::CreateAndShowWindow()
{
m_accelerators.reset(LoadAcceleratorsW(m_instance, MAKEINTRESOURCE(IDC_POWERRENAMEUIHOST)));
WNDCLASSEXW wcex = { sizeof(wcex) };
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = m_instance;
wcex.hIcon = LoadIconW(m_instance, MAKEINTRESOURCE(IDC_POWERRENAMEUIHOST));
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
wcex.lpszClassName = c_WindowClass;
wcex.hIconSm = LoadIconW(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassExW(&wcex); // don't test result, handle error at CreateWindow
wchar_t title[64];
LoadStringW(m_instance, IDS_APP_TITLE, title, ARRAYSIZE(title));
m_window = CreateWindowW(c_WindowClass, title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, m_instance, this);
THROW_LAST_ERROR_IF(!m_window);
ShowWindow(m_window, SW_SHOWNORMAL);
UpdateWindow(m_window);
SetFocus(m_window);
}
bool AppWindow::OnCreate(HWND, LPCREATESTRUCT) noexcept
{
m_mainUserControl = winrt::PowerRenameUILib::MainWindow();
m_xamlIsland = CreateDesktopWindowsXamlSource(WS_TABSTOP, m_mainUserControl);
PopulateExplorerItems();
SetHandlers();
ReadSettings();
m_mainUserControl.UIUpdatesItem().ButtonRenameEnabled(false);
InitAutoComplete();
SearchReplaceChanged();
return true;
}
void AppWindow::OnCommand(HWND, int id, HWND hwndControl, UINT codeNotify) noexcept
{
switch (id)
{
case IDM_ABOUT:
DialogBoxW(m_instance, MAKEINTRESOURCE(IDD_ABOUTBOX), WindowHandle(), [](HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -> INT_PTR {
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL))
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
});
break;
case IDM_EXIT:
PostQuitMessage(0);
break;
}
}
void AppWindow::OnDestroy(HWND hwnd) noexcept
{
base_type::OnDestroy(hwnd);
}
void AppWindow::OnResize(HWND, UINT state, int cx, int cy) noexcept
{
SetWindowPos(m_xamlIsland, NULL, 0, 0, cx, cy, SWP_SHOWWINDOW);
}
HRESULT AppWindow::CreateShellItemArrayFromPaths(
std::vector<std::wstring> files,
IShellItemArray** shellItemArray)
{
*shellItemArray = nullptr;
PIDLIST_ABSOLUTE* itemList = nullptr;
itemList = new (std::nothrow) PIDLIST_ABSOLUTE[files.size()];
HRESULT hr = itemList ? S_OK : E_OUTOFMEMORY;
UINT itemsCnt = 0;
for (const auto& file : files)
{
const DWORD BUFSIZE = 4096;
TCHAR buffer[BUFSIZE] = TEXT("");
auto retval = GetFullPathName(file.c_str(), BUFSIZE, buffer, NULL);
if (retval != 0 && PathFileExists(buffer))
{
hr = SHParseDisplayName(buffer, nullptr, &itemList[itemsCnt], 0, nullptr);
++itemsCnt;
}
}
if (SUCCEEDED(hr) && itemsCnt > 0)
{
hr = SHCreateShellItemArrayFromIDLists(itemsCnt, const_cast<LPCITEMIDLIST*>(itemList), shellItemArray);
for (UINT i = 0; i < itemsCnt; i++)
{
CoTaskMemFree(itemList[i]);
}
}
else
{
hr = E_FAIL;
}
delete[] itemList;
return hr;
}
void AppWindow::PopulateExplorerItems()
{
UINT count = 0;
m_prManager->GetVisibleItemCount(&count);
UINT currDepth = 0;
std::stack<UINT> parents{};
UINT prevId = 0;
parents.push(0);
for (UINT i = 0; i < count; ++i)
{
CComPtr<IPowerRenameItem> renameItem;
if (SUCCEEDED(m_prManager->GetVisibleItemByIndex(i, &renameItem)))
{
int id = 0;
renameItem->GetId(&id);
PWSTR originalName = nullptr;
renameItem->GetOriginalName(&originalName);
PWSTR newName = nullptr;
renameItem->GetNewName(&newName);
bool selected;
renameItem->GetSelected(&selected);
UINT depth = 0;
renameItem->GetDepth(&depth);
bool isFolder = false;
bool isSubFolderContent = false;
winrt::check_hresult(renameItem->GetIsFolder(&isFolder));
if (depth > currDepth)
{
parents.push(prevId);
currDepth = depth;
}
else
{
while (currDepth > depth)
{
parents.pop();
currDepth--;
}
currDepth = depth;
}
m_mainUserControl.AddExplorerItem(
id, originalName, newName == nullptr ? hstring{} : hstring{ newName }, isFolder ? 0 : 1, parents.top(), selected);
prevId = id;
}
}
}
HRESULT AppWindow::InitAutoComplete()
{
HRESULT hr = S_OK;
if (CSettingsInstance().GetMRUEnabled())
{
hr = CPowerRenameMRU::CPowerRenameMRUSearch_CreateInstance(&m_searchMRU);
if (SUCCEEDED(hr))
{
for (const auto& item : m_searchMRU->GetMRUStrings())
{
if (!item.empty())
{
m_mainUserControl.AppendSearchMRU(item);
}
}
}
if (SUCCEEDED(hr))
{
hr = CPowerRenameMRU::CPowerRenameMRUReplace_CreateInstance(&m_replaceMRU);
if (SUCCEEDED(hr))
{
for (const auto& item : m_replaceMRU->GetMRUStrings())
{
if (!item.empty())
{
m_mainUserControl.AppendReplaceMRU(item);
}
}
}
}
}
return hr;
}
HRESULT AppWindow::EnumerateShellItems(_In_ IEnumShellItems* enumShellItems)
{
HRESULT hr = S_OK;
// Enumerate the data object and populate the manager
if (m_prManager)
{
m_disableCountUpdate = true;
// Ensure we re-create the enumerator
m_prEnum = nullptr;
hr = CPowerRenameEnum::s_CreateInstance(nullptr, m_prManager, IID_PPV_ARGS(&m_prEnum));
if (SUCCEEDED(hr))
{
hr = m_prEnum->Start(enumShellItems);
}
m_disableCountUpdate = false;
}
return hr;
}
void AppWindow::SearchReplaceChanged(bool forceRenaming)
{
// Pass updated search and replace terms to the IPowerRenameRegEx handler
CComPtr<IPowerRenameRegEx> prRegEx;
if (m_prManager && SUCCEEDED(m_prManager->GetRenameRegEx(&prRegEx)))
{
winrt::hstring searchTerm = m_mainUserControl.AutoSuggestBoxSearch().Text();
prRegEx->PutSearchTerm(searchTerm.c_str(), forceRenaming);
winrt::hstring replaceTerm = m_mainUserControl.AutoSuggestBoxReplace().Text();
prRegEx->PutReplaceTerm(replaceTerm.c_str(), forceRenaming);
}
}
void AppWindow::ValidateFlags(PowerRenameFlags flag)
{
if (flag == Uppercase)
{
if (m_mainUserControl.ToggleButtonUpperCase().IsChecked())
{
m_mainUserControl.ToggleButtonLowerCase().IsChecked(false);
m_mainUserControl.ToggleButtonTitleCase().IsChecked(false);
m_mainUserControl.ToggleButtonCapitalize().IsChecked(false);
}
}
else if (flag == Lowercase)
{
if (m_mainUserControl.ToggleButtonLowerCase().IsChecked())
{
m_mainUserControl.ToggleButtonUpperCase().IsChecked(false);
m_mainUserControl.ToggleButtonTitleCase().IsChecked(false);
m_mainUserControl.ToggleButtonCapitalize().IsChecked(false);
}
}
else if (flag == Titlecase)
{
if (m_mainUserControl.ToggleButtonTitleCase().IsChecked())
{
m_mainUserControl.ToggleButtonUpperCase().IsChecked(false);
m_mainUserControl.ToggleButtonLowerCase().IsChecked(false);
m_mainUserControl.ToggleButtonCapitalize().IsChecked(false);
}
}
else if (flag == Capitalized)
{
if (m_mainUserControl.ToggleButtonCapitalize().IsChecked())
{
m_mainUserControl.ToggleButtonUpperCase().IsChecked(false);
m_mainUserControl.ToggleButtonLowerCase().IsChecked(false);
m_mainUserControl.ToggleButtonTitleCase().IsChecked(false);
}
}
m_flagValidationInProgress = true;
}
void AppWindow::UpdateFlag(PowerRenameFlags flag, UpdateFlagCommand command)
{
DWORD flags{};
m_prManager->GetFlags(&flags);
if (command == UpdateFlagCommand::Set)
{
flags |= flag;
}
else if (command == UpdateFlagCommand::Reset)
{
flags &= ~flag;
}
// Ensure we update flags
if (m_prManager)
{
m_prManager->PutFlags(flags);
}
}
void AppWindow::SetHandlers()
{
m_mainUserControl.UIUpdatesItem().PropertyChanged([&](winrt::Windows::Foundation::IInspectable const& sender, Data::PropertyChangedEventArgs const& e) {
std::wstring property{ e.PropertyName() };
if (property == L"ShowAll")
{
SwitchView();
}
else if (property == L"ChangedItemId")
{
ToggleItem(m_mainUserControl.UIUpdatesItem().ChangedExplorerItemId(), m_mainUserControl.UIUpdatesItem().Checked());
}
else if (property == L"ToggleAll")
{
ToggleAll();
}
else if (property == L"Rename")
{
Rename(m_mainUserControl.UIUpdatesItem().CloseUIWindow());
}
});
// AutoSuggestBox Search
m_mainUserControl.AutoSuggestBoxSearch().TextChanged([&](winrt::Windows::Foundation::IInspectable const& sender, AutoSuggestBoxTextChangedEventArgs const&) {
SearchReplaceChanged();
});
// AutoSuggestBox Replace
m_mainUserControl.AutoSuggestBoxReplace().TextChanged([&](winrt::Windows::Foundation::IInspectable const& sender, AutoSuggestBoxTextChangedEventArgs const&) {
SearchReplaceChanged();
});
// ToggleButton UpperCase
m_mainUserControl.ToggleButtonUpperCase().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(Uppercase);
UpdateFlag(Uppercase, UpdateFlagCommand::Set);
});
m_mainUserControl.ToggleButtonUpperCase().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(Uppercase, UpdateFlagCommand::Reset);
});
// ToggleButton LowerCase
m_mainUserControl.ToggleButtonLowerCase().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(Lowercase);
UpdateFlag(Lowercase, UpdateFlagCommand::Set);
});
m_mainUserControl.ToggleButtonLowerCase().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(Lowercase, UpdateFlagCommand::Reset);
});
// ToggleButton TitleCase
m_mainUserControl.ToggleButtonTitleCase().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(Titlecase);
UpdateFlag(Titlecase, UpdateFlagCommand::Set);
});
m_mainUserControl.ToggleButtonTitleCase().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(Titlecase, UpdateFlagCommand::Reset);
});
// ToggleButton Capitalize
m_mainUserControl.ToggleButtonCapitalize().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(Capitalized);
UpdateFlag(Capitalized, UpdateFlagCommand::Set);
});
m_mainUserControl.ToggleButtonCapitalize().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(Capitalized, UpdateFlagCommand::Reset);
});
// CheckBox Regex
m_mainUserControl.CheckBoxRegex().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(UseRegularExpressions);
UpdateFlag(UseRegularExpressions, UpdateFlagCommand::Set);
});
m_mainUserControl.CheckBoxRegex().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(UseRegularExpressions, UpdateFlagCommand::Reset);
});
// CheckBox CaseSensitive
m_mainUserControl.CheckBoxCaseSensitive().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(CaseSensitive);
UpdateFlag(CaseSensitive, UpdateFlagCommand::Set);
});
m_mainUserControl.CheckBoxCaseSensitive().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(CaseSensitive, UpdateFlagCommand::Reset);
});
// ComboBox RenameParts
m_mainUserControl.ComboBoxRenameParts().SelectionChanged([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
if (m_mainUserControl.ComboBoxRenameParts().SelectedIndex() == 0)
{ // Filename + extension
UpdateFlag(NameOnly, UpdateFlagCommand::Reset);
UpdateFlag(ExtensionOnly, UpdateFlagCommand::Reset);
}
else if (m_mainUserControl.ComboBoxRenameParts().SelectedIndex() == 1) // Filename Only
{
ValidateFlags(NameOnly);
UpdateFlag(ExtensionOnly, UpdateFlagCommand::Reset);
UpdateFlag(NameOnly, UpdateFlagCommand::Set);
}
else if (m_mainUserControl.ComboBoxRenameParts().SelectedIndex() == 2) // Extension Only
{
ValidateFlags(ExtensionOnly);
UpdateFlag(NameOnly, UpdateFlagCommand::Reset);
UpdateFlag(ExtensionOnly, UpdateFlagCommand::Set);
}
});
// CheckBox MatchAllOccurences
m_mainUserControl.CheckBoxMatchAll().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(MatchAllOccurences);
UpdateFlag(MatchAllOccurences, UpdateFlagCommand::Set);
});
m_mainUserControl.CheckBoxMatchAll().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(MatchAllOccurences, UpdateFlagCommand::Reset);
});
// ToggleButton IncludeFiles
m_mainUserControl.ToggleButtonIncludeFiles().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(ExcludeFiles);
UpdateFlag(ExcludeFiles, UpdateFlagCommand::Reset);
});
m_mainUserControl.ToggleButtonIncludeFiles().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(ExcludeFiles, UpdateFlagCommand::Set);
});
// ToggleButton IncludeFolders
m_mainUserControl.ToggleButtonIncludeFolders().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(ExcludeFolders);
UpdateFlag(ExcludeFolders, UpdateFlagCommand::Reset);
});
m_mainUserControl.ToggleButtonIncludeFolders().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(ExcludeFolders, UpdateFlagCommand::Set);
});
// ToggleButton IncludeSubfolders
m_mainUserControl.ToggleButtonIncludeSubfolders().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(ExcludeSubfolders);
UpdateFlag(ExcludeSubfolders, UpdateFlagCommand::Reset);
});
m_mainUserControl.ToggleButtonIncludeSubfolders().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(ExcludeSubfolders, UpdateFlagCommand::Set);
});
// CheckBox EnumerateItems
m_mainUserControl.ToggleButtonEnumerateItems().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
ValidateFlags(EnumerateItems);
UpdateFlag(EnumerateItems, UpdateFlagCommand::Set);
});
m_mainUserControl.ToggleButtonEnumerateItems().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
UpdateFlag(EnumerateItems, UpdateFlagCommand::Reset);
});
// ButtonSettings
m_mainUserControl.ButtonSettings().Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
OpenSettingsApp();
});
}
void AppWindow::ToggleItem(int32_t id, bool checked)
{
CComPtr<IPowerRenameItem> spItem;
m_prManager->GetItemById(id, &spItem);
spItem->PutSelected(checked);
UpdateCounts();
}
void AppWindow::ToggleAll()
{
UINT itemCount = 0;
m_prManager->GetItemCount(&itemCount);
bool selected = m_mainUserControl.CheckBoxSelectAll().IsChecked().GetBoolean();
for (UINT i = 0; i < itemCount; i++)
{
CComPtr<IPowerRenameItem> spItem;
if (SUCCEEDED(m_prManager->GetItemByIndex(i, &spItem)))
{
spItem->PutSelected(selected);
}
}
UpdateCounts();
}
void AppWindow::SwitchView()
{
m_prManager->SwitchFilter(0);
PopulateExplorerItems();
}
void AppWindow::Rename(bool closeWindow)
{
if (m_prManager)
{
m_prManager->Rename(m_window, closeWindow);
}
// Persist the current settings. We only do this when
// a rename is actually performed. Not when the user
// closes/cancels the dialog.
WriteSettings();
}
HRESULT AppWindow::ReadSettings()
{
// Check if we should read flags from settings
// or the defaults from the manager.
DWORD flags = 0;
if (CSettingsInstance().GetPersistState())
{
flags = CSettingsInstance().GetFlags();
m_mainUserControl.AutoSuggestBoxSearch().Text(CSettingsInstance().GetSearchText().c_str());
m_mainUserControl.AutoSuggestBoxReplace().Text(CSettingsInstance().GetReplaceText().c_str());
}
else
{
m_prManager->GetFlags(&flags);
}
m_prManager->PutFlags(flags);
SetCheckboxesFromFlags(flags);
return S_OK;
}
HRESULT AppWindow::WriteSettings()
{
// Check if we should store our settings
if (CSettingsInstance().GetPersistState())
{
DWORD flags = 0;
m_prManager->GetFlags(&flags);
CSettingsInstance().SetFlags(flags);
winrt::hstring searchTerm = m_mainUserControl.AutoSuggestBoxSearch().Text();
CSettingsInstance().SetSearchText(std::wstring{ searchTerm });
if (CSettingsInstance().GetMRUEnabled() && m_searchMRU)
{
CComPtr<IPowerRenameMRU> spSearchMRU;
if (SUCCEEDED(m_searchMRU->QueryInterface(IID_PPV_ARGS(&spSearchMRU))))
{
spSearchMRU->AddMRUString(searchTerm.c_str());
}
}
winrt::hstring replaceTerm = m_mainUserControl.AutoSuggestBoxReplace().Text();
CSettingsInstance().SetReplaceText(std::wstring{ replaceTerm });
if (CSettingsInstance().GetMRUEnabled() && m_replaceMRU)
{
CComPtr<IPowerRenameMRU> spReplaceMRU;
if (SUCCEEDED(m_replaceMRU->QueryInterface(IID_PPV_ARGS(&spReplaceMRU))))
{
spReplaceMRU->AddMRUString(replaceTerm.c_str());
}
}
Trace::SettingsChanged();
}
return S_OK;
}
HRESULT AppWindow::OpenSettingsApp()
{
std::wstring path = get_module_folderpath(g_hostHInst);
path += L"\\..\\..\\PowerToys.exe";
std::wstring openSettings = L"--open-settings=PowerRename";
CString commandLine;
commandLine.Format(_T("\"%s\""), path.c_str());
commandLine.AppendFormat(_T(" %s"), openSettings.c_str());
int nSize = commandLine.GetLength() + 1;
LPTSTR lpszCommandLine = new TCHAR[nSize];
_tcscpy_s(lpszCommandLine, nSize, commandLine);
STARTUPINFO startupInfo;
ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
startupInfo.cb = sizeof(STARTUPINFO);
startupInfo.wShowWindow = SW_SHOWNORMAL;
PROCESS_INFORMATION processInformation;
// Start the resizer
CreateProcess(
NULL,
lpszCommandLine,
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&startupInfo,
&processInformation);
delete[] lpszCommandLine;
if (!CloseHandle(processInformation.hProcess))
{
return HRESULT_FROM_WIN32(GetLastError());
}
if (!CloseHandle(processInformation.hThread))
{
return HRESULT_FROM_WIN32(GetLastError());
}
return S_OK;
}
void AppWindow::SetCheckboxesFromFlags(DWORD flags)
{
if (flags & CaseSensitive)
{
m_mainUserControl.CheckBoxCaseSensitive().IsChecked(true);
}
if (flags & MatchAllOccurences)
{
m_mainUserControl.CheckBoxMatchAll().IsChecked(true);
}
if (flags & UseRegularExpressions)
{
m_mainUserControl.CheckBoxRegex().IsChecked(true);
}
if (flags & EnumerateItems)
{
m_mainUserControl.ToggleButtonEnumerateItems().IsChecked(true);
}
if (flags & ExcludeFiles)
{
m_mainUserControl.ToggleButtonIncludeFiles().IsChecked(false);
}
if (flags & ExcludeFolders)
{
m_mainUserControl.ToggleButtonIncludeFolders().IsChecked(false);
}
if (flags & ExcludeSubfolders)
{
m_mainUserControl.ToggleButtonIncludeSubfolders().IsChecked(false);
}
if (flags & NameOnly)
{
m_mainUserControl.ComboBoxRenameParts().SelectedIndex(1);
}
else if (flags & ExtensionOnly)
{
m_mainUserControl.ComboBoxRenameParts().SelectedIndex(2);
}
if (flags & Uppercase)
{
m_mainUserControl.ToggleButtonUpperCase().IsChecked(true);
}
else if (flags & Lowercase)
{
m_mainUserControl.ToggleButtonLowerCase().IsChecked(true);
}
else if (flags & Titlecase)
{
m_mainUserControl.ToggleButtonTitleCase().IsChecked(true);
}
else if (flags & Capitalized)
{
m_mainUserControl.ToggleButtonCapitalize().IsChecked(true);
}
}
void AppWindow::UpdateCounts()
{
// This method is CPU intensive. We disable it during certain operations
// for performance reasons.
if (m_disableCountUpdate)
{
return;
}
UINT selectedCount = 0;
UINT renamingCount = 0;
if (m_prManager)
{
m_prManager->GetSelectedItemCount(&selectedCount);
m_prManager->GetRenameItemCount(&renamingCount);
}
if (m_selectedCount != selectedCount ||
m_renamingCount != renamingCount)
{
m_selectedCount = selectedCount;
m_renamingCount = renamingCount;
// Update counts UI elements if/when added
// Update Rename button state
m_mainUserControl.UIUpdatesItem().ButtonRenameEnabled(renamingCount > 0);
}
}
HRESULT AppWindow::OnItemAdded(_In_ IPowerRenameItem* renameItem)
{
return S_OK;
}
HRESULT AppWindow::OnUpdate(_In_ IPowerRenameItem* renameItem)
{
int id;
HRESULT hr = renameItem->GetId(&id);
if (SUCCEEDED(hr))
{
PWSTR newName = nullptr;
hr = renameItem->GetNewName(&newName);
if (SUCCEEDED(hr))
{
hstring newNameStr = newName == nullptr ? hstring{} : newName;
m_mainUserControl.UpdateExplorerItem(id, newNameStr);
}
}
UpdateCounts();
return S_OK;
}
HRESULT AppWindow::OnRename(_In_ IPowerRenameItem* renameItem)
{
int id;
HRESULT hr = renameItem->GetId(&id);
if (SUCCEEDED(hr))
{
PWSTR newName = nullptr;
hr = renameItem->GetOriginalName(&newName);
if (SUCCEEDED(hr))
{
hstring newNameStr = newName == nullptr ? hstring{} : newName;
m_mainUserControl.UpdateRenamedExplorerItem(id, newNameStr);
}
}
UpdateCounts();
return S_OK;
}
HRESULT AppWindow::OnError(_In_ IPowerRenameItem* renameItem)
{
return S_OK;
}
HRESULT AppWindow::OnRegExStarted(_In_ DWORD threadId)
{
return S_OK;
}
HRESULT AppWindow::OnRegExCanceled(_In_ DWORD threadId)
{
return S_OK;
}
HRESULT AppWindow::OnRegExCompleted(_In_ DWORD threadId)
{
if (m_flagValidationInProgress)
{
m_flagValidationInProgress = false;
}
else
{
DWORD filter = 0;
m_prManager->GetFilter(&filter);
if (filter == PowerRenameFilters::ShouldRename)
{
m_mainUserControl.ExplorerItems().Clear();
PopulateExplorerItems();
}
}
return S_OK;
}
HRESULT AppWindow::OnRenameStarted()
{
return S_OK;
}
HRESULT AppWindow::OnRenameCompleted(bool closeUIWindowAfterRenaming)
{
if (closeUIWindowAfterRenaming)
{
// Close the window
PostMessage(m_window, WM_CLOSE, (WPARAM)0, (LPARAM)0);
}
else
{
// Force renaming work to start so newly renamed items are processed right away
SearchReplaceChanged(true);
}
return S_OK;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
#define BUFSIZE 4096 * 4
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (hStdin == INVALID_HANDLE_VALUE)
ExitProcess(1);
BOOL bSuccess;
WCHAR chBuf[BUFSIZE];
DWORD dwRead;
std::vector<std::wstring> files;
for (;;)
{
// Read from standard input and stop on error or no data.
bSuccess = ReadFile(hStdin, chBuf, BUFSIZE * sizeof(wchar_t), &dwRead, NULL);
if (!bSuccess || dwRead == 0)
break;
std::wstring inputBatch{ chBuf, dwRead / sizeof(wchar_t) };
std::wstringstream ss(inputBatch);
std::wstring item;
wchar_t delimiter = '?';
while (std::getline(ss, item, delimiter))
{
files.push_back(item);
}
if (!bSuccess)
break;
}
g_hostHInst = hInstance;
winrt::init_apartment(winrt::apartment_type::single_threaded);
winrt::PowerRenameUILib::App app;
const auto result = AppWindow::Show(hInstance, files);
app.Close();
}

View file

@ -0,0 +1,153 @@
#pragma once
#include "pch.h"
#include "resource.h"
#include "XamlBridge.h"
#include <PowerRenameEnum.h>
#include <PowerRenameItem.h>
#include <PowerRenameManager.h>
#include <PowerRenameInterfaces.h>
#include <PowerRenameMRU.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.system.h>
#pragma push_macro("GetCurrentTime")
#undef GetCurrentTime
#include <winrt/windows.ui.xaml.hosting.h>
#pragma pop_macro("GetCurrentTime")
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
#include <winrt/windows.ui.xaml.controls.h>
#include <winrt/windows.ui.xaml.controls.primitives.h>
#include <winrt/Windows.ui.xaml.media.h>
#include <winrt/Windows.ui.xaml.data.h>
#include <winrt/Windows.UI.Core.h>
#include <winrt/PowerRenameUILib.h>
using namespace winrt;
using namespace Windows::UI;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Composition;
using namespace Windows::UI::Xaml::Hosting;
using namespace Windows::Foundation::Numerics;
using namespace Windows::UI::Xaml::Controls;
class AppWindow : public DesktopWindowT<AppWindow>
{
public:
// Proxy class to Advise() PRManager, as AppWindow can't implement IPowerRenameManagerEvents
class UIHostPowerRenameManagerEvents : public IPowerRenameManagerEvents
{
public:
UIHostPowerRenameManagerEvents(AppWindow* app) :
m_refCount{ 1 }, m_app{ app }
{
}
IFACEMETHODIMP_(ULONG)
AddRef()
{
return InterlockedIncrement(&m_refCount);
}
IFACEMETHODIMP_(ULONG)
Release()
{
long refCount = InterlockedDecrement(&m_refCount);
if (refCount == 0)
{
delete this;
}
return refCount;
}
IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _Outptr_ void** ppv)
{
static const QITAB qit[] = {
QITABENT(UIHostPowerRenameManagerEvents, IPowerRenameManagerEvents),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
HRESULT OnItemAdded(_In_ IPowerRenameItem* renameItem) override { return m_app->OnItemAdded(renameItem); }
HRESULT OnUpdate(_In_ IPowerRenameItem* renameItem) override { return m_app->OnUpdate(renameItem); }
HRESULT OnRename(_In_ IPowerRenameItem* renameItem) override { return m_app->OnRename(renameItem); }
HRESULT OnError(_In_ IPowerRenameItem* renameItem) override { return m_app->OnError(renameItem); }
HRESULT OnRegExStarted(_In_ DWORD threadId) override { return m_app->OnRegExStarted(threadId); }
HRESULT OnRegExCanceled(_In_ DWORD threadId) override { return m_app->OnRegExCanceled(threadId); }
HRESULT OnRegExCompleted(_In_ DWORD threadId) override { return m_app->OnRegExCompleted(threadId); }
HRESULT OnRenameStarted() override { return m_app->OnRenameStarted(); }
HRESULT OnRenameCompleted(bool closeUIWindowAfterRenaming) override { return m_app->OnRenameCompleted(closeUIWindowAfterRenaming); }
private:
long m_refCount;
AppWindow* m_app;
};
static int Show(HINSTANCE hInstance, std::vector<std::wstring> files);
LRESULT MessageHandler(UINT message, WPARAM wParam, LPARAM lParam) noexcept;
private:
enum class UpdateFlagCommand
{
Set = 0,
Reset
};
AppWindow(HINSTANCE hInstance, std::vector<std::wstring> files) noexcept;
void CreateAndShowWindow();
bool OnCreate(HWND, LPCREATESTRUCT) noexcept;
void OnCommand(HWND, int id, HWND hwndControl, UINT codeNotify) noexcept;
void OnDestroy(HWND hwnd) noexcept;
void OnResize(HWND, UINT state, int cx, int cy) noexcept;
HRESULT CreateShellItemArrayFromPaths(std::vector<std::wstring> files, IShellItemArray** shellItemArray);
void PopulateExplorerItems();
HRESULT InitAutoComplete();
HRESULT EnumerateShellItems(_In_ IEnumShellItems* enumShellItems);
void SearchReplaceChanged(bool forceRenaming = false);
void ValidateFlags(PowerRenameFlags flag);
void UpdateFlag(PowerRenameFlags flag, UpdateFlagCommand command);
void SetHandlers();
void ToggleItem(int32_t id, bool checked);
void ToggleAll();
void SwitchView();
void Rename(bool closeWindow);
HRESULT ReadSettings();
HRESULT WriteSettings();
HRESULT OpenSettingsApp();
void SetCheckboxesFromFlags(DWORD flags);
void UpdateCounts();
HRESULT OnItemAdded(_In_ IPowerRenameItem* renameItem);
HRESULT OnUpdate(_In_ IPowerRenameItem* renameItem);
HRESULT OnRename(_In_ IPowerRenameItem* renameItem);
HRESULT OnError(_In_ IPowerRenameItem* renameItem);
HRESULT OnRegExStarted(_In_ DWORD threadId);
HRESULT OnRegExCanceled(_In_ DWORD threadId);
HRESULT OnRegExCompleted(_In_ DWORD threadId);
HRESULT OnRenameStarted();
HRESULT OnRenameCompleted(bool closeUIWindowAfterRenaming);
wil::unique_haccel m_accelerators;
const HINSTANCE m_instance;
HWND m_xamlIsland{};
HWND m_window{};
winrt::PowerRenameUILib::MainWindow m_mainUserControl{ nullptr };
bool m_disableCountUpdate = false;
CComPtr<IPowerRenameManager> m_prManager;
CComPtr<IUnknown> m_dataSource;
CComPtr<IPowerRenameEnum> m_prEnum;
UIHostPowerRenameManagerEvents m_managerEvents;
DWORD m_cookie = 0;
CComPtr<IPowerRenameMRU> m_searchMRU;
CComPtr<IPowerRenameMRU> m_replaceMRU;
UINT m_selectedCount = 0;
UINT m_renamingCount = 0;
bool m_flagValidationInProgress = false;
};

View file

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 115 KiB

View file

@ -0,0 +1,150 @@
//Microsoft Visual C++ generated resource script.
⼀⼀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀爀攀猀漀甀爀挀攀⸀栀∀ഀ<EFBFBD>
<EFBFBD>
⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开刀䔀䄀䐀伀一䰀夀开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䜀攀渀攀爀愀琀攀搀 昀爀漀洀 琀栀攀 吀䔀堀吀䤀一䌀䰀唀䐀䔀 爀攀猀漀甀爀挀攀⸀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⌀椀昀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀琀愀爀最攀琀瘀攀爀⸀栀∀ഀ<EFBFBD>
⌀攀渀搀椀昀ഀ<EFBFBD>
⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
⌀椀渀挀氀甀搀攀 ∀眀椀渀搀漀眀猀⸀栀∀ഀ<EFBFBD>
⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开刀䔀䄀䐀伀一䰀夀开匀夀䴀䈀伀䰀匀ഀ<EFBFBD>
<EFBFBD>
⌀椀昀 ℀搀攀昀椀渀攀搀䄀䘀堀开刀䔀匀伀唀刀䌀䔀开䐀䰀䰀⤀ 簀簀 搀攀昀椀渀攀搀䄀䘀堀开吀䄀刀䜀开䔀一唀⤀ഀ<EFBFBD>
䰀䄀一䜀唀䄀䜀䔀 㤀Ⰰ ㄀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䤀挀漀渀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
⼀⼀ 䤀挀漀渀 眀椀琀栀 氀漀眀攀猀琀 䤀䐀 瘀愀氀甀攀 瀀氀愀挀攀搀 昀椀爀猀琀 琀漀 攀渀猀甀爀攀 愀瀀瀀氀椀挀愀琀椀漀渀 椀挀漀渀ഀ<EFBFBD>
⼀⼀ 爀攀洀愀椀渀猀 挀漀渀猀椀猀琀攀渀琀 漀渀 愀氀氀 猀礀猀琀攀洀猀⸀ഀ<EFBFBD>
<EFBFBD>
䤀䐀䤀开倀伀圀䔀刀刀䔀一䄀䴀䔀唀䤀䠀伀匀吀       䤀䌀伀一         ∀倀漀眀攀爀刀攀渀愀洀攀唀䤀䠀漀猀琀⸀椀挀漀∀ഀ<EFBFBD>
䤀䐀䤀开匀䴀䄀䰀䰀                   䤀䌀伀一         ∀猀洀愀氀氀⸀椀挀漀∀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䴀攀渀甀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
䤀䐀䌀开倀伀圀䔀刀刀䔀一䄀䴀䔀唀䤀䠀伀匀吀 䴀䔀一唀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    倀伀倀唀倀 ∀☀䘀椀氀攀∀ഀ<EFBFBD>
    䈀䔀䜀䤀一ഀ<EFBFBD>
        䴀䔀一唀䤀吀䔀䴀 ∀䔀☀砀椀琀∀Ⰰ                䤀䐀䴀开䔀堀䤀吀ഀ<EFBFBD>
    䔀一䐀ഀ<EFBFBD>
    倀伀倀唀倀 ∀☀䠀攀氀瀀∀ഀ<EFBFBD>
    䈀䔀䜀䤀一ഀ<EFBFBD>
        䴀䔀一唀䤀吀䔀䴀 ∀☀䄀戀漀甀琀 ⸀⸀⸀∀Ⰰ           䤀䐀䴀开䄀䈀伀唀吀ഀ<EFBFBD>
    䔀一䐀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䄀挀挀攀氀攀爀愀琀漀爀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
䤀䐀䌀开倀伀圀䔀刀刀䔀一䄀䴀䔀唀䤀䠀伀匀吀 䄀䌀䌀䔀䰀䔀刀䄀吀伀刀匀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀㼀∀Ⰰ            䤀䐀䴀开䄀䈀伀唀吀Ⰰ              䄀匀䌀䤀䤀Ⰰ  䄀䰀吀ഀ<EFBFBD>
    ∀⼀∀Ⰰ            䤀䐀䴀开䄀䈀伀唀吀Ⰰ              䄀匀䌀䤀䤀Ⰰ  䄀䰀吀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䐀椀愀氀漀最ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
䤀䐀䐀开䄀䈀伀唀吀䈀伀堀 䐀䤀䄀䰀伀䜀䔀堀     ㄀㜀  㘀㈀ഀ<EFBFBD>
匀吀夀䰀䔀 䐀匀开匀䔀吀䘀伀一吀  䐀匀开䴀伀䐀䄀䰀䘀刀䄀䴀䔀  䐀匀开䘀䤀堀䔀䐀匀夀匀  圀匀开倀伀倀唀倀  圀匀开䌀䄀倀吀䤀伀一  圀匀开匀夀匀䴀䔀一唀ഀ<EFBFBD>
䌀䄀倀吀䤀伀一 ∀䄀戀漀甀琀 倀漀眀攀爀刀攀渀愀洀攀唀䤀䠀漀猀琀∀ഀ<EFBFBD>
䘀伀一吀 㠀Ⰰ ∀䴀匀 匀栀攀氀氀 䐀氀最∀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    䤀䌀伀一            䤀䐀刀开䴀䄀䤀一䘀刀䄀䴀䔀Ⰰ䤀䐀䌀开匀吀䄀吀䤀䌀Ⰰ㄀㐀Ⰰ㄀㐀Ⰰ㈀㄀Ⰰ㈀ <EFBFBD>
    䰀吀䔀堀吀           ∀倀漀眀攀爀刀攀渀愀洀攀唀䤀䠀漀猀琀Ⰰ 嘀攀爀猀椀漀渀 ㄀⸀ ∀Ⰰ䤀䐀䌀开匀吀䄀吀䤀䌀Ⰰ㐀㈀Ⰰ㄀㐀Ⰰ㄀㄀㐀Ⰰ㠀Ⰰ匀匀开一伀倀刀䔀䘀䤀堀ഀ<EFBFBD>
    䰀吀䔀堀吀           ∀䌀漀瀀礀爀椀最栀琀 挀⤀  ㈀㄀∀Ⰰ䤀䐀䌀开匀吀䄀吀䤀䌀Ⰰ㐀㈀Ⰰ㈀㘀Ⰰ㄀㄀㐀Ⰰ㠀ഀ<EFBFBD>
    䐀䔀䘀倀唀匀䠀䈀唀吀吀伀一   ∀伀䬀∀Ⰰ䤀䐀伀䬀Ⰰ㄀㄀㌀Ⰰ㐀㄀Ⰰ㔀 Ⰰ㄀㐀Ⰰ圀匀开䜀刀伀唀倀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䐀䔀匀䤀䜀一䤀一䘀伀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
⌀椀昀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
䜀唀䤀䐀䔀䰀䤀一䔀匀 䐀䔀匀䤀䜀一䤀一䘀伀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    䤀䐀䐀开䄀䈀伀唀吀䈀伀堀Ⰰ 䐀䤀䄀䰀伀䜀ഀ<EFBFBD>
    䈀䔀䜀䤀一ഀ<EFBFBD>
        䰀䔀䘀吀䴀䄀刀䜀䤀一Ⰰ 㜀ഀ<EFBFBD>
        刀䤀䜀䠀吀䴀䄀刀䜀䤀一Ⰰ ㄀㘀㌀ഀ<EFBFBD>
        吀伀倀䴀䄀刀䜀䤀一Ⰰ 㜀ഀ<EFBFBD>
        䈀伀吀吀伀䴀䴀䄀刀䜀䤀一Ⰰ 㔀㔀ഀ<EFBFBD>
    䔀一䐀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
<EFBFBD>
⌀椀昀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 吀䔀堀吀䤀一䌀䰀唀䐀䔀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀爀攀猀漀甀爀挀攀⸀栀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀⌀椀昀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀椀渀挀氀甀搀攀 ∀∀琀愀爀最攀琀瘀攀爀⸀栀∀∀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀攀渀搀椀昀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀搀攀昀椀渀攀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀椀渀挀氀甀搀攀 ∀∀眀椀渀搀漀眀猀⸀栀∀∀尀爀尀渀∀ഀ<EFBFBD>
    ∀⌀甀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䠀䤀䐀䐀䔀一开匀夀䴀䈀伀䰀匀尀爀尀渀∀ഀ<EFBFBD>
    ∀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
 吀䔀堀吀䤀一䌀䰀唀䐀䔀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
    ∀尀爀尀渀∀ഀ<EFBFBD>
    ∀尀 ∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 匀琀爀椀渀最 吀愀戀氀攀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
匀吀刀䤀一䜀吀䄀䈀䰀䔀ഀ<EFBFBD>
䈀䔀䜀䤀一ഀ<EFBFBD>
   䤀䐀䌀开倀伀圀䔀刀刀䔀一䄀䴀䔀唀䤀䠀伀匀吀   ∀倀伀圀䔀刀刀䔀一䄀䴀䔀唀䤀䠀伀匀吀∀ഀ<EFBFBD>
   䤀䐀匀开䄀倀倀开吀䤀吀䰀䔀       ∀倀漀眀攀爀刀攀渀愀洀攀∀ഀ<EFBFBD>
䔀一䐀ഀ<EFBFBD>
<EFBFBD>
⌀攀渀搀椀昀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
<EFBFBD>
<EFBFBD>
<EFBFBD>
⌀椀昀渀搀攀昀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
⼀⼀ 䜀攀渀攀爀愀琀攀搀 昀爀漀洀 琀栀攀 吀䔀堀吀䤀一䌀䰀唀䐀䔀 爀攀猀漀甀爀挀攀⸀ഀ<EFBFBD>
⼀⼀ഀ<EFBFBD>
<EFBFBD>
⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀⼀ഀ<EFBFBD>
⌀攀渀搀椀昀    ⼀⼀ 渀漀琀 䄀倀匀吀唀䐀䤀伀开䤀一嘀伀䬀䔀䐀ഀ<EFBFBD>
<EFBFBD>

View file

@ -0,0 +1,165 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.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>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{f7ec4e6c-19ca-4fbd-9918-b8ac5fef4f63}</ProjectGuid>
<RootNamespace>PowerRenameUIHost</RootNamespace>
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
<TargetPlatformMinVersion>$(WindowsTargetPlatformVersion)</TargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WindowsAppContainer>false</WindowsAppContainer>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<WindowsAppContainer>false</WindowsAppContainer>
</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" />
<Import Project="..\..\..\..\Solution.props" />
</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" />
<Import Project="..\..\..\..\Solution.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\PowerRename\</OutDir>
<TargetName>PowerRename</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\PowerRename\</OutDir>
<TargetName>PowerRename</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\;$(ProjectDir)..\..\..\common\Telemetry;$(ProjectDir)..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<TreatWarningAsError>true</TreatWarningAsError>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\;$(ProjectDir)..\..\..\common\Telemetry;$(ProjectDir)..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="framework.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="PowerRenameUIHost.h" />
<ClInclude Include="Resource.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="XamlBridge.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="PowerRenameUIHost.cpp" />
<ClCompile Include="XamlBridge.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PowerRenameUIHost.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="PowerRenameUIHost.ico" />
<Image Include="small.ico" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Manifest Include="app.manifest" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.210803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.210803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<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')" />
<Import Project="..\..\..\..\packages\boost.1.72.0.0\build\boost.targets" Condition="Exists('..\..\..\..\packages\boost.1.72.0.0\build\boost.targets')" />
<Import Project="..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets" Condition="Exists('..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.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.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.210803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.210803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<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'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost.1.72.0.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost.1.72.0.0\build\boost.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets'))" />
</Target>
<PropertyGroup>
<AppProjectName>PowerRenameUILib</AppProjectName>
</PropertyGroup>
<PropertyGroup>
<AppIncludeDirectories>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\;$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\Generated Files\;</AppIncludeDirectories>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\$(AppProjectName)\$(AppProjectName).vcxproj" />
<ProjectReference Include="..\lib\PowerRenameLib.vcxproj">
<Project>{51920f1f-c28c-4adf-8660-4238766796c2}</Project>
</ProjectReference>
</ItemGroup>
</Project>

View file

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PowerRenameUIHost.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="XamlBridge.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="PowerRenameUIHost.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="XamlBridge.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PowerRenameUIHost.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="PowerRenameUIHost.ico">
<Filter>Resource Files</Filter>
</Image>
<Image Include="small.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Manifest Include="app.manifest" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,30 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by PowerRenameUIHost.rc
#define IDS_APP_TITLE 103
#define IDR_MAINFRAME 128
#define IDD_POWERRENAMEUIHOST_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDI_POWERRENAMEUIHOST 107
#define IDI_SMALL 108
#define IDC_POWERRENAMEUIHOST 109
#define IDC_MYICON 2
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 130
#define _APS_NEXT_RESOURCE_VALUE 129
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif

View file

@ -0,0 +1,249 @@
#include "pch.h"
#include "XamlBridge.h"
#include "Resource.h"
#include <exception>
bool DesktopWindow::FilterMessage(const MSG* msg)
{
// When multiple child windows are present it is needed to pre dispatch messages to all
// DesktopWindowXamlSource instances so keyboard accelerators and
// keyboard focus work correctly.
for (auto& xamlSource : m_xamlSources)
{
BOOL xamlSourceProcessedMessage = FALSE;
winrt::check_hresult(xamlSource.as<IDesktopWindowXamlSourceNative2>()->PreTranslateMessage(msg, &xamlSourceProcessedMessage));
if (xamlSourceProcessedMessage != FALSE)
{
return true;
}
}
return false;
}
const auto static invalidReason = static_cast<winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason>(-1);
winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason GetReasonFromKey(WPARAM key)
{
auto reason = invalidReason;
if (key == VK_TAB)
{
byte keyboardState[256] = {};
WINRT_VERIFY(::GetKeyboardState(keyboardState));
reason = (keyboardState[VK_SHIFT] & 0x80) ?
winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Last :
winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::First;
}
else if (key == VK_LEFT)
{
reason = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Left;
}
else if (key == VK_RIGHT)
{
reason = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Right;
}
else if (key == VK_UP)
{
reason = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Up;
}
else if (key == VK_DOWN)
{
reason = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Down;
}
return reason;
}
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource DesktopWindow::GetNextFocusedIsland(const MSG* msg)
{
if (msg->message == WM_KEYDOWN)
{
const auto key = msg->wParam;
auto reason = GetReasonFromKey(key);
if (reason != invalidReason)
{
const BOOL previous =
(reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::First ||
reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Down ||
reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Right) ?
false :
true;
const auto currentFocusedWindow = ::GetFocus();
const auto nextElement = ::GetNextDlgTabItem(m_window.get(), currentFocusedWindow, previous);
for (auto& xamlSource : m_xamlSources)
{
HWND islandWnd{};
winrt::check_hresult(xamlSource.as<IDesktopWindowXamlSourceNative>()->get_WindowHandle(&islandWnd));
if (nextElement == islandWnd)
{
return xamlSource;
}
}
}
}
return nullptr;
}
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource DesktopWindow::GetFocusedIsland()
{
for (auto& xamlSource : m_xamlSources)
{
if (xamlSource.HasFocus())
{
return xamlSource;
}
}
return nullptr;
}
bool DesktopWindow::NavigateFocus(MSG* msg)
{
if (const auto nextFocusedIsland = GetNextFocusedIsland(msg))
{
const auto previousFocusedWindow = ::GetFocus();
RECT rect = {};
WINRT_VERIFY(::GetWindowRect(previousFocusedWindow, &rect));
const auto nativeIsland = nextFocusedIsland.as<IDesktopWindowXamlSourceNative>();
HWND islandWnd = nullptr;
winrt::check_hresult(nativeIsland->get_WindowHandle(&islandWnd));
POINT pt = { rect.left, rect.top };
SIZE size = { rect.right - rect.left, rect.bottom - rect.top };
::ScreenToClient(islandWnd, &pt);
const auto hintRect = winrt::Windows::Foundation::Rect({ static_cast<float>(pt.x), static_cast<float>(pt.y), static_cast<float>(size.cx), static_cast<float>(size.cy) });
const auto reason = GetReasonFromKey(msg->wParam);
const auto request = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationRequest(reason, hintRect);
m_lastFocusRequestId = request.CorrelationId();
const auto result = nextFocusedIsland.NavigateFocus(request);
return result.WasFocusMoved();
}
else
{
const bool islandIsFocused = GetFocusedIsland() != nullptr;
byte keyboardState[256] = {};
WINRT_VERIFY(::GetKeyboardState(keyboardState));
const bool isMenuModifier = keyboardState[VK_MENU] & 0x80;
if (islandIsFocused && !isMenuModifier)
{
return false;
}
const bool isDialogMessage = !!IsDialogMessage(m_window.get(), msg);
return isDialogMessage;
}
}
int DesktopWindow::MessageLoop(HACCEL accelerators)
{
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0))
{
const bool processedMessage = FilterMessage(&msg);
if (!processedMessage && !TranslateAcceleratorW(msg.hwnd, accelerators, &msg))
{
if (!NavigateFocus(&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
return static_cast<int>(msg.wParam);
}
static const WPARAM invalidKey = (WPARAM)-1;
WPARAM GetKeyFromReason(winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason reason)
{
auto key = invalidKey;
if (reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Last || reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::First)
{
key = VK_TAB;
}
else if (reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Left)
{
key = VK_LEFT;
}
else if (reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Right)
{
key = VK_RIGHT;
}
else if (reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Up)
{
key = VK_UP;
}
else if (reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Down)
{
key = VK_DOWN;
}
return key;
}
void DesktopWindow::OnTakeFocusRequested(winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource const& sender, winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSourceTakeFocusRequestedEventArgs const& args)
{
if (args.Request().CorrelationId() != m_lastFocusRequestId)
{
const auto reason = args.Request().Reason();
const BOOL previous =
(reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::First ||
reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Down ||
reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Right) ?
false :
true;
const auto nativeXamlSource = sender.as<IDesktopWindowXamlSourceNative>();
HWND senderHwnd = nullptr;
winrt::check_hresult(nativeXamlSource->get_WindowHandle(&senderHwnd));
MSG msg = {};
msg.hwnd = senderHwnd;
msg.message = WM_KEYDOWN;
msg.wParam = GetKeyFromReason(reason);
if (!NavigateFocus(&msg))
{
const auto nextElement = ::GetNextDlgTabItem(m_window.get(), senderHwnd, previous);
::SetFocus(nextElement);
}
}
else
{
const auto request = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationRequest(winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Restore);
m_lastFocusRequestId = request.CorrelationId();
sender.NavigateFocus(request);
}
}
HWND DesktopWindow::CreateDesktopWindowsXamlSource(DWORD extraWindowStyles, const winrt::Windows::UI::Xaml::UIElement& content)
{
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource desktopSource;
auto interop = desktopSource.as<IDesktopWindowXamlSourceNative>();
// Parent the DesktopWindowXamlSource object to current window
winrt::check_hresult(interop->AttachToWindow(m_window.get()));
HWND xamlSourceWindow{}; // Lifetime controlled desktopSource
winrt::check_hresult(interop->get_WindowHandle(&xamlSourceWindow));
const DWORD style = GetWindowLongW(xamlSourceWindow, GWL_STYLE) | extraWindowStyles;
SetWindowLongW(xamlSourceWindow, GWL_STYLE, style);
desktopSource.Content(content);
m_takeFocusEventRevokers.push_back(desktopSource.TakeFocusRequested(winrt::auto_revoke, { this, &DesktopWindow::OnTakeFocusRequested }));
m_xamlSources.push_back(desktopSource);
return xamlSourceWindow;
}
void DesktopWindow::ClearXamlIslands()
{
for (auto& takeFocusRevoker : m_takeFocusEventRevokers)
{
takeFocusRevoker.revoke();
}
m_takeFocusEventRevokers.clear();
for (auto& xamlSource : m_xamlSources)
{
xamlSource.Close();
}
m_xamlSources.clear();
}

View file

@ -0,0 +1,108 @@
#pragma once
#include <unknwn.h> // To enable support for non-WinRT interfaces, unknwn.h must be included before any C++/WinRT headers.
#include <winrt/Windows.System.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#pragma push_macro("GetCurrentTime")
#undef GetCurrentTime
#include <winrt/Windows.UI.Xaml.Hosting.h>
#pragma pop_macro("GetCurrentTime")
#include <winrt/Windows.UI.Xaml.Markup.h>
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
#include <windowsx.h>
#include <wil/resource.h>
class DesktopWindow
{
protected:
int MessageLoop(HACCEL accelerators);
HWND CreateDesktopWindowsXamlSource(DWORD extraStyles, const winrt::Windows::UI::Xaml::UIElement& content);
void ClearXamlIslands();
HWND WindowHandle() const
{
return m_window.get();
}
static void OnNCCreate(HWND window, LPARAM lparam) noexcept
{
auto cs = reinterpret_cast<CREATESTRUCT*>(lparam);
auto that = static_cast<DesktopWindow*>(cs->lpCreateParams);
that->m_window.reset(window); // take ownership of the window
SetWindowLongPtrW(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(that));
}
private:
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource GetFocusedIsland();
bool FilterMessage(const MSG* msg);
void OnTakeFocusRequested(winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource const& sender, winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSourceTakeFocusRequestedEventArgs const& args);
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource GetNextFocusedIsland(const MSG* msg);
bool NavigateFocus(MSG* msg);
wil::unique_hwnd m_window;
winrt::guid m_lastFocusRequestId;
std::vector<winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource::TakeFocusRequested_revoker> m_takeFocusEventRevokers;
std::vector<winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource> m_xamlSources;
};
template<typename T>
struct DesktopWindowT : public DesktopWindow
{
protected:
using base_type = DesktopWindowT<T>;
static LRESULT __stdcall WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
{
if (message == WM_NCCREATE)
{
OnNCCreate(window, lparam);
}
else if (message == WM_NCDESTROY)
{
SetWindowLongPtrW(window, GWLP_USERDATA, 0);
}
else if (auto that = reinterpret_cast<T*>(GetWindowLongPtrW(window, GWLP_USERDATA)))
{
return that->MessageHandler(message, wparam, lparam);
}
return DefWindowProcW(window, message, wparam, lparam);
}
LRESULT MessageHandler(UINT message, WPARAM wParam, LPARAM lParam) noexcept
{
switch (message)
{
HANDLE_MSG(WindowHandle(), WM_DESTROY, OnDestroy);
HANDLE_MSG(WindowHandle(), WM_ACTIVATE, OnActivate);
HANDLE_MSG(WindowHandle(), WM_SETFOCUS, OnSetFocus);
}
return DefWindowProcW(WindowHandle(), message, wParam, lParam);
}
void OnDestroy(HWND)
{
ClearXamlIslands();
PostQuitMessage(0);
}
private:
void OnActivate(HWND, UINT state, HWND hwndActDeact, BOOL fMinimized)
{
if (state == WA_INACTIVE)
{
m_hwndLastFocus = GetFocus();
}
}
void OnSetFocus(HWND, HWND hwndOldFocus)
{
if (m_hwndLastFocus)
{
SetFocus(m_hwndLastFocus);
}
}
HWND m_hwndLastFocus = nullptr;
};

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmV3="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0">
<asmV3:file name="PowerRenameUILib.dll">
<activatableClass name="PowerRenameUILib.App" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass name="PowerRenameUILib.XamlMetadataProvider" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass name="PowerRenameUILib.MainWindow" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
</asmV3:file>
</assembly>

View file

@ -0,0 +1,15 @@
// header.h : include file for standard system include files,
// or project specific include files
//
#pragma once
#include "targetver.h"
// #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.72.0.0" targetFramework="native" />
<package id="boost_regex-vc142" version="1.72.0.0" targetFramework="native" />
<package id="Microsoft.Toolkit.Win32.UI.SDK" version="6.1.2" targetFramework="native" />
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
<package id="Microsoft.VCRTForwarders.140" version="1.0.7" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.210803.1" targetFramework="native" />
</packages>

View file

@ -0,0 +1,5 @@
#pragma once
#include "framework.h"
#include <atlstr.h>
#include <stack>

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View file

@ -0,0 +1,18 @@
#include "pch.h"
#include "App.h"
#include "App.g.cpp"
using namespace winrt;
using namespace Windows::UI::Xaml;
namespace winrt::PowerRenameUILib::implementation
{
App::App()
{
Initialize();
AddRef();
m_inner.as<::IUnknown>()->Release();
}
App::~App()
{
Close();
}
}

View file

@ -0,0 +1,18 @@
#pragma once
#include "App.g.h"
#include "App.base.h"
namespace winrt::PowerRenameUILib::implementation
{
class App : public AppT2<App>
{
public:
App();
~App();
};
}
namespace winrt::PowerRenameUILib::factory_implementation
{
class App : public AppT<App, implementation::App>
{
};
}

View file

@ -0,0 +1,7 @@
namespace PowerRenameUILib
{
[default_interface] runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
{
App();
}
}

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View file

@ -0,0 +1,105 @@
#include "pch.h"
#include "ExplorerItem.h"
#include "ExplorerItem.g.cpp"
namespace winrt::PowerRenameUILib::implementation
{
ExplorerItem::ExplorerItem(int32_t id, hstring const& original, hstring const& renamed, int32_t type, bool checked) :
m_id{ id }, m_idStr{ std::to_wstring(id) }, m_original{ original }, m_renamed{ renamed }, m_type{ type }, m_checked{ checked }
{
if (m_type == static_cast<UINT>(ExplorerItemType::Folder))
{
m_children = winrt::single_threaded_observable_vector<PowerRenameUILib::ExplorerItem>();
}
}
int32_t ExplorerItem::Id()
{
return m_id;
}
hstring ExplorerItem::IdStr()
{
return m_idStr;
}
hstring ExplorerItem::Original()
{
return m_original;
}
void ExplorerItem::Original(hstring const& value)
{
if (m_original != value)
{
m_original = value;
m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Original" });
}
}
hstring ExplorerItem::Renamed()
{
return m_renamed;
}
void ExplorerItem::Renamed(hstring const& value)
{
if (m_renamed != value)
{
m_renamed = value;
m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Renamed" });
}
}
int32_t ExplorerItem::Type()
{
return m_type;
}
void ExplorerItem::Type(int32_t value)
{
if (m_type != value)
{
m_type = value;
m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Type" });
}
}
bool ExplorerItem::Checked()
{
return m_checked;
}
void ExplorerItem::Checked(bool value)
{
if (m_checked != value)
{
m_checked = value;
m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Checked" });
}
}
winrt::Windows::Foundation::Collections::IObservableVector<winrt::PowerRenameUILib::ExplorerItem> ExplorerItem::Children()
{
return m_children;
}
void ExplorerItem::Children(Windows::Foundation::Collections::IObservableVector<PowerRenameUILib::ExplorerItem> const& value)
{
if (m_children != value)
{
m_children = value;
m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Children" });
}
}
winrt::event_token ExplorerItem::PropertyChanged(winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
return m_propertyChanged.add(handler);
}
void ExplorerItem::PropertyChanged(winrt::event_token const& token) noexcept
{
m_propertyChanged.remove(token);
}
}

View file

@ -0,0 +1,48 @@
#pragma once
#include "ExplorerItem.g.h"
namespace winrt::PowerRenameUILib::implementation
{
struct ExplorerItem : ExplorerItemT<ExplorerItem>
{
enum class ExplorerItemType
{
Folder = 0,
File = 1
};
ExplorerItem() = delete;
ExplorerItem(int32_t id, hstring const& original, hstring const& renamed, int32_t type, bool checked);
int32_t Id();
hstring IdStr();
hstring Original();
void Original(hstring const& value);
hstring Renamed();
void Renamed(hstring const& value);
int32_t Type();
void Type(int32_t value);
bool Checked();
void Checked(bool value);
Windows::Foundation::Collections::IObservableVector<PowerRenameUILib::ExplorerItem> Children();
void Children(Windows::Foundation::Collections::IObservableVector<PowerRenameUILib::ExplorerItem> const& value);
winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
void PropertyChanged(winrt::event_token const& token) noexcept;
private:
int32_t m_id;
hstring m_idStr;
winrt::hstring m_original;
winrt::hstring m_renamed;
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUILib::ExplorerItem> m_children;
int32_t m_type;
bool m_checked;
winrt::event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
};
}
namespace winrt::PowerRenameUILib::factory_implementation
{
struct ExplorerItem : ExplorerItemT<ExplorerItem, implementation::ExplorerItem>
{
};
}

View file

@ -0,0 +1,14 @@
namespace PowerRenameUILib
{
runtimeclass ExplorerItem : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
ExplorerItem(Int32 id, String original, String renamed, Int32 type, Boolean checked);
Int32 Id { get; };
String IdStr { get; };
String Original;
String Renamed;
Int32 Type;
Boolean Checked;
Windows.Foundation.Collections.IObservableVector<ExplorerItem> Children;
}
}

View file

@ -0,0 +1,37 @@
#include "pch.h"
#include "ExplorerItemTemplateSelector.h"
#include "ExplorerItemTemplateSelector.g.cpp"
namespace winrt::PowerRenameUILib::implementation
{
Windows::UI::Xaml::DataTemplate ExplorerItemTemplateSelector::SelectTemplateCore(IInspectable const& item)
{
ExplorerItem explorerItem = (ExplorerItem&)item;
return explorerItem.Type() == 0 ? m_folderTemplate : m_fileTemplate;
}
Windows::UI::Xaml::DataTemplate ExplorerItemTemplateSelector::SelectTemplateCore(IInspectable const&, Windows::UI::Xaml::DependencyObject const&)
{
return Windows::UI::Xaml::DataTemplate();
}
winrt::Windows::UI::Xaml::DataTemplate ExplorerItemTemplateSelector::FolderTemplate()
{
return m_folderTemplate;
}
void ExplorerItemTemplateSelector::FolderTemplate(winrt::Windows::UI::Xaml::DataTemplate const& value)
{
m_folderTemplate = value;
}
winrt::Windows::UI::Xaml::DataTemplate ExplorerItemTemplateSelector::FileTemplate()
{
return m_fileTemplate;
}
void ExplorerItemTemplateSelector::FileTemplate(winrt::Windows::UI::Xaml::DataTemplate const& value)
{
m_fileTemplate = value;
}
}

View file

@ -0,0 +1,28 @@
#pragma once
#include "ExplorerItemTemplateSelector.g.h"
namespace winrt::PowerRenameUILib::implementation
{
struct ExplorerItemTemplateSelector : ExplorerItemTemplateSelectorT<ExplorerItemTemplateSelector>
{
ExplorerItemTemplateSelector() = default;
Windows::UI::Xaml::DataTemplate SelectTemplateCore(IInspectable const&);
Windows::UI::Xaml::DataTemplate SelectTemplateCore(IInspectable const&, Windows::UI::Xaml::DependencyObject const&);
winrt::Windows::UI::Xaml::DataTemplate FolderTemplate();
void FolderTemplate(winrt::Windows::UI::Xaml::DataTemplate const& value);
winrt::Windows::UI::Xaml::DataTemplate FileTemplate();
void FileTemplate(winrt::Windows::UI::Xaml::DataTemplate const& value);
private:
Windows::UI::Xaml::DataTemplate m_folderTemplate{ nullptr };
Windows::UI::Xaml::DataTemplate m_fileTemplate{ nullptr };
};
}
namespace winrt::PowerRenameUILib::factory_implementation
{
struct ExplorerItemTemplateSelector : ExplorerItemTemplateSelectorT<ExplorerItemTemplateSelector, implementation::ExplorerItemTemplateSelector>
{
};
}

View file

@ -0,0 +1,11 @@
namespace PowerRenameUILib
{
[bindable]
[default_interface] runtimeclass ExplorerItemTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
{
ExplorerItemTemplateSelector();
Windows.UI.Xaml.DataTemplate FolderTemplate;
Windows.UI.Xaml.DataTemplate FileTemplate;
}
}

View file

@ -4,11 +4,11 @@
"LanguageSet": "Azure_Languages",
"LocItems": [
{
"SourceFile": "src\\modules\\powerrename\\ui\\Resources.resx",
"SourceFile": "src\\modules\\powerrename\\PowerRenameUILib\\Strings\\en-us\\Resources.resw",
"CopyOption": "LangIDOnName",
"OutputPath": "src\\modules\\powerrename\\ui"
"OutputPath": "src\\modules\\powerrename\\PowerRenameUILib\\Strings"
}
]
}
]
}
}

View file

@ -0,0 +1,326 @@
#include "pch.h"
#include "MainWindow.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif
using namespace winrt;
using namespace Windows::UI::Xaml;
namespace winrt::PowerRenameUILib::implementation
{
MainWindow::MainWindow() :
m_allSelected{ true }
{
m_searchMRU = winrt::single_threaded_observable_vector<hstring>();
m_replaceMRU = winrt::single_threaded_observable_vector<hstring>();
m_explorerItems = winrt::single_threaded_observable_vector<PowerRenameUILib::ExplorerItem>();
m_searchRegExShortcuts = winrt::single_threaded_observable_vector<PowerRenameUILib::PatternSnippet>();
auto resourceLoader{ Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView() };
m_searchRegExShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"\\.", resourceLoader.GetString(L"RegExCheatSheet_MatchAny")));
m_searchRegExShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"\\d", resourceLoader.GetString(L"RegExCheatSheet_MatchDigit")));
m_searchRegExShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"\\D", resourceLoader.GetString(L"RegExCheatSheet_MatchNonDigit")));
m_searchRegExShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"\\w", resourceLoader.GetString(L"RegExCheatSheet_MatchNonWS")));
m_searchRegExShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"\\S", resourceLoader.GetString(L"RegExCheatSheet_MatchWordChar")));
m_searchRegExShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"\\S+", resourceLoader.GetString(L"RegExCheatSheet_MatchSeveralWS")));
m_searchRegExShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"\\b", resourceLoader.GetString(L"RegExCheatSheet_MatchWordBoundary")));
m_dateTimeShortcuts = winrt::single_threaded_observable_vector<PowerRenameUILib::PatternSnippet>();
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$YYYY", resourceLoader.GetString(L"DateTimeCheatSheet_FullYear")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$YY", resourceLoader.GetString(L"DateTimeCheatSheet_YearLastTwoDigits")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$Y", resourceLoader.GetString(L"DateTimeCheatSheet_YearLastDigit")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$MMMM", resourceLoader.GetString(L"DateTimeCheatSheet_MonthName")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$MMM", resourceLoader.GetString(L"DateTimeCheatSheet_MonthNameAbbr")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$MM", resourceLoader.GetString(L"DateTimeCheatSheet_MonthDigitLZero")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$M", resourceLoader.GetString(L"DateTimeCheatSheet_MonthDigit")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$DDDD", resourceLoader.GetString(L"DateTimeCheatSheet_DayName")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$DDD", resourceLoader.GetString(L"DateTimeCheatSheet_DayNameAbbr")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$DD", resourceLoader.GetString(L"DateTimeCheatSheet_DayDigitLZero")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$D", resourceLoader.GetString(L"DateTimeCheatSheet_DayDigit")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$hh", resourceLoader.GetString(L"DateTimeCheatSheet_HoursLZero")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$h", resourceLoader.GetString(L"DateTimeCheatSheet_Hours")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$mm", resourceLoader.GetString(L"DateTimeCheatSheet_MinutesLZero")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$m", resourceLoader.GetString(L"DateTimeCheatSheet_Minutes")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$ss", resourceLoader.GetString(L"DateTimeCheatSheet_SecondsLZero")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$s", resourceLoader.GetString(L"DateTimeCheatSheet_Seconds")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$fff", resourceLoader.GetString(L"DateTimeCheatSheet_MilliSeconds3D")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$ff", resourceLoader.GetString(L"DateTimeCheatSheet_MilliSeconds2D")));
m_dateTimeShortcuts.Append(winrt::make<PowerRenameUILib::implementation::PatternSnippet>(L"$f", resourceLoader.GetString(L"DateTimeCheatSheet_MilliSeconds1D")));
InitializeComponent();
}
Windows::Foundation::Collections::IObservableVector<hstring> MainWindow::SearchMRU()
{
return m_searchMRU;
}
Windows::Foundation::Collections::IObservableVector<hstring> MainWindow::ReplaceMRU()
{
return m_replaceMRU;
}
winrt::Windows::Foundation::Collections::IObservableVector<winrt::PowerRenameUILib::ExplorerItem> MainWindow::ExplorerItems()
{
return m_explorerItems;
}
winrt::Windows::Foundation::Collections::IObservableVector<winrt::PowerRenameUILib::PatternSnippet> MainWindow::SearchRegExShortcuts()
{
return m_searchRegExShortcuts;
}
winrt::Windows::Foundation::Collections::IObservableVector<winrt::PowerRenameUILib::PatternSnippet> MainWindow::DateTimeShortcuts()
{
return m_dateTimeShortcuts;
}
Windows::UI::Xaml::Controls::AutoSuggestBox MainWindow::AutoSuggestBoxSearch()
{
return textBox_search();
}
Windows::UI::Xaml::Controls::AutoSuggestBox MainWindow::AutoSuggestBoxReplace()
{
return textBox_replace();
}
Windows::UI::Xaml::Controls::CheckBox MainWindow::CheckBoxRegex()
{
return checkBox_regex();
}
Windows::UI::Xaml::Controls::CheckBox MainWindow::CheckBoxCaseSensitive()
{
return checkBox_case();
}
Windows::UI::Xaml::Controls::CheckBox MainWindow::CheckBoxMatchAll()
{
return checkBox_matchAll();
}
Windows::UI::Xaml::Controls::ComboBox MainWindow::ComboBoxRenameParts()
{
return comboBox_renameParts();
}
Windows::UI::Xaml::Controls::Primitives::ToggleButton MainWindow::ToggleButtonIncludeFiles()
{
return toggleButton_includeFiles();
}
Windows::UI::Xaml::Controls::Primitives::ToggleButton MainWindow::ToggleButtonIncludeFolders()
{
return toggleButton_includeFolders();
}
Windows::UI::Xaml::Controls::Primitives::ToggleButton MainWindow::ToggleButtonIncludeSubfolders()
{
return toggleButton_includeSubfolders();
}
Windows::UI::Xaml::Controls::Primitives::ToggleButton MainWindow::ToggleButtonEnumerateItems()
{
return toggleButton_enumItems();
}
Windows::UI::Xaml::Controls::Primitives::ToggleButton MainWindow::ToggleButtonUpperCase()
{
return toggleButton_upperCase();
}
Windows::UI::Xaml::Controls::Primitives::ToggleButton MainWindow::ToggleButtonLowerCase()
{
return toggleButton_lowerCase();
}
Windows::UI::Xaml::Controls::Primitives::ToggleButton MainWindow::ToggleButtonTitleCase()
{
return toggleButton_titleCase();
}
Windows::UI::Xaml::Controls::Primitives::ToggleButton MainWindow::ToggleButtonCapitalize()
{
return toggleButton_capitalize();
}
Windows::UI::Xaml::Controls::Button MainWindow::ButtonSettings()
{
return button_settings();
}
Windows::UI::Xaml::Controls::CheckBox MainWindow::CheckBoxSelectAll()
{
return checkBox_selectAll();
}
PowerRenameUILib::UIUpdates MainWindow::UIUpdatesItem()
{
return m_uiUpdatesItem;
}
void MainWindow::AddExplorerItem(int32_t id, hstring const& original, hstring const& renamed, int32_t type, int32_t parentId, bool checked)
{
auto newItem = winrt::make<PowerRenameUILib::implementation::ExplorerItem>(id, original, renamed, type, checked);
if (parentId == 0)
{
m_explorerItems.Append(newItem);
}
else
{
auto parent = FindById(parentId);
parent.Children().Append(newItem);
}
}
void MainWindow::UpdateExplorerItem(int32_t id, hstring const& newName)
{
auto itemToUpdate = FindById(id);
if (itemToUpdate != NULL)
{
itemToUpdate.Renamed(newName);
}
}
void MainWindow::UpdateRenamedExplorerItem(int32_t id, hstring const& newOriginalName)
{
auto itemToUpdate = FindById(id);
if (itemToUpdate != NULL)
{
itemToUpdate.Original(newOriginalName);
itemToUpdate.Renamed(L"");
}
}
void MainWindow::AppendSearchMRU(hstring const& value)
{
m_searchMRU.Append(value);
}
void MainWindow::AppendReplaceMRU(hstring const& value)
{
m_replaceMRU.Append(value);
}
PowerRenameUILib::ExplorerItem MainWindow::FindById(int32_t id)
{
auto fakeRoot = winrt::make<PowerRenameUILib::implementation::ExplorerItem>(0, L"Fake", L"", 0, false);
fakeRoot.Children(m_explorerItems);
return FindById(fakeRoot, id);
}
PowerRenameUILib::ExplorerItem MainWindow::FindById(PowerRenameUILib::ExplorerItem& root, int32_t id)
{
if (root.Id() == id)
return root;
if (root.Type() == static_cast<UINT>(ExplorerItem::ExplorerItemType::Folder))
{
for (auto c : root.Children())
{
auto result = FindById(c, id);
if (result != NULL)
return result;
}
}
return NULL;
}
void MainWindow::ToggleAll(PowerRenameUILib::ExplorerItem node, bool checked)
{
if (node == NULL)
return;
node.Checked(checked);
if (node.Type() == static_cast<UINT>(ExplorerItem::ExplorerItemType::Folder))
{
for (auto c : node.Children())
{
ToggleAll(c, checked);
}
}
}
void MainWindow::Checked_ids(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const&)
{
auto checkbox = sender.as<Windows::UI::Xaml::Controls::CheckBox>();
auto id = std::stoi(std::wstring{ checkbox.Name() });
auto item = FindById(id);
if (checkbox.IsChecked().GetBoolean() != item.Checked())
{
m_uiUpdatesItem.Checked(checkbox.IsChecked().GetBoolean());
m_uiUpdatesItem.ChangedExplorerItemId(id);
}
}
void MainWindow::SelectAll(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::RoutedEventArgs const&)
{
if (checkBox_selectAll().IsChecked().GetBoolean() != m_allSelected)
{
auto fakeRoot = winrt::make<PowerRenameUILib::implementation::ExplorerItem>(0, L"Fake", L"", 0, false);
fakeRoot.Children(m_explorerItems);
ToggleAll(fakeRoot, checkBox_selectAll().IsChecked().GetBoolean());
m_uiUpdatesItem.ToggleAll();
m_allSelected = !m_allSelected;
}
}
void MainWindow::ShowAll(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::RoutedEventArgs const&)
{
button_showAll().IsChecked(true);
button_showRenamed().IsChecked(false);
if (!m_uiUpdatesItem.ShowAll())
{
m_explorerItems.Clear();
m_uiUpdatesItem.ShowAll(true);
}
}
void MainWindow::ShowRenamed(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::RoutedEventArgs const&)
{
button_showRenamed().IsChecked(true);
button_showAll().IsChecked(false);
if (m_uiUpdatesItem.ShowAll())
{
m_explorerItems.Clear();
m_uiUpdatesItem.ShowAll(false);
}
}
void MainWindow::RegExItemClick(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::Controls::ItemClickEventArgs const& e)
{
auto s = e.ClickedItem().try_as<PatternSnippet>();
RegExFlyout().Hide();
textBox_search().Text(textBox_search().Text() + s->Code());
}
void MainWindow::DateTimeItemClick(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::Controls::ItemClickEventArgs const& e)
{
auto s = e.ClickedItem().try_as<PatternSnippet>();
DateTimeFlyout().Hide();
textBox_replace().Text(textBox_replace().Text() + s->Code());
}
void MainWindow::button_rename_Click(winrt::Microsoft::UI::Xaml::Controls::SplitButton const&, winrt::Microsoft::UI::Xaml::Controls::SplitButtonClickEventArgs const&)
{
m_uiUpdatesItem.CloseUIWindow(false);
m_uiUpdatesItem.Rename();
}
void MainWindow::MenuFlyoutItem_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::RoutedEventArgs const&)
{
m_uiUpdatesItem.CloseUIWindow(true);
m_uiUpdatesItem.Rename();
}
void MainWindow::OpenDocs(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::RoutedEventArgs const&)
{
Windows::System::Launcher::LaunchUriAsync(winrt::Windows::Foundation::Uri{ L"https://aka.ms/PowerToysOverview_PowerRename" });
}
}

View file

@ -0,0 +1,88 @@
#pragma once
#include "winrt/Windows.UI.Xaml.h"
#include "winrt/Windows.UI.Xaml.Markup.h"
#include "winrt/Windows.UI.Xaml.Interop.h"
#include "winrt/Windows.UI.Xaml.Controls.Primitives.h"
#include "MainWindow.g.h"
#include "PatternSnippet.h"
#include "ExplorerItem.h"
#include "ExplorerItemTemplateSelector.h"
namespace winrt::PowerRenameUILib::implementation
{
struct MainWindow : MainWindowT<MainWindow>
{
MainWindow();
Windows::Foundation::Collections::IObservableVector<hstring> SearchMRU();
Windows::Foundation::Collections::IObservableVector<hstring> ReplaceMRU();
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUILib::ExplorerItem> ExplorerItems();
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUILib::PatternSnippet> SearchRegExShortcuts();
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUILib::PatternSnippet> DateTimeShortcuts();
Windows::UI::Xaml::Controls::AutoSuggestBox AutoSuggestBoxSearch();
Windows::UI::Xaml::Controls::AutoSuggestBox AutoSuggestBoxReplace();
Windows::UI::Xaml::Controls::CheckBox CheckBoxRegex();
Windows::UI::Xaml::Controls::CheckBox CheckBoxCaseSensitive();
Windows::UI::Xaml::Controls::CheckBox CheckBoxMatchAll();
Windows::UI::Xaml::Controls::ComboBox ComboBoxRenameParts();
Windows::UI::Xaml::Controls::Primitives::ToggleButton ToggleButtonIncludeFiles();
Windows::UI::Xaml::Controls::Primitives::ToggleButton ToggleButtonIncludeFolders();
Windows::UI::Xaml::Controls::Primitives::ToggleButton ToggleButtonIncludeSubfolders();
Windows::UI::Xaml::Controls::Primitives::ToggleButton ToggleButtonUpperCase();
Windows::UI::Xaml::Controls::Primitives::ToggleButton ToggleButtonLowerCase();
Windows::UI::Xaml::Controls::Primitives::ToggleButton ToggleButtonTitleCase();
Windows::UI::Xaml::Controls::Primitives::ToggleButton ToggleButtonCapitalize();
Windows::UI::Xaml::Controls::Primitives::ToggleButton ToggleButtonEnumerateItems();
Windows::UI::Xaml::Controls::Button ButtonSettings();
Windows::UI::Xaml::Controls::CheckBox CheckBoxSelectAll();
PowerRenameUILib::UIUpdates UIUpdatesItem();
void AddExplorerItem(int32_t id, hstring const& original, hstring const& renamed, int32_t type, int32_t parentId, bool checked);
void UpdateExplorerItem(int32_t id, hstring const& newName);
void UpdateRenamedExplorerItem(int32_t id, hstring const& newOriginalName);
void AppendSearchMRU(hstring const& value);
void AppendReplaceMRU(hstring const& value);
void Checked_ids(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void SelectAll(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void ShowAll(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void ShowRenamed(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
private:
bool m_allSelected;
PowerRenameUILib::UIUpdates m_uiUpdatesItem;
PowerRenameUILib::ExplorerItem FindById(int32_t id);
PowerRenameUILib::ExplorerItem FindById(PowerRenameUILib::ExplorerItem& root, int32_t id);
void ToggleAll(PowerRenameUILib::ExplorerItem node, bool checked);
winrt::Windows::Foundation::Collections::IObservableVector<hstring> m_searchMRU;
winrt::Windows::Foundation::Collections::IObservableVector<hstring> m_replaceMRU;
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUILib::ExplorerItem> m_explorerItems;
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUILib::PatternSnippet> m_searchRegExShortcuts;
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUILib::PatternSnippet> m_dateTimeShortcuts;
public:
void RegExItemClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::ItemClickEventArgs const& e);
void DateTimeItemClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::ItemClickEventArgs const& e);
void button_rename_Click(winrt::Microsoft::UI::Xaml::Controls::SplitButton const& sender, winrt::Microsoft::UI::Xaml::Controls::SplitButtonClickEventArgs const& args);
void MenuFlyoutItem_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void OpenDocs(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
};
}
namespace winrt::PowerRenameUILib::factory_implementation
{
struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow>
{
};
}

View file

@ -0,0 +1,61 @@
import "ExplorerItem.idl";
import "PatternSnippet.idl";
namespace PowerRenameUILib
{
runtimeclass UIUpdates : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
UIUpdates();
Boolean ShowAll;
Int32 ChangedExplorerItemId;
Boolean Checked;
void ToggleAll();
Boolean CloseUIWindow();
void CloseUIWindow(Boolean closeUIWindow);
Boolean ButtonRenameEnabled;
void Rename();
}
[default_interface] runtimeclass MainWindow : Windows.UI.Xaml.Controls.UserControl
{
MainWindow();
Windows.Foundation.Collections.IObservableVector<String> SearchMRU { get; };
Windows.Foundation.Collections.IObservableVector<String> ReplaceMRU { get; };
Windows.Foundation.Collections.IObservableVector<ExplorerItem> ExplorerItems { get; };
Windows.Foundation.Collections.IObservableVector<PatternSnippet> SearchRegExShortcuts { get; };
Windows.Foundation.Collections.IObservableVector<PatternSnippet> DateTimeShortcuts { get; };
Windows.UI.Xaml.Controls.AutoSuggestBox AutoSuggestBoxSearch { get; };
Windows.UI.Xaml.Controls.AutoSuggestBox AutoSuggestBoxReplace { get; };
Windows.UI.Xaml.Controls.CheckBox CheckBoxRegex { get; };
Windows.UI.Xaml.Controls.CheckBox CheckBoxCaseSensitive { get; };
Windows.UI.Xaml.Controls.CheckBox CheckBoxMatchAll { get; };
Windows.UI.Xaml.Controls.Primitives.ToggleButton ToggleButtonEnumerateItems { get; };
Windows.UI.Xaml.Controls.ComboBox ComboBoxRenameParts { get; };
Windows.UI.Xaml.Controls.Primitives.ToggleButton ToggleButtonIncludeFiles { get; };
Windows.UI.Xaml.Controls.Primitives.ToggleButton ToggleButtonIncludeFolders { get; };
Windows.UI.Xaml.Controls.Primitives.ToggleButton ToggleButtonIncludeSubfolders { get; };
Windows.UI.Xaml.Controls.Button ButtonSettings { get; };
Windows.UI.Xaml.Controls.CheckBox CheckBoxSelectAll { get; };
Windows.UI.Xaml.Controls.Primitives.ToggleButton ToggleButtonUpperCase { get; };
Windows.UI.Xaml.Controls.Primitives.ToggleButton ToggleButtonLowerCase { get; };
Windows.UI.Xaml.Controls.Primitives.ToggleButton ToggleButtonTitleCase { get; };
Windows.UI.Xaml.Controls.Primitives.ToggleButton ToggleButtonCapitalize { get; };
void AddExplorerItem(Int32 id, String original, String renamed, Int32 type, Int32 parentId, Boolean checked);
void UpdateExplorerItem(Int32 id, String newName);
void UpdateRenamedExplorerItem(Int32 id, String newOriginalName);
void AppendSearchMRU(String value);
void AppendReplaceMRU(String value);
UIUpdates UIUpdatesItem { get; };
}
}

View file

@ -0,0 +1,326 @@
<UserControl x:Class="PowerRenameUILib.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:PowerRenameUILib" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="using:Microsoft.UI.Xaml.Controls" xmlns:muxc="using:Microsoft.UI.Xaml.Controls" controls:BackdropMaterial.ApplyToRootOrPageBackground="True" xmlns:animatedVisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals" mc:Ignorable="d">
<UserControl.Resources>
<local:ExplorerItemTemplateSelector x:Key="ExplorerItemTemplateSelector" FolderTemplate="{StaticResource FolderTemplate}" FileTemplate="{StaticResource FileTemplate}" />
<local:ExplorerItemTemplateSelector x:Key="RenamedExplorerItemTemplateSelector" FolderTemplate="{StaticResource RenamedFolderTemplate}" FileTemplate="{StaticResource RenamedFileTemplate}" />
<DataTemplate x:Key="FileTemplate" x:DataType="local:ExplorerItem">
<Grid Height="24" Margin="0,4,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="36" />
<ColumnDefinition Width="36" />
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<CheckBox TabIndex="0" Grid.Column="0" XYFocusKeyboardNavigation="Enabled" Checked="Checked_ids" IsTabStop="True" Unchecked="Checked_ids" Content="" Name="{x:Bind IdStr}" AutomationProperties.Name="{x:Bind Original}" AutomationProperties.HelpText="{x:Bind Renamed}" IsChecked="{x:Bind Checked, Mode=TwoWay}" />
<Image Width="16" Source="ms-appx:///Assets/file.png" HorizontalAlignment="Left" Grid.Column="1" />
<TextBlock Text="{x:Bind Original, Mode=OneWay}" Foreground="{ThemeResource TextFillColorSecondaryBrush}" VerticalAlignment="Center" FontSize="12" Grid.Column="2" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="FolderTemplate" x:DataType="local:ExplorerItem">
<Grid Margin="0,4,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="36" />
<ColumnDefinition Width="36" />
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="24" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<CheckBox TabIndex="0" IsTabStop="True" XYFocusKeyboardNavigation="Enabled" Grid.Row="0" Grid.Column="0" Checked="Checked_ids" Unchecked="Checked_ids" Content="" Name="{x:Bind IdStr}" AutomationProperties.Name="{x:Bind Original}" AutomationProperties.HelpText="{x:Bind Renamed}" IsChecked="{x:Bind Checked, Mode=TwoWay}" />
<Image Width="16" Source="ms-appx:///Assets/folder.png" HorizontalAlignment="Left" Grid.Column="1" />
<TextBlock Text="{x:Bind Original, Mode=OneWay}" Foreground="{ThemeResource TextFillColorSecondaryBrush}" VerticalAlignment="Center" FontSize="12" Grid.Column="2" />
<ListView Grid.ColumnSpan="3" IsTabStop="false" XYFocusKeyboardNavigation="Enabled" SelectionMode="None" IsItemClickEnabled="False" ItemsSource="{x:Bind Children}" Grid.Row="1" ItemTemplateSelector="{StaticResource ExplorerItemTemplateSelector}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsTabStop" Value="False" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</DataTemplate>
<DataTemplate x:Key="RenamedFileTemplate" x:DataType="local:ExplorerItem">
<Grid Height="24" Margin="0,4,0,0">
<TextBlock Text="{x:Bind Renamed, Mode=OneWay}" FontWeight="SemiBold" VerticalAlignment="Center" FontSize="14" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="RenamedFolderTemplate" x:DataType="local:ExplorerItem">
<Grid Margin="0,4,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="24" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="{x:Bind Renamed, Mode=OneWay}" FontWeight="Bold" VerticalAlignment="Center" FontSize="14" />
<ListView IsTabStop="false" Margin="-12,0,0,0" SelectionMode="None" IsItemClickEnabled="False" ItemsSource="{x:Bind Children}" Grid.Row="1" ItemTemplateSelector="{StaticResource RenamedExplorerItemTemplateSelector}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsTabStop" Value="False" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Padding="20">
<Grid.RowDefinitions>
<RowDefinition Height="0" /> <!-- 48 if we need to draw the title bar ourself -->
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Row="1" Grid.Column="1" Background="{ThemeResource LayerFillColorDefaultBrush}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" CornerRadius="8" BorderThickness="1" BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="48" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="36" />
<ColumnDefinition Width="48" />
<ColumnDefinition Width="Auto" MinWidth="324" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="48" />
</Grid.ColumnDefinitions>
<CheckBox x:Name="checkBox_selectAll" IsChecked="True" Content="" x:Uid="SelectAllCheckBox" Margin="16,0,0,0" Checked="SelectAll" Unchecked="SelectAll" />
<Image Width="16" Grid.Column="1" Source="ms-appx:///Assets/file.png" HorizontalAlignment="Center" />
<TextBlock x:Uid="TxtBlock_Original" Grid.Column="2" FontWeight="Medium" Margin="2,-2,0,0" VerticalAlignment="Center" />
<AppBarSeparator Grid.Column="3" Margin="-6,4,0,4" HorizontalAlignment="Left" />
<TextBlock x:Uid="TxtBlock_Renamed" FontWeight="Medium" Grid.Column="3" Margin="4,-2,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" />
<Button Content="&#xE16E;" Background="Transparent" FontFamily="{ThemeResource SymbolThemeFontFamily}" Height="32" x:Uid="FilterButton" Grid.Column="4" BorderThickness="0" HorizontalAlignment="Right" Margin="0,0,8,0">
<Button.Flyout>
<MenuBarItemFlyout Placement="Bottom">
<controls:RadioMenuFlyoutItem x:Name="button_showAll" Click="ShowAll" x:Uid="ShowAll" IsChecked="True" GroupName="Filter" />
<controls:RadioMenuFlyoutItem x:Name="button_showRenamed" Click="ShowRenamed" x:Uid="ShowOnly" GroupName="Filter" />
</MenuBarItemFlyout>
</Button.Flyout>
</Button>
<Rectangle Height="1" Grid.ColumnSpan="5" Fill="{ThemeResource CardStrokeColorDefaultBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" />
<ScrollViewer Grid.ColumnSpan="6" HorizontalScrollMode="Enabled" Grid.Row="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="286" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListView IsTabStop="false" SelectionMode="None" XYFocusKeyboardNavigation="Enabled" IsItemClickEnabled="False" ItemsSource="{x:Bind ExplorerItems, Mode=OneWay}" Margin="4,0,0,0" ItemTemplateSelector="{StaticResource ExplorerItemTemplateSelector}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsTabStop" Value="False" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
<!--<controls:ItemsRepeater ItemsSource="{x:Bind ExplorerItems, Mode=OneWay}"
Margin="16,0,0,0"
ItemTemplate="{StaticResource ExplorerItemTemplateSelector}" />-->
<ListView Grid.Column="1" IsTabStop="false" SelectionMode="None" IsItemClickEnabled="False" ItemsSource="{x:Bind ExplorerItems, Mode=OneWay}" ItemTemplateSelector="{StaticResource RenamedExplorerItemTemplateSelector}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsTabStop" Value="False" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
<!--<controls:ItemsRepeater ItemsSource="{x:Bind ExplorerItems, Mode=OneWay}"
Grid.Column="1"
ItemTemplate="{StaticResource RenamedExplorerItemTemplateSelector}" />-->
</Grid>
</ScrollViewer>
</Grid>
<Grid Grid.Column="0" Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="48" />
</Grid.RowDefinitions>
<ScrollViewer>
<StackPanel Orientation="Vertical" Padding="0,0,0,16" Margin="0,0,20,0">
<Grid>
<AutoSuggestBox x:Name="textBox_search" x:Uid="SearchBox" Height="48" VerticalContentAlignment="Center" ItemsSource="{x:Bind SearchMRU}" />
<Button FontFamily="{ThemeResource SymbolThemeFontFamily}" VerticalAlignment="Center" Visibility="{Binding ElementName=checkBox_regex, Path=IsChecked}" MinHeight="32" Margin="4" x:Uid="RegExButton" Background="Transparent" BorderBrush="Transparent" Content="&#xE946;" HorizontalAlignment="Right">
<Button.Flyout>
<Flyout x:Name="RegExFlyout">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="*" />
<RowDefinition Height="48" />
</Grid.RowDefinitions>
<TextBlock x:Uid="RegExCheatSheet_Title" FontWeight="SemiBold" />
<ListView ItemsSource="{x:Bind SearchRegExShortcuts}" Grid.Row="1" IsItemClickEnabled="True" Margin="-4,12,0,0" ItemClick="RegExItemClick">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:PatternSnippet">
<Grid ColumnSpacing="8" Margin="-10,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border CornerRadius="4" Padding="8" HorizontalAlignment="Left" BorderThickness="1" BorderBrush="{ThemeResource ButtonBorderBrush}" Background="{ThemeResource ButtonBackground}">
<TextBlock FontFamily="Consolas" Foreground="{ThemeResource ButtonForeground}" Text="{x:Bind Code}" />
</Border>
<TextBlock Text="{x:Bind Description}" FontSize="12" Grid.Column="1" Margin="0,0,0,0" Foreground="{ThemeResource TextFillColorSecondaryBrush}" VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<HyperlinkButton Grid.Row="2" VerticalAlignment="Bottom">
<TextBlock x:Uid="RegExCheatSheet_LearnMore" />
</HyperlinkButton>
</Grid>
</Flyout>
</Button.Flyout>
</Button>
</Grid>
<CheckBox x:Name="checkBox_regex" x:Uid="CheckBox_RegEx" Margin="2,12,0,0" />
<CheckBox x:Name="checkBox_matchAll" x:Uid="CheckBox_MatchAll" Margin="2,4,0,0" />
<CheckBox x:Name="checkBox_case" x:Uid="CheckBox_Case" Margin="2,4,0,0" />
<Rectangle Height="1" Fill="{ThemeResource CardStrokeColorDefaultBrush}" HorizontalAlignment="Stretch" Margin="0,16,0,20" />
<Grid>
<AutoSuggestBox x:Name="textBox_replace" Margin="0,0,0,0" x:Uid="ReplaceBox" Height="48" VerticalContentAlignment="Center" Padding="12,12,0,0" ItemsSource="{x:Bind ReplaceMRU}" />
<Button FontFamily="{ThemeResource SymbolThemeFontFamily}" VerticalAlignment="Center" MinHeight="32" Margin="4" x:Uid="FileCreationButton" Background="Transparent" BorderBrush="Transparent" Content="&#xE946;" HorizontalAlignment="Right">
<Button.Flyout>
<Flyout x:Name="DateTimeFlyout" ShouldConstrainToRootBounds="False">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Uid="DateTimeCheatSheet_Title" FontWeight="SemiBold" />
<ListView ItemsSource="{x:Bind DateTimeShortcuts}" Grid.Row="1" IsItemClickEnabled="True" Margin="-4,12,0,0" ItemClick="DateTimeItemClick">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:PatternSnippet">
<Grid ColumnSpacing="8" Margin="-10,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="56" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border CornerRadius="4" Padding="8" HorizontalAlignment="Left" BorderThickness="1" BorderBrush="{ThemeResource ButtonBorderBrush}" Background="{ThemeResource ButtonBackground}">
<TextBlock FontFamily="Consolas" Foreground="{ThemeResource ButtonForeground}" Text="{x:Bind Code}" />
</Border>
<TextBlock Text="{x:Bind Description}" FontSize="12" Grid.Column="1" Margin="0,0,0,0" Foreground="{ThemeResource TextFillColorSecondaryBrush}" VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Flyout>
</Button.Flyout>
</Button>
</Grid>
<TextBlock x:Uid="TextBox_ApplyTo" x:Name="ApplyToLabel" FontSize="12" Margin="0,20,0,8" Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<StackPanel Orientation="Horizontal" Grid.Column="1" Spacing="4" Grid.Row="1">
<ComboBox x:Name="comboBox_renameParts" SelectedIndex="0" Width="200" AutomationProperties.LabeledBy="{Binding ElementName=ApplyToLabel}" HorizontalAlignment="Stretch" Grid.Column="0" Grid.Row="1">
<x:String>Filename + extension</x:String>
<x:String>Filename only</x:String>
<x:String>Extension only</x:String>
</ComboBox>
<AppBarSeparator Margin="5,0,5,0" />
<ToggleButton x:Name="toggleButton_includeFiles" Content="&#xE160;" MinHeight="32" IsChecked="True" FontFamily="{ThemeResource SymbolThemeFontFamily}" x:Uid="ToggleButton_IncludeFiles" Style="{StaticResource CustomToggleButtonStyle}" />
<ToggleButton x:Name="toggleButton_includeFolders" Content="&#xE8B7;" MinHeight="32" IsChecked="True" FontFamily="{ThemeResource SymbolThemeFontFamily}" x:Uid="ToggleButton_IncludeFolders" Style="{StaticResource CustomToggleButtonStyle}" />
<ToggleButton x:Name="toggleButton_includeSubfolders" Content="&#xE12F;" MinHeight="32" IsChecked="True" FontFamily="{ThemeResource SymbolThemeFontFamily}" x:Uid="ToggleButton_IncludeSubFolders" Style="{StaticResource CustomToggleButtonStyle}" />
</StackPanel>
<TextBlock x:Uid="TextBlock_TextFormatting" FontSize="12" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Margin="0,20,0,8" />
<StackPanel Orientation="Horizontal" Spacing="4">
<ToggleButton x:Name="toggleButton_lowerCase" Content="aa" FontWeight="Medium" MinHeight="32" x:Uid="ToggleButton_Lowercase" Style="{StaticResource CustomToggleButtonStyle}" />
<ToggleButton x:Name="toggleButton_upperCase" Content="AA" FontWeight="Medium" MinHeight="32" x:Uid="ToggleButton_Uppercase" Style="{StaticResource CustomToggleButtonStyle}" />
<ToggleButton x:Name="toggleButton_titleCase" Content="Aa" FontWeight="Medium" MinHeight="32" x:Uid="ToggleButton_TitleCase" Style="{StaticResource CustomToggleButtonStyle}" />
<ToggleButton x:Name="toggleButton_capitalize" Content="Aa Aa" FontWeight="Medium" MinHeight="32" x:Uid="ToggleButton_Capitalize" Style="{StaticResource CustomToggleButtonStyle}" />
<AppBarSeparator Margin="5,0,5,0" />
<ToggleButton x:Name="toggleButton_enumItems" Content="&#xEA40;" FontFamily="{ThemeResource SymbolThemeFontFamily}" MinHeight="32" x:Uid="ToggleButton_EnumItems" Style="{StaticResource CustomToggleButtonStyle}" />
</StackPanel>
</StackPanel>
</ScrollViewer>
<Rectangle Height="1" Fill="{ThemeResource CardStrokeColorDefaultBrush}" HorizontalAlignment="Stretch" Margin="0,0,20,0" VerticalAlignment="Top" Grid.Row="1" />
<StackPanel Orientation="Horizontal" Grid.Row="1" Spacing="8" Margin="0" Grid.Column="1" VerticalAlignment="Bottom" HorizontalAlignment="Left">
<Button x:Name="button_settings" Height="32" x:Uid="TxtBlock_ButtonSettings" FontFamily="{ThemeResource SymbolThemeFontFamily}" Grid.Row="5" Padding="6" Background="Transparent" BorderBrush="Transparent" Grid.Column="1">
<Button.Content>
<controls:AnimatedIcon x:Name="SearchAnimatedIcon">
<controls:AnimatedIcon.Source>
<animatedVisuals:AnimatedSettingsVisualSource />
</controls:AnimatedIcon.Source>
<controls:AnimatedIcon.FallbackIconSource>
<controls:SymbolIconSource Symbol="Setting" />
</controls:AnimatedIcon.FallbackIconSource>
</controls:AnimatedIcon>
</Button.Content>
</Button>
<Button x:Name="button_docs" Content="&#xE11B;" FontFamily="{ThemeResource SymbolThemeFontFamily}" x:Uid="DocsButton" Background="Transparent" BorderBrush="Transparent" Grid.Row="1" Height="32" VerticalAlignment="Bottom" HorizontalAlignment="Left" Click="OpenDocs" />
<!--<Button Content="&#xE728;"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
ToolTipService.ToolTip="Presets"
Background="Transparent"
BorderBrush="Transparent"
Grid.Row="1"
Height="36"
VerticalAlignment="Bottom"
HorizontalAlignment="Left">
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem Text="Photo rule 1" />
<MenuFlyoutItem Text="Date time rule" />
<MenuFlyoutItem Text="And another rule" />
</MenuFlyout>
</Button.Flyout>
</Button>-->
</StackPanel>
<muxc:SplitButton Grid.Row="1" Style="{StaticResource SplitAccentButtonStyle}" x:Name="button_rename" Margin="0,0,20,0" x:Uid="ButtonApply" Click="button_rename_Click" HorizontalAlignment="Right" VerticalAlignment="Bottom" IsEnabled="{x:Bind UIUpdatesItem.ButtonRenameEnabled, Mode=OneWay}">
<muxc:SplitButton.Content>
<StackPanel Orientation="Horizontal">
<FontIcon Glyph="&#xE13E;" FontSize="14" VerticalAlignment="Center" Margin="0,2,10,0" />
<TextBlock x:Uid="TxtBlock_ButtonApply" />
</StackPanel>
</muxc:SplitButton.Content>
<muxc:SplitButton.Flyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="TxtBlock_ButtonApplyAndClose" Click="MenuFlyoutItem_Click" />
</MenuFlyout>
</muxc:SplitButton.Flyout>
</muxc:SplitButton>
</Grid>
<!--<StackPanel x:Name="TitleBar" Orientation="Horizontal">
<Image Source="Assets/PowerRename.png" Width="16" Height="16" VerticalAlignment="Top" Margin="20,9,0,0"/>
<TextBlock Text="PowerRename" Style="{StaticResource CaptionTextBlockStyle}" Margin="18,8,8,0" VerticalAlignment="Top" />
</StackPanel>-->
</Grid>
</UserControl>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
<Identity Name="661b0d33-8cab-4599-adca-0976e0346f63" Publisher="CN=ms" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="661b0d33-8cab-4599-adca-0976e0346f63" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>PowerRenameUILib</DisplayName>
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="placeholder.exe" EntryPoint="PowerRenameUILib.App">
<uap:VisualElements DisplayName="PowerRenameUILib" Description="Project for a single page C++/WinRT Universal Windows Platform (UWP) app with no predefined layout" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"></uap:DefaultTile>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
</Capabilities>
</Package>

View file

@ -0,0 +1,49 @@
#include "pch.h"
#include "PatternSnippet.h"
#include "PatternSnippet.g.cpp"
namespace winrt::PowerRenameUILib::implementation
{
PatternSnippet::PatternSnippet(hstring const& code, hstring const& description) :
m_code{ code }, m_description{ description }
{
}
hstring PatternSnippet::Code()
{
return m_code;
}
void PatternSnippet::Code(hstring const& value)
{
if (m_code != value)
{
m_code = value;
m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Code" });
}
}
hstring PatternSnippet::Description()
{
return m_description;
}
void PatternSnippet::Description(hstring const& value)
{
if (m_description != value)
{
m_description = value;
m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Description" });
}
}
winrt::event_token PatternSnippet::PropertyChanged(winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
return m_propertyChanged.add(handler);
}
void PatternSnippet::PropertyChanged(winrt::event_token const& token) noexcept
{
m_propertyChanged.remove(token);
}
}

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