mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-01 01:46:50 +01:00
Compare commits
21 Commits
docs-overh
...
dev/snickl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
808066f272 | ||
|
|
6e571d44a3 | ||
|
|
69aa98fabc | ||
|
|
f34735edeb | ||
|
|
c6cee94456 | ||
|
|
0323ebea58 | ||
|
|
bd132d9b40 | ||
|
|
69064fab99 | ||
|
|
a64de74f3b | ||
|
|
7772bfb777 | ||
|
|
0f279002f8 | ||
|
|
0c425fd1d7 | ||
|
|
03a9ac1ac7 | ||
|
|
837d5ca543 | ||
|
|
2ff5adbdd4 | ||
|
|
faebd21a2d | ||
|
|
6412d5722e | ||
|
|
9f68b37bbd | ||
|
|
21a3c216da | ||
|
|
725535b760 | ||
|
|
9c2e83d6eb |
1
.github/actions/spell-check/allow/names.txt
vendored
1
.github/actions/spell-check/allow/names.txt
vendored
@@ -55,6 +55,7 @@ clayton
|
||||
Coplen
|
||||
craigloewen
|
||||
crutkas
|
||||
Chubercik
|
||||
damienleroy
|
||||
daverayment
|
||||
davidegiacometti
|
||||
|
||||
1
.github/actions/spell-check/excludes.txt
vendored
1
.github/actions/spell-check/excludes.txt
vendored
@@ -127,3 +127,4 @@
|
||||
^tools/Verification scripts/Check preview handler registration\.ps1$
|
||||
ignore$
|
||||
^src/modules/registrypreview/RegistryPreviewUILib/Controls/HexBox/.*$
|
||||
^src/common/CalculatorEngineCommon/exprtk\.hpp$
|
||||
|
||||
52
.github/actions/spell-check/expect.txt
vendored
52
.github/actions/spell-check/expect.txt
vendored
@@ -141,7 +141,7 @@ boxmodel
|
||||
BPBF
|
||||
bpmf
|
||||
bpp
|
||||
Breadcrumb
|
||||
breadcrumb
|
||||
Browsable
|
||||
BROWSEINFO
|
||||
bsd
|
||||
@@ -192,7 +192,6 @@ CImage
|
||||
cla
|
||||
CLASSDC
|
||||
CLASSNOTAVAILABLE
|
||||
cleanmgr
|
||||
clickable
|
||||
clickonce
|
||||
CLIENTEDGE
|
||||
@@ -204,7 +203,6 @@ CLIPSIBLINGS
|
||||
closesocket
|
||||
clp
|
||||
CLSCTX
|
||||
CLSCTXLOCALSERVER
|
||||
clsids
|
||||
Clusion
|
||||
cmder
|
||||
@@ -496,7 +494,6 @@ FFFF
|
||||
FILEEXPLORER
|
||||
FILEFLAGS
|
||||
FILEFLAGSMASK
|
||||
FILELOCKSMITH
|
||||
FILELOCKSMITHCONTEXTMENU
|
||||
FILELOCKSMITHEXT
|
||||
FILELOCKSMITHLIBINTEROP
|
||||
@@ -762,7 +759,6 @@ IUI
|
||||
IUnknown
|
||||
IUse
|
||||
IWIC
|
||||
iwr
|
||||
jfif
|
||||
jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi
|
||||
jjw
|
||||
@@ -1287,7 +1283,6 @@ prvpane
|
||||
psapi
|
||||
pscid
|
||||
PSECURITY
|
||||
psexec
|
||||
psfgao
|
||||
psfi
|
||||
PSMODULEPATH
|
||||
@@ -1545,7 +1540,6 @@ SLGP
|
||||
sln
|
||||
SMALLICON
|
||||
smartphone
|
||||
smileys
|
||||
SMTO
|
||||
SNAPPROCESS
|
||||
snk
|
||||
@@ -1682,7 +1676,6 @@ TESTONLY
|
||||
testprocess
|
||||
TEXCOORD
|
||||
TEXTBOXNEWLINE
|
||||
TEXTEXTRACTOR
|
||||
TEXTINCLUDE
|
||||
tfopen
|
||||
tgz
|
||||
@@ -1890,7 +1883,6 @@ WINDOWPOSCHANGING
|
||||
WINDOWSBUILDNUMBER
|
||||
windowssearch
|
||||
windowssettings
|
||||
windowsterminal
|
||||
WINDOWSTYLES
|
||||
WINDOWSTYLESICON
|
||||
winerror
|
||||
@@ -1994,7 +1986,6 @@ YStr
|
||||
YTM
|
||||
YVIRTUALSCREEN
|
||||
ZEROINIT
|
||||
Zhiwei
|
||||
zonable
|
||||
zoneset
|
||||
Zoneszonabletester
|
||||
@@ -2013,10 +2004,47 @@ culori
|
||||
Evercoder
|
||||
LCh
|
||||
CIELCh
|
||||
CLSCTXINPROCALL
|
||||
IIDI
|
||||
irow
|
||||
lcid
|
||||
ppwsz
|
||||
rguid
|
||||
VARTYPE
|
||||
advancedpaste
|
||||
appxpackage
|
||||
Ashcraft
|
||||
CDPX
|
||||
commandnotfound
|
||||
copyable
|
||||
Corpor
|
||||
cropandlock
|
||||
environmentvariables
|
||||
fileexploreraddons
|
||||
filelocksmith
|
||||
findmymouse
|
||||
fucntion
|
||||
fuzzingtesting
|
||||
hostsfileeditor
|
||||
hotfixes
|
||||
IDOn
|
||||
lcl
|
||||
LIBFUZZER
|
||||
makepri
|
||||
mikeclayton
|
||||
mousehighlighter
|
||||
mousejump
|
||||
mousepointer
|
||||
mouseutils
|
||||
MVPs
|
||||
onebranch
|
||||
PMs
|
||||
Psr
|
||||
quickaccent
|
||||
regsvr
|
||||
screenruler
|
||||
sharpfuzz
|
||||
sourced
|
||||
stuttery
|
||||
textextractor
|
||||
Windowss
|
||||
XLoc
|
||||
zonability
|
||||
|
||||
@@ -11,14 +11,13 @@
|
||||
"PowerToys.ActionRunner.exe",
|
||||
"PowerToys.Update.exe",
|
||||
"PowerToys.BackgroundActivatorDLL.dll",
|
||||
"Notifications.dll",
|
||||
"os-detection.dll",
|
||||
|
||||
"PowerToys.exe",
|
||||
"PowerToys.FilePreviewCommon.dll",
|
||||
"PowerToys.Interop.dll",
|
||||
"Tools\\PowerToys.BugReportTool.exe",
|
||||
"StylesReportTool\\PowerToys.StylesReportTool.exe",
|
||||
"Telemetry.dll",
|
||||
|
||||
"CalculatorEngineCommon.dll",
|
||||
"PowerToys.ManagedTelemetry.dll",
|
||||
"PowerToys.ManagedCommon.dll",
|
||||
@@ -33,7 +32,7 @@
|
||||
"PowerToys.AlwaysOnTopModuleInterface.dll",
|
||||
|
||||
"PowerToys.CmdNotFoundModuleInterface.dll",
|
||||
"PowerToys.CmdNotFound.dll",
|
||||
|
||||
|
||||
"PowerToys.ColorPicker.dll",
|
||||
"PowerToys.ColorPickerUI.dll",
|
||||
@@ -54,7 +53,7 @@
|
||||
"PowerToys.Awake.exe",
|
||||
"PowerToys.Awake.dll",
|
||||
|
||||
"fancyzones.dll",
|
||||
|
||||
"PowerToys.FancyZonesEditor.exe",
|
||||
"PowerToys.FancyZonesEditor.dll",
|
||||
"PowerToys.FancyZonesEditorCommon.dll",
|
||||
@@ -136,7 +135,7 @@
|
||||
"PowerToys.PowerLauncher.dll",
|
||||
"PowerToys.PowerLauncher.exe",
|
||||
"PowerToys.PowerLauncher.Telemetry.dll",
|
||||
"Wox.dll",
|
||||
|
||||
"Wox.Infrastructure.dll",
|
||||
"Wox.Plugin.dll",
|
||||
"RunPlugins\\Calculator\\Microsoft.PowerToys.Run.Plugin.Calculator.dll",
|
||||
@@ -275,16 +274,16 @@
|
||||
"Mono.Cecil.Pdb.dll",
|
||||
"Mono.Cecil.Rocks.dll",
|
||||
"Newtonsoft.Json.dll",
|
||||
"Newtonsoft.Json.Bson.dll",
|
||||
|
||||
"NLog.dll",
|
||||
"HtmlAgilityPack.dll",
|
||||
"Markdig.Signed.dll",
|
||||
"HelixToolkit.dll",
|
||||
"HelixToolkit.Core.Wpf.dll",
|
||||
"Mages.Core.dll",
|
||||
"JetBrains.Annotations.dll",
|
||||
|
||||
"NLog.Extensions.Logging.dll",
|
||||
"getfilesiginforedist.dll",
|
||||
|
||||
"concrt140_app.dll",
|
||||
"msvcp140_1_app.dll",
|
||||
"msvcp140_2_app.dll",
|
||||
@@ -294,22 +293,8 @@
|
||||
"vcomp140_app.dll",
|
||||
"vcruntime140_1_app.dll",
|
||||
"vcruntime140_app.dll",
|
||||
"WinUI3Apps\\CommunityToolkit.Labs.WinUI.SettingsControls.dll",
|
||||
|
||||
"UnicodeInformation.dll",
|
||||
"Vanara.Core.dll",
|
||||
"Vanara.PInvoke.ComCtl32.dll",
|
||||
"Vanara.PInvoke.Cryptography.dll",
|
||||
"Vanara.PInvoke.Gdi32.dll",
|
||||
"Vanara.PInvoke.Kernel32.dll",
|
||||
"Vanara.PInvoke.Ole.dll",
|
||||
"Vanara.PInvoke.Rpc.dll",
|
||||
"Vanara.PInvoke.Security.dll",
|
||||
"Vanara.PInvoke.Shared.dll",
|
||||
"Vanara.PInvoke.Shell32.dll",
|
||||
"Vanara.PInvoke.ShlwApi.dll",
|
||||
"Vanara.PInvoke.User32.dll",
|
||||
"WinUI3Apps\\clrcompression.dll",
|
||||
"WinUI3Apps\\Microsoft.Graphics.Canvas.Interop.dll",
|
||||
"Microsoft.Web.WebView2.Core.dll",
|
||||
"Microsoft.Web.WebView2.WinForms.dll",
|
||||
"Microsoft.Web.WebView2.Wpf.dll",
|
||||
@@ -336,7 +321,7 @@
|
||||
"Testably.Abstractions.FileSystem.Interface.dll",
|
||||
"WinUI3Apps\\Testably.Abstractions.FileSystem.Interface.dll",
|
||||
"ColorCode.Core.dll",
|
||||
"ColorCode.UWP.dll",
|
||||
|
||||
"UnitsNet.dll",
|
||||
"UtfUnknown.dll",
|
||||
"Wpf.Ui.dll"
|
||||
|
||||
@@ -32,22 +32,22 @@
|
||||
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
|
||||
<PackageVersion Include="MessagePack" Version="3.1.3" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.6" />
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.7" />
|
||||
<!-- Including Microsoft.Bcl.AsyncInterfaces to force version, since it's used by Microsoft.SemanticKernel. -->
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.6" />
|
||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.16" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.6" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.6" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.6" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.6" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.6" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.15.0" />
|
||||
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
|
||||
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
|
||||
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
|
||||
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.6" />
|
||||
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
|
||||
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.6" />
|
||||
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.7" />
|
||||
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.3.183" />
|
||||
<!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll at the same version contained inside the NET SDK we're currently building on CI. -->
|
||||
<!--
|
||||
@@ -75,28 +75,28 @@
|
||||
<PackageVersion Include="StreamJsonRpc" Version="2.21.69" />
|
||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
|
||||
<!-- Package System.CodeDom added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Management but the 8.0.1 version wasn't published to nuget. -->
|
||||
<PackageVersion Include="System.CodeDom" Version="9.0.6" />
|
||||
<PackageVersion Include="System.CodeDom" Version="9.0.7" />
|
||||
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
|
||||
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.6" />
|
||||
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.6" />
|
||||
<PackageVersion Include="System.Data.OleDb" Version="9.0.6" />
|
||||
<PackageVersion Include="System.ComponentModel.Composition" Version="9.0.7" />
|
||||
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.7" />
|
||||
<PackageVersion Include="System.Data.OleDb" Version="9.0.7" />
|
||||
<!-- Package System.Data.SqlClient added to force it as a dependency of Microsoft.Windows.Compatibility to the latest version available at this time. -->
|
||||
<PackageVersion Include="System.Data.SqlClient" Version="4.9.0" />
|
||||
<!-- Package System.Diagnostics.EventLog added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Data.OleDb but the 8.0.1 version wasn't published to nuget. -->
|
||||
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.6" />
|
||||
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.7" />
|
||||
<!-- Package System.Diagnostics.PerformanceCounter added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.11. -->
|
||||
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.6" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="9.0.6" />
|
||||
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.7" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="9.0.7" />
|
||||
<PackageVersion Include="System.IO.Abstractions" Version="22.0.13" />
|
||||
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="22.0.13" />
|
||||
<PackageVersion Include="System.Management" Version="9.0.6" />
|
||||
<PackageVersion Include="System.Management" Version="9.0.7" />
|
||||
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
|
||||
<PackageVersion Include="System.Reactive" Version="6.0.1" />
|
||||
<PackageVersion Include="System.Runtime.Caching" Version="9.0.6" />
|
||||
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.6" />
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.6" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.6" />
|
||||
<PackageVersion Include="System.Runtime.Caching" Version="9.0.7" />
|
||||
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.7" />
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.7" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.7" />
|
||||
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageVersion Include="UnicodeInformation" Version="2.6.0" />
|
||||
<PackageVersion Include="UnitsNet" Version="5.56.0" />
|
||||
|
||||
42
NOTICE.md
42
NOTICE.md
@@ -1517,23 +1517,23 @@ SOFTWARE.
|
||||
- Mages 3.0.0
|
||||
- Markdig.Signed 0.34.0
|
||||
- MessagePack 3.1.3
|
||||
- Microsoft.Bcl.AsyncInterfaces 9.0.6
|
||||
- Microsoft.Bcl.AsyncInterfaces 9.0.7
|
||||
- Microsoft.Bot.AdaptiveExpressions.Core 4.23.0
|
||||
- Microsoft.CodeAnalysis.NetAnalyzers 9.0.0
|
||||
- Microsoft.Data.Sqlite 9.0.6
|
||||
- Microsoft.Data.Sqlite 9.0.7
|
||||
- Microsoft.Diagnostics.Tracing.TraceEvent 3.1.16
|
||||
- Microsoft.DotNet.ILCompiler (A)
|
||||
- Microsoft.Extensions.DependencyInjection 9.0.6
|
||||
- Microsoft.Extensions.Hosting 9.0.6
|
||||
- Microsoft.Extensions.Hosting.WindowsServices 9.0.6
|
||||
- Microsoft.Extensions.Logging 9.0.6
|
||||
- Microsoft.Extensions.Logging.Abstractions 9.0.6
|
||||
- Microsoft.Extensions.DependencyInjection 9.0.7
|
||||
- Microsoft.Extensions.Hosting 9.0.7
|
||||
- Microsoft.Extensions.Hosting.WindowsServices 9.0.7
|
||||
- Microsoft.Extensions.Logging 9.0.7
|
||||
- Microsoft.Extensions.Logging.Abstractions 9.0.7
|
||||
- Microsoft.NET.ILLink.Tasks (A)
|
||||
- Microsoft.SemanticKernel 1.15.0
|
||||
- Microsoft.Toolkit.Uwp.Notifications 7.1.2
|
||||
- Microsoft.Web.WebView2 1.0.2903.40
|
||||
- Microsoft.Win32.SystemEvents 9.0.6
|
||||
- Microsoft.Windows.Compatibility 9.0.6
|
||||
- Microsoft.Win32.SystemEvents 9.0.7
|
||||
- Microsoft.Windows.Compatibility 9.0.7
|
||||
- Microsoft.Windows.CsWin32 0.3.183
|
||||
- Microsoft.Windows.CsWinRT 2.2.0
|
||||
- Microsoft.Windows.SDK.BuildTools 10.0.26100.4188
|
||||
@@ -1553,25 +1553,25 @@ SOFTWARE.
|
||||
- SkiaSharp.Views.WinUI 2.88.9
|
||||
- StreamJsonRpc 2.21.69
|
||||
- StyleCop.Analyzers 1.2.0-beta.556
|
||||
- System.CodeDom 9.0.6
|
||||
- System.CodeDom 9.0.7
|
||||
- System.CommandLine 2.0.0-beta4.22272.1
|
||||
- System.ComponentModel.Composition 9.0.6
|
||||
- System.Configuration.ConfigurationManager 9.0.6
|
||||
- System.Data.OleDb 9.0.6
|
||||
- System.ComponentModel.Composition 9.0.7
|
||||
- System.Configuration.ConfigurationManager 9.0.7
|
||||
- System.Data.OleDb 9.0.7
|
||||
- System.Data.SqlClient 4.9.0
|
||||
- System.Diagnostics.EventLog 9.0.6
|
||||
- System.Diagnostics.PerformanceCounter 9.0.6
|
||||
- System.Drawing.Common 9.0.6
|
||||
- System.Diagnostics.EventLog 9.0.7
|
||||
- System.Diagnostics.PerformanceCounter 9.0.7
|
||||
- System.Drawing.Common 9.0.7
|
||||
- System.IO.Abstractions 22.0.13
|
||||
- System.IO.Abstractions.TestingHelpers 22.0.13
|
||||
- System.Management 9.0.6
|
||||
- System.Management 9.0.7
|
||||
- System.Net.Http 4.3.4
|
||||
- System.Private.Uri 4.3.2
|
||||
- System.Reactive 6.0.1
|
||||
- System.Runtime.Caching 9.0.6
|
||||
- System.ServiceProcess.ServiceController 9.0.6
|
||||
- System.Text.Encoding.CodePages 9.0.6
|
||||
- System.Text.Json 9.0.6
|
||||
- System.Runtime.Caching 9.0.7
|
||||
- System.ServiceProcess.ServiceController 9.0.7
|
||||
- System.Text.Encoding.CodePages 9.0.7
|
||||
- System.Text.Json 9.0.7
|
||||
- System.Text.RegularExpressions 4.3.1
|
||||
- UnicodeInformation 2.6.0
|
||||
- UnitsNet 5.56.0
|
||||
|
||||
234
README.md
234
README.md
@@ -35,19 +35,19 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
Go to the [Microsoft PowerToys GitHub releases page][github-release-link] and click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user.
|
||||
|
||||
<!-- items that need to be updated release to release -->
|
||||
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.92%22
|
||||
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.91%22
|
||||
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.91.1/PowerToysUserSetup-0.91.1-x64.exe
|
||||
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.91.1/PowerToysUserSetup-0.91.1-arm64.exe
|
||||
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.91.1/PowerToysSetup-0.91.1-x64.exe
|
||||
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.91.1/PowerToysSetup-0.91.1-arm64.exe
|
||||
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.93%22
|
||||
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.92%22
|
||||
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.92.0/PowerToysUserSetup-0.92.0-x64.exe
|
||||
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.92.0/PowerToysUserSetup-0.92.0-arm64.exe
|
||||
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.92.0/PowerToysSetup-0.92.0-x64.exe
|
||||
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.92.0/PowerToysSetup-0.92.0-arm64.exe
|
||||
|
||||
| Description | Filename | sha256 hash |
|
||||
|----------------|----------|-------------|
|
||||
| Per user - x64 | [PowerToysUserSetup-0.91.1-x64.exe][ptUserX64] | 42EA4A3E8C79A5456476D19E72B3E2AB9393A89C4DC7442EB7EE5A1E3490D38A |
|
||||
| Per user - ARM64 | [PowerToysUserSetup-0.91.1-arm64.exe][ptUserArm64] | F3F433FE04049F9197411D792AADEBF34E3BE7FE16327BD8B73D2A046ED8BAF6 |
|
||||
| Machine wide - x64 | [PowerToysSetup-0.91.1-x64.exe][ptMachineX64] | EC4BC3A8625775866B0ED4577CCF83E6EC7B1A0AD267379DDBAF4FE49C7B5BDD |
|
||||
| Machine wide - ARM64 | [PowerToysSetup-0.91.1-arm64.exe][ptMachineArm64] | 9CB8911008420D0E446AE3D5CE365E447FA4DF9DCF9337F3A80F933C00FC3689 |
|
||||
| Description | Filename |
|
||||
|----------------|----------|
|
||||
| Per user - x64 | [PowerToysUserSetup-0.92.0-x64.exe][ptUserX64] |
|
||||
| Per user - ARM64 | [PowerToysUserSetup-0.92.0-arm64.exe][ptUserArm64] |
|
||||
| Machine wide - x64 | [PowerToysSetup-0.92.0-x64.exe][ptMachineX64] |
|
||||
| Machine wide - ARM64 | [PowerToysSetup-0.92.0-arm64.exe][ptMachineArm64] |
|
||||
|
||||
This is our preferred method.
|
||||
|
||||
@@ -85,7 +85,7 @@ We ask that **before you start work on a feature that you would like to contribu
|
||||
|
||||
Most contributions require you to agree to a [Contributor License Agreement (CLA)][oss-CLA] declaring that you grant us the rights to use your contribution and that you have permission to do so.
|
||||
|
||||
For guidance on developing for PowerToys, please read the [developer docs](/doc/devdocs) for a detailed breakdown. This includes how to setup your computer to compile.
|
||||
For guidance on developing for PowerToys, please read the [developer docs](./doc/devdocs) for a detailed breakdown. This includes how to setup your computer to compile.
|
||||
|
||||
## What's Happening
|
||||
|
||||
@@ -93,166 +93,138 @@ For guidance on developing for PowerToys, please read the [developer docs](/doc/
|
||||
|
||||
Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on.
|
||||
|
||||
### 0.91 - May 2025 Update
|
||||
### 0.92 - June 2025 Update
|
||||
|
||||
In this release, we focused on new features, stability, and automation.
|
||||
In this release, we focused on new features, stability, optimization improvements, and automation.
|
||||
|
||||
**✨Highlights**
|
||||
|
||||
- We focused on greatly improving the Command Palette's performance and fixing a large number of bugs. Some new features we've added are:
|
||||
- Added the ability for Command Palette to search any file using a fallback command.
|
||||
- Added the ability to make the Command Palette global hotkey a low-level keyboard hook.
|
||||
- Added open URL fallback command for the WebSearch extension, enabling users to directly open URLs in the browser from Command Palette.
|
||||
- You can now define custom formats in the Date and Time plugins of PT Run and Command Palette. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
|
||||
### Advanced Paste
|
||||
|
||||
- Fixed an issue where Advanced Paste failed to create the OCR engine for certain English language tags (e.g., en-CA) by initializing the OCR engine with the user profile language. Thanks [@cryolithic](https://github.com/cryolithic)!
|
||||
- PowerToys settings now has a toggle for the system tray icon, giving users control over its visibility based on personal preference. Thanks [@BLM16](https://github.com/BLM16)!
|
||||
- Command Palette now has Ahead-of-Time ([AOT](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot)) compatibility for all first-party extensions, improved extensibility, and core UX fixes, resulting in better performance and stability across commands.
|
||||
- Color Picker now has customizable mouse button actions, enabling more personalized workflows by assigning functions to left, right, and middle clicks. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
- Bug Report Tool now has a faster and clearer reporting process, with progress indicators, improved compression, auto-cleanup of old trace logs, and inclusion of MSIX installer logs for more efficient diagnostics.
|
||||
- File Explorer add-ons now have improved rendering stability, resolving issues with PDF previews, blank thumbnails, and text file crashes during file browsing.
|
||||
|
||||
### Color Picker
|
||||
|
||||
- Fixed an issue where a resource leak caused hangs or crashes by properly disposing of the Graphics object. Thanks [@dcog989](https://github.com/dcog989)!
|
||||
- Fixed an issue where Color Picker exited on Backspace keypress by ensuring it only closes when focused and aligning Escape/Backspace behavior. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
- Added support for Oklab and Oklch color formats in Color Picker. Thanks [@lemonyte](https://github.com/lemonyte)!
|
||||
- Added mouse button actions so you can choose what left, right, or middle click does. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
|
||||
### Command Not Found
|
||||
### Crop & Lock
|
||||
|
||||
- Updated the WinGet Command Not Found script to only enable the experimental features if they exist.
|
||||
- Aligned window styling with current Windows theme for a cleaner look. Thanks [@sadirano](https://github.com/sadirano)!
|
||||
|
||||
### Command Palette
|
||||
|
||||
- Updated bug template to include Command Palette module.
|
||||
- Fixed an issue where the toast window was not scaled for DPI, causing layout issues under display scaling.
|
||||
- Fixed an issue where Up/Down keyboard navigation didn't move selection when the caret was at position 0, and added continuous navigation like PT Run v1. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Updated the Time and Date extension code to simplify it and improve clarity.
|
||||
- Fixed an issue where capitalization in the command causes failure when trying to go to the mouse pointer, resolved by adjusting the command to lowercase.
|
||||
- Added open URL fallback command for the WebSearch extension, enabling users to directly open URLs in the browser from the Command Palette. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Added setting to enable/disable system tray icon in CmdPal and aligned terminology with Windows 11. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Fixed an alias update issue by removing the old alias when a new one is set.
|
||||
- Resolved GitHub casing conflict by migrating Exts and exts into a new ext directory, ensuring consistent structure across platforms and preventing path fragmentation.
|
||||
- Fix an issue where the 'Create New Extension' command generated empty file names.
|
||||
- Added the ability to make the global hotkey a low-level keyboard hook.
|
||||
- Added support for JUMBO thumbnails, enabling access to high-resolution icons.
|
||||
- Fixed crashes when CmdPal auto-hid itself while an MSAL dialog was opened, by preventing CmdPal from hiding if it's disabled.
|
||||
- Added support for immediately selecting search text when a page is loaded.
|
||||
- Fixed a bug where extension settings pages failed to reload on reopen by updating the settings form when extension settings are saved.
|
||||
- Fixed an issue where the Command Palette failed to launch from the runner.
|
||||
- Refactored and ported the PowerToys Run v1 calculator logic into Command Palette, added settings support, and improved fallback behavior.
|
||||
- Re-added support for list item keyboard shortcuts.
|
||||
- Enhanced accessibility in Command Palette by adding proper labels, refining animations, improving localization, and fixed a11y related issues.
|
||||
- Ported custom format support to the Time and Date plugin, reordered and cleaned up settings, improved error messaging, and fixed edge-case crashes for more robust and user-friendly behavior. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Added fallback item for system command.
|
||||
- Fixed a bug in Windows System Command where the key prompt incorrectly displayed "Empty" for the "Open Recycle Bin" action. Thanks [@jironemo](https://github.com/jironemo)!
|
||||
- Fixed an issue where the 'more commands' list showed commands that shouldn't be visible. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Fixed an issue where the details view in Command Palette displayed an oversized icon and misaligned text, aligning it with Windows Search behavior.
|
||||
- Fixed a bug where empty screen content and command bar commands were cut off when using long labels, ensuring proper layout and visibility.
|
||||
- Improved CmdPal’s WinGet integration by fixing version display for installed packages, enabling updates with icons, and migrating the preview winget API to a stable version.
|
||||
- Fixed a bug where commands for ContentPage didn't update until after exit, by ensuring context menus are fully initialized when they change.
|
||||
- Added fallback support to the TimeDate extension, enabling direct date/time queries without pre-selecting the command.
|
||||
- Added import of Common.Dotnet.AotCompatibility.props across multiple CmdPal project files to enhance AOT compilation support.
|
||||
- Fixed a crash in CmdPal settings caused by a null HotKey when settings.json is missing or lacks a defined hotkey. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Added support for filterable, nested context menus in CmdPal, including a search box to maintain focus behavior.
|
||||
- Refactored CmdPal classes to improve JSON serialization and introduced new serialization contexts for better performance and maintainability.
|
||||
- Added support for ahead-of-time (AoT) compilation.
|
||||
- Added retry mechanism for CmdPal launch.
|
||||
- Removed some unused files from CmdPal.Common to simplify the codebase and facilitate marking it as AoT-compatible.
|
||||
- Fixed a bug where a race condition in the update of SearchText caused the cursor in the input box to automatically jump to the end of the line, ensuring SearchText is only updated after it has actually been changed.
|
||||
- Added support for searching any file in the fallback command.
|
||||
- Cleaned up AoT-related code to prevent duplicate operations during testing.
|
||||
- Reduced CmdPal load time by parallelizing extension startup and adding timeouts to prevent misbehaving extensions from blocking others.
|
||||
- Enhanced UI behavior by dismissing the details pane when the list gets emptied, avoiding inconsistent visual states.
|
||||
- Added support to unset the fallback command in CmdPal when no matching command is found, ensuring cleaner reload behavior.
|
||||
- Fixed a leak in the CmdPal extension template by addressing improper ComServer use.
|
||||
- Prevented CmdPal window from maximizing on title bar double-click to maintain intended window behavior. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Fixed an issue where the Settings UI launched too small by making window dimensions DPI-aware and enforcing minimum width and height using WinUIEx.
|
||||
- Fixed white flash and one-time animation issues in CmdPal by cloaking the window instead of hiding it.
|
||||
- Fixed a bug where all extension settings were fetched on startup by lazy-loading extension settings, reducing initialization overhead.
|
||||
- Added support for protecting CmdPal from crashes on Adaptive Card parse failure.
|
||||
- Replaced shell:AppsFolder with URI activation in CmdPal to improve reliability.
|
||||
- Added ability to open CmdPal settings from PowerToys Settings.
|
||||
- Added ability for CmdPal to observe and dynamically update extension details by tracking property changes on the selected item.
|
||||
- Bumped the toolkit version used in the CmdPal extension template to 0.2.0.
|
||||
- Enhanced performance by resolving a regression in page loading.
|
||||
- Applied consistent hotkey handling across all Command Palette commands for a smoother user experience.
|
||||
- Improved graceful closing of Command Palette. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Fixed consistency issue for extensions' alias with "Direct" setting and enabled localization for "Direct" and "Indirect" for better user understanding. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Improved visual clarity by styling critical context items correctly.
|
||||
- Automatically focused the field when only one is present on the content page.
|
||||
- Improved stability and efficiency when loading file icons in SDK ThumbnailHelper.cs by removing unnecessary operations. Thanks [@OldUser101](https://github.com/OldUser101)!
|
||||
- Enhanced details view with commands implementation. (See [Extension sample](./src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleListPageWithDetails.cs))
|
||||
|
||||
### Image Resizer
|
||||
### Command Palette extensions
|
||||
|
||||
- Fixed an issue where deleting an Image Resizer preset removed the wrong preset.
|
||||
- Added "Copy Path" command to *App* search results for convenience. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
- Improved *Calculator* input experience by ignoring leading equal signs. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
- Corrected input handling in the *Calculator* extension to avoid showing errors for input with only leading whitespace.
|
||||
- Improved *New Extension* wizard by validating names to prevent namespace errors.
|
||||
- Ensured consistent context items display for the *Run* extension between fallback and top-level results.
|
||||
- Fixed missing *Time & Date* commands in fallback results. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Fixed outdated results in the *Time & Date* extension. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Fixed an issue where *Web Search* always opened Microsoft Edge instead of the user's default browser on Windows 11 24H2 and later. Thanks [@RuggMatt](https://github.com/RuggMatt)!
|
||||
- Improved ordering of *Windows Settings* extension search results from alphabetical to relevance-based for quicker access.
|
||||
- Added "Restart Windows Explorer" command to the *Windows System Commands* provider for gracefully terminate and relaunch explorer.exe. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
|
||||
### Keyboard Manager
|
||||
### Command Palette Ahead-of-Time (AOT) readiness
|
||||
|
||||
- Fixed an issue where a modifier key, when set without specifying left or right, would get stuck due to incorrect key handling by tracking the pressed keys and sending the correct key accordingly. Thanks [@mantaionut](https://github.com/mantaionut)!
|
||||
- We’ve made foundational changes to prepare the Command Palette for future Ahead-of-Time (AOT) publishing. This includes replacing the calculator library with ExprTk, improving COM object handling, refining Win32 interop, and correcting trimming behavior—all to ensure compatibility, performance, and reliability under AOT constraints. All first-party extensions are now AOT-compatible. These improvements lay the groundwork for publishing Command Palette as an AOT application in the next release.
|
||||
- Special thanks to [@Sergio0694](https://github.com/Sergio0694) for guidance on making COM APIs AOT-compatible, [@jtschuster](https://github.com/jtschuster) for fixing COM object handling, [@ArashPartow](https://github.com/ArashPartow) from ExprTk for integration suggestions, and [@tian-lt](https://github.com/tian-lt) from the Windows Calculator team for valuable suggestion throughout the migration journey and review.
|
||||
- As part of the upcoming release, we’re also enabling AOT compatibility for key dependencies, including markdown rendering, Adaptive Cards, internal logging and telemetry library, and the core Command Palette UX.
|
||||
|
||||
### FancyZones
|
||||
|
||||
- Fixed DPI-scaling issues to ensure FancyZones Editor displays crisply on high-resolution monitors. Thanks [@HO-COOH](https://github.com/HO-COOH)! This inspired us a broader review across other PowerToys modules, leading to DPI display optimizations in Awake, Color Picker, PowerAccent, and more.
|
||||
|
||||
### File Explorer add-ons
|
||||
|
||||
- Fixed potential failures in PDF previewer and thumbnail generation, improving reliability when browsing PDF files. Thanks [@mohiuddin-khan-shiam](https://github.com/mohiuddin-khan-shiam)!
|
||||
- Prevented Monaco Preview Handler crash when opening UTF-8-BOM text files.
|
||||
|
||||
### Hosts File Editor
|
||||
|
||||
- Added an in-app *“Learn more”* link to warning dialogs for quick guidance. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
|
||||
### Mouse Without Borders
|
||||
|
||||
- Fixed firewall rule so MWB now accepts connections from IPs outside your local subnet.
|
||||
- Cleaned legacy logs to reduce disk usage and noise.
|
||||
|
||||
### Peek
|
||||
|
||||
- Updated QOI reader so 3-channel QOI images preview correctly in Peek and File Explorer. Thanks [@mbartlett21](https://github.com/mbartlett21)!
|
||||
- Added codec detection with a clear warning when a video can’t be previewed, along with a link to the Microsoft Store to download the required codec.
|
||||
|
||||
### PowerRename
|
||||
|
||||
- Enhanced PowerRename's time formatting capabilities by adding 12-hour time format patterns with AM/PM support. Thanks [@bitmap4](https://github.com/bitmap4)!
|
||||
- Added support for $YY-$MM-$DD in ModificationTime and AccessTime to enable flexible date-based renaming.
|
||||
|
||||
### PowerToys Run
|
||||
|
||||
- Added support for custom formats in the "Time and Date" plugin and improved error messages for invalid input formats. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Fix two crashes: one for WFT on very early dates and another for calculating the week of the month on very late dates (e.g., 31.12.9999), and reorder UI settings. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Fix an issue where capitalization in the command causes failure when trying to go to the mouse pointer, resolved by adjusting the command to lowercase.
|
||||
- Added version details to plugin error messages for 'Loading error' and 'Init error'. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Enhanced result model by adding support for preventing usage-based ordering, giving plugin developers greater control over sorting behavior. Thanks [@CoreyHayward](https://github.com/CoreyHayward) and [@htcfreek](https://github.com/htcfreek)!
|
||||
|
||||
### Quick Accent
|
||||
|
||||
- Updated the letter mapping in GetDefaultLetterKeyEPO, replacing "ǔ" with "ŭ" for the VK_U key to accurately reflect Esperanto phonetics. Thanks [@OlegKharchevkin](https://github.com/OlegKharchevkin)!
|
||||
- Fixed an issue where Quick Accent did not work properly when using the on-screen keyboard. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Suppressed error UI for known WPF-related crashes to reduce user confusion, while retaining diagnostic logging for analysis. This targets COMException 0xD0000701 and 0x80263001 caused by temporary DWM unavailability.
|
||||
|
||||
### Registry Preview
|
||||
|
||||
- Enhanced Registry Preview to support pasting registry keys and values without manually writing the file header, and added a new button for resetting the app. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Added "Extended data preview" via magnifier icon and context menu in the Data Grid, enabled easier inspection of complex registry types like REG_BINARY, REG_EXPAND_SZ, and REG_MULTI_SZ, etc. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Improved file-saving experience in Registry Preview by aligning with Notepad-like behavior, enhancing user prompts, error handling, and preventing crashes during unsaved or interrupted actions. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
|
||||
### Settings
|
||||
|
||||
- Fix an issue where the Settings app randomly showed a blank icon in the taskbar by deferring icon assignment until the window is activated.
|
||||
- Added the ability to maximize the "What's New" window for a more comfortable reading experience.
|
||||
- Added an option to hide or show the PowerToys system tray icon. Thanks [@BLM16](https://github.com/BLM16)!
|
||||
- Improved settings to show progress while a bug report package is being generated.
|
||||
|
||||
### Workspaces
|
||||
|
||||
- Fixed bugs where Steam games were not captured or launched correctly by updating window filtering and integrating Steam URL protocol handling.
|
||||
- Stored Workspaces icons in user AppData to ensure profile portability and prevent loss during temporary folder cleanup.
|
||||
- Enabled capture and launch of PWAs on non-default Edge or Chrome profiles, ensuring consistent behavior during creation and execution.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Added QuickNotes to the third-party plugins documentation for PowerToys Run. Thanks [@ruslanlap](https://github.com/ruslanlap)!
|
||||
- Added Weather and Pomodoro plugins to the PowerToys Run third-party plugin documentation. Thanks [@ruslanlap](https://github.com/ruslanlap)!
|
||||
- Added the Linear plugin to PowerToys Run's third-party plugin documentation. Thanks [@vednig](https://github.com/vednig)!
|
||||
- Fixed formatting issues in documentation files and updated contributor and team member information. Thanks [@DanielEScherzer](https://github.com/DanielEScherzer) and [@RokyZevon](https://github.com/RokyZevon)!
|
||||
- Added SpeedTest and Dictionary Definition to the third-party plugins documentation for PowerToys Run. Thanks [@ruslanlap](https://github.com/ruslanlap)!
|
||||
- Corrected sample links and typo in Command Palette documentation. Thanks [@daverayment](https://github.com/daverayment) and [@roycewilliams](https://github.com/roycewilliams)!
|
||||
|
||||
### Development
|
||||
|
||||
- Updated GitHub Action to install .NET 9 for MSStore release support.
|
||||
- Updated version placeholder in bug_report.yml to prevent incorrect v0.70.0 versioning in issue reports.
|
||||
- Updated GitHub Action to upgrade actions/setup-dotnet from version 3 to version 4 for MSStore release.
|
||||
- Added securityContext to WinGet configuration files, allowing invocation from user context and prompting a single UAC for elevated resources in a separate process. Thanks [@mdanish-kh](https://github.com/mdanish-kh)!
|
||||
- Changed log file extensions from .txt to .log to support proper file associations and tooling compatibility, and added logs for Workspace. Thanks [@benwa](https://github.com/benwa)!
|
||||
- Upgraded testing framework dependencies and aligned package versions across components.
|
||||
- Upgraded dependencies to fix vulnerabilities.
|
||||
- Enhanced repository security by pinning GitHub Actions and Docker tags to immutable full-length commits and integrating automated dependency vulnerability scanning via Dependency Review Workflow. Thanks [@Nick2bad4u](https://github.com/Nick2bad4u)!
|
||||
- Upgraded Boost dependencies to a newer version.
|
||||
- Upgraded toolkit to the latest version, suppressed AoT-related warnings.
|
||||
- Fixed an issue where missing signing for newly added files caused build failures.
|
||||
- Update release pipeline to prevent publishing private symbols for 100 years.
|
||||
- Introduced fuzzing for PowerRename to improve reliability and added setup guidance for extending fuzzing to other C++ modules.
|
||||
- Added centralized pre-creation of generated folders for all .csproj projects to prevent build failures.
|
||||
- Updated WinAppSDK to the latest 1.7 version.
|
||||
- Upgraded Boost dependencies to the latest version for the PowerRename Fuzzing project.
|
||||
- Updated the ADO area path in tsa.json to resolve TSA pipeline errors caused by a deprecated path.
|
||||
- Initiated AoT support for CmdPal with foundational work in progress.
|
||||
|
||||
### Tool/General
|
||||
- Updated .NET libraries to 9.0.6 for performance and security. Thanks [@snickler](https://github.com/snickler)!
|
||||
- Updated WinAppSDK to 1.7.2 for better stability and Windows support.
|
||||
- Introduced a one-step local build script that generates a signed installer, enhancing developer productivity.
|
||||
- Generated portable PDBs so cross-platform debuggers can read symbol files, improving debugging experience in VSCode and other tools.
|
||||
- Simplified WinGet configuration files by using the [Microsoft.Windows.Settings](https://www.powershellgallery.com/packages/Microsoft.Windows.Settings) module to enable Developer Mode. Thanks [@mdanish-kh](https://github.com/mdanish-kh)!
|
||||
- Adjusted build scripts for the latest Az.Accounts module to keep CI green.
|
||||
- Streamlined release pipeline by removing hard-coded telemetry version numbers, and unified Command Palette versioning with Windows Terminal's versioning method for consistent updates.
|
||||
- Enhanced the build validation step to show detailed differences between NOTICE.md and actual package dependencies and versions.
|
||||
- Improved spell-checking accuracy across the repo. Thanks [@rovercoder](https://github.com/rovercoder)!
|
||||
- Upgraded CI to TouchdownBuild v5 for faster pipelines.
|
||||
- Added context comments to *Resources.resw* to help translators.
|
||||
- Expanded fuzz testing coverage to include FancyZones.
|
||||
- Integrated all unit tests into the CI pipeline, increasing from ~3,000 to ~5,000 tests.
|
||||
- Enabled daily UI test automation on the main branch, now covering over 370 UI tests for end-to-end validation.
|
||||
- Newly added unit tests for WorkspacesLib to improve reliability and maintainability.
|
||||
|
||||
- Added support for automating bug report creation by generating a pre-filled GitHub issue URL with system and diagnostic information. Thanks [@donlaci](https://github.com/donlaci)!
|
||||
- Added scripts to locally build the installer, ensuring the CmdPal can also be launched in a local environment.
|
||||
- Removed export PFX logic to eliminate hardcoded password usage and resolve PSScriptAnalyzer security warning.
|
||||
- Added PowerShell script and CI integration to enforce consistent use of Common.Dotnet.CsWinRT.props across all C# projects under the src folder.
|
||||
|
||||
### What is being planned for version 0.92
|
||||
### General
|
||||
|
||||
For [v0.92][github-next-release-work], we'll work on the items below:
|
||||
- Updated bug report compression library (cziplib 0.3.3) for faster and more reliable package creation. Thanks [@Chubercik](https://github.com/Chubercik)!
|
||||
- Included App Installer (“AppX Deployment Server”) event logs in bug reports for more thorough diagnostics.
|
||||
|
||||
### What is being planned for version 0.93
|
||||
|
||||
For [v0.93][github-next-release-work], we'll work on the items below:
|
||||
|
||||
- Continued Command Palette polish
|
||||
- New UI Automation tests
|
||||
- New UI automation tests
|
||||
- Working on installer upgrades
|
||||
- Working on shortcut conflict detection
|
||||
- Upgrading Keyboard Manager's editor UI
|
||||
- Stability, bug fixes
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
## Localization on the pipeline (CDPX)
|
||||
[The localization step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L45-L52) is run on the pipeline before the solution is built. This step runs the [build-localization](https://github.com/microsoft/PowerToys/blob/main/.pipelines/build-localization.cmd) script, which generates resx files for all the projects with localization enabled using the `Localization.XLoc` package.
|
||||
|
||||
The [`Localization.XLoc`](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L24-L25) tool is run on the repo root, and it checks for all occurrences of `LocProject.json`. Each localized project has a `LocProject.json` file in the project root, which contains the location of the English resx file, list of languages for localization, and the output path where the localized resx files are to be copied to. In addition to this, some other parameters can be set, such as whether the language ID should be added as a folder in the file path or in the file name. When the CDPX pipeline is run, the localization team is notified of changes in the English resx files. For each project with localization enabled, a `loc` folder (see [this](https://github.com/microsoft/PowerToys/tree/main/src/modules/launcher/Microsoft.Launcher/loc) for example) is created in the same directory as the `LocProject.json` file. The folder contains language specific folders which in turn have a nested folder path equivalent to `OutputPath` in the `LocProject.json`. Each of these folders contain one `lcl` file. The `lcl` files contain the English resources along with their translation for that language. These are described in more detail in the [Lcl files section](#lcl-files). Once the `.resx` files are generated, they will be used during the `Build PowerToys` step for localized versions of the modules.
|
||||
The [`Localization.XLoc`](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/build-localization.cmd#L24-L25) tool is run on the repo root, and it checks for all occurrences of `LocProject.json`. Each localized project has a `LocProject.json` file in the project root, which contains the location of the English resx file, list of languages for localization, and the output path where the localized resx files are to be copied to. In addition to this, some other parameters can be set, such as whether the language ID should be added as a folder in the file path or in the file name. When the CDPX pipeline is run, the localization team is notified of changes in the English resx files. For each project with localization enabled, a `loc` folder (see [the loc folder in the Microsoft.Launcher module](https://github.com/microsoft/PowerToys/tree/main/src/modules/launcher/Microsoft.Launcher/loc) for example) is created in the same directory as the `LocProject.json` file. The folder contains language specific folders which in turn have a nested folder path equivalent to `OutputPath` in the `LocProject.json`. Each of these folders contain one `lcl` file. The `lcl` files contain the English resources along with their translation for that language. These are described in more detail in the [Lcl files section](#lcl-files). Once the `.resx` files are generated, they will be used during the `Build PowerToys` step for localized versions of the modules.
|
||||
|
||||
Since the localization script requires certain nuget packages, the [`restore-localization`](https://github.com/microsoft/PowerToys/blob/main/.pipelines/restore-localization.cmd) script is run before running `build-localization` to install all the required packages. This script must [run in the `restore` step](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L37-L39) of pipeline because [the host is network isolated](https://onebranch.visualstudio.com/Pipeline/_wiki/wikis/Pipeline.wiki/2066/Consuming-Packages-in-a-CDPx-Pipeline?anchor=overview) at the `build` step. The [Toolset package source](https://github.com/microsoft/PowerToys/blob/86d77103e9c69686c297490acb04775d43ef8b76/.pipelines/pipeline.user.windows.yml#L23) is used for this.
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ This document outlines the process for preparing and publishing PowerToys releas
|
||||
- Uses semantic versioning: `MAJOR.MINOR.PATCH`
|
||||
- MINOR version increases with regular releases (e.g., 0.89.0)
|
||||
- PATCH version increases for hotfixes (e.g., 0.87.0 → 0.87.1)
|
||||
- Each release version must be higher than the previous one for proper updating
|
||||
- Each release version must be greater than the previous one for proper updating
|
||||
|
||||
## Testing Process
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ The `OneFuzzConfig.json` file provides critical information for deploying fuzzin
|
||||
],
|
||||
"adoTemplate": [
|
||||
{
|
||||
"AssignedTo": "PowerToys@microsoft.com",
|
||||
"AssignedTo": "leilzh@microsoft.com",
|
||||
"jobNotificationEmail": "PowerToys@microsoft.com"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<?include $(sys.CURRENTDIR)\Common.wxi?>
|
||||
|
||||
<?define ImageResizerAssetsFiles=?>
|
||||
<?define ImageResizerAssetsFilesPath=$(var.BinDir)Assets\ImageResizer\?>
|
||||
<?define ImageResizerAssetsFilesPath=$(var.BinDir)WinUI3Apps\Assets\ImageResizer\?>
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="BaseApplicationsAssetsFolder">
|
||||
<DirectoryRef Id="WinUI3AppsAssetsFolder">
|
||||
<Directory Id="ImageResizerAssetsFolder" Name="ImageResizer" />
|
||||
</DirectoryRef>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
<Component Id="Module_ImageResizer_Registry" Win64="yes">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{51B4D7E5-7568-4234-B4BB-47FB3C016A69}\InprocServer32">
|
||||
<RegistryValue Value="[INSTALLFOLDER]PowerToys.ImageResizerExt.dll" Type="string" />
|
||||
<RegistryValue Value="[WinUI3AppsInstallFolder]PowerToys.ImageResizerExt.dll" Type="string" />
|
||||
<RegistryValue Name="ThreadingModel" Value="Apartment" Type="string" />
|
||||
</RegistryKey>
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="ImageResizer_$(var.IdSafeLanguage)_Component" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<File Id="ImageResizer_$(var.IdSafeLanguage)_File" Source="$(var.BinDir)\$(var.Language)\PowerToys.ImageResizer.resources.dll" />
|
||||
<File Id="ImageResizer_$(var.IdSafeLanguage)_File" Source="$(var.BinDir)\WinUI3Apps\$(var.Language)\PowerToys.ImageResizer.resources.dll" />
|
||||
</Component>
|
||||
<Component
|
||||
Id="ColorPicker_$(var.IdSafeLanguage)_Component"
|
||||
|
||||
@@ -179,7 +179,7 @@ Generate-FileList -fileDepsJson "" -fileListName HostsAssetsFiles -wxsFilePath $
|
||||
Generate-FileComponents -fileListName "HostsAssetsFiles" -wxsFilePath $PSScriptRoot\Hosts.wxs -regroot $registryroot
|
||||
|
||||
#ImageResizer
|
||||
Generate-FileList -fileDepsJson "" -fileListName ImageResizerAssetsFiles -wxsFilePath $PSScriptRoot\ImageResizer.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\Assets\ImageResizer"
|
||||
Generate-FileList -fileDepsJson "" -fileListName ImageResizerAssetsFiles -wxsFilePath $PSScriptRoot\ImageResizer.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\ImageResizer"
|
||||
Generate-FileComponents -fileListName "ImageResizerAssetsFiles" -wxsFilePath $PSScriptRoot\ImageResizer.wxs -regroot $registryroot
|
||||
|
||||
#New+
|
||||
|
||||
@@ -11,26 +11,35 @@ namespace Common.UI
|
||||
{
|
||||
public enum SettingsWindow
|
||||
{
|
||||
Overview = 0,
|
||||
Dashboard = 0,
|
||||
Overview,
|
||||
AlwaysOnTop,
|
||||
Awake,
|
||||
ColorPicker,
|
||||
CmdNotFound,
|
||||
FancyZones,
|
||||
FileLocksmith,
|
||||
Run,
|
||||
ImageResizer,
|
||||
KBM,
|
||||
MouseUtils,
|
||||
MouseWithoutBorders,
|
||||
Peek,
|
||||
PowerAccent,
|
||||
PowerLauncher,
|
||||
PowerPreview,
|
||||
PowerRename,
|
||||
FileExplorer,
|
||||
ShortcutGuide,
|
||||
Hosts,
|
||||
MeasureTool,
|
||||
PowerOCR,
|
||||
Workspaces,
|
||||
RegistryPreview,
|
||||
CropAndLock,
|
||||
EnvironmentVariables,
|
||||
Dashboard,
|
||||
AdvancedPaste,
|
||||
Workspaces,
|
||||
NewPlus,
|
||||
CmdPal,
|
||||
ZoomIt,
|
||||
}
|
||||
@@ -39,14 +48,22 @@ namespace Common.UI
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SettingsWindow.Dashboard:
|
||||
return "Dashboard";
|
||||
case SettingsWindow.Overview:
|
||||
return "Overview";
|
||||
case SettingsWindow.AlwaysOnTop:
|
||||
return "AlwaysOnTop";
|
||||
case SettingsWindow.Awake:
|
||||
return "Awake";
|
||||
case SettingsWindow.ColorPicker:
|
||||
return "ColorPicker";
|
||||
case SettingsWindow.CmdNotFound:
|
||||
return "CmdNotFound";
|
||||
case SettingsWindow.FancyZones:
|
||||
return "FancyZones";
|
||||
case SettingsWindow.FileLocksmith:
|
||||
return "FileLocksmith";
|
||||
case SettingsWindow.Run:
|
||||
return "Run";
|
||||
case SettingsWindow.ImageResizer:
|
||||
@@ -55,6 +72,16 @@ namespace Common.UI
|
||||
return "KBM";
|
||||
case SettingsWindow.MouseUtils:
|
||||
return "MouseUtils";
|
||||
case SettingsWindow.MouseWithoutBorders:
|
||||
return "MouseWithoutBorders";
|
||||
case SettingsWindow.Peek:
|
||||
return "Peek";
|
||||
case SettingsWindow.PowerAccent:
|
||||
return "PowerAccent";
|
||||
case SettingsWindow.PowerLauncher:
|
||||
return "PowerLauncher";
|
||||
case SettingsWindow.PowerPreview:
|
||||
return "PowerPreview";
|
||||
case SettingsWindow.PowerRename:
|
||||
return "PowerRename";
|
||||
case SettingsWindow.FileExplorer:
|
||||
@@ -67,18 +94,18 @@ namespace Common.UI
|
||||
return "MeasureTool";
|
||||
case SettingsWindow.PowerOCR:
|
||||
return "PowerOcr";
|
||||
case SettingsWindow.Workspaces:
|
||||
return "Workspaces";
|
||||
case SettingsWindow.RegistryPreview:
|
||||
return "RegistryPreview";
|
||||
case SettingsWindow.CropAndLock:
|
||||
return "CropAndLock";
|
||||
case SettingsWindow.EnvironmentVariables:
|
||||
return "EnvironmentVariables";
|
||||
case SettingsWindow.Dashboard:
|
||||
return "Dashboard";
|
||||
case SettingsWindow.AdvancedPaste:
|
||||
return "AdvancedPaste";
|
||||
case SettingsWindow.Workspaces:
|
||||
return "Workspaces";
|
||||
case SettingsWindow.NewPlus:
|
||||
return "NewPlus";
|
||||
case SettingsWindow.CmdPal:
|
||||
return "CmdPal";
|
||||
case SettingsWindow.ZoomIt:
|
||||
|
||||
@@ -21,7 +21,7 @@ public static partial class Kernel32
|
||||
out int pBytesReturned,
|
||||
IntPtr lpOverlapped);
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
|
||||
[LibraryImport("kernel32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16, EntryPoint = "CreateFileW")]
|
||||
public static partial int CreateFile(
|
||||
string lpFileName,
|
||||
FileAccessType dwDesiredAccess,
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Reflection;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OpenQA.Selenium.Appium;
|
||||
using OpenQA.Selenium.Appium.Windows;
|
||||
using static Microsoft.PowerToys.UITest.WindowHelper;
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
@@ -41,18 +42,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
this.locationPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
|
||||
CheckWinAppDriverAndRoot();
|
||||
|
||||
var runnerProcessInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = locationPath + this.runnerPath,
|
||||
Verb = "runas",
|
||||
};
|
||||
|
||||
if (scope == PowerToysModule.PowerToysSettings)
|
||||
{
|
||||
this.ExitExe(runnerProcessInfo.FileName);
|
||||
this.runner = Process.Start(runnerProcessInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -76,6 +65,7 @@ namespace Microsoft.PowerToys.UITest
|
||||
public SessionHelper Init()
|
||||
{
|
||||
this.ExitExe(this.locationPath + this.sessionPath);
|
||||
|
||||
this.StartExe(this.locationPath + this.sessionPath);
|
||||
|
||||
Assert.IsNotNull(this.Driver, $"Failed to initialize the test environment. Driver is null.");
|
||||
@@ -89,19 +79,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
public void Cleanup()
|
||||
{
|
||||
ExitScopeExe();
|
||||
try
|
||||
{
|
||||
if (this.scope == PowerToysModule.PowerToysSettings)
|
||||
{
|
||||
runner?.Kill();
|
||||
runner?.WaitForExit(); // Optional: Wait for the process to exit
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Handle exceptions if needed
|
||||
Debug.WriteLine($"Exception during Cleanup: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -135,10 +112,65 @@ namespace Microsoft.PowerToys.UITest
|
||||
public void StartExe(string appPath)
|
||||
{
|
||||
var opts = new AppiumOptions();
|
||||
opts.AddAdditionalCapability("app", appPath);
|
||||
|
||||
// if we want to start settings, we need to use the runner exe to open settings
|
||||
if (scope == PowerToysModule.PowerToysSettings)
|
||||
{
|
||||
TryLaunchPowerToysSettings(opts);
|
||||
}
|
||||
else
|
||||
{
|
||||
opts.AddAdditionalCapability("app", appPath);
|
||||
}
|
||||
|
||||
this.Driver = NewWindowsDriver(opts);
|
||||
}
|
||||
|
||||
private void TryLaunchPowerToysSettings(AppiumOptions opts)
|
||||
{
|
||||
CheckWinAppDriverAndRoot();
|
||||
|
||||
var runnerProcessInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = locationPath + this.runnerPath,
|
||||
Verb = "runas",
|
||||
Arguments = "--open-settings",
|
||||
};
|
||||
|
||||
this.ExitExe(runnerProcessInfo.FileName);
|
||||
this.runner = Process.Start(runnerProcessInfo);
|
||||
Thread.Sleep(5000);
|
||||
|
||||
if (root != null)
|
||||
{
|
||||
const int maxRetries = 3;
|
||||
const int delayMs = 5000;
|
||||
var windowName = "PowerToys Settings";
|
||||
|
||||
for (int attempt = 1; attempt <= maxRetries; attempt++)
|
||||
{
|
||||
var settingsWindow = ApiHelper.FindDesktopWindowHandler(
|
||||
new[] { windowName, AdministratorPrefix + windowName });
|
||||
|
||||
if (settingsWindow.Count > 0)
|
||||
{
|
||||
var hexHwnd = settingsWindow[0].HWnd.ToString("x");
|
||||
opts.AddAdditionalCapability("appTopLevelWindow", hexHwnd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (attempt < maxRetries)
|
||||
{
|
||||
Thread.Sleep(delayMs);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TimeoutException("Failed to find PowerToys Settings window after multiple attempts.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new exe and takes control of it.
|
||||
/// </summary>
|
||||
@@ -176,6 +208,19 @@ namespace Microsoft.PowerToys.UITest
|
||||
public void ExitScopeExe()
|
||||
{
|
||||
ExitExe(sessionPath);
|
||||
try
|
||||
{
|
||||
if (this.scope == PowerToysModule.PowerToysSettings)
|
||||
{
|
||||
runner?.Kill();
|
||||
runner?.WaitForExit(); // Optional: Wait for the process to exit
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Handle exceptions if needed
|
||||
Debug.WriteLine($"Exception during Cleanup: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,18 +4,9 @@
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Appium;
|
||||
using OpenQA.Selenium.Appium.Windows;
|
||||
using Windows.Devices.Display.Core;
|
||||
using Windows.Foundation.Metadata;
|
||||
using static Microsoft.PowerToys.UITest.UITestBase.NativeMethods;
|
||||
using static Microsoft.PowerToys.UITest.WindowHelper;
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
@@ -77,16 +68,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
|
||||
this.sessionHelper = new SessionHelper(scope).Init();
|
||||
this.Session = new Session(this.sessionHelper.GetRoot(), this.sessionHelper.GetDriver(), scope, size);
|
||||
|
||||
if (this.scope == PowerToysModule.PowerToysSettings)
|
||||
{
|
||||
// close Debug warning dialog if any
|
||||
// Such debug warning dialog seems only appear in PowerToys Settings
|
||||
if (this.FindAll("DEBUG").Count > 0)
|
||||
{
|
||||
this.Find("DEBUG").Find<Button>("Close").Click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
internal static class WindowHelper
|
||||
public static class WindowHelper
|
||||
{
|
||||
internal const string AdministratorPrefix = "Administrator: ";
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "PowerToys@microsoft.com",
|
||||
"AssignedTo": "leilzh@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SALT",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "PowerToys@microsoft.com",
|
||||
"AssignedTo": "leilzh@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SALT",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
@@ -57,7 +57,7 @@
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "PowerToys@microsoft.com",
|
||||
"AssignedTo": "leilzh@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SALT",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
@@ -98,7 +98,7 @@
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "PowerToys@microsoft.com",
|
||||
"AssignedTo": "leilzh@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SALT",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
@@ -139,7 +139,7 @@
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "PowerToys@microsoft.com",
|
||||
"AssignedTo": "leilzh@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SALT",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Page
|
||||
<Page
|
||||
x:Class="WorkspacesEditor.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -172,7 +172,7 @@
|
||||
VerticalContentAlignment="Stretch"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Visibility="{Binding IsWorkspacesViewEmpty, Mode=OneWay, Converter={StaticResource BooleanToInvertedVisibilityConverter}, UpdateSourceTrigger=PropertyChanged}">
|
||||
<ItemsControl ItemsSource="{Binding WorkspacesView, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
|
||||
<ItemsControl x:Name="WorkspacesItemsControl" ItemsSource="{Binding WorkspacesView, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel
|
||||
@@ -235,7 +235,10 @@
|
||||
Grid.Column="1"
|
||||
Margin="12,12,12,12"
|
||||
Orientation="Vertical">
|
||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<StackPanel
|
||||
x:Name="WorkspaceActionGroup"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="MoreButton"
|
||||
HorizontalAlignment="Right"
|
||||
@@ -248,7 +251,8 @@
|
||||
</Button>
|
||||
<Popup
|
||||
AllowsTransparency="True"
|
||||
IsOpen="{Binding IsPopupVisible, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Closed="PopupClosed"
|
||||
IsOpen="{Binding IsPopupVisible, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Placement="Left"
|
||||
PlacementTarget="{Binding ElementName=MoreButton}"
|
||||
StaysOpen="False">
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
using System.Windows.Controls.Primitives;
|
||||
using ManagedCommon;
|
||||
using WorkspacesEditor.Models;
|
||||
using WorkspacesEditor.ViewModels;
|
||||
|
||||
@@ -42,17 +43,28 @@ namespace WorkspacesEditor
|
||||
e.Handled = true;
|
||||
Button button = sender as Button;
|
||||
Project selectedProject = button.DataContext as Project;
|
||||
selectedProject.IsPopupVisible = false;
|
||||
|
||||
_mainViewModel.DeleteProject(selectedProject);
|
||||
}
|
||||
|
||||
private void MoreButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_mainViewModel.CloseAllPopups();
|
||||
e.Handled = true;
|
||||
Button button = sender as Button;
|
||||
Project project = button.DataContext as Project;
|
||||
project.IsPopupVisible = true;
|
||||
}
|
||||
|
||||
private void PopupClosed(object sender, object e)
|
||||
{
|
||||
if (sender is Popup p && p.DataContext is Project proj)
|
||||
{
|
||||
proj.IsPopupVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void LaunchButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
@@ -437,7 +437,11 @@ namespace WorkspacesEditor.ViewModels
|
||||
private void RunSnapshotTool(bool isExistingProjectLaunched)
|
||||
{
|
||||
Process process = new Process();
|
||||
process.StartInfo = new ProcessStartInfo(@".\PowerToys.WorkspacesSnapshotTool.exe");
|
||||
|
||||
var exeDir = Path.GetDirectoryName(Environment.ProcessPath);
|
||||
var snapshotUtilsPath = Path.Combine(exeDir, "PowerToys.WorkspacesSnapshotTool.exe");
|
||||
|
||||
process.StartInfo = new ProcessStartInfo(snapshotUtilsPath);
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
process.StartInfo.Arguments = isExistingProjectLaunched ? $"{(int)InvokePoint.LaunchAndEdit}" : string.Empty;
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
MouseLeave="AppBorder_MouseLeave">
|
||||
<Expander
|
||||
Margin="0,0,20,0"
|
||||
AutomationProperties.AutomationId="{Binding AppName}"
|
||||
AutomationProperties.Name="{Binding AppName}"
|
||||
FlowDirection="RightToLeft"
|
||||
IsEnabled="{Binding IsIncluded, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsExpanded="{Binding IsExpanded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
|
||||
@@ -399,7 +401,11 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ItemsControl ItemTemplateSelector="{StaticResource AppListDataTemplateSelector}" ItemsSource="{Binding ApplicationsListed, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ItemsControl
|
||||
x:Name="CapturedAppList"
|
||||
AutomationProperties.Name="Captured Application List"
|
||||
ItemTemplateSelector="{StaticResource AppListDataTemplateSelector}"
|
||||
ItemsSource="{Binding ApplicationsListed, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -0,0 +1,605 @@
|
||||
// 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.Diagnostics;
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace WorkspacesEditorUITest;
|
||||
|
||||
[TestClass]
|
||||
[Ignore("not stable")]
|
||||
public class WorkspacesEditingPageTests : WorkspacesUiAutomationBase
|
||||
{
|
||||
public WorkspacesEditingPageTests()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.RemoveApp")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestRemoveAppFromWorkspace()
|
||||
{
|
||||
// Find app list
|
||||
var appList = Find<Custom>("AppList");
|
||||
var initialAppCount = appList.FindAll<Custom>(By.ClassName("AppItem")).Count;
|
||||
|
||||
if (initialAppCount == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to remove");
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove first app
|
||||
var firstApp = appList.FindAll<Custom>(By.ClassName("AppItem"))[0];
|
||||
var appName = firstApp.GetAttribute("Name");
|
||||
|
||||
var removeButton = firstApp.Find<Button>("Remove");
|
||||
removeButton.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify app removed from list
|
||||
var finalAppCount = appList.FindAll<Custom>(By.ClassName("AppItem")).Count;
|
||||
Assert.AreEqual(initialAppCount - 1, finalAppCount, "App should be removed from list");
|
||||
|
||||
// Verify preview updated
|
||||
var previewPane = Find<Pane>("Preview");
|
||||
var windowPreviews = previewPane.FindAll<Custom>(By.ClassName("WindowPreview"));
|
||||
Assert.AreEqual(finalAppCount, windowPreviews.Count, "Preview should show correct number of windows");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.RemoveAndAddBackApp")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestRemoveAndAddBackApp()
|
||||
{
|
||||
// Find app list
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
if (apps.Count == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to test");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstApp = apps[0];
|
||||
var appName = firstApp.GetAttribute("Name");
|
||||
|
||||
// Remove app
|
||||
var removeButton = firstApp.Find<Button>("Remove");
|
||||
removeButton.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify removed app shows in "removed apps" section
|
||||
Assert.IsTrue(Has<Button>("Add back"), "Should have 'Add back' button for removed apps");
|
||||
|
||||
// Add back the app
|
||||
var addBackButton = Find<Button>("Add back");
|
||||
addBackButton.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify app is back in the list
|
||||
var restoredApp = appList.Find<Custom>(By.Name(appName), timeoutMS: 2000);
|
||||
Assert.IsNotNull(restoredApp, "App should be restored to the list");
|
||||
|
||||
// Verify preview updated
|
||||
var previewPane = Find<Pane>("Preview");
|
||||
var windowPreviews = previewPane.FindAll<Custom>(By.ClassName("WindowPreview"));
|
||||
var currentAppCount = appList.FindAll<Custom>(By.ClassName("AppItem")).Count;
|
||||
Assert.AreEqual(currentAppCount, windowPreviews.Count, "Preview should show all windows again");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.SetAppMinimized")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestSetAppMinimized()
|
||||
{
|
||||
// Find first app
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
if (apps.Count == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to test");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstApp = apps[0];
|
||||
|
||||
// Find and toggle minimized checkbox
|
||||
var minimizedCheckbox = firstApp.Find<CheckBox>("Minimized");
|
||||
bool wasMinimized = minimizedCheckbox.IsChecked;
|
||||
|
||||
minimizedCheckbox.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify state changed
|
||||
Assert.AreNotEqual(wasMinimized, minimizedCheckbox.IsChecked, "Minimized state should toggle");
|
||||
|
||||
// Verify preview reflects the change
|
||||
var previewPane = Find<Pane>("Preview");
|
||||
var windowPreviews = previewPane.FindAll<Custom>(By.ClassName("WindowPreview"));
|
||||
|
||||
// The first window preview should indicate minimized state
|
||||
if (minimizedCheckbox.IsChecked && windowPreviews.Count > 0)
|
||||
{
|
||||
var firstPreview = windowPreviews[0];
|
||||
var opacity = firstPreview.GetAttribute("Opacity");
|
||||
|
||||
// Minimized windows might have reduced opacity or other visual indicator
|
||||
Assert.IsNotNull(opacity, "Minimized window should have visual indication in preview");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.SetAppMaximized")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestSetAppMaximized()
|
||||
{
|
||||
// Find first app
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
if (apps.Count == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to test");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstApp = apps[0];
|
||||
|
||||
// Find and toggle maximized checkbox
|
||||
var maximizedCheckbox = firstApp.Find<CheckBox>("Maximized");
|
||||
bool wasMaximized = maximizedCheckbox.IsChecked;
|
||||
|
||||
maximizedCheckbox.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify state changed
|
||||
Assert.AreNotEqual(wasMaximized, maximizedCheckbox.IsChecked, "Maximized state should toggle");
|
||||
|
||||
// Verify preview reflects the change
|
||||
var previewPane = Find<Pane>("Preview");
|
||||
if (maximizedCheckbox.IsChecked)
|
||||
{
|
||||
// Maximized window should fill the preview area
|
||||
var windowPreviews = previewPane.FindAll<Custom>(By.ClassName("WindowPreview"));
|
||||
if (windowPreviews.Count > 0)
|
||||
{
|
||||
var firstPreview = windowPreviews[0];
|
||||
|
||||
// Check if preview shows maximized state
|
||||
var width = firstPreview.GetAttribute("Width");
|
||||
var height = firstPreview.GetAttribute("Height");
|
||||
Assert.IsNotNull(width, "Maximized window should have width in preview");
|
||||
Assert.IsNotNull(height, "Maximized window should have height in preview");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.LaunchAsAdmin")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestSetLaunchAsAdmin()
|
||||
{
|
||||
// Find app that supports admin launch
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
bool foundAdminCapableApp = false;
|
||||
foreach (var app in apps)
|
||||
{
|
||||
try
|
||||
{
|
||||
var adminCheckbox = app.Find<CheckBox>("Launch as admin", timeoutMS: 1000);
|
||||
if (adminCheckbox != null && adminCheckbox.IsChecked)
|
||||
{
|
||||
foundAdminCapableApp = true;
|
||||
bool wasAdmin = adminCheckbox.IsChecked;
|
||||
|
||||
adminCheckbox.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify state changed
|
||||
Assert.AreNotEqual(wasAdmin, adminCheckbox.IsChecked, "Admin launch state should toggle");
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// This app doesn't support admin launch
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundAdminCapableApp)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace support admin launch");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.AddCLIArgs")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestAddCommandLineArguments()
|
||||
{
|
||||
// Find first app
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
if (apps.Count == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to test");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstApp = apps[0];
|
||||
|
||||
// Find CLI args textbox
|
||||
var cliArgsTextBox = firstApp.Find<TextBox>("Command line arguments", timeoutMS: 2000);
|
||||
if (cliArgsTextBox == null)
|
||||
{
|
||||
Assert.Inconclusive("App does not support command line arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add test arguments
|
||||
string testArgs = "--test-arg value";
|
||||
cliArgsTextBox.SetText(testArgs);
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify arguments were entered
|
||||
Assert.AreEqual(testArgs, cliArgsTextBox.Text, "Command line arguments should be set");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.ChangeAppPosition")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestManuallyChangeAppPosition()
|
||||
{
|
||||
// Find first app
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
if (apps.Count == 0)
|
||||
{
|
||||
Assert.Inconclusive("No apps in workspace to test");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstApp = apps[0];
|
||||
|
||||
// Find position controls
|
||||
var xPositionBox = firstApp.Find<TextBox>("X position", timeoutMS: 2000);
|
||||
var yPositionBox = firstApp.Find<TextBox>("Y position", timeoutMS: 2000);
|
||||
|
||||
if (xPositionBox == null || yPositionBox == null)
|
||||
{
|
||||
// Try alternate approach with spinners
|
||||
var positionSpinners = firstApp.FindAll<Custom>(By.ClassName("SpinBox"));
|
||||
if (positionSpinners.Count >= 2)
|
||||
{
|
||||
xPositionBox = positionSpinners[0].Find<TextBox>(By.ClassName("TextBox"));
|
||||
yPositionBox = positionSpinners[1].Find<TextBox>(By.ClassName("TextBox"));
|
||||
}
|
||||
}
|
||||
|
||||
if (xPositionBox != null && yPositionBox != null)
|
||||
{
|
||||
// Change position
|
||||
xPositionBox.SetText("200");
|
||||
Thread.Sleep(500);
|
||||
|
||||
yPositionBox.SetText("150");
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Verify preview updated
|
||||
var previewPane = Find<Pane>("Preview");
|
||||
var windowPreviews = previewPane.FindAll<Custom>(By.ClassName("WindowPreview"));
|
||||
Assert.IsTrue(windowPreviews.Count > 0, "Preview should show window at new position");
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Inconclusive("Could not find position controls");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.ChangeWorkspaceName")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestChangeWorkspaceName()
|
||||
{
|
||||
// Find workspace name textbox
|
||||
var nameTextBox = Find<TextBox>("Workspace name");
|
||||
string originalName = nameTextBox.Text;
|
||||
|
||||
// Change name
|
||||
string newName = "Renamed_Workspace_" + DateTime.Now.Ticks;
|
||||
nameTextBox.SetText(newName);
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Save changes
|
||||
var saveButton = Find<Button>("Save");
|
||||
saveButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify we're back at main list
|
||||
Assert.IsTrue(Has<Custom>("WorkspacesList"), "Should return to main list after saving");
|
||||
|
||||
// Verify workspace was renamed
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var renamedWorkspace = workspacesList.Find<Custom>(By.Name(newName), timeoutMS: 2000);
|
||||
Assert.IsNotNull(renamedWorkspace, "Workspace should be renamed in the list");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.SaveAndCancelWork")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestSaveAndCancelButtons()
|
||||
{
|
||||
// Make a change
|
||||
var nameTextBox = Find<TextBox>("Workspace name");
|
||||
string originalName = nameTextBox.Text;
|
||||
string tempName = originalName + "_temp";
|
||||
|
||||
nameTextBox.SetText(tempName);
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Test Cancel button
|
||||
var cancelButton = Find<Button>("Cancel");
|
||||
cancelButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify returned to main list without saving
|
||||
Assert.IsTrue(Has<Custom>("WorkspacesList"), "Should return to main list");
|
||||
|
||||
// Go back to editing
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspace = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"))[0];
|
||||
workspace.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify name wasn't changed
|
||||
nameTextBox = Find<TextBox>("Workspace name");
|
||||
Assert.AreEqual(originalName, nameTextBox.Text, "Name should not be changed after cancel");
|
||||
|
||||
// Now test Save button
|
||||
nameTextBox.SetText(tempName);
|
||||
Thread.Sleep(500);
|
||||
|
||||
var saveButton = Find<Button>("Save");
|
||||
saveButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify saved
|
||||
workspacesList = Find<Custom>("WorkspacesList");
|
||||
var savedWorkspace = workspacesList.Find<Custom>(By.Name(tempName), timeoutMS: 2000);
|
||||
Assert.IsNotNull(savedWorkspace, "Workspace should be saved with new name");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.NavigateWithoutSaving")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestNavigateToMainPageWithoutSaving()
|
||||
{
|
||||
// Make a change
|
||||
var nameTextBox = Find<TextBox>("Workspace name");
|
||||
string originalName = nameTextBox.Text;
|
||||
|
||||
nameTextBox.SetText(originalName + "_unsaved");
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Click on "Workspaces" navigation/breadcrumb
|
||||
if (Has<NavigationViewItem>("Workspaces", timeoutMS: 1000))
|
||||
{
|
||||
var workspacesNav = Find<NavigationViewItem>("Workspaces");
|
||||
workspacesNav.Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
else if (Has<HyperlinkButton>("Workspaces", timeoutMS: 1000))
|
||||
{
|
||||
var workspacesBreadcrumb = Find<HyperlinkButton>("Workspaces");
|
||||
workspacesBreadcrumb.Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
// If there's a confirmation dialog, handle it
|
||||
if (Has<Button>("Discard", timeoutMS: 1000))
|
||||
{
|
||||
Find<Button>("Discard").Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Verify returned to main list
|
||||
Assert.IsTrue(Has<Custom>("WorkspacesList"), "Should return to main list");
|
||||
|
||||
// Verify changes weren't saved
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var unsavedWorkspace = workspacesList.Find<Custom>(By.Name(originalName + "_unsaved"), timeoutMS: 1000);
|
||||
Assert.IsNull(unsavedWorkspace, "Unsaved changes should not persist");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.CreateDesktopShortcut")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestCreateDesktopShortcut()
|
||||
{
|
||||
// Find desktop shortcut checkbox
|
||||
var shortcutCheckbox = Find<CheckBox>("Create desktop shortcut");
|
||||
|
||||
// Get desktop path
|
||||
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
|
||||
// Get workspace name to check for shortcut
|
||||
var nameTextBox = Find<TextBox>("Workspace name");
|
||||
string workspaceName = nameTextBox.Text;
|
||||
string shortcutPath = Path.Combine(desktopPath, $"{workspaceName}.lnk");
|
||||
|
||||
// Clean up any existing shortcut
|
||||
if (File.Exists(shortcutPath))
|
||||
{
|
||||
File.Delete(shortcutPath);
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Check the checkbox
|
||||
if (!shortcutCheckbox.IsChecked)
|
||||
{
|
||||
shortcutCheckbox.Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Save
|
||||
var saveButton = Find<Button>("Save");
|
||||
saveButton.Click();
|
||||
Thread.Sleep(2000); // Give time for shortcut creation
|
||||
|
||||
// Verify shortcut was created
|
||||
Assert.IsTrue(File.Exists(shortcutPath), "Desktop shortcut should be created");
|
||||
|
||||
// Clean up
|
||||
if (File.Exists(shortcutPath))
|
||||
{
|
||||
File.Delete(shortcutPath);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.DesktopShortcutState")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestDesktopShortcutCheckboxState()
|
||||
{
|
||||
// Get workspace name
|
||||
var nameTextBox = Find<TextBox>("Workspace name");
|
||||
string workspaceName = nameTextBox.Text;
|
||||
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
string shortcutPath = Path.Combine(desktopPath, $"{workspaceName}.lnk");
|
||||
|
||||
// Find checkbox
|
||||
var shortcutCheckbox = Find<CheckBox>("Create desktop shortcut");
|
||||
|
||||
// Test 1: When shortcut exists
|
||||
if (!File.Exists(shortcutPath))
|
||||
{
|
||||
// Create shortcut first
|
||||
if (!shortcutCheckbox.IsChecked)
|
||||
{
|
||||
shortcutCheckbox.Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
Find<Button>("Save").Click();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Navigate back to editing
|
||||
NavigateToEditingPage();
|
||||
}
|
||||
|
||||
shortcutCheckbox = Find<CheckBox>("Create desktop shortcut");
|
||||
Assert.IsTrue(shortcutCheckbox.IsChecked, "Checkbox should be checked when shortcut exists");
|
||||
|
||||
// Test 2: Remove shortcut
|
||||
if (File.Exists(shortcutPath))
|
||||
{
|
||||
File.Delete(shortcutPath);
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Re-navigate to refresh state
|
||||
Find<Button>("Cancel").Click();
|
||||
Thread.Sleep(1000);
|
||||
NavigateToEditingPage();
|
||||
|
||||
shortcutCheckbox = Find<CheckBox>("Create desktop shortcut");
|
||||
Assert.IsFalse(shortcutCheckbox.IsChecked, "Checkbox should be unchecked when shortcut doesn't exist");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditingPage.LaunchAndEdit")]
|
||||
[TestCategory("Workspaces Editing Page UI")]
|
||||
public void TestLaunchAndEditCapture()
|
||||
{
|
||||
// Find Launch and Edit button
|
||||
var launchEditButton = Find<Button>("Launch and Edit");
|
||||
launchEditButton.Click();
|
||||
Thread.Sleep(3000); // Wait for apps to launch
|
||||
|
||||
// Open a new application
|
||||
Process.Start("calc.exe");
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Click Capture
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Verify new app was added
|
||||
var appList = Find<Custom>("AppList");
|
||||
var apps = appList.FindAll<Custom>(By.ClassName("AppItem"));
|
||||
|
||||
bool foundCalculator = false;
|
||||
foreach (var app in apps)
|
||||
{
|
||||
var appName = app.GetAttribute("Name");
|
||||
if (appName.Contains("Calculator", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foundCalculator = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.IsTrue(foundCalculator, "Newly opened Calculator should be captured and added");
|
||||
|
||||
// Clean up
|
||||
foreach (var process in Process.GetProcessesByName("CalculatorApp"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
foreach (var process in Process.GetProcessesByName("Calculator"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
private void NavigateToEditingPage()
|
||||
{
|
||||
// Ensure we have at least one workspace
|
||||
if (!Has<Custom>("WorkspacesList", timeoutMS: 1000))
|
||||
{
|
||||
CreateTestWorkspace();
|
||||
}
|
||||
|
||||
// Click on first workspace to edit
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItems = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"));
|
||||
|
||||
if (workspaceItems.Count == 0)
|
||||
{
|
||||
CreateTestWorkspace();
|
||||
workspaceItems = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"));
|
||||
}
|
||||
|
||||
workspaceItems[0].Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
private void CreateTestWorkspace()
|
||||
{
|
||||
// Open a test app
|
||||
Process.Start("notepad.exe");
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Create workspace
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Capture
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Save with default name
|
||||
var saveButton = Find<Button>("Save");
|
||||
saveButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Close test app
|
||||
foreach (var process in Process.GetProcessesByName("notepad"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,10 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
namespace WorkspacesEditorUITest;
|
||||
|
||||
[TestClass]
|
||||
public class WorkspacesEditorTests : UITestBase
|
||||
public class WorkspacesEditorTests : WorkspacesUiAutomationBase
|
||||
{
|
||||
public WorkspacesEditorTests()
|
||||
: base(PowerToysModule.Workspaces, WindowSize.Medium)
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -21,4 +21,217 @@ public class WorkspacesEditorTests : UITestBase
|
||||
{
|
||||
Assert.IsTrue(this.Has<Button>("Create Workspace"), "Should have create workspace button");
|
||||
}
|
||||
|
||||
/*
|
||||
[TestMethod("WorkspacesEditor.Editor.NewWorkspaceAppearsInList")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestNewWorkspaceAppearsInListAfterCapture()
|
||||
{
|
||||
// Open test application
|
||||
OpenNotepad();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Create workspace
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Capture
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Save workspace
|
||||
var saveButton = Find<Button>("Save");
|
||||
saveButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify workspace appears in list
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItems = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"));
|
||||
Assert.IsTrue(workspaceItems.Count > 0, "New workspace should appear in the list");
|
||||
|
||||
CloseNotepad();
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.CancelCaptureDoesNotAddWorkspace")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestCancelCaptureDoesNotAddWorkspace()
|
||||
{
|
||||
// Count existing workspaces
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var initialCount = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem")).Count;
|
||||
|
||||
// Create workspace
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Cancel
|
||||
var cancelButton = Find<Button>("Cancel");
|
||||
cancelButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify count hasn't changed
|
||||
var finalCount = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem")).Count;
|
||||
Assert.AreEqual(initialCount, finalCount, "Workspace count should not change after canceling");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.SearchFiltersWorkspaces")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestSearchFiltersWorkspaces()
|
||||
{
|
||||
// Create test workspaces first
|
||||
CreateTestWorkspace("TestWorkspace1");
|
||||
CreateTestWorkspace("TestWorkspace2");
|
||||
CreateTestWorkspace("DifferentName");
|
||||
|
||||
// Find search box
|
||||
var searchBox = Find<TextBox>("Search");
|
||||
searchBox.SetText("TestWorkspace");
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify filtered results
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var visibleItems = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"));
|
||||
|
||||
// Should only show items matching "TestWorkspace"
|
||||
Assert.IsTrue(visibleItems.Count >= 2, "Should show at least 2 TestWorkspace items");
|
||||
|
||||
// Clear search
|
||||
searchBox.SetText(string.Empty);
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.SortByWorks")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestSortByFunctionality()
|
||||
{
|
||||
// Find sort dropdown
|
||||
var sortDropdown = Find<ComboBox>("SortBy");
|
||||
sortDropdown.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Select different sort options
|
||||
var sortOptions = FindAll<Custom>(By.ClassName("ComboBoxItem"));
|
||||
if (sortOptions.Count > 1)
|
||||
{
|
||||
sortOptions[1].Click(); // Select second option
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify list is updated (we can't easily verify sort order in UI tests)
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
Assert.IsNotNull(workspacesList, "Workspaces list should still be visible after sorting");
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.SortByPersists")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestSortByPersistsAfterRestart()
|
||||
{
|
||||
// Set sort option
|
||||
var sortDropdown = Find<ComboBox>("SortBy");
|
||||
sortDropdown.Click();
|
||||
Thread.Sleep(500);
|
||||
|
||||
var sortOptions = FindAll<Custom>(By.ClassName("ComboBoxItem"));
|
||||
string selectedOption = string.Empty;
|
||||
if (sortOptions.Count > 1)
|
||||
{
|
||||
sortOptions[1].Click(); // Select second option
|
||||
selectedOption = sortDropdown.Text;
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
// Restart editor
|
||||
RestartScopeExe();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Verify sort option persisted
|
||||
sortDropdown = Find<ComboBox>("SortBy");
|
||||
Assert.AreEqual(selectedOption, sortDropdown.Text, "Sort option should persist after restart");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.RemoveWorkspace")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestRemoveWorkspace()
|
||||
{
|
||||
// Create a test workspace
|
||||
CreateTestWorkspace("WorkspaceToRemove");
|
||||
|
||||
// Find the workspace in the list
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItem = workspacesList.Find<Custom>(By.Name("WorkspaceToRemove"));
|
||||
|
||||
// Click remove button
|
||||
var removeButton = workspaceItem.Find<Button>("Remove");
|
||||
removeButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Confirm removal if dialog appears
|
||||
if (Has<Button>("Yes"))
|
||||
{
|
||||
Find<Button>("Yes").Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
// Verify workspace is removed
|
||||
Assert.IsFalse(Has(By.Name("WorkspaceToRemove")), "Workspace should be removed from list");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.EditOpensEditingPage")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestEditOpensEditingPage()
|
||||
{
|
||||
// Create a test workspace if none exist
|
||||
if (!Has<Custom>("WorkspacesList"))
|
||||
{
|
||||
CreateTestWorkspace("TestWorkspace");
|
||||
}
|
||||
|
||||
// Find first workspace
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItem = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"))[0];
|
||||
|
||||
// Click edit button
|
||||
var editButton = workspaceItem.Find<Button>("Edit");
|
||||
editButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify editing page opened
|
||||
Assert.IsTrue(Has<Button>("Save"), "Should have Save button on editing page");
|
||||
Assert.IsTrue(Has<Button>("Cancel"), "Should have Cancel button on editing page");
|
||||
|
||||
// Go back
|
||||
Find<Button>("Cancel").Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Editor.ClickWorkspaceOpensEditingPage")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestClickWorkspaceOpensEditingPage()
|
||||
{
|
||||
// Create a test workspace if none exist
|
||||
if (!Has<Custom>("WorkspacesList"))
|
||||
{
|
||||
CreateTestWorkspace("TestWorkspace");
|
||||
}
|
||||
|
||||
// Find first workspace
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItem = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"))[0];
|
||||
|
||||
// Click on the workspace item itself
|
||||
workspaceItem.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify editing page opened
|
||||
Assert.IsTrue(Has<Button>("Save"), "Should have Save button on editing page");
|
||||
Assert.IsTrue(Has<Button>("Cancel"), "Should have Cancel button on editing page");
|
||||
|
||||
// Go back
|
||||
Find<Button>("Cancel").Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\UITestAutomation\UITestAutomation.csproj" />
|
||||
<ProjectReference Include="..\WorkspacesEditor\WorkspacesEditor.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
// 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 Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace WorkspacesEditorUITest;
|
||||
|
||||
[TestClass]
|
||||
[Ignore("NOT STABLE")]
|
||||
public class WorkspacesLauncherTest : WorkspacesUiAutomationBase
|
||||
{
|
||||
public WorkspacesLauncherTest()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Launcher.LaunchFromEditor")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestLaunchWorkspaceFromEditor()
|
||||
{
|
||||
ClearWorkspaces();
|
||||
var uuid = Guid.NewGuid().ToString("N").Substring(0, 8);
|
||||
CreateTestWorkspace(uuid);
|
||||
|
||||
CloseNotepad();
|
||||
|
||||
var launchButton = Find<Button>(By.Name("Launch"));
|
||||
launchButton.Click();
|
||||
|
||||
Task.Delay(2000).Wait();
|
||||
|
||||
var processes = System.Diagnostics.Process.GetProcessesByName("notepad");
|
||||
|
||||
Assert.IsTrue(processes?.Length > 0);
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Launcher.CancelLaunch")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestCancelLaunch()
|
||||
{
|
||||
// Create workspace with multiple apps
|
||||
CreateWorkspaceWithApps();
|
||||
|
||||
// Launch workspace
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItem = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"))[0];
|
||||
var launchButton = workspaceItem.Find<Button>("Launch");
|
||||
launchButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Cancel launch
|
||||
if (Has<Button>("Cancel launch"))
|
||||
{
|
||||
Find<Button>("Cancel launch").Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify launcher closed
|
||||
Assert.IsFalse(Has<Window>("Workspaces Launcher"), "Launcher window should close after cancel");
|
||||
}
|
||||
|
||||
// Close any apps that may have launched
|
||||
CloseTestApplications();
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesEditor.Launcher.DismissKeepsLaunching")]
|
||||
[TestCategory("Workspaces UI")]
|
||||
public void TestDismissKeepsAppsLaunching()
|
||||
{
|
||||
// Create workspace with apps
|
||||
CreateWorkspaceWithApps();
|
||||
|
||||
// Launch workspace
|
||||
var workspacesList = Find<Custom>("WorkspacesList");
|
||||
var workspaceItem = workspacesList.FindAll<Custom>(By.ClassName("WorkspaceItem"))[0];
|
||||
var launchButton = workspaceItem.Find<Button>("Launch");
|
||||
launchButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Dismiss launcher
|
||||
if (Has<Button>("Dismiss"))
|
||||
{
|
||||
Find<Button>("Dismiss").Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Verify launcher closed but apps continue launching
|
||||
Assert.IsFalse(Has<Window>("Workspaces Launcher"), "Launcher window should close after dismiss");
|
||||
|
||||
// Wait for apps to finish launching
|
||||
Thread.Sleep(3000);
|
||||
|
||||
// Verify apps launched (notepad should be open)
|
||||
Assert.IsTrue(WindowHelper.IsWindowOpen("Notepad"), "Apps should continue launching after dismiss");
|
||||
}
|
||||
|
||||
// Close launched apps
|
||||
CloseTestApplications();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
// 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 Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace WorkspacesEditorUITest;
|
||||
|
||||
[TestClass]
|
||||
public class WorkspacesSettingsTests : UITestBase
|
||||
{
|
||||
public WorkspacesSettingsTests()
|
||||
: base(PowerToysModule.PowerToysSettings, WindowSize.Medium)
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.LaunchFromSettings")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
public void TestLaunchEditorFromSettingsPage()
|
||||
{
|
||||
GoToSettingsPageAndEnable();
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.ActivationShortcut")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
public void TestActivationShortcutCustomization()
|
||||
{
|
||||
GoToSettingsPageAndEnable();
|
||||
|
||||
// Find the activation shortcut control
|
||||
var shortcutButton = Find<Button>("Activation shortcut");
|
||||
Assert.IsNotNull(shortcutButton, "Activation shortcut control should exist");
|
||||
|
||||
// Test customizing the shortcut
|
||||
shortcutButton.Click();
|
||||
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// Send new key combination (Win+Ctrl+W)
|
||||
SendKeys(Key.Win, Key.Ctrl, Key.W);
|
||||
|
||||
var saveButton = Find<Button>("Save");
|
||||
|
||||
Assert.IsNotNull(saveButton, "Save button should exist after editing shortcut");
|
||||
|
||||
saveButton.Click();
|
||||
|
||||
var helpText = shortcutButton.HelpText;
|
||||
Assert.AreEqual("Win + Ctrl + W", helpText, "Activation shortcut should be updated to Win + Ctrl + W");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.EnableToggle")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
public void TestEnableDisableModule()
|
||||
{
|
||||
GoToSettingsPageAndEnable();
|
||||
|
||||
// Find the enable toggle
|
||||
var enableToggle = Find<ToggleSwitch>("Enable Workspaces");
|
||||
Assert.IsNotNull(enableToggle, "Enable Workspaces toggle should exist");
|
||||
|
||||
Assert.IsTrue(enableToggle.IsOn, "Enable Workspaces toggle should be in the 'on' state");
|
||||
|
||||
// Toggle the state
|
||||
enableToggle.Click();
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
// Verify state changed
|
||||
Assert.IsFalse(enableToggle.IsOn, "Toggle state should change");
|
||||
|
||||
// Verify related controls are enabled/disabled accordingly
|
||||
var launchButton = Find<Button>("Launch editor");
|
||||
Assert.IsFalse(launchButton.Enabled, "Launch editor button should be disabled when module is disabled");
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.LaunchByActivationShortcut")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
[Ignore("Wait until settings & runner can be connected in framework")]
|
||||
public void TestLaunchEditorByActivationShortcut()
|
||||
{
|
||||
// Ensure module is enabled
|
||||
var enableToggle = Find<ToggleSwitch>("Enable Workspaces");
|
||||
if (!enableToggle.IsOn)
|
||||
{
|
||||
enableToggle.Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Close settings window to test shortcut
|
||||
ExitScopeExe();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Default shortcut is Win+Ctrl+`
|
||||
SendKeys(Key.Win, Key.Ctrl, Key.W);
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Verify editor opened
|
||||
Assert.IsTrue(WindowHelper.IsWindowOpen("Workspaces Editor"), "Workspaces Editor should open with activation shortcut");
|
||||
|
||||
// Reopen settings for next tests
|
||||
RestartScopeExe();
|
||||
NavigateToWorkspacesSettings();
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.DisableModuleNoLaunch")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
[Ignore("Wait until settings & runner can be connected in framework")]
|
||||
public void TestDisabledModuleDoesNotLaunchByShortcut()
|
||||
{
|
||||
// Disable the module
|
||||
var enableToggle = Find<ToggleSwitch>("Enable Workspaces");
|
||||
if (enableToggle.IsOn)
|
||||
{
|
||||
enableToggle.Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
// Close settings to test shortcut
|
||||
ExitScopeExe();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Try to launch with shortcut
|
||||
SendKeys(Key.Win, Key.Ctrl, Key.W);
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Verify editor did not open
|
||||
Assert.IsFalse(WindowHelper.IsWindowOpen("Workspaces Editor"), "Workspaces Editor should not open when module is disabled");
|
||||
|
||||
// Reopen settings and re-enable the module
|
||||
RestartScopeExe();
|
||||
NavigateToWorkspacesSettings();
|
||||
|
||||
enableToggle = Find<ToggleSwitch>("Enable Workspaces");
|
||||
if (!enableToggle.IsOn)
|
||||
{
|
||||
enableToggle.Click();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSettings.QuickAccessLaunch")]
|
||||
[TestCategory("Workspaces Settings UI")]
|
||||
[Ignore("Wait until tray icon supported is in framework")]
|
||||
public void TestLaunchFromQuickAccess()
|
||||
{
|
||||
// This test verifies the "quick access" mention in settings
|
||||
// Look for any quick access related UI elements
|
||||
var quickAccessInfo = FindAll(By.LinkText("quick access"));
|
||||
|
||||
if (quickAccessInfo.Count > 0)
|
||||
{
|
||||
Assert.IsTrue(quickAccessInfo.Count > 0, "Quick access information should be present in settings");
|
||||
}
|
||||
|
||||
// Note: Actual system tray/quick access interaction would require
|
||||
// more complex automation that might be platform-specific
|
||||
}
|
||||
|
||||
private void NavigateToWorkspacesSettings()
|
||||
{
|
||||
// Find and click Workspaces in the navigation
|
||||
var workspacesNavItem = Find<NavigationViewItem>("Workspaces");
|
||||
workspacesNavItem.Click();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
private void GoToSettingsPageAndEnable()
|
||||
{
|
||||
if (this.FindAll<NavigationViewItem>("Workspaces").Count == 0)
|
||||
{
|
||||
this.Find<NavigationViewItem>("Windowing & Layouts").Click();
|
||||
}
|
||||
|
||||
this.Find<NavigationViewItem>("Workspaces").Click();
|
||||
|
||||
var enableButton = this.Find<ToggleSwitch>("Enable Workspaces");
|
||||
Assert.IsNotNull(enableButton, "Enable Workspaces toggle should exist");
|
||||
|
||||
if (!enableButton.IsOn)
|
||||
{
|
||||
enableButton.Click();
|
||||
Task.Delay(500).Wait(); // Wait for the toggle animation and state change
|
||||
}
|
||||
|
||||
// Verify it's now enabled
|
||||
Assert.IsTrue(enableButton.IsOn, "Enable Workspaces toggle should be in the 'on' state");
|
||||
}
|
||||
|
||||
private void AttachWorkspacesEditor()
|
||||
{
|
||||
Task.Delay(200).Wait();
|
||||
this.Session.Attach(PowerToysModule.Workspaces);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// 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 Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using WorkspacesEditor.Utils;
|
||||
|
||||
namespace WorkspacesEditorUITest;
|
||||
|
||||
[TestClass]
|
||||
public class WorkspacesSnapshotTests : WorkspacesUiAutomationBase
|
||||
{
|
||||
public WorkspacesSnapshotTests()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSnapshot.CancelCapture")]
|
||||
[TestCategory("Workspaces Snapshot UI")]
|
||||
public void TestCaptureCancel()
|
||||
{
|
||||
AttachWorkspacesEditor();
|
||||
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
AttachSnapshotWindow();
|
||||
|
||||
var cancelButton = Find<Button>("Cancel");
|
||||
|
||||
Assert.IsNotNull(cancelButton, "Capture button should exist");
|
||||
|
||||
cancelButton.Click();
|
||||
}
|
||||
|
||||
[TestMethod("WorkspacesSnapshot.CapturePackagedApps")]
|
||||
[TestCategory("Workspaces Snapshot UI")]
|
||||
public void TestCapturePackagedApplications()
|
||||
{
|
||||
OpenCalculator();
|
||||
|
||||
// OpenWindowsSettings();
|
||||
Task.Delay(2000).Wait();
|
||||
|
||||
AttachWorkspacesEditor();
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
AttachSnapshotWindow();
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Task.Delay(3000).Wait();
|
||||
|
||||
// Verify captured windows by reading the temporary workspaces file as the ground truth.
|
||||
var editorIO = new WorkspacesEditorIO();
|
||||
var workspace = editorIO.ParseTempProject();
|
||||
|
||||
Assert.IsNotNull(workspace, "Workspace data should be deserialized.");
|
||||
Assert.IsNotNull(workspace.Applications, "Workspace should contain a list of apps.");
|
||||
|
||||
bool isCalculatorFound = workspace.Applications.Any(app => app.AppPath.Contains("Calculator", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// bool isSettingsFound = workspace.Applications.Any(app => app.AppPath.Contains("Settings", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.IsTrue(isCalculatorFound, "Calculator should be captured in the workspace data.");
|
||||
|
||||
// Assert.IsTrue(isSettingsFound, "Settings should be captured in the workspace data.");
|
||||
|
||||
// Cancel to clean up
|
||||
AttachWorkspacesEditor();
|
||||
Find<Button>("Cancel").Click();
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// Close test applications
|
||||
CloseCalculator();
|
||||
|
||||
// CloseWindowsSettings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
// 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.Diagnostics;
|
||||
using Microsoft.PowerToys.UITest;
|
||||
|
||||
namespace WorkspacesEditorUITest
|
||||
{
|
||||
public class WorkspacesUiAutomationBase : UITestBase
|
||||
{
|
||||
public WorkspacesUiAutomationBase()
|
||||
: base(PowerToysModule.Workspaces, WindowSize.Medium)
|
||||
{
|
||||
}
|
||||
|
||||
protected void CreateTestWorkspace(string name)
|
||||
{
|
||||
// Open notepad for capture
|
||||
OpenNotepad();
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// Create workspace
|
||||
AttachWorkspacesEditor();
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
// Capture
|
||||
AttachSnapshotWindow();
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Task.Delay(5000).Wait();
|
||||
|
||||
// Set name
|
||||
var nameTextBox = Find<TextBox>("EditNameTextBox");
|
||||
nameTextBox.SetText(name);
|
||||
|
||||
// Save
|
||||
Find<Button>("Save Workspace").Click();
|
||||
|
||||
// Close notepad
|
||||
CloseNotepad();
|
||||
}
|
||||
|
||||
// DO NOT USE UNTIL FRAMEWORK AVAILABLE, CAN'T FIND BUTTON FOR SECOND LOOP
|
||||
protected void ClearWorkspaces()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var root = Find<Element>(By.AccessibilityId("WorkspacesItemsControl"));
|
||||
var buttons = root.FindAll<Button>(By.AccessibilityId("MoreButton"));
|
||||
|
||||
Debug.WriteLine($"Found {buttons.Count} button");
|
||||
|
||||
var button = buttons[^1];
|
||||
|
||||
button.Click();
|
||||
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
var remove = Find<Button>(By.Name("Remove"));
|
||||
remove.Click();
|
||||
|
||||
Task.Delay(500).Wait();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.Message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void CreateWorkspaceWithApps()
|
||||
{
|
||||
// Open multiple test applications
|
||||
OpenTestApplications();
|
||||
Thread.Sleep(3000);
|
||||
|
||||
// Create workspace
|
||||
var createButton = Find<Button>("Create Workspace");
|
||||
createButton.Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Capture
|
||||
var captureButton = Find<Button>("Capture");
|
||||
captureButton.Click();
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// Save
|
||||
Find<Button>("Save").Click();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Close test applications
|
||||
CloseTestApplications();
|
||||
}
|
||||
|
||||
protected void OpenTestApplications()
|
||||
{
|
||||
OpenNotepad();
|
||||
|
||||
// Could add more applications here
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
protected void CloseTestApplications()
|
||||
{
|
||||
CloseNotepad();
|
||||
}
|
||||
|
||||
protected void CloseWorkspacesEditor()
|
||||
{
|
||||
// Find and close the Workspaces Editor window
|
||||
if (WindowHelper.IsWindowOpen("Workspaces Editor"))
|
||||
{
|
||||
var editorWindow = Find<Window>("Workspaces Editor");
|
||||
editorWindow.Close();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
protected void ResetShortcutToDefault(Custom shortcutControl)
|
||||
{
|
||||
// Right-click on the shortcut control to open context menu
|
||||
shortcutControl.Click(rightClick: true);
|
||||
Thread.Sleep(500);
|
||||
|
||||
// Look for a "Reset to default" or similar option in the context menu
|
||||
try
|
||||
{
|
||||
// Try to find various possible menu item texts for reset option
|
||||
var resetOption = Find("Reset to default");
|
||||
resetOption?.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// Try alternative text
|
||||
var resetOption = Find("Reset");
|
||||
resetOption?.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
// Try another alternative
|
||||
var resetOption = Find("Default");
|
||||
resetOption?.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If context menu doesn't have reset option, try keyboard shortcut
|
||||
// ESC to close any open menus first
|
||||
SendKeys(Key.Esc);
|
||||
Thread.Sleep(200);
|
||||
|
||||
// Click on the control and try to clear it with standard shortcuts
|
||||
shortcutControl.Click();
|
||||
Thread.Sleep(200);
|
||||
|
||||
// Try Ctrl+A to select all, then Delete to clear
|
||||
SendKeys(Key.Ctrl, Key.A);
|
||||
Thread.Sleep(100);
|
||||
SendKeys(Key.Delete);
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void OpenNotepad()
|
||||
{
|
||||
var process = System.Diagnostics.Process.Start("notepad.exe");
|
||||
Task.Delay(1000).Wait();
|
||||
}
|
||||
|
||||
protected void CloseNotepad()
|
||||
{
|
||||
var processes = System.Diagnostics.Process.GetProcessesByName("notepad");
|
||||
foreach (var process in processes)
|
||||
{
|
||||
try
|
||||
{
|
||||
process.Kill();
|
||||
process.WaitForExit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachPowertoySetting()
|
||||
{
|
||||
Task.Delay(200).Wait();
|
||||
this.Session.Attach(PowerToysModule.PowerToysSettings);
|
||||
}
|
||||
|
||||
protected void AttachWorkspacesEditor()
|
||||
{
|
||||
Task.Delay(200).Wait();
|
||||
this.Session.Attach(PowerToysModule.Workspaces);
|
||||
}
|
||||
|
||||
protected void AttachSnapshotWindow()
|
||||
{
|
||||
Task.Delay(5000).Wait();
|
||||
this.Session.Attach("Snapshot Creator");
|
||||
}
|
||||
|
||||
protected void OpenCalculator()
|
||||
{
|
||||
Process.Start("calc.exe");
|
||||
Task.Delay(1000).Wait();
|
||||
}
|
||||
|
||||
protected void CloseCalculator()
|
||||
{
|
||||
foreach (var process in Process.GetProcessesByName("CalculatorApp"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
foreach (var process in Process.GetProcessesByName("Calculator"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
|
||||
protected void OpenWindowsSettings()
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "ms-settings:",
|
||||
UseShellExecute = true,
|
||||
});
|
||||
Task.Delay(500).Wait();
|
||||
}
|
||||
|
||||
protected void CloseWindowsSettings()
|
||||
{
|
||||
foreach (var process in Process.GetProcessesByName("SystemSettings"))
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,6 @@
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250513003" />
|
||||
<PackageVersion Include="Shmuelie.WinRTServer" Version="2.1.1" />
|
||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.6" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.7" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -21,7 +21,7 @@ public partial class AppStateModel : ObservableObject
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// STATE HERE
|
||||
public RecentCommandsManager RecentCommands { get; private set; } = new();
|
||||
public RecentCommandsManager RecentCommands { get; set; } = new();
|
||||
|
||||
// END SETTINGS
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -32,22 +32,6 @@ internal sealed partial class NewExtensionForm : NewExtensionFormBase
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_page_title)}},
|
||||
"size": "large"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_page_text)}},
|
||||
"wrap": true
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_name_header)}},
|
||||
"weight": "bolder",
|
||||
"size": "default"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_name_description)}},
|
||||
"wrap": true
|
||||
},
|
||||
{
|
||||
"type": "Input.Text",
|
||||
"label": {{FormatJsonString(Properties.Resources.builtin_create_extension_name_label)}},
|
||||
@@ -59,14 +43,11 @@ internal sealed partial class NewExtensionForm : NewExtensionFormBase
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_display_name_header)}},
|
||||
"weight": "bolder",
|
||||
"size": "default"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_display_name_description)}},
|
||||
"wrap": true
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_name_description)}},
|
||||
"wrap": true,
|
||||
"size": "small",
|
||||
"isSubtle": true,
|
||||
"spacing": "none"
|
||||
},
|
||||
{
|
||||
"type": "Input.Text",
|
||||
@@ -74,18 +55,16 @@ internal sealed partial class NewExtensionForm : NewExtensionFormBase
|
||||
"isRequired": true,
|
||||
"errorMessage": {{FormatJsonString(Properties.Resources.builtin_create_extension_display_name_required)}},
|
||||
"id": "DisplayName",
|
||||
"placeholder": "My new extension"
|
||||
"placeholder": "My new extension",
|
||||
"spacing": "medium"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_directory_header)}},
|
||||
"weight": "bolder",
|
||||
"size": "default"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_directory_description)}},
|
||||
"wrap": true
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_display_name_description)}},
|
||||
"wrap": true,
|
||||
"size": "small",
|
||||
"isSubtle": true,
|
||||
"spacing": "none"
|
||||
},
|
||||
{
|
||||
"type": "Input.Text",
|
||||
@@ -93,7 +72,16 @@ internal sealed partial class NewExtensionForm : NewExtensionFormBase
|
||||
"isRequired": true,
|
||||
"errorMessage": {{FormatJsonString(Properties.Resources.builtin_create_extension_directory_required)}},
|
||||
"id": "OutputPath",
|
||||
"placeholder": "C:\\users\\me\\dev"
|
||||
"placeholder": "C:\\users\\me\\dev",
|
||||
"spacing": "medium"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": {{FormatJsonString(Properties.Resources.builtin_create_extension_directory_description)}},
|
||||
"wrap": true,
|
||||
"size": "small",
|
||||
"isSubtle": true,
|
||||
"spacing": "none"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Microsoft.CmdPal.UI.ViewModels.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Where should the new extension be created? This path will be created if it doesn't exist.
|
||||
/// Looks up a localized string similar to Select the folder where the new extension will be created. The path will be created if it doesn't exist..
|
||||
/// </summary>
|
||||
public static string builtin_create_extension_directory_description {
|
||||
get {
|
||||
@@ -78,15 +78,6 @@ namespace Microsoft.CmdPal.UI.ViewModels.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Output path.
|
||||
/// </summary>
|
||||
public static string builtin_create_extension_directory_header {
|
||||
get {
|
||||
return ResourceManager.GetString("builtin_create_extension_directory_header", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Output path.
|
||||
/// </summary>
|
||||
@@ -106,7 +97,7 @@ namespace Microsoft.CmdPal.UI.ViewModels.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The name of your extension as users will see it..
|
||||
/// Looks up a localized string similar to The name of the extension as it will appear to users..
|
||||
/// </summary>
|
||||
public static string builtin_create_extension_display_name_description {
|
||||
get {
|
||||
@@ -114,15 +105,6 @@ namespace Microsoft.CmdPal.UI.ViewModels.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Display name.
|
||||
/// </summary>
|
||||
public static string builtin_create_extension_display_name_header {
|
||||
get {
|
||||
return ResourceManager.GetString("builtin_create_extension_display_name_header", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Display name.
|
||||
/// </summary>
|
||||
@@ -151,7 +133,7 @@ namespace Microsoft.CmdPal.UI.ViewModels.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to This is the name of your new extension project. It should be a valid C# class name. Best practice is to also include the word 'Extension' in the name..
|
||||
/// Looks up a localized string similar to Enter a valid C# class name for the new extension project. It's recommended to include the word "Extension" in the name..
|
||||
/// </summary>
|
||||
public static string builtin_create_extension_name_description {
|
||||
get {
|
||||
@@ -159,15 +141,6 @@ namespace Microsoft.CmdPal.UI.ViewModels.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Extension name.
|
||||
/// </summary>
|
||||
public static string builtin_create_extension_name_header {
|
||||
get {
|
||||
return ResourceManager.GetString("builtin_create_extension_name_header", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Extension name.
|
||||
/// </summary>
|
||||
@@ -205,16 +178,7 @@ namespace Microsoft.CmdPal.UI.ViewModels.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use this page to create a new extension project..
|
||||
/// </summary>
|
||||
public static string builtin_create_extension_page_text {
|
||||
get {
|
||||
return ResourceManager.GetString("builtin_create_extension_page_text", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Create your new extension.
|
||||
/// Looks up a localized string similar to Create a new extension.
|
||||
/// </summary>
|
||||
public static string builtin_create_extension_page_title {
|
||||
get {
|
||||
|
||||
@@ -180,16 +180,10 @@
|
||||
<value>Once you're ready to test deploy the package locally with Visual Studio, then run the \"Reload\" command in the Command Palette to load your new extension.</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_page_title" xml:space="preserve">
|
||||
<value>Create your new extension</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_page_text" xml:space="preserve">
|
||||
<value>Use this page to create a new extension project.</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_name_header" xml:space="preserve">
|
||||
<value>Extension name</value>
|
||||
<value>Create a new extension</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_name_description" xml:space="preserve">
|
||||
<value>This is the name of your new extension project. It should be a valid C# class name. Best practice is to also include the word 'Extension' in the name.</value>
|
||||
<value>Enter a valid C# class name for the new extension project. It's recommended to include the word "Extension" in the name.</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_name_label" xml:space="preserve">
|
||||
<value>Extension name</value>
|
||||
@@ -197,11 +191,8 @@
|
||||
<data name="builtin_create_extension_name_required" xml:space="preserve">
|
||||
<value>Extension name is required and must be a valid C# identifier (start with a letter or underscore, followed by letters, numbers, or underscores)</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_display_name_header" xml:space="preserve">
|
||||
<value>Display name</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_display_name_description" xml:space="preserve">
|
||||
<value>The name of your extension as users will see it.</value>
|
||||
<value>The name of the extension as it will appear to users.</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_display_name_label" xml:space="preserve">
|
||||
<value>Display name</value>
|
||||
@@ -209,11 +200,8 @@
|
||||
<data name="builtin_create_extension_display_name_required" xml:space="preserve">
|
||||
<value>Display name is required</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_directory_header" xml:space="preserve">
|
||||
<value>Output path</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_directory_description" xml:space="preserve">
|
||||
<value>Where should the new extension be created? This path will be created if it doesn't exist</value>
|
||||
<value>Select the folder where the new extension will be created. The path will be created if it doesn't exist.</value>
|
||||
</data>
|
||||
<data name="builtin_create_extension_directory_label" xml:space="preserve">
|
||||
<value>Output path</value>
|
||||
|
||||
@@ -130,7 +130,7 @@ public partial class SettingsModel : ObservableObject
|
||||
{
|
||||
foreach (var item in newSettings)
|
||||
{
|
||||
savedSettings[item.Key] = item.Value != null ? item.Value.DeepClone() : null;
|
||||
savedSettings[item.Key] = item.Value?.DeepClone();
|
||||
}
|
||||
|
||||
var serialized = savedSettings.ToJsonString(JsonSerializationContext.Default.Options);
|
||||
@@ -188,6 +188,8 @@ public partial class SettingsModel : ObservableObject
|
||||
[JsonSerializable(typeof(HistoryItem))]
|
||||
[JsonSerializable(typeof(SettingsModel))]
|
||||
[JsonSerializable(typeof(AppStateModel))]
|
||||
[JsonSerializable(typeof(RecentCommandsManager))]
|
||||
[JsonSerializable(typeof(List<string>), TypeInfoPropertyName = "StringList")]
|
||||
[JsonSerializable(typeof(List<HistoryItem>), TypeInfoPropertyName = "HistoryList")]
|
||||
[JsonSerializable(typeof(Dictionary<string, object>), TypeInfoPropertyName = "Dictionary")]
|
||||
[JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true, IncludeFields = true, PropertyNameCaseInsensitive = true, AllowTrailingCommas = true)]
|
||||
|
||||
@@ -38,7 +38,7 @@ public sealed class AdaptiveCardsConfig
|
||||
"fontFamily": "'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
|
||||
"fontSizes": {
|
||||
"small": 12,
|
||||
"default": 12,
|
||||
"default": 14,
|
||||
"medium": 14,
|
||||
"large": 20,
|
||||
"extraLarge": 26
|
||||
@@ -199,7 +199,7 @@ public sealed class AdaptiveCardsConfig
|
||||
"fontFamily": "'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
|
||||
"fontSizes": {
|
||||
"small": 12,
|
||||
"default": 12,
|
||||
"default": 14,
|
||||
"medium": 14,
|
||||
"large": 20,
|
||||
"extraLarge": 26
|
||||
|
||||
@@ -100,6 +100,16 @@
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<Style x:Key="HotkeyStyle" TargetType="Border">
|
||||
<Style.Setters>
|
||||
<Setter Property="Padding" Value="4" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="Background" Value="{ThemeResource ControlFillColorSecondaryBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource DividerStrokeColorDefaultBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="6" />
|
||||
</Style.Setters>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
@@ -193,17 +203,12 @@
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.PrimaryCommand.Name, Mode=OneWay}" />
|
||||
<Border
|
||||
Padding="4"
|
||||
Background="{ThemeResource SubtleFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<Border Style="{StaticResource HotkeyStyle}">
|
||||
<FontIcon
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="10"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
Glyph="" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
@@ -221,32 +226,20 @@
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.SecondaryCommand.Name, Mode=OneWay}" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="2">
|
||||
<Border
|
||||
Padding="4,2,4,2"
|
||||
VerticalAlignment="Center"
|
||||
Background="{ThemeResource SubtleFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<Border Padding="4,2,4,2" Style="{StaticResource HotkeyStyle}">
|
||||
<TextBlock
|
||||
CharacterSpacing="4"
|
||||
FontSize="10"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
Text="Ctrl" />
|
||||
</Border>
|
||||
<Border
|
||||
Padding="4"
|
||||
VerticalAlignment="Center"
|
||||
Background="{ThemeResource SubtleFillColorSecondaryBrush}"
|
||||
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<Border Style="{StaticResource HotkeyStyle}">
|
||||
<FontIcon
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="10"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
Glyph="" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
@@ -267,7 +260,6 @@
|
||||
Opened="Flyout_Opened"
|
||||
Placement="TopEdgeAlignedRight">
|
||||
<StackPanel>
|
||||
|
||||
<ListView
|
||||
x:Name="CommandsDropdown"
|
||||
MinWidth="248"
|
||||
@@ -288,7 +280,6 @@
|
||||
<TransitionCollection />
|
||||
</ListView.ItemContainerTransitions>
|
||||
</ListView>
|
||||
|
||||
<TextBox
|
||||
x:Name="ContextFilterBox"
|
||||
x:Uid="ContextFilterBox"
|
||||
@@ -296,7 +287,6 @@
|
||||
KeyDown="ContextFilterBox_KeyDown"
|
||||
PreviewKeyDown="ContextFilterBox_PreviewKeyDown"
|
||||
TextChanged="ContextFilterBox_TextChanged" />
|
||||
|
||||
</StackPanel>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
|
||||
@@ -19,6 +19,5 @@
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid x:Name="ContentGrid" />
|
||||
</UserControl>
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
<StaticResource x:Key="TagBackground" ResourceKey="ControlSolidFillColorDefaultBrush" />
|
||||
<StaticResource x:Key="TagBorderBrush" ResourceKey="ControlStrokeColorSecondaryBrush" />
|
||||
<StaticResource x:Key="TagBackground" ResourceKey="ControlFillColorSecondaryBrush" />
|
||||
<StaticResource x:Key="TagBorderBrush" ResourceKey="DividerStrokeColorDefaultBrush" />
|
||||
<StaticResource x:Key="TagForeground" ResourceKey="TextFillColorTertiaryBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="TagBackground" ResourceKey="ControlSolidFillColorDefaultBrush" />
|
||||
<StaticResource x:Key="TagBorderBrush" ResourceKey="ControlStrokeColorSecondaryBrush" />
|
||||
<StaticResource x:Key="TagBackground" ResourceKey="ControlFillColorSecondaryBrush" />
|
||||
<StaticResource x:Key="TagBorderBrush" ResourceKey="DividerStrokeColorDefaultBrush" />
|
||||
<StaticResource x:Key="TagForeground" ResourceKey="TextFillColorTertiaryBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
|
||||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
<Grid Background="{ThemeResource CardBackgroundFillColorDefaultBrush}">
|
||||
<Grid>
|
||||
<ScrollView VerticalAlignment="Top" VerticalScrollMode="Enabled">
|
||||
<ItemsRepeater
|
||||
VerticalAlignment="Stretch"
|
||||
|
||||
@@ -380,19 +380,19 @@
|
||||
To="24,0,0"
|
||||
Duration="0:0:0.187" />
|
||||
</animations:Implicit.HideAnimations>
|
||||
<Grid Margin="12">
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<cpcontrols:IconBox
|
||||
x:Name="HeroImageBorder"
|
||||
Width="64"
|
||||
Margin="16,8,16,16"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,0,16,16"
|
||||
HorizontalAlignment="Left"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
SourceKey="{x:Bind ViewModel.Details.HeroImage, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}"
|
||||
@@ -400,17 +400,15 @@
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
FontSize="18"
|
||||
FontWeight="SemiBold"
|
||||
Text="{x:Bind ViewModel.Details.Title, Mode=OneWay}"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="WrapWholeWords"
|
||||
Visibility="{x:Bind ViewModel.Details.Title, Converter={StaticResource StringNotEmptyToVisibilityConverter}, Mode=OneWay}" />
|
||||
|
||||
<toolkit:MarkdownTextBlock
|
||||
Grid.Row="2"
|
||||
Margin="0,12,0,24"
|
||||
Margin="0,4,0,24"
|
||||
Background="Transparent"
|
||||
Header3FontSize="12"
|
||||
Header3FontWeight="Normal"
|
||||
|
||||
@@ -82,7 +82,7 @@ public static class CalculateEngine
|
||||
return default;
|
||||
}
|
||||
|
||||
var decimalResult = Convert.ToDecimal(result, cultureInfo);
|
||||
var decimalResult = Convert.ToDecimal(result, new CultureInfo("en-US"));
|
||||
|
||||
var roundedResult = FormatMax15Digits(decimalResult, cultureInfo);
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings;
|
||||
internal static class ResultHelper
|
||||
{
|
||||
internal static List<ListItem> GetResultList(
|
||||
in IEnumerable<Classes.WindowsSetting> list,
|
||||
string query)
|
||||
in IEnumerable<Classes.WindowsSetting> list)
|
||||
{
|
||||
var resultList = new List<ListItem>(list.Count());
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Classes;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowsSettings.Helpers;
|
||||
|
||||
internal static class ScoringHelper
|
||||
{
|
||||
// Rank settings by how they matched the search query. Order is:
|
||||
// 1. Exact Name (10 points)
|
||||
// 2. Name Starts With (8 points)
|
||||
// 3. Name (5 points)
|
||||
// 4. Area (4 points)
|
||||
// 5. AltName (2 points)
|
||||
// 6. Settings path (1 point)
|
||||
internal static (WindowsSetting Setting, int Score) SearchScoringPredicate(string query, WindowsSetting setting)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
// If no search string is entered skip query comparison.
|
||||
return (setting, 0);
|
||||
}
|
||||
|
||||
if (string.Equals(setting.Name, query, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return (setting, 10);
|
||||
}
|
||||
|
||||
if (setting.Name.StartsWith(query, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return (setting, 8);
|
||||
}
|
||||
|
||||
if (setting.Name.Contains(query, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return (setting, 5);
|
||||
}
|
||||
|
||||
if (!(setting.Areas is null))
|
||||
{
|
||||
foreach (var area in setting.Areas)
|
||||
{
|
||||
// Search for areas on normal queries.
|
||||
if (area.Contains(query, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return (setting, 4);
|
||||
}
|
||||
|
||||
// Search for Area only on queries with action char.
|
||||
if (area.Contains(query.Replace(":", string.Empty), StringComparison.CurrentCultureIgnoreCase)
|
||||
&& query.EndsWith(":", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return (setting, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(setting.AltNames is null))
|
||||
{
|
||||
foreach (var altName in setting.AltNames)
|
||||
{
|
||||
if (altName.Contains(query, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return (setting, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search by key char '>' for app name and settings path
|
||||
if (query.Contains('>') && ResultHelper.FilterBySettingsPath(setting, query))
|
||||
{
|
||||
return (setting, 1);
|
||||
}
|
||||
|
||||
return (setting, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Classes;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Commands;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Helpers;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowsSettings.Pages;
|
||||
|
||||
internal sealed partial class FallbackWindowsSettingsItem : FallbackCommandItem
|
||||
{
|
||||
private readonly Classes.WindowsSettings _windowsSettings;
|
||||
|
||||
private readonly string _title = Resources.settings_fallback_title;
|
||||
private readonly string _subtitle = Resources.settings_fallback_subtitle;
|
||||
|
||||
public FallbackWindowsSettingsItem(Classes.WindowsSettings windowsSettings)
|
||||
: base(new NoOpCommand(), Resources.settings_title)
|
||||
{
|
||||
Icon = IconHelpers.FromRelativePath("Assets\\WindowsSettings.svg");
|
||||
_windowsSettings = windowsSettings;
|
||||
}
|
||||
|
||||
public override void UpdateQuery(string query)
|
||||
{
|
||||
Command = new NoOpCommand();
|
||||
Title = string.Empty;
|
||||
Subtitle = string.Empty;
|
||||
Icon = null;
|
||||
MoreCommands = null;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(query) ||
|
||||
_windowsSettings?.Settings is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var filteredList = _windowsSettings.Settings
|
||||
.Select(setting => ScoringHelper.SearchScoringPredicate(query, setting))
|
||||
.Where(scoredSetting => scoredSetting.Score > 0)
|
||||
.OrderByDescending(scoredSetting => scoredSetting.Score);
|
||||
|
||||
if (!filteredList.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (filteredList.Count() == 1 ||
|
||||
filteredList.Any(a => a.Score == 10))
|
||||
{
|
||||
var setting = filteredList.First().Setting;
|
||||
|
||||
Title = setting.Name;
|
||||
Subtitle = setting.JoinedFullSettingsPath;
|
||||
Icon = IconHelpers.FromRelativePath("Assets\\WindowsSettings.svg");
|
||||
Command = new OpenSettingsCommand(setting)
|
||||
{
|
||||
Icon = IconHelpers.FromRelativePath("Assets\\WindowsSettings.svg"),
|
||||
Name = setting.Name,
|
||||
};
|
||||
|
||||
// There is a case with MMC snap-ins where we don't have .msc files fort them. Then we need to show the note for this results in subtitle too.
|
||||
// These results have mmc.exe as command and their note property is filled.
|
||||
if (setting.Command == "mmc.exe" && !string.IsNullOrEmpty(setting.Note))
|
||||
{
|
||||
Subtitle += $"\u0020\u0020\u002D\u0020\u0020{Resources.Note}: {setting.Note}"; // "\u0020\u0020\u002D\u0020\u0020" = "<space><space><minus><space><space>"
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// We found more than one result. Make our command take
|
||||
// us to the Windows Settings search page, prepopulated with this search.
|
||||
var settingsPage = new WindowsSettingsListPage(_windowsSettings, query);
|
||||
Title = string.Format(CultureInfo.CurrentCulture, _title, query);
|
||||
Icon = IconHelpers.FromRelativePath("Assets\\WindowsSettings.svg");
|
||||
Subtitle = _subtitle;
|
||||
Command = settingsPage;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Classes;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Helpers;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Properties;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
@@ -18,11 +20,17 @@ internal sealed partial class WindowsSettingsListPage : DynamicListPage
|
||||
public WindowsSettingsListPage(Classes.WindowsSettings windowsSettings)
|
||||
{
|
||||
Icon = IconHelpers.FromRelativePath("Assets\\WindowsSettings.svg");
|
||||
Name = "Windows Settings";
|
||||
Name = Resources.settings_title;
|
||||
Id = "com.microsoft.cmdpal.windowsSettings";
|
||||
_windowsSettings = windowsSettings;
|
||||
}
|
||||
|
||||
public WindowsSettingsListPage(Classes.WindowsSettings windowsSettings, string query)
|
||||
: this(windowsSettings)
|
||||
{
|
||||
SearchText = query;
|
||||
}
|
||||
|
||||
public List<ListItem> Query(string query)
|
||||
{
|
||||
if (_windowsSettings?.Settings is null)
|
||||
@@ -31,87 +39,21 @@ internal sealed partial class WindowsSettingsListPage : DynamicListPage
|
||||
}
|
||||
|
||||
var filteredList = _windowsSettings.Settings
|
||||
.Select(SearchScoringPredicate)
|
||||
.Select(setting => ScoringHelper.SearchScoringPredicate(query, setting))
|
||||
.Where(scoredSetting => scoredSetting.Score > 0)
|
||||
.OrderByDescending(scoredSetting => scoredSetting.Score)
|
||||
.Select(scoredSetting => scoredSetting.Setting);
|
||||
|
||||
var newList = ResultHelper.GetResultList(filteredList, query);
|
||||
var newList = ResultHelper.GetResultList(filteredList);
|
||||
return newList;
|
||||
|
||||
// Rank settings by how they matched the search query. Order is:
|
||||
// 1. Exact Name (10 points)
|
||||
// 2. Name Starts With (8 points)
|
||||
// 3. Name (5 points)
|
||||
// 4. Area (4 points)
|
||||
// 5. AltName (2 points)
|
||||
// 6. Settings path (1 point)
|
||||
(WindowsSetting Setting, int Score) SearchScoringPredicate(WindowsSetting setting)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
// If no search string is entered skip query comparison.
|
||||
return (setting, 0);
|
||||
}
|
||||
|
||||
if (string.Equals(setting.Name, query, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return (setting, 10);
|
||||
}
|
||||
|
||||
if (setting.Name.StartsWith(query, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return (setting, 8);
|
||||
}
|
||||
|
||||
if (setting.Name.Contains(query, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return (setting, 5);
|
||||
}
|
||||
|
||||
if (!(setting.Areas is null))
|
||||
{
|
||||
foreach (var area in setting.Areas)
|
||||
{
|
||||
// Search for areas on normal queries.
|
||||
if (area.Contains(query, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return (setting, 4);
|
||||
}
|
||||
|
||||
// Search for Area only on queries with action char.
|
||||
if (area.Contains(query.Replace(":", string.Empty), StringComparison.CurrentCultureIgnoreCase)
|
||||
&& query.EndsWith(":", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return (setting, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(setting.AltNames is null))
|
||||
{
|
||||
foreach (var altName in setting.AltNames)
|
||||
{
|
||||
if (altName.Contains(query, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return (setting, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search by key char '>' for app name and settings path
|
||||
if (query.Contains('>') && ResultHelper.FilterBySettingsPath(setting, query))
|
||||
{
|
||||
return (setting, 1);
|
||||
}
|
||||
|
||||
return (setting, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateSearchText(string oldSearch, string newSearch)
|
||||
{
|
||||
RaiseItemsChanged(0);
|
||||
if (oldSearch != newSearch)
|
||||
{
|
||||
RaiseItemsChanged(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override IListItem[] GetItems()
|
||||
|
||||
@@ -3840,6 +3840,42 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Search Windows settings for this device.
|
||||
/// </summary>
|
||||
internal static string settings_fallback_subtitle {
|
||||
get {
|
||||
return ResourceManager.GetString("settings_fallback_subtitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Search for "{0}" in Windows settings.
|
||||
/// </summary>
|
||||
internal static string settings_fallback_title {
|
||||
get {
|
||||
return ResourceManager.GetString("settings_fallback_title", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Navigate to specific Windows settings.
|
||||
/// </summary>
|
||||
internal static string settings_subtitle {
|
||||
get {
|
||||
return ResourceManager.GetString("settings_subtitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Windows Settings.
|
||||
/// </summary>
|
||||
internal static string settings_title {
|
||||
get {
|
||||
return ResourceManager.GetString("settings_title", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Settings app.
|
||||
/// </summary>
|
||||
|
||||
@@ -2085,4 +2085,16 @@
|
||||
<data name="WindowsSettingsProvider_DisplayName" xml:space="preserve">
|
||||
<value>Windows Settings</value>
|
||||
</data>
|
||||
<data name="settings_title" xml:space="preserve">
|
||||
<value>Windows Settings</value>
|
||||
</data>
|
||||
<data name="settings_subtitle" xml:space="preserve">
|
||||
<value>Navigate to specific Windows settings</value>
|
||||
</data>
|
||||
<data name="settings_fallback_title" xml:space="preserve">
|
||||
<value>Search for "{0}" in Windows settings</value>
|
||||
</data>
|
||||
<data name="settings_fallback_subtitle" xml:space="preserve">
|
||||
<value>Search Windows settings for this device</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Helpers;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Pages;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Properties;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
@@ -17,6 +18,8 @@ public partial class WindowsSettingsCommandsProvider : CommandProvider
|
||||
private readonly WindowsSettings.Classes.WindowsSettings? _windowsSettings;
|
||||
#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
|
||||
private readonly FallbackWindowsSettingsItem _fallback;
|
||||
|
||||
public WindowsSettingsCommandsProvider()
|
||||
{
|
||||
Id = "Windows.Settings";
|
||||
@@ -26,9 +29,10 @@ public partial class WindowsSettingsCommandsProvider : CommandProvider
|
||||
_windowsSettings = JsonSettingsListHelper.ReadAllPossibleSettings();
|
||||
_searchSettingsListItem = new CommandItem(new WindowsSettingsListPage(_windowsSettings))
|
||||
{
|
||||
Title = "Windows Settings",
|
||||
Subtitle = "Navigate to specific Windows settings",
|
||||
Title = Resources.settings_title,
|
||||
Subtitle = Resources.settings_subtitle,
|
||||
};
|
||||
_fallback = new(_windowsSettings);
|
||||
|
||||
UnsupportedSettingsHelper.FilterByBuild(_windowsSettings);
|
||||
|
||||
@@ -42,4 +46,6 @@ public partial class WindowsSettingsCommandsProvider : CommandProvider
|
||||
_searchSettingsListItem
|
||||
];
|
||||
}
|
||||
|
||||
public override IFallbackCommandItem[] FallbackCommands() => [_fallback];
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "PowerToys@microsoft.com",
|
||||
"AssignedTo": "leilzh@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SALT",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
|
||||
@@ -615,7 +615,7 @@ namespace UITests_FancyZones
|
||||
// test settings
|
||||
Microsoft.PowerToys.UITest.CheckBox useShiftCheckBox = this.Find<Microsoft.PowerToys.UITest.CheckBox>("Hold Shift key to activate zones while dragging a window");
|
||||
Microsoft.PowerToys.UITest.CheckBox useNonPrimaryMouseCheckBox = this.Find<Microsoft.PowerToys.UITest.CheckBox>("Use a non-primary mouse button to toggle zone activation");
|
||||
Microsoft.PowerToys.UITest.CheckBox makeDraggedWindowTransparent = this.Find<Microsoft.PowerToys.UITest.CheckBox>("Make dragged window transparent");
|
||||
Microsoft.PowerToys.UITest.CheckBox makeDraggedWindowTransparent = this.Find<Microsoft.PowerToys.UITest.CheckBox>("Make the dragged window transparent");
|
||||
|
||||
Find<Microsoft.PowerToys.UITest.CheckBox>("Show zone number").SetCheck(false, 100);
|
||||
Find<Slider>("Opacity (%)").QuickSetValue(100); // make highlight color visible with opacity 100
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<TargetName>PowerToys.ImageResizerContextMenu</TargetName>
|
||||
<!-- Needs a different int dir to avoid conflicts in msix creation. -->
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\TemporaryBuild\obj\$(ProjectName)\</IntDir>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetName>PowerToys.$(ProjectName)</TargetName>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\</OutDir>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
|
||||
<TargetName>PowerToys.ImageResizerExt</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>PowerToys.ImageResizer</AssemblyTitle>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)</OutputPath>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
|
||||
|
||||
@@ -363,7 +363,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
|
||||
RenamedEventArgs e = new RenamedEventArgs(WatcherChangeTypes.Renamed, directory, path, oldpath);
|
||||
|
||||
string oldFullPath = directory + "\\" + oldpath;
|
||||
string fullPath = directory + "\\" + path;
|
||||
string newFullPath = directory + "\\" + path;
|
||||
string linkingTo = Directory.GetCurrentDirectory();
|
||||
|
||||
// ShellLinkHelper must be mocked for lnk applications
|
||||
@@ -372,19 +372,8 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
|
||||
Win32Program.ShellLinkHelper = mockShellLink.Object;
|
||||
|
||||
// old item and new item are the actual items when they are in existence
|
||||
Win32Program olditem = new Win32Program
|
||||
{
|
||||
Name = "oldpath",
|
||||
ExecutableName = oldpath,
|
||||
FullPath = linkingTo,
|
||||
};
|
||||
|
||||
Win32Program newitem = new Win32Program
|
||||
{
|
||||
Name = "path",
|
||||
ExecutableName = path,
|
||||
FullPath = linkingTo,
|
||||
};
|
||||
Win32Program olditem = Win32Program.GetAppFromPath(oldFullPath);
|
||||
Win32Program newitem = Win32Program.GetAppFromPath(newFullPath);
|
||||
|
||||
win32ProgramRepository.Add(olditem);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "PowerToys@microsoft.com",
|
||||
"AssignedTo": "leilzh@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SALT",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "PowerToys@microsoft.com",
|
||||
"AssignedTo": "leilzh@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SALT",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
@@ -60,7 +60,7 @@
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "PowerToys@microsoft.com",
|
||||
"AssignedTo": "leilzh@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SALT",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
|
||||
@@ -149,7 +149,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
||||
std::vector<std::wstring_view> knownModules = {
|
||||
L"PowerToys.FancyZonesModuleInterface.dll",
|
||||
L"PowerToys.powerpreview.dll",
|
||||
L"PowerToys.ImageResizerExt.dll",
|
||||
L"WinUI3Apps/PowerToys.ImageResizerExt.dll",
|
||||
L"PowerToys.KeyboardManager.dll",
|
||||
L"PowerToys.Launcher.dll",
|
||||
L"WinUI3Apps/PowerToys.PowerRenameExt.dll",
|
||||
|
||||
@@ -671,14 +671,22 @@ std::string ESettingsWindowNames_to_string(ESettingsWindowNames value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case ESettingsWindowNames::Dashboard:
|
||||
return "Dashboard";
|
||||
case ESettingsWindowNames::Overview:
|
||||
return "Overview";
|
||||
case ESettingsWindowNames::AlwaysOnTop:
|
||||
return "AlwaysOnTop";
|
||||
case ESettingsWindowNames::Awake:
|
||||
return "Awake";
|
||||
case ESettingsWindowNames::ColorPicker:
|
||||
return "ColorPicker";
|
||||
case ESettingsWindowNames::CmdNotFound:
|
||||
return "CmdNotFound";
|
||||
case ESettingsWindowNames::FancyZones:
|
||||
return "FancyZones";
|
||||
case ESettingsWindowNames::FileLocksmith:
|
||||
return "FileLocksmith";
|
||||
case ESettingsWindowNames::Run:
|
||||
return "Run";
|
||||
case ESettingsWindowNames::ImageResizer:
|
||||
@@ -687,6 +695,16 @@ std::string ESettingsWindowNames_to_string(ESettingsWindowNames value)
|
||||
return "KBM";
|
||||
case ESettingsWindowNames::MouseUtils:
|
||||
return "MouseUtils";
|
||||
case ESettingsWindowNames::MouseWithoutBorders:
|
||||
return "MouseWithoutBorders";
|
||||
case ESettingsWindowNames::Peek:
|
||||
return "Peek";
|
||||
case ESettingsWindowNames::PowerAccent:
|
||||
return "PowerAccent";
|
||||
case ESettingsWindowNames::PowerLauncher:
|
||||
return "PowerLauncher";
|
||||
case ESettingsWindowNames::PowerPreview:
|
||||
return "PowerPreview";
|
||||
case ESettingsWindowNames::PowerRename:
|
||||
return "PowerRename";
|
||||
case ESettingsWindowNames::FileExplorer:
|
||||
@@ -707,8 +725,6 @@ std::string ESettingsWindowNames_to_string(ESettingsWindowNames value)
|
||||
return "CropAndLock";
|
||||
case ESettingsWindowNames::EnvironmentVariables:
|
||||
return "EnvironmentVariables";
|
||||
case ESettingsWindowNames::Dashboard:
|
||||
return "Dashboard";
|
||||
case ESettingsWindowNames::AdvancedPaste:
|
||||
return "AdvancedPaste";
|
||||
case ESettingsWindowNames::NewPlus:
|
||||
@@ -728,10 +744,18 @@ std::string ESettingsWindowNames_to_string(ESettingsWindowNames value)
|
||||
|
||||
ESettingsWindowNames ESettingsWindowNames_from_string(std::string value)
|
||||
{
|
||||
if (value == "Overview")
|
||||
if (value == "Dashboard")
|
||||
{
|
||||
return ESettingsWindowNames::Dashboard;
|
||||
}
|
||||
else if (value == "Overview")
|
||||
{
|
||||
return ESettingsWindowNames::Overview;
|
||||
}
|
||||
else if (value == "AlwaysOnTop")
|
||||
{
|
||||
return ESettingsWindowNames::AlwaysOnTop;
|
||||
}
|
||||
else if (value == "Awake")
|
||||
{
|
||||
return ESettingsWindowNames::Awake;
|
||||
@@ -740,10 +764,18 @@ ESettingsWindowNames ESettingsWindowNames_from_string(std::string value)
|
||||
{
|
||||
return ESettingsWindowNames::ColorPicker;
|
||||
}
|
||||
else if (value == "CmdNotFound")
|
||||
{
|
||||
return ESettingsWindowNames::CmdNotFound;
|
||||
}
|
||||
else if (value == "FancyZones")
|
||||
{
|
||||
return ESettingsWindowNames::FancyZones;
|
||||
}
|
||||
else if (value == "FileLocksmith")
|
||||
{
|
||||
return ESettingsWindowNames::FileLocksmith;
|
||||
}
|
||||
else if (value == "Run")
|
||||
{
|
||||
return ESettingsWindowNames::Run;
|
||||
@@ -760,6 +792,26 @@ ESettingsWindowNames ESettingsWindowNames_from_string(std::string value)
|
||||
{
|
||||
return ESettingsWindowNames::MouseUtils;
|
||||
}
|
||||
else if (value == "MouseWithoutBorders")
|
||||
{
|
||||
return ESettingsWindowNames::MouseWithoutBorders;
|
||||
}
|
||||
else if (value == "Peek")
|
||||
{
|
||||
return ESettingsWindowNames::Peek;
|
||||
}
|
||||
else if (value == "PowerAccent")
|
||||
{
|
||||
return ESettingsWindowNames::PowerAccent;
|
||||
}
|
||||
else if (value == "PowerLauncher")
|
||||
{
|
||||
return ESettingsWindowNames::PowerLauncher;
|
||||
}
|
||||
else if (value == "PowerPreview")
|
||||
{
|
||||
return ESettingsWindowNames::PowerPreview;
|
||||
}
|
||||
else if (value == "PowerRename")
|
||||
{
|
||||
return ESettingsWindowNames::PowerRename;
|
||||
@@ -800,10 +852,6 @@ ESettingsWindowNames ESettingsWindowNames_from_string(std::string value)
|
||||
{
|
||||
return ESettingsWindowNames::EnvironmentVariables;
|
||||
}
|
||||
else if (value == "Dashboard")
|
||||
{
|
||||
return ESettingsWindowNames::Dashboard;
|
||||
}
|
||||
else if (value == "AdvancedPaste")
|
||||
{
|
||||
return ESettingsWindowNames::AdvancedPaste;
|
||||
|
||||
@@ -6,13 +6,21 @@ enum class ESettingsWindowNames
|
||||
{
|
||||
Dashboard = 0,
|
||||
Overview,
|
||||
AlwaysOnTop,
|
||||
Awake,
|
||||
ColorPicker,
|
||||
CmdNotFound,
|
||||
FancyZones,
|
||||
FileLocksmith,
|
||||
Run,
|
||||
ImageResizer,
|
||||
KBM,
|
||||
MouseUtils,
|
||||
MouseWithoutBorders,
|
||||
Peek,
|
||||
PowerAccent,
|
||||
PowerLauncher,
|
||||
PowerPreview,
|
||||
PowerRename,
|
||||
FileExplorer,
|
||||
ShortcutGuide,
|
||||
|
||||
@@ -436,6 +436,10 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
case "KBM": return typeof(KeyboardManagerPage);
|
||||
case "MouseUtils": return typeof(MouseUtilsPage);
|
||||
case "MouseWithoutBorders": return typeof(MouseWithoutBordersPage);
|
||||
case "Peek": return typeof(PeekPage);
|
||||
case "PowerAccent": return typeof(PowerAccentPage);
|
||||
case "PowerLauncher": return typeof(PowerLauncherPage);
|
||||
case "PowerPreview": return typeof(PowerPreviewPage);
|
||||
case "PowerRename": return typeof(PowerRenamePage);
|
||||
case "QuickAccent": return typeof(PowerAccentPage);
|
||||
case "FileExplorer": return typeof(PowerPreviewPage);
|
||||
@@ -444,7 +448,6 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
case "MeasureTool": return typeof(MeasureToolPage);
|
||||
case "Hosts": return typeof(HostsPage);
|
||||
case "RegistryPreview": return typeof(RegistryPreviewPage);
|
||||
case "Peek": return typeof(PeekPage);
|
||||
case "CropAndLock": return typeof(CropAndLockPage);
|
||||
case "EnvironmentVariables": return typeof(EnvironmentVariablesPage);
|
||||
case "NewPlus": return typeof(NewPlusPage);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
<UserControl.Resources>
|
||||
<x:Double x:Key="PageMaxWidth">1000</x:Double>
|
||||
<x:Double x:Key="PageHeaderMaxWidth">1020</x:Double>
|
||||
<tkconverters:DoubleToVisibilityConverter
|
||||
x:Name="doubleToVisibilityConverter"
|
||||
FalseValue="Collapsed"
|
||||
@@ -26,7 +27,7 @@
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
x:Name="Header"
|
||||
MaxWidth="{StaticResource PageMaxWidth}"
|
||||
MaxWidth="{StaticResource PageHeaderMaxWidth}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
AutomationProperties.HeadingLevel="1"
|
||||
|
||||
@@ -88,16 +88,9 @@
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
x:Uid="AlwaysOnTop_SoundTitle"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<CheckBox x:Uid="AlwaysOnTop_Sound" IsChecked="{x:Bind ViewModel.SoundEnabled, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
<tkcontrols:SettingsCard x:Uid="AlwaysOnTop_Sound" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.SoundEnabled, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="ExcludedApps" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
|
||||
@@ -294,7 +294,7 @@
|
||||
<tkcontrols:SettingsCard x:Uid="General_SettingsBackupAndRestoreLocationText">
|
||||
<Grid ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
@@ -405,76 +405,83 @@
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
</controls:SettingsGroup>
|
||||
<controls:SettingsGroup x:Uid="General_DiagnosticsAndFeedback" Visibility="Visible">
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<HyperlinkButton
|
||||
x:Uid="GeneralPage_DiagnosticsAndFeedback_Link"
|
||||
Margin="0,0,0,8"
|
||||
Padding="0"
|
||||
NavigateUri="https://aka.ms/powertoys-data-and-privacy-documentation" />
|
||||
<tkcontrols:SettingsCard
|
||||
x:Uid="GeneralPage_EnableDataDiagnostics"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsDataDiagnosticsGPOManaged, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.EnableDataDiagnostics, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<InfoBar
|
||||
x:Uid="GPO_SettingIsManaged"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsDataDiagnosticsGPOManaged, Mode=OneWay}"
|
||||
IsTabStop="{x:Bind ViewModel.IsDataDiagnosticsGPOManaged, Mode=OneWay}"
|
||||
Severity="Informational">
|
||||
<InfoBar.IconSource>
|
||||
<FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsExpander
|
||||
x:Uid="GeneralPage_ViewDiagnosticData"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsDataDiagnosticsGPOManaged, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="GeneralPage_EnableViewDiagnosticData" IsEnabled="{x:Bind ViewModel.EnableDataDiagnostics, Mode=TwoWay}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.EnableViewDataDiagnostics, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard
|
||||
x:Uid="GeneralPage_ViewDiagnosticDataViewer"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Click="ViewDiagnosticData_Click"
|
||||
IsClickEnabled="True" />
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
<InfoBar
|
||||
x:Uid="GeneralPage_ViewDiagnosticDataViewerInfo"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind Mode=OneWay, Path=ViewModel.ViewDiagnosticDataViewerChanged}"
|
||||
IsTabStop="{x:Bind Mode=OneWay, Path=ViewModel.ViewDiagnosticDataViewerChanged}"
|
||||
Severity="Informational">
|
||||
<InfoBar.ActionButton>
|
||||
<Button x:Uid="GeneralPage_ViewDiagnosticDataViewerInfoButton" Click="Click_ViewDiagnosticDataViewerRestart" />
|
||||
</InfoBar.ActionButton>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsCard
|
||||
x:Uid="GeneralPage_ReportBugPackage"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
Visibility="{x:Bind ViewModel.IsBugReportRunning, Converter={StaticResource ReverseBoolToVisibilityConverter}, Mode=OneWay}">
|
||||
<controls:SettingsGroup x:Uid="General_DiagnosticsAndFeedback">
|
||||
<tkcontrols:SettingsExpander
|
||||
x:Uid="GeneralPage_EnableDataDiagnostics"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsDataDiagnosticsGPOManaged, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Description>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock
|
||||
x:Uid="GeneralPage_EnableDataDiagnosticsText"
|
||||
Style="{StaticResource SecondaryTextStyle}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<HyperlinkButton
|
||||
x:Uid="GeneralPage_DiagnosticsAndFeedback_Link"
|
||||
Margin="0,2,0,0"
|
||||
FontWeight="SemiBold"
|
||||
NavigateUri="https://aka.ms/powertoys-data-and-privacy-documentation" />
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsExpander.Description>
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.EnableDataDiagnostics, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="GeneralPage_EnableViewDiagnosticData" IsEnabled="{x:Bind ViewModel.EnableDataDiagnostics, Mode=TwoWay}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.EnableViewDataDiagnostics, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsCard.Description>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock
|
||||
x:Uid="GeneralPage_EnableViewDiagnosticDataText"
|
||||
Style="{StaticResource SecondaryTextStyle}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<HyperlinkButton
|
||||
Margin="0,2,0,0"
|
||||
Click="ViewDiagnosticData_Click"
|
||||
Content="View diagnostic data"
|
||||
FontWeight="SemiBold" />
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsCard.Description>
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsExpander.ItemsFooter>
|
||||
<InfoBar
|
||||
x:Uid="GeneralPage_ViewDiagnosticDataViewerInfo"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0,0,4,4"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind Mode=OneWay, Path=ViewModel.ViewDiagnosticDataViewerChanged}"
|
||||
IsTabStop="{x:Bind Mode=OneWay, Path=ViewModel.ViewDiagnosticDataViewerChanged}"
|
||||
Severity="Informational">
|
||||
<InfoBar.ActionButton>
|
||||
<Button x:Uid="GeneralPage_ViewDiagnosticDataViewerInfoButton" Click="Click_ViewDiagnosticDataViewerRestart" />
|
||||
</InfoBar.ActionButton>
|
||||
</InfoBar>
|
||||
</tkcontrols:SettingsExpander.ItemsFooter>
|
||||
</tkcontrols:SettingsExpander>
|
||||
<InfoBar
|
||||
x:Uid="GPO_SettingIsManaged"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsDataDiagnosticsGPOManaged, Mode=OneWay}"
|
||||
IsTabStop="{x:Bind ViewModel.IsDataDiagnosticsGPOManaged, Mode=OneWay}"
|
||||
Severity="Informational">
|
||||
<InfoBar.IconSource>
|
||||
<FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsCard x:Uid="GeneralPage_ReportBugPackage" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button
|
||||
x:Uid="GeneralPageReportBugPackage"
|
||||
HorizontalAlignment="Right"
|
||||
Click="BugReportToolClicked"
|
||||
IsEnabled="{x:Bind ViewModel.IsBugReportRunning, Converter={StaticResource BoolNegationConverter}, Mode=OneWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard
|
||||
x:Uid="GeneralPage_ReportBugPackage"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
Visibility="{x:Bind ViewModel.IsBugReportRunning, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
|
||||
Visibility="{x:Bind ViewModel.IsBugReportRunning, Converter={StaticResource ReverseBoolToVisibilityConverter}, Mode=OneWay}" />
|
||||
<ProgressRing
|
||||
Width="24"
|
||||
Height="24"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</StackPanel>
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{x:Bind ViewModel.IsBugReportRunning, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@@ -152,10 +152,10 @@
|
||||
<comment>"Screen Ruler" is the name of the utility</comment>
|
||||
</data>
|
||||
<data name="MeasureTool_DefaultMeasureStyle.Header" xml:space="preserve">
|
||||
<value>Default measure style</value>
|
||||
<value>Default mode</value>
|
||||
</data>
|
||||
<data name="MeasureTool_DefaultMeasureStyle.Description" xml:space="preserve">
|
||||
<value>The utility will start having the selected style activated</value>
|
||||
<value>The measuring mode that is used when activated</value>
|
||||
</data>
|
||||
<data name="MeasureTool_DefaultMeasureStyle_None.Content" xml:space="preserve">
|
||||
<value>None</value>
|
||||
@@ -234,7 +234,7 @@
|
||||
<value>Security key</value>
|
||||
</data>
|
||||
<data name="MouseWithoutBorders_SecurityKey.Description" xml:space="preserve">
|
||||
<value>The key must be auto generated in one machine by clicking on New Key, then typed in other machines</value>
|
||||
<value>To set up, generate the key on one machine, and enter it manually on other machines.</value>
|
||||
</data>
|
||||
<data name="MouseWithoutBorders_NewKey.Content" xml:space="preserve">
|
||||
<value>New key</value>
|
||||
@@ -274,7 +274,7 @@
|
||||
<value>Adding a firewall rule might help solve connection issues.</value>
|
||||
</data>
|
||||
<data name="MouseWithoutBorders_RunAsAdminText.Title" xml:space="preserve">
|
||||
<value>You need to run as administrator to modify this setting.</value>
|
||||
<value>This setting can only be changed when running as administrator</value>
|
||||
</data>
|
||||
<data name="MouseWithoutBorders_ServiceUserUninstallWarning.Title" xml:space="preserve">
|
||||
<value>If PowerToys is installed as a user, uninstalling/upgrading may require the Mouse Without Borders service to be removed manually later.</value>
|
||||
@@ -361,7 +361,7 @@
|
||||
<value>Hide the mouse cursor at the top edge of the screen when switching to other machine. This option also steals the focus from any full-screen app to ensure the keyboard input is redirected.</value>
|
||||
</data>
|
||||
<data name="MouseWithoutBorders_DrawMouseCursor.Description" xml:space="preserve">
|
||||
<value>Mouse cursor may not be visible in Windows 10 and later versions of Windows when there is no physical mouse attached.</value>
|
||||
<value>The mouse cursor may not appear on Windows 10 and later if no physical mouse is connected.</value>
|
||||
</data>
|
||||
<data name="MouseWithoutBorders_ValidateRemoteMachineIP.Description" xml:space="preserve">
|
||||
<value>Reverse DNS lookup to validate machine IP Address.</value>
|
||||
@@ -804,7 +804,7 @@
|
||||
<comment>launches the FancyZones layout editor application</comment>
|
||||
</data>
|
||||
<data name="FancyZones_MakeDraggedWindowTransparentCheckBoxControl.Content" xml:space="preserve">
|
||||
<value>Make dragged window transparent</value>
|
||||
<value>Make the dragged window transparent</value>
|
||||
</data>
|
||||
<data name="FancyZones_MouseDragCheckBoxControl_Header.Content" xml:space="preserve">
|
||||
<value>Use a non-primary mouse button to toggle zone activation</value>
|
||||
@@ -1304,7 +1304,7 @@
|
||||
<value>Always run as administrator</value>
|
||||
</data>
|
||||
<data name="GeneralSettings_AlwaysRunAsAdminText.Description" xml:space="preserve">
|
||||
<value>You need to run as administrator to use this setting</value>
|
||||
<value>This setting can only be changed when running as administrator</value>
|
||||
</data>
|
||||
<data name="GeneralSettings_RunningAsUserText" xml:space="preserve">
|
||||
<value>Running as user</value>
|
||||
@@ -1465,7 +1465,7 @@ Made with 💗 by Microsoft and the PowerToys community.</value>
|
||||
<comment>Preview Pane and File Explorer are app/feature names in Windows. 'Alt + P' is a shortcut</comment>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_RunAsAdminRequired.Title" xml:space="preserve">
|
||||
<value>You need to run as administrator to modify these settings.</value>
|
||||
<value>This setting can only be changed when running as administrator</value>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_RebootRequired.Title" xml:space="preserve">
|
||||
<value>A reboot may be required for changes to these settings to take effect</value>
|
||||
@@ -1520,7 +1520,7 @@ Made with 💗 by Microsoft and the PowerToys community.</value>
|
||||
<value>Mouse actions</value>
|
||||
</data>
|
||||
<data name="ColorPicker_MouseActions.Description" xml:space="preserve">
|
||||
<value>Choose what clicking individual buttons does</value>
|
||||
<value>Customize the function of each mouse button</value>
|
||||
</data>
|
||||
<data name="ColorPicker_PrimaryClick.Header" xml:space="preserve">
|
||||
<value>Primary click</value>
|
||||
@@ -1544,7 +1544,7 @@ Made with 💗 by Microsoft and the PowerToys community.</value>
|
||||
<value>Picker behavior</value>
|
||||
</data>
|
||||
<data name="ColorPicker_CopiedColorRepresentation.Description" xml:space="preserve">
|
||||
<value>This format will be copied to your clipboard</value>
|
||||
<value>Format will be copied to your clipboard</value>
|
||||
</data>
|
||||
<data name="KBM_KeysCannotBeRemapped.Text" xml:space="preserve">
|
||||
<value>Learn more about remapping limitations</value>
|
||||
@@ -1736,7 +1736,7 @@ Made with 💗 by Microsoft and the PowerToys community.</value>
|
||||
<value>Show color name</value>
|
||||
</data>
|
||||
<data name="ColorPicker_ShowColorName.Description" xml:space="preserve">
|
||||
<value>This will show the name of the color when picking a color</value>
|
||||
<value>Displays the color name while picking a color</value>
|
||||
</data>
|
||||
<data name="ImageResizer_DefaultSize_Large" xml:space="preserve">
|
||||
<value>Large</value>
|
||||
@@ -2056,7 +2056,7 @@ Take a moment to preview the various utilities listed or view our comprehensive
|
||||
<value>Diagnostic data</value>
|
||||
</data>
|
||||
<data name="Oobe_Overview_EnableDataDiagnostics.Description" xml:space="preserve">
|
||||
<value>Helps inform bug fixes, performance, and product decisions</value>
|
||||
<value>Helps us make PowerToys faster, more stable, and better over time</value>
|
||||
</data>
|
||||
<data name="Oobe_WhatsNew_DataDiagnostics_InfoBar.Header" xml:space="preserve">
|
||||
<value>Turn on diagnostic data to help us improve PowerToys?</value>
|
||||
@@ -2710,7 +2710,7 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<value>Spotlight initial zoom</value>
|
||||
</data>
|
||||
<data name="MouseUtils_FindMyMouse_SpotlightInitialZoom.Description" xml:space="preserve">
|
||||
<value>Spotlight zoom factor at animation start</value>
|
||||
<value>Spotlight zoom factor at the start of the animation</value>
|
||||
</data>
|
||||
<data name="MouseUtils_FindMyMouse_AnimationDurationMs.Header" xml:space="preserve">
|
||||
<value>Animation duration (ms)</value>
|
||||
@@ -2724,23 +2724,23 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<value>Animations are disabled in your system settings.</value>
|
||||
</data>
|
||||
<data name="MouseUtils_FindMyMouse_ShakingMinimumDistance.Header" xml:space="preserve">
|
||||
<value>Shake minimum distance</value>
|
||||
<value>Minimum shake distance</value>
|
||||
</data>
|
||||
<data name="MouseUtils_FindMyMouse_ShakingMinimumDistance.Description" xml:space="preserve">
|
||||
<value>The minimum distance for mouse shaking activation, for adjusting sensitivity</value>
|
||||
<value>The minimum distance the mouse must move to be considered a shake. Lower values increase sensitivity.</value>
|
||||
</data>
|
||||
<data name="MouseUtils_FindMyMouse_ShakingIntervalMs.Header" xml:space="preserve">
|
||||
<value>Shake Interval (ms)</value>
|
||||
<value>Shake detection interval (ms)</value>
|
||||
<comment>ms = milliseconds</comment>
|
||||
</data>
|
||||
<data name="MouseUtils_FindMyMouse_ShakingIntervalMs.Description" xml:space="preserve">
|
||||
<value>The span of time during which we track mouse movement to detect shaking, for adjusting sensitivity</value>
|
||||
<value>Time window used to monitor mouse movement for shake detection. Shorter intervals may detect quicker shakes.</value>
|
||||
</data>
|
||||
<data name="MouseUtils_FindMyMouse_ShakingFactor.Header" xml:space="preserve">
|
||||
<value>Shake factor (percent)</value>
|
||||
<value>Shake sensitivity factor (percent)</value>
|
||||
</data>
|
||||
<data name="MouseUtils_FindMyMouse_ShakingFactor.Description" xml:space="preserve">
|
||||
<value>Mouse shaking is detected by checking how much the mouse pointer has travelled when compared to the diagonal of the movement area. Reducing this factor increases sensitivity.</value>
|
||||
<value>Determines how far the pointer must move, relative to the screen diagonal, to count as a shake. Lower values make it more sensitive.</value>
|
||||
</data>
|
||||
<data name="MouseUtils_MouseHighlighter.Header" xml:space="preserve">
|
||||
<value>Mouse Highlighter</value>
|
||||
@@ -2840,7 +2840,7 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<value>Windows default</value>
|
||||
</data>
|
||||
<data name="ColorModeHeader.Header" xml:space="preserve">
|
||||
<value>App theme</value>
|
||||
<value>Theme</value>
|
||||
</data>
|
||||
<data name="FancyZones_Zone_Appearance.Description" xml:space="preserve">
|
||||
<value>Customize the way zones look</value>
|
||||
@@ -2848,9 +2848,6 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<data name="FancyZones_Zone_Appearance.Header" xml:space="preserve">
|
||||
<value>Zone appearance</value>
|
||||
</data>
|
||||
<data name="LearnMore.Content" xml:space="preserve">
|
||||
<value>Learn more</value>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_ToggleSwitch_Thumbnail_GCODE.Header" xml:space="preserve">
|
||||
<value>Geometric Code</value>
|
||||
<comment>File type, do not translate</comment>
|
||||
@@ -2906,13 +2903,13 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<value>Reparent shortcut</value>
|
||||
</data>
|
||||
<data name="CropAndLock_ReparentActivation_Shortcut.Description" xml:space="preserve">
|
||||
<value>Shortcut to crop an application's window into a cropped window. This is experimental and can cause issues with some applications, since the cropped window will contain the original application window.</value>
|
||||
<value>Creates a cropped version of an application’s window by embedding the original app into a new window. This is experimental and may cause issues due to the reparenting behavior.</value>
|
||||
</data>
|
||||
<data name="CropAndLock_ThumbnailActivation_Shortcut.Header" xml:space="preserve">
|
||||
<value>Thumbnail shortcut</value>
|
||||
</data>
|
||||
<data name="CropAndLock_ThumbnailActivation_Shortcut.Description" xml:space="preserve">
|
||||
<value>Shortcut to crop and create a thumbnail of another window. The application isn't controllable through the thumbnail but it'll have less compatibility issues. </value>
|
||||
<value>Creates a cropped, non-interactive thumbnail of another window. Improves app compatibility.</value>
|
||||
</data>
|
||||
<data name="CropAndLock.SecondaryLinksHeader" xml:space="preserve">
|
||||
<value>Attribution</value>
|
||||
@@ -2980,12 +2977,6 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<value>Do not activate when Game Mode is on</value>
|
||||
<comment>Game Mode is a Windows feature</comment>
|
||||
</data>
|
||||
<data name="AlwaysOnTop_SoundTitle.Header" xml:space="preserve">
|
||||
<value>Sound</value>
|
||||
</data>
|
||||
<data name="AlwaysOnTop_Sound.Content" xml:space="preserve">
|
||||
<value>Play a sound when pinning a window</value>
|
||||
</data>
|
||||
<data name="AlwaysOnTop_Behavior.Header" xml:space="preserve">
|
||||
<value>Behavior</value>
|
||||
</data>
|
||||
@@ -3061,10 +3052,10 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<value>Behavior</value>
|
||||
</data>
|
||||
<data name="Peek_AlwaysRunNotElevated.Header" xml:space="preserve">
|
||||
<value>Always run not elevated, even when PowerToys is elevated</value>
|
||||
<value>Always run without elevation (even if PowerToys is elevated)</value>
|
||||
</data>
|
||||
<data name="Peek_AlwaysRunNotElevated.Description" xml:space="preserve">
|
||||
<value>Tries to run Peek without elevated permissions, to fix access to network shares. You need to disable and re-enable Peek for changes to this value to take effect.</value>
|
||||
<value>Runs Peek without admin permissions to improve access to network shares. To apply this change, you must disable and re-enable Peek.</value>
|
||||
<comment>Peek is a product name, do not loc</comment>
|
||||
</data>
|
||||
<data name="Peek_CloseAfterLosingFocus.Header" xml:space="preserve">
|
||||
@@ -3072,13 +3063,13 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<comment>Peek is a product name, do not loc</comment>
|
||||
</data>
|
||||
<data name="Peek_ConfirmFileDelete.Header" xml:space="preserve">
|
||||
<value>Ask for confirmation before deleting files</value>
|
||||
<value>Confirm before deleting files</value>
|
||||
</data>
|
||||
<data name="Peek_ConfirmFileDelete.Description" xml:space="preserve">
|
||||
<value>When enabled, you will be prompted to confirm before moving files to the Recycle Bin.</value>
|
||||
<value>You'll be asked to confirm before files are moved to the Recycle Bin</value>
|
||||
</data>
|
||||
<data name="FancyZones_DisableRoundCornersOnWindowSnap.Content" xml:space="preserve">
|
||||
<value>Disable round corners when window is snapped</value>
|
||||
<value>Disable rounded corners when a window is snapped</value>
|
||||
</data>
|
||||
<data name="PowerLauncher_SearchQueryTuningEnabled.Description" xml:space="preserve">
|
||||
<value>Fine tune results ordering</value>
|
||||
@@ -3111,7 +3102,7 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<value>Global sort order score modifier</value>
|
||||
</data>
|
||||
<data name="AlwaysOnTop_RoundCorners.Content" xml:space="preserve">
|
||||
<value>Enable round corners</value>
|
||||
<value>Enable rounded corners</value>
|
||||
</data>
|
||||
<data name="LearnMore_QuickAccent.Text" xml:space="preserve">
|
||||
<value>Learn more about Quick Accent</value>
|
||||
@@ -3164,9 +3155,6 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="AlwaysOnTop_ShortDescription" xml:space="preserve">
|
||||
<value>Pin a window</value>
|
||||
</data>
|
||||
<data name="Awake_ShortDescription" xml:space="preserve">
|
||||
<value>Keep your PC awake</value>
|
||||
</data>
|
||||
<data name="ColorPicker_ShortDescription" xml:space="preserve">
|
||||
<value>Pick a color</value>
|
||||
</data>
|
||||
@@ -3185,9 +3173,6 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="FindMyMouse_ShortDescription" xml:space="preserve">
|
||||
<value>Find the mouse</value>
|
||||
</data>
|
||||
<data name="ImageResizer_ShortDescription" xml:space="preserve">
|
||||
<value>Resize images from right-click context menu</value>
|
||||
</data>
|
||||
<data name="MouseHighlighter_ShortDescription" xml:space="preserve">
|
||||
<value>Highlight clicks</value>
|
||||
</data>
|
||||
@@ -3197,9 +3182,6 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="MouseCrosshairs_ShortDescription" xml:space="preserve">
|
||||
<value>Draw crosshairs centered on the mouse pointer</value>
|
||||
</data>
|
||||
<data name="MouseWithoutBorders_ShortDescription" xml:space="preserve">
|
||||
<value>Move your cursor across multiple devices</value>
|
||||
</data>
|
||||
<data name="AdvancedPaste_ShortDescription" xml:space="preserve">
|
||||
<value>An AI powered tool to put your clipboard content into any format you need, focused towards developer workflows.</value>
|
||||
</data>
|
||||
@@ -3212,9 +3194,6 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="Peek_ShortDescription" xml:space="preserve">
|
||||
<value>Quick and easy previewer</value>
|
||||
</data>
|
||||
<data name="PowerRename_ShortDescription" xml:space="preserve">
|
||||
<value>Rename files and folders from right-click context menu</value>
|
||||
</data>
|
||||
<data name="Run_ShortDescription" xml:space="preserve">
|
||||
<value>A quick launcher</value>
|
||||
</data>
|
||||
@@ -3315,7 +3294,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<comment>ms = milliseconds</comment>
|
||||
</data>
|
||||
<data name="QuickAccent_InputTimeMs.Description" xml:space="preserve">
|
||||
<value>Hold the key down for this much time to make the accent menu appear (ms)</value>
|
||||
<value>How long a key must be held before the accent menu appears</value>
|
||||
<comment>ms = milliseconds</comment>
|
||||
</data>
|
||||
<data name="QuickAccent_ExcludedApps.Description" xml:space="preserve">
|
||||
@@ -3646,7 +3625,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<comment>"Hosts File Editor" is a product name</comment>
|
||||
</data>
|
||||
<data name="Hosts_AdditionalLinesPosition.Header" xml:space="preserve">
|
||||
<value>Position of additional content</value>
|
||||
<value>Placement of additional content</value>
|
||||
</data>
|
||||
<data name="Hosts_AdditionalLinesPosition_Bottom.Content" xml:space="preserve">
|
||||
<value>Bottom</value>
|
||||
@@ -3674,7 +3653,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<comment>"Hosts File Editor" is the name of the utility</comment>
|
||||
</data>
|
||||
<data name="Hosts_Toggle_LaunchAdministrator.Description" xml:space="preserve">
|
||||
<value>Needs to be launched as administrator in order to make changes to the hosts file</value>
|
||||
<value>Required in order to make changes to the hosts file</value>
|
||||
</data>
|
||||
<data name="Hosts_Toggle_LaunchAdministrator.Header" xml:space="preserve">
|
||||
<value>Launch as administrator</value>
|
||||
@@ -3716,7 +3695,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Environment Variables</value>
|
||||
</data>
|
||||
<data name="EnvironmentVariables_Toggle_LaunchAdministrator.Description" xml:space="preserve">
|
||||
<value>Needs to be launched as administrator in order to make changes to the system environment variables</value>
|
||||
<value>Required in order to make changes to the system environment variables</value>
|
||||
</data>
|
||||
<data name="EnvironmentVariables_Toggle_LaunchAdministrator.Header" xml:space="preserve">
|
||||
<value>Launch as administrator</value>
|
||||
@@ -3757,7 +3736,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>This setting is managed by your organization.</value>
|
||||
</data>
|
||||
<data name="Hosts_AdditionalLinesPosition.Description" xml:space="preserve">
|
||||
<value>Additional content includes the file header and lines that can't parse</value>
|
||||
<value>Includes items like the file header and any lines that can’t be parsed</value>
|
||||
</data>
|
||||
<data name="TextExtractor_Languages.Header" xml:space="preserve">
|
||||
<value>Preferred language</value>
|
||||
@@ -3794,7 +3773,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Experimentation</value>
|
||||
</data>
|
||||
<data name="GeneralPage_EnableExperimentation.Description" xml:space="preserve">
|
||||
<value>Note: Only Windows Insider builds may be selected for experimentation</value>
|
||||
<value>Only Windows Insider builds may be selected for experimentation</value>
|
||||
<comment>{Locked="Windows Insider"}</comment>
|
||||
</data>
|
||||
<data name="GeneralPage_EnableExperimentation.Header" xml:space="preserve">
|
||||
@@ -3804,28 +3783,13 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Diagnostics & feedback</value>
|
||||
</data>
|
||||
<data name="GeneralPage_DiagnosticsAndFeedback_Link.Content" xml:space="preserve">
|
||||
<value>Learn more about the information we log & how it gets used</value>
|
||||
<value>Learn more about the logged information and how it's used</value>
|
||||
</data>
|
||||
<data name="GeneralPage_EnableDataDiagnostics.Header" xml:space="preserve">
|
||||
<value>Diagnostic data</value>
|
||||
</data>
|
||||
<data name="GeneralPage_EnableDataDiagnostics.Description" xml:space="preserve">
|
||||
<value>Helps inform bug fixes, performance, and improvements</value>
|
||||
</data>
|
||||
<data name="GeneralPage_ViewDiagnosticData.Header" xml:space="preserve">
|
||||
<value>View diagnostic data</value>
|
||||
</data>
|
||||
<data name="GeneralPage_EnableViewDiagnosticData.Header" xml:space="preserve">
|
||||
<value>Enable viewing</value>
|
||||
</data>
|
||||
<data name="GeneralPage_EnableViewDiagnosticData.Description" xml:space="preserve">
|
||||
<value>Uses up to 1GB (or more) of hard drive space on your PC</value>
|
||||
</data>
|
||||
<data name="GeneralPage_ViewDiagnosticDataViewer.Header" xml:space="preserve">
|
||||
<value>Diagnostic data viewer</value>
|
||||
</data>
|
||||
<data name="GeneralPage_ViewDiagnosticDataViewer.Description" xml:space="preserve">
|
||||
<value>Generate .xml files containing readable diagnostic data. Folder may include .xml and .etl files</value>
|
||||
<value>Save logs to this device</value>
|
||||
</data>
|
||||
<data name="Shell_AdvancedPaste.Content" xml:space="preserve">
|
||||
<value>Advanced Paste</value>
|
||||
@@ -3988,9 +3952,6 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="QuickAccessTxt.Text" xml:space="preserve">
|
||||
<value>Quick access</value>
|
||||
</data>
|
||||
<data name="UpdateAvailable.Title" xml:space="preserve">
|
||||
<value>Update available</value>
|
||||
</data>
|
||||
<data name="FileExplorerPreview_Toggle_Monaco_Max_File_Size.Header" xml:space="preserve">
|
||||
<value>Maximum file size to preview</value>
|
||||
<comment>Size refers to the disk space used by a file</comment>
|
||||
@@ -4055,7 +4016,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Activation shortcut</value>
|
||||
</data>
|
||||
<data name="MouseUtils_MouseJump_ThumbnailSize.Header" xml:space="preserve">
|
||||
<value>Thumbnail Size</value>
|
||||
<value>Thumbnail size</value>
|
||||
</data>
|
||||
<data name="MouseUtils_MouseJump_ThumbnailSize_Description_Prefix.Text" xml:space="preserve">
|
||||
<value>Constrain thumbnail image size to a maximum of</value>
|
||||
@@ -4190,11 +4151,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Launch Registry Preview</value>
|
||||
</data>
|
||||
<data name="RegistryPreview_DefaultRegApp.Header" xml:space="preserve">
|
||||
<value>Default app</value>
|
||||
</data>
|
||||
<data name="RegistryPreview_DefaultRegApp.Description" xml:space="preserve">
|
||||
<value>Make Registry Preview default app for opening .reg files</value>
|
||||
<comment>Registry Preview is app name. Do not localize.</comment>
|
||||
<value>Make Registry Preview the default app for .reg files</value>
|
||||
</data>
|
||||
<data name="AdvancedPaste_ShortcutWarning.Title" xml:space="preserve">
|
||||
<value>Using this shortcut may prevent non-text paste actions (e.g. images, files) or built-in paste plain text actions in other applications from functioning.</value>
|
||||
@@ -4272,12 +4229,6 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="Shell_Dashboard.Content" xml:space="preserve">
|
||||
<value>Dashboard</value>
|
||||
</data>
|
||||
<data name="DisabledModules.Text" xml:space="preserve">
|
||||
<value>Disabled modules</value>
|
||||
</data>
|
||||
<data name="EnabledModules.Text" xml:space="preserve">
|
||||
<value>Enabled modules</value>
|
||||
</data>
|
||||
<data name="Peek_Preview_GroupSettings.Header" xml:space="preserve">
|
||||
<value>Preview</value>
|
||||
</data>
|
||||
@@ -4321,7 +4272,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Show the release notes after an update</value>
|
||||
</data>
|
||||
<data name="ShowSystemTrayIcon.Description" xml:space="preserve">
|
||||
<value>This settings page is accessible by running the PowerToys executable again</value>
|
||||
<value>To access settings, run the PowerToys executable again</value>
|
||||
</data>
|
||||
<data name="ShowSystemTrayIcon.Header" xml:space="preserve">
|
||||
<value>Show system tray icon</value>
|
||||
@@ -4421,10 +4372,6 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>New+</value>
|
||||
<comment>New+ is the name of the utility. Localize product name in accordance with Windows New</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Product_Description.Description" xml:space="preserve">
|
||||
<value>Create files and folders from a personalized set of templates</value>
|
||||
<comment>New+ product description</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Learn_More.Text" xml:space="preserve">
|
||||
<value>Learn more about New+</value>
|
||||
<comment>New+ learn more link. Localize product name in accordance with Windows New</comment>
|
||||
@@ -4461,15 +4408,15 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<comment>Display options label</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Hide_File_Extension_Toggle.Header" xml:space="preserve">
|
||||
<value>Hide template filename extension</value>
|
||||
<value>Hide the file extension in template names</value>
|
||||
<comment>Template file name extension settings toggle</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Hide_Starting_Digits_Toggle.Header" xml:space="preserve">
|
||||
<value>Hide template filename starting digits, spaces, and dots</value>
|
||||
<value>Hide leading digits, spaces, and dots in template filenames</value>
|
||||
<comment>Template filename starting digits settings toggle</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Hide_Starting_Digits_Description.Text" xml:space="preserve">
|
||||
<value>This option is useful when using digits, spaces and dots at the beginning of filenames to control the display order of templates</value>
|
||||
<value>Ignores digits, spaces, and dots at the start of filenames—useful for sorting templates without showing those characters</value>
|
||||
<comment>Template filename starting digits settings toggle</comment>
|
||||
</data>
|
||||
<data name="NewPlus_behavior.Header" xml:space="preserve">
|
||||
@@ -4856,13 +4803,13 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<value>Open settings</value>
|
||||
</data>
|
||||
<data name="LanguageHeader.Header" xml:space="preserve">
|
||||
<value>Application language</value>
|
||||
<value>Language</value>
|
||||
</data>
|
||||
<data name="LanguageHeader.Description" xml:space="preserve">
|
||||
<value>PowerToys will use OS language by default.</value>
|
||||
<value>PowerToys matches your Windows language by default</value>
|
||||
</data>
|
||||
<data name="LanguageRestartInfo.Title" xml:space="preserve">
|
||||
<value>Restart PowerToys for language change to take effect.</value>
|
||||
<value>Restart PowerToys to apply language changes</value>
|
||||
</data>
|
||||
<data name="LanguageRestartInfoButton.Content" xml:space="preserve">
|
||||
<value>Restart</value>
|
||||
@@ -5057,7 +5004,7 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<value>Generate bug report package</value>
|
||||
</data>
|
||||
<data name="GeneralPage_ReportBugPackage.Description" xml:space="preserve">
|
||||
<value>Create zip folder with logs on the Desktop</value>
|
||||
<value>Log files will be zipped to your desktop</value>
|
||||
</data>
|
||||
<data name="GeneralPageReportBugPackage.Content" xml:space="preserve">
|
||||
<value>Generate package</value>
|
||||
@@ -5080,4 +5027,41 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<data name="HighlightMode_Spotlight_Mode.Content" xml:space="preserve">
|
||||
<value>Spotlight</value>
|
||||
</data>
|
||||
<data name="LearnMore.Content" xml:space="preserve">
|
||||
<value>Learn more</value>
|
||||
</data>
|
||||
<data name="Awake_ShortDescription" xml:space="preserve">
|
||||
<value>Keep your PC awake</value>
|
||||
</data>
|
||||
<data name="ImageResizer_ShortDescription" xml:space="preserve">
|
||||
<value>Resize images from right-click context menu</value>
|
||||
</data>
|
||||
<data name="MouseWithoutBorders_ShortDescription" xml:space="preserve">
|
||||
<value>Move your cursor across multiple devices</value>
|
||||
</data>
|
||||
<data name="PowerRename_ShortDescription" xml:space="preserve">
|
||||
<value>Rename files and folders from right-click context menu</value>
|
||||
</data>
|
||||
<data name="GeneralPage_EnableDataDiagnosticsText.Text" xml:space="preserve">
|
||||
<value>Helps us make PowerToys faster, more stable, and better over time</value>
|
||||
</data>
|
||||
<data name="UpdateAvailable.Title" xml:space="preserve">
|
||||
<value>Update available</value>
|
||||
</data>
|
||||
<data name="DisabledModules.Text" xml:space="preserve">
|
||||
<value>Disabled modules</value>
|
||||
</data>
|
||||
<data name="EnabledModules.Text" xml:space="preserve">
|
||||
<value>Enabled modules</value>
|
||||
</data>
|
||||
<data name="NewPlus_Product_Description.Description" xml:space="preserve">
|
||||
<value>Create files and folders from a personalized set of templates</value>
|
||||
<comment>New+ product description</comment>
|
||||
</data>
|
||||
<data name="AlwaysOnTop_Sound.Header" xml:space="preserve">
|
||||
<value>Play a sound when pinning a window</value>
|
||||
</data>
|
||||
<data name="GeneralPage_EnableViewDiagnosticDataText.Text" xml:space="preserve">
|
||||
<value>Stores diagnostic data locally in .xml format; folder may include .etl files as well. May use up 1 GB or more of disk space.</value>
|
||||
</data>
|
||||
</root>
|
||||
Reference in New Issue
Block a user