Compare commits
2 Commits
issue/102-
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0c197da67 | ||
|
|
122148ca58 |
2
.github/actions/spell-check/allow/code.txt
vendored
@@ -320,4 +320,4 @@ MRUINFO
|
||||
REGSTR
|
||||
|
||||
# Misc Win32 APIs and PInvokes
|
||||
INVOKEIDLIST
|
||||
INVOKEIDLIST
|
||||
8
.github/actions/spell-check/expect.txt
vendored
@@ -27,7 +27,6 @@ admx
|
||||
advancedpaste
|
||||
advancedpasteui
|
||||
advancedpasteuishortcut
|
||||
advapi32
|
||||
advfirewall
|
||||
AFeature
|
||||
affordances
|
||||
@@ -248,7 +247,6 @@ CONFIGW
|
||||
CONFLICTINGMODIFIERKEY
|
||||
CONFLICTINGMODIFIERSHORTCUT
|
||||
CONOUT
|
||||
coreclr
|
||||
constexpr
|
||||
contentdialog
|
||||
contentfiles
|
||||
@@ -270,8 +268,6 @@ cpcontrols
|
||||
cph
|
||||
cplusplus
|
||||
CPower
|
||||
cpptools
|
||||
cppvsdbg
|
||||
cppwinrt
|
||||
createdump
|
||||
CREATEPROCESS
|
||||
@@ -283,7 +279,6 @@ CRH
|
||||
critsec
|
||||
cropandlock
|
||||
Crossdevice
|
||||
csdevkit
|
||||
CSearch
|
||||
CSettings
|
||||
cso
|
||||
@@ -1456,6 +1451,7 @@ rstringalnum
|
||||
rstringalpha
|
||||
rstringdigit
|
||||
rtb
|
||||
RTB
|
||||
RTLREADING
|
||||
rtm
|
||||
runas
|
||||
@@ -1802,7 +1798,6 @@ UIA
|
||||
UIEx
|
||||
uild
|
||||
uitests
|
||||
UITo
|
||||
ULONGLONG
|
||||
ums
|
||||
uncompilable
|
||||
@@ -2017,7 +2012,6 @@ XButton
|
||||
xclip
|
||||
xcopy
|
||||
XDeployment
|
||||
xdf
|
||||
XDocument
|
||||
XElement
|
||||
xfd
|
||||
|
||||
43
.github/copilot-instructions.md
vendored
@@ -1,43 +0,0 @@
|
||||
# PowerToys – Copilot guide (concise)
|
||||
|
||||
This is the top-level guide for AI changes. Keep edits small, follow existing patterns, and cite exact paths in PRs.
|
||||
|
||||
Repo map (1‑line per area)
|
||||
- Core apps: `src/runner/**` (tray/loader), `src/settings-ui/**` (Settings app)
|
||||
- Shared libs: `src/common/**`
|
||||
- Modules: `src/modules/*` (one per utility; Command Palette in `src/modules/cmdpal/**`)
|
||||
- Build tools/docs: `tools/**`, `doc/devdocs/**`
|
||||
|
||||
Build and test (defaults)
|
||||
- Prerequisites: Visual Studio 2022 17.4+, minimal Windows 10 1803+.
|
||||
- Build discipline:
|
||||
- One terminal per operation (build → test). Don’t switch/open new ones mid-flow.
|
||||
- After making changes, `cd` to the project folder that changed (`.csproj`/`.vcxproj`).
|
||||
- Use script(s) to build, synchronously block and wait in foreground for it to finish: `tools/build/build.ps1|.cmd` (current folder), `build-essentials.*` (once per brand new build for missing nuget packages)
|
||||
- Treat build **exit code 0** as success; any non-zero exit code is a failure, have Copilot read the errors log in the build folder (e.g., `build.*.*.errors.log`) and surface problems.
|
||||
- Don’t start tests or launch Runner until the previous step succeeded.
|
||||
- Tests (fast + targeted):
|
||||
- Find the test project by product code prefix (e.g., FancyZones, AdvancedPaste). Look for a sibling folder or 1–2 levels up named like `<Product>*UnitTests` or `<Product>*UITests`.
|
||||
- Build the test project, wait for **exit**, then run only those tests via VS Test Explorer or `vstest.console.exe` with filters. Avoid `dotnet test` in this repo.
|
||||
- Add/adjust tests when changing behavior; if skipped, state why (e.g., comment-only, string rename).
|
||||
|
||||
Pull requests (expectations)
|
||||
- Atomic: one logical change; no drive‑by refactors.
|
||||
- Describe: problem / approach / risk / test evidence.
|
||||
- List: touched paths if not obvious.
|
||||
|
||||
When to ask for clarification
|
||||
- Ambiguous spec after scanning relevant docs (see below).
|
||||
- Cross-module impact (shared enum/struct) not clear.
|
||||
- Security / elevation / installer changes.
|
||||
|
||||
Logging (use existing stacks)
|
||||
- C++: `src/common/logger/**` (`Logger::info|warn|error|debug`). Keep hot paths quiet (hooks, tight loops).
|
||||
- C#: `ManagedCommon.Logger` (`LogInfo|LogWarning|LogError|LogDebug|LogTrace`). Some UIs use injected `ILogger` via `LoggerInstance.Logger`.
|
||||
|
||||
Docs to consult
|
||||
- `tools/build/BUILD-GUIDELINES.md`
|
||||
- `doc/devdocs/core/architecture.md`, `doc/devdocs/core/runner.md`, `doc/devdocs/core/settings/readme.md`, `doc/devdocs/modules/readme.md`
|
||||
|
||||
Done checklist (self review before finishing)
|
||||
- Build clean? Tests updated/passed? No unintended formatting? Any new dependency? Documented skips?
|
||||
@@ -1,19 +0,0 @@
|
||||
name: Automatic New Issue Deduplication
|
||||
on:
|
||||
issues:
|
||||
types: [opened, reopened]
|
||||
permissions:
|
||||
models: read
|
||||
issues: write
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.issue.number }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
deduplicate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Deduplicate Action
|
||||
uses: pelikhan/action-genai-issue-dedup@v0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
label_as_duplicate: true
|
||||
@@ -1,38 +0,0 @@
|
||||
# .pipelines/v2/nightly-prewarm.yml
|
||||
# Nightly pre-warm that reuses your existing ci.yml as-is
|
||||
|
||||
trigger: none
|
||||
pr: none
|
||||
|
||||
# (18:00 UTC) — adjust as you like
|
||||
schedules:
|
||||
- cron: "0 18 * * *" # UTC
|
||||
displayName: Nightly pre-warm (main)
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: true
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
|
||||
parameters:
|
||||
- name: buildPlatforms
|
||||
type: object
|
||||
default:
|
||||
- x64
|
||||
- arm64
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
displayName: "Enable MSBuild Caching"
|
||||
default: true
|
||||
- name: msBuildCacheIsReadOnly
|
||||
type: boolean
|
||||
displayName: "MSBuild Cache Read Only"
|
||||
default: false
|
||||
|
||||
extends:
|
||||
template: templates/pipeline-ci-build.yml
|
||||
parameters:
|
||||
buildPlatforms: ${{ parameters.buildPlatforms }}
|
||||
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
|
||||
msBuildCacheIsReadOnly: ${{ parameters.msBuildCacheIsReadOnly }}
|
||||
@@ -32,7 +32,7 @@ parameters:
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
displayName: "Enable MSBuild Caching"
|
||||
default: false
|
||||
default: true
|
||||
- name: runTests
|
||||
type: boolean
|
||||
displayName: "Run Tests"
|
||||
|
||||
@@ -50,9 +50,6 @@ parameters:
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
default: false
|
||||
- name: msBuildCacheIsReadOnly
|
||||
type: boolean
|
||||
default: true
|
||||
- name: runTests
|
||||
type: boolean
|
||||
default: true
|
||||
@@ -157,11 +154,6 @@ jobs:
|
||||
$MSBuildCacheParameters += " -reportfileaccesses"
|
||||
$MSBuildCacheParameters += " -p:MSBuildCacheEnabled=true"
|
||||
$MSBuildCacheParameters += " -p:MSBuildCacheLogDirectory=$(LogOutputDirectory)\MSBuildCacheLogs"
|
||||
# Cache read-only policy controlled by parameter
|
||||
$cacheIsReadOnly = "${{ parameters.msBuildCacheIsReadOnly }}"
|
||||
if ($cacheIsReadOnly -eq "True") {
|
||||
$MSBuildCacheParameters += " /p:MSBuildCacheRemoteCacheIsReadOnly=true"
|
||||
}
|
||||
Write-Host "MSBuildCacheParameters: $MSBuildCacheParameters"
|
||||
Write-Host "##vso[task.setvariable variable=MSBuildCacheParameters]$MSBuildCacheParameters"
|
||||
displayName: Prepare MSBuildCache variables
|
||||
@@ -419,28 +411,9 @@ jobs:
|
||||
!**\obj\**
|
||||
|
||||
- pwsh: |-
|
||||
$Packages = Get-ChildItem -Recurse -Filter "Microsoft.CmdPal.UI_*.msix"
|
||||
Write-Host "Found $($Packages.Count) CmdPal MSIX package(s):"
|
||||
foreach ($pkg in $Packages) {
|
||||
Write-Host " - $($pkg.FullName)"
|
||||
}
|
||||
|
||||
if ($Packages.Count -gt 0) {
|
||||
# Priority: Look for platform-specific MSIX (x64/arm64) first, then fallback to any
|
||||
$PlatformPackage = $Packages | Where-Object { $_.Name -match "Microsoft\.CmdPal\.UI_.*_(x64|arm64)\.msix$" } | Select-Object -First 1
|
||||
if ($PlatformPackage) {
|
||||
$Package = $PlatformPackage
|
||||
Write-Host "Using platform-specific package: $($Package.FullName)"
|
||||
} else {
|
||||
$Package = $Packages | Select-Object -First 1
|
||||
Write-Host "Using first available package: $($Package.FullName)"
|
||||
}
|
||||
|
||||
$PackageFilename = $Package.FullName
|
||||
Write-Host "##vso[task.setvariable variable=CmdPalPackagePath]${PackageFilename}"
|
||||
} else {
|
||||
Write-Warning "No CmdPal MSIX packages found!"
|
||||
}
|
||||
$Package = (Get-ChildItem -Recurse -Filter "Microsoft.CmdPal.UI_*.msix" | Select -First 1)
|
||||
$PackageFilename = $Package.FullName
|
||||
Write-Host "##vso[task.setvariable variable=CmdPalPackagePath]${PackageFilename}"
|
||||
displayName: Locate the CmdPal MSIX
|
||||
|
||||
- ${{ if eq(parameters.codeSign, true) }}:
|
||||
|
||||
@@ -13,9 +13,6 @@ parameters:
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
default: false
|
||||
- name: msBuildCacheIsReadOnly
|
||||
type: boolean
|
||||
default: true
|
||||
- name: runTests
|
||||
type: boolean
|
||||
default: true
|
||||
@@ -55,7 +52,6 @@ stages:
|
||||
buildConfigurations: [Release]
|
||||
enablePackageCaching: true
|
||||
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
|
||||
msBuildCacheIsReadOnly: ${{ parameters.msBuildCacheIsReadOnly }}
|
||||
runTests: ${{ parameters.runTests }}
|
||||
useVSPreview: ${{ parameters.useVSPreview }}
|
||||
useLatestWinAppSDK: ${{ parameters.useLatestWinAppSDK }}
|
||||
|
||||
43
.vscode/launch.json
vendored
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"inputs": [
|
||||
{
|
||||
"id": "arch",
|
||||
"type": "pickString",
|
||||
"description": "Select target architecture",
|
||||
"options": ["x64", "arm64"],
|
||||
"default": "x64"
|
||||
}
|
||||
],
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run native executable (no build)",
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}\\${input:arch}\\Debug\\PowerToys.exe",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "C/C++ Attach to PowerToys Process (native)",
|
||||
"type": "cppvsdbg",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}",
|
||||
"symbolSearchPath": "${workspaceFolder}\\${input:arch}\\Debug;${workspaceFolder}\\Debug;${workspaceFolder}\\symbols"
|
||||
},
|
||||
{
|
||||
"name": "Run managed code (managed, no build, ARCH configurable)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}\\${input:arch}\\Debug\\WinUI3Apps\\PowerToys.Settings.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": {},
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -45,7 +45,7 @@
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.8" />
|
||||
<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.3179.45" />
|
||||
<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.8" />
|
||||
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
|
||||
@@ -57,8 +57,8 @@
|
||||
This is present due to a bug in CsWinRT where WPF projects cause the analyzer to fail.
|
||||
-->
|
||||
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4948" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.250907003" />
|
||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4188" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250513003" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
|
||||
<PackageVersion Include="ModernWpfUI" Version="0.9.4" />
|
||||
|
||||
@@ -262,6 +262,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{B39DC643
|
||||
src\common\utils\EventLocker.h = src\common\utils\EventLocker.h
|
||||
src\common\utils\EventWaiter.h = src\common\utils\EventWaiter.h
|
||||
src\common\utils\excluded_apps.h = src\common\utils\excluded_apps.h
|
||||
src\common\utils\shell_ext_registration.h = src\common\utils\shell_ext_registration.h
|
||||
src\common\utils\exec.h = src\common\utils\exec.h
|
||||
src\common\utils\game_mode.h = src\common\utils\game_mode.h
|
||||
src\common\utils\gpo.h = src\common\utils\gpo.h
|
||||
@@ -281,7 +282,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{B39DC643
|
||||
src\common\utils\registry.h = src\common\utils\registry.h
|
||||
src\common\utils\resources.h = src\common\utils\resources.h
|
||||
src\common\utils\serialized.h = src\common\utils\serialized.h
|
||||
src\common\utils\shell_ext_registration.h = src\common\utils\shell_ext_registration.h
|
||||
src\common\utils\string_utils.h = src\common\utils\string_utils.h
|
||||
src\common\utils\timeutil.h = src\common\utils\timeutil.h
|
||||
src\common\utils\UnhandledExceptionHandler.h = src\common\utils\UnhandledExceptionHandler.h
|
||||
@@ -793,10 +793,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Window
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.UnitTestBase", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.UnitTestsBase\Microsoft.CmdPal.Ext.UnitTestBase.csproj", "{00D8659C-2068-40B6-8B86-759CD6284BBB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{E11826E1-76DF-42AC-985C-164CC2EE57A1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScreenRuler.UITests", "src\modules\MeasureTool\Tests\ScreenRuler.UITests\ScreenRuler.UITests.csproj", "{66C069F8-C548-4CA6-8CDE-239104D68E88}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Apps.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Apps.UnitTests\Microsoft.CmdPal.Ext.Apps.UnitTests.csproj", "{E816D7B1-4688-4ECB-97CC-3D8E798F3830}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Bookmarks.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Bookmarks.UnitTests\Microsoft.CmdPal.Ext.Bookmarks.UnitTests.csproj", "{E816D7B3-4688-4ECB-97CC-3D8E798F3832}"
|
||||
@@ -2699,22 +2695,6 @@ Global
|
||||
{61CBF221-9452-4934-B685-146285E080D7}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{61CBF221-9452-4934-B685-146285E080D7}.Release|x64.ActiveCfg = Release|x64
|
||||
{61CBF221-9452-4934-B685-146285E080D7}.Release|x64.Build.0 = Release|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|x64.Build.0 = Debug|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|x64.ActiveCfg = Release|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|x64.Build.0 = Release|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|x64.Build.0 = Release|x64
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2731,6 +2711,30 @@ Global
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}.Release|x64.ActiveCfg = Release|x64
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}.Release|x64.Build.0 = Release|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|x64.Build.0 = Debug|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|x64.ActiveCfg = Release|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|x64.Build.0 = Release|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|x64.Build.0 = Release|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.Build.0 = Debug|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.ActiveCfg = Release|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.Build.0 = Release|x64
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2883,14 +2887,6 @@ Global
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.ActiveCfg = Release|x64
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.Build.0 = Release|x64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Debug|x64.Build.0 = Debug|x64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Release|x64.ActiveCfg = Release|x64
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88}.Release|x64.Build.0 = Release|x64
|
||||
{E816D7B1-4688-4ECB-97CC-3D8E798F3830}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{E816D7B1-4688-4ECB-97CC-3D8E798F3830}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{E816D7B1-4688-4ECB-97CC-3D8E798F3830}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2932,6 +2928,7 @@ Global
|
||||
{D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9} = {264B412F-DB8B-4CF8-A74B-96998B183045}
|
||||
{1AFB6476-670D-4E80-A464-657E01DFF482} = {557C4636-D7E1-4838-A504-7D19B725EE95}
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
@@ -3197,10 +3194,10 @@ Global
|
||||
{9BC1C986-1E97-4D07-A7B1-CE226C239EFA} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{99CA1509-FB73-456E-AFAF-AB89C017BD72} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
|
||||
{61CBF221-9452-4934-B685-146285E080D7} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1} = {2C318EC3-BA86-4372-B1BC-DB0F33C208B2}
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9} = {68328142-5B31-4715-BCBB-7B6345EE0971}
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{14AFD976-B4D2-49D0-9E6C-AA93CC061B8A} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{9D3F3793-EFE3-4525-8782-238015DABA62} = {66E1534A-1587-42B2-912F-45C994D32904}
|
||||
@@ -3236,8 +3233,6 @@ Global
|
||||
{E816D7AF-4688-4ECB-97CC-3D8E798F3828} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E816D7B0-4688-4ECB-97CC-3D8E798F3829} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{00D8659C-2068-40B6-8B86-759CD6284BBB} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E11826E1-76DF-42AC-985C-164CC2EE57A1} = {7AC943C9-52E8-44CF-9083-744D8049667B}
|
||||
{66C069F8-C548-4CA6-8CDE-239104D68E88} = {E11826E1-76DF-42AC-985C-164CC2EE57A1}
|
||||
{E816D7B1-4688-4ECB-97CC-3D8E798F3830} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E816D7B3-4688-4ECB-97CC-3D8E798F3832} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
{E816D7B2-4688-4ECB-97CC-3D8E798F3831} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||
|
||||
@@ -18,8 +18,8 @@ You can build the entire solution from the command line, which is sometimes fast
|
||||
1. Open Developer Command Prompt for VS 2022
|
||||
2. Navigate to the repository root directory
|
||||
3. Run the following command(don't forget to set the correct platform):
|
||||
```pwsh
|
||||
msbuild -restore -p:RestorePackagesConfig=true -p:Platform=ARM64 -m PowerToys.sln /tl /p:NuGetInteractive="true"
|
||||
```
|
||||
msbuild -restore -p:RestorePackagesConfig=true -p:Platform=ARM64 -m PowerToys.sln
|
||||
```
|
||||
4. This process should complete in approximately 13-14 minutes for a full build
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
## Developing PowerToys with Visual Studio Code
|
||||
|
||||
This guide shows how to build, debug, and contribute to PowerToys using VS Code instead of (or alongside) full Visual Studio. It focuses on common inner‑loop tasks for C++, .NET, and mixed scenarios present in the solution.
|
||||
|
||||
> PowerToys is a large mixed C++ / C# / WinAppSDK solution. VS Code works well for incremental development and quick module iterations, but occasionally you may still prefer full Visual Studio for designer tooling or specialized diagnostics.
|
||||
|
||||
---
|
||||
VS Code extensions Needed:
|
||||
|
||||
| Area | Extension | Notes |
|
||||
|------|-----------|-------|
|
||||
| C++ | ms-vscode.cpptools | IntelliSense, debugging (cppvsdbg) |
|
||||
| C# | ms-dotnettools.csdevkit (or C#) | Language service / test explorer |
|
||||
|
||||
---
|
||||
|
||||
## Building in VS Code
|
||||
### Configure developer powershell for vs2022 for more convenient dev in vscode.
|
||||
1. Configure profile in in settings, entry: "terminal.integrated.profiles.windows"
|
||||
2. Add below config as entry:
|
||||
```json
|
||||
"Developer PowerShell for VS 2022": {
|
||||
// Configure based on your preference
|
||||
"path": "C:\\Program Files\\WindowsApps\\Microsoft.PowerShell_7.5.2.0_arm64__8wekyb3d8bbwe\\pwsh.exe",
|
||||
"args": [
|
||||
"-NoExit",
|
||||
"-Command",
|
||||
"& {",
|
||||
"$orig = Get-Location;",
|
||||
// Configure based on your environment
|
||||
"& 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\Tools\\Launch-VsDevShell.ps1';",
|
||||
"Set-Location $orig",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
```
|
||||
3. [Optional] Set Developer PowerShell for VS 2022 as your default profile, so that you can get a deep integration with vscode coding agent.
|
||||
|
||||
4. Now You can build with plain `msbuild` or configure tasks.json in below section
|
||||
Or reach out to "tools\build\BUILD-GUIDELINES.md"
|
||||
|
||||
### Sample plain msbuild command
|
||||
```powershell
|
||||
# Restore:
|
||||
msbuild powertoys.sln -t:restore -p:configuration=debug -p:platform=x64 -m
|
||||
|
||||
# Build powertoys sln
|
||||
msbuild powertoys.sln -p:configuration=debug -p:platform=x64 -m
|
||||
|
||||
# dotnet project
|
||||
msbuild src\settings-ui\Settings.UI\PowerToys.Settings.csproj -p:Platform=x64 -p:Configuration=Debug -m
|
||||
|
||||
# native project
|
||||
msbuild "src\modules\MouseUtils\FindMyMouse\FindMyMouse.vcxproj" -p:Configuration=Debug -p:Platform=x64 -m
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
### Existing launch configuration
|
||||
|
||||
The repo provides `.vscode/launch.json` with:
|
||||
|
||||
- `Run PowerToys.exe (no build)`: Launches the already-built executable at `x64/Debug/PowerToys.exe` using `cppvsdbg`.
|
||||
|
||||
Build first, then press F5. To switch configuration (Release / ARM64) either edit the path or create additional launch entries.
|
||||
|
||||
### Attaching to a running instance
|
||||
|
||||
If PowerToys is already running, you can attach to that process:
|
||||
|
||||
2. VS Code command palette: “C/C++: (Windows) Attach to Process”.
|
||||
3. Filter for `PowerToys.exe` / module-specific processes.
|
||||
|
||||
### Debugging managed components
|
||||
|
||||
Many modules have a managed component loaded into the PowerToys process. `cppvsdbg` can debug mixed mode, but if you need richer .NET inspection you can create a second configuration using `type: coreclr` and `processId` attachment after the native launch, or just attach separately:
|
||||
|
||||
Similar for attach to managed code.
|
||||
> Note: In arm64 machine, can only debug arm64 code.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run native executable (no build)",
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}\\x64\\Debug\\PowerToys.exe",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "C/C++ Attach to PowerToys Process (native)",
|
||||
"type": "cppvsdbg",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}",
|
||||
"symbolSearchPath": "${workspaceFolder}\\x64\\Debug;${workspaceFolder}\\Debug;${workspaceFolder}\\symbols"
|
||||
},
|
||||
{
|
||||
"name": "Run managed code (managed, no build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}\\arm64\\Debug\\WinUI3Apps\\PowerToys.Settings.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": {},
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
---
|
||||
|
||||
## 6. Common tasks & tips
|
||||
|
||||
| Task | Command / Action | Notes |
|
||||
|------|------------------|-------|
|
||||
| Clean | `git clean -xdf` (careful) or `msbuild /t:Clean PowerToys.sln` | Deep clean removes packages & build outputs |
|
||||
| Rebuild single project | `msbuild path\to\proj.vcxproj /t:Rebuild -p:Platform=x64 -p:Configuration=Debug` | Faster than whole solution |
|
||||
| Generate installer (rare in inner loop) | See `tools\build\build-installer.ps1` | Usually not needed for local debug |
|
||||
| Resource conversion errors | Re-run restore + build | Triggers custom PowerShell targets |
|
||||
@@ -9,6 +9,13 @@
|
||||
<Fragment>
|
||||
<DirectoryRef Id="WinUI3AppsInstallFolder">
|
||||
<Directory Id="CmdPalInstallFolder" Name="CmdPal">
|
||||
<Directory Id="CmdPalDepsInstallFolder" Name="Dependencies">
|
||||
<?if $(sys.BUILDARCH) = x64 ?>
|
||||
<Directory Id="CmdPalDepsX64InstallFolder" Name="x64" />
|
||||
<?else ?>
|
||||
<Directory Id="CmdPalDepsArm64InstallFolder" Name="arm64" />
|
||||
<?endif ?>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</DirectoryRef>
|
||||
|
||||
@@ -26,14 +33,41 @@
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<?if $(sys.BUILDARCH) = x64 ?>
|
||||
<DirectoryRef Id="CmdPalDepsX64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\x64">
|
||||
<Component Id="Module_CmdPal_Deps" Win64="yes" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<?else ?>
|
||||
<DirectoryRef Id="CmdPalDepsArm64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\arm64">
|
||||
<Component Id="Module_CmdPal_Deps" Win64="yes" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<File Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\arm64\Microsoft.VCLibs.ARM64.14.00.Desktop.appx" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<?endif ?>
|
||||
|
||||
<ComponentGroup Id="CmdPalComponentGroup">
|
||||
<Component Id="RemoveCmdPalFolder" Guid="2DF90C08-CC75-4245-A14E-B82904636C53" Directory="INSTALLFOLDER">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="RemoveCmdPalFolder" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveCmdPalInstallDirFolder" Directory="CmdPalInstallFolder" On="uninstall"/>
|
||||
<RemoveFolder Id="RemoveCmdPalDepsInstallDirFolder" Directory="CmdPalDepsInstallFolder" On="uninstall"/>
|
||||
<?if $(sys.BUILDARCH) = x64 ?>
|
||||
<RemoveFolder Id="RemoveCmdPalDepsX64InstallDirFolder" Directory="CmdPalDepsX64InstallFolder" On="uninstall"/>
|
||||
<?else ?>
|
||||
<RemoveFolder Id="RemoveCmdPalDepsArm64InstallDirFolder" Directory="CmdPalDepsArm64InstallFolder" On="uninstall"/>
|
||||
<?endif ?>
|
||||
</Component>
|
||||
<ComponentRef Id="Module_CmdPal" />
|
||||
<ComponentRef Id="Module_CmdPal_Deps" />
|
||||
</ComponentGroup>
|
||||
|
||||
</Fragment>
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
<ComponentGroupRef Id="MonacoSRCHeatGenerated" />
|
||||
<ComponentGroupRef Id="WorkspacesComponentGroup" />
|
||||
<ComponentGroupRef Id="CmdPalComponentGroup" />
|
||||
<ComponentRef Id="UninstallRegistryComponent" />
|
||||
</Feature>
|
||||
|
||||
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLFOLDER]" After="CostFinalize" />
|
||||
@@ -513,6 +514,15 @@
|
||||
<Binary Id="PTCustomActions" SourceFile="$(var.PowerToysSetupCustomActions.TargetPath)" />
|
||||
</Fragment>
|
||||
|
||||
<!-- Ensure InstallLocation is set in uninstall registry -->
|
||||
<Fragment>
|
||||
<Component Id="UninstallRegistryComponent" Guid="*" Directory="INSTALLFOLDER">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductCode]">
|
||||
<RegistryValue Name="InstallLocation" Type="string" Value="[INSTALLFOLDER]" />
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</Fragment>
|
||||
|
||||
<!-- Installation directory structure -->
|
||||
<Fragment>
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
<Fragment>
|
||||
<DirectoryRef Id="WinUI3AppsInstallFolder">
|
||||
<Directory Id="CmdPalInstallFolder" Name="CmdPal">
|
||||
<Directory Id="CmdPalDepsInstallFolder" Name="Dependencies">
|
||||
<?if $(sys.BUILDARCH) = x64 ?>
|
||||
<Directory Id="CmdPalDepsX64InstallFolder" Name="x64" />
|
||||
<?else?>
|
||||
<Directory Id="CmdPalDepsArm64InstallFolder" Name="arm64" />
|
||||
<?endif?>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="CmdPalInstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test">
|
||||
@@ -18,14 +25,40 @@
|
||||
<?endif?>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<?if $(sys.BUILDARCH) = x64 ?>
|
||||
<DirectoryRef Id="CmdPalDepsX64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\x64">
|
||||
<Component Id="Module_CmdPal_Deps" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0" Bitness="always64">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
<File Id="Microsoft.VCLibs.x64.14.00.Desktop.appx" Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<?else?>
|
||||
<DirectoryRef Id="CmdPalDepsArm64InstallFolder" FileSource="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\arm64">
|
||||
<Component Id="Module_CmdPal_Deps" Guid="C2790FC4-0665-4462-947A-D942A2AABFF0" Bitness="always64">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="Module_CmdPal_Deps" Value="" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
<File Id="Microsoft.VCLibs.ARM64.14.00.Desktop.appx" Source="$(var.CmdPalBuildDir)AppPackages\Microsoft.CmdPal.UI_$(var.CmdPalVersion)_Test\Dependencies\arm64\Microsoft.VCLibs.ARM64.14.00.Desktop.appx" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<?endif?>
|
||||
<ComponentGroup Id="CmdPalComponentGroup">
|
||||
<Component Id="RemoveCmdPalFolder" Guid="2DF90C08-CC75-4245-A14E-B82904636C53" Directory="INSTALLFOLDER">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="RemoveCmdPalFolder" Value="" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveCmdPalInstallDirFolder" Directory="CmdPalInstallFolder" On="uninstall" />
|
||||
<RemoveFolder Id="RemoveCmdPalDepsInstallDirFolder" Directory="CmdPalDepsInstallFolder" On="uninstall" />
|
||||
<?if $(sys.BUILDARCH) = x64 ?>
|
||||
<RemoveFolder Id="RemoveCmdPalDepsX64InstallDirFolder" Directory="CmdPalDepsX64InstallFolder" On="uninstall" />
|
||||
<?else?>
|
||||
<RemoveFolder Id="RemoveCmdPalDepsArm64InstallDirFolder" Directory="CmdPalDepsArm64InstallFolder" On="uninstall" />
|
||||
<?endif?>
|
||||
</Component>
|
||||
<ComponentRef Id="Module_CmdPal" />
|
||||
<ComponentRef Id="Module_CmdPal_Deps" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
<ComponentGroupRef Id="MonacoSRCHeatGenerated" />
|
||||
<ComponentGroupRef Id="WorkspacesComponentGroup" />
|
||||
<ComponentGroupRef Id="CmdPalComponentGroup" />
|
||||
<ComponentRef Id="UninstallRegistryComponent" />
|
||||
</Feature>
|
||||
|
||||
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLFOLDER]" After="CostFinalize" />
|
||||
@@ -254,6 +255,15 @@
|
||||
<Binary Id="PTCustomActions" SourceFile="$(var.PowerToysSetupCustomActionsVNext.TargetPath)" />
|
||||
</Fragment>
|
||||
|
||||
<!-- Ensure InstallLocation is set in uninstall registry -->
|
||||
<Fragment>
|
||||
<Component Id="UninstallRegistryComponent" Guid="*" Directory="INSTALLFOLDER">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductCode]">
|
||||
<RegistryValue Name="InstallLocation" Type="string" Value="[INSTALLFOLDER]" />
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</Fragment>
|
||||
|
||||
<!-- Installation directory structure -->
|
||||
<Fragment>
|
||||
<StandardDirectory Id="$(var.DefaultInstallDir)">
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
Workspaces,
|
||||
PowerRename,
|
||||
CommandPalette,
|
||||
ScreenRuler,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,7 +104,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
[PowerToysModule.Workspaces] = new ModuleInfo("PowerToys.WorkspacesEditor.exe", "Workspaces Editor"),
|
||||
[PowerToysModule.PowerRename] = new ModuleInfo("PowerToys.PowerRename.exe", "PowerRename", "WinUI3Apps"),
|
||||
[PowerToysModule.CommandPalette] = new ModuleInfo("Microsoft.CmdPal.UI.exe", "PowerToys Command Palette", "WinUI3Apps\\CmdPal"),
|
||||
[PowerToysModule.ScreenRuler] = new ModuleInfo("PowerToys.MeasureToolUI.exe", "PowerToys.ScreenRuler", "WinUI3Apps"),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
@@ -95,7 +94,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
Task.Delay(1000).Wait();
|
||||
AddScreenShotsToTestResultsDirectory();
|
||||
AddLogFilesToTestResultsDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,92 +598,6 @@ namespace Microsoft.PowerToys.UITest
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies PowerToys log files to test results directory when test fails.
|
||||
/// Renames files to include the directory structure after \PowerToys.
|
||||
/// </summary>
|
||||
protected void AddLogFilesToTestResultsDirectory()
|
||||
{
|
||||
try
|
||||
{
|
||||
var localAppDataLow = Path.Combine(
|
||||
Environment.GetEnvironmentVariable("USERPROFILE") ?? string.Empty,
|
||||
"AppData",
|
||||
"LocalLow",
|
||||
"Microsoft",
|
||||
"PowerToys");
|
||||
|
||||
if (Directory.Exists(localAppDataLow))
|
||||
{
|
||||
CopyLogFilesFromDirectory(localAppDataLow, string.Empty);
|
||||
}
|
||||
|
||||
var localAppData = Path.Combine(
|
||||
Environment.GetEnvironmentVariable("LOCALAPPDATA") ?? string.Empty,
|
||||
"Microsoft",
|
||||
"PowerToys");
|
||||
|
||||
if (Directory.Exists(localAppData))
|
||||
{
|
||||
CopyLogFilesFromDirectory(localAppData, string.Empty);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Don't fail the test if log file copying fails
|
||||
Console.WriteLine($"Failed to copy log files: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursively copies log files from a directory and renames them with directory structure.
|
||||
/// </summary>
|
||||
/// <param name="sourceDir">Source directory to copy from</param>
|
||||
/// <param name="relativePath">Relative path from PowerToys folder</param>
|
||||
private void CopyLogFilesFromDirectory(string sourceDir, string relativePath)
|
||||
{
|
||||
if (!Directory.Exists(sourceDir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Process log files in current directory
|
||||
var logFiles = Directory.GetFiles(sourceDir, "*.log");
|
||||
foreach (var logFile in logFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileName = Path.GetFileName(logFile);
|
||||
var fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
|
||||
var extension = Path.GetExtension(fileName);
|
||||
|
||||
// Create new filename with directory structure
|
||||
var directoryPart = string.IsNullOrEmpty(relativePath) ? string.Empty : relativePath.Replace("\\", "-") + "-";
|
||||
var newFileName = $"{directoryPart}{fileNameWithoutExt}{extension}";
|
||||
|
||||
// Copy file to test results directory with new name
|
||||
var testResultsDir = TestContext.TestResultsDirectory ?? Path.GetTempPath();
|
||||
var destinationPath = Path.Combine(testResultsDir, newFileName);
|
||||
|
||||
File.Copy(logFile, destinationPath, true);
|
||||
TestContext.AddResultFile(destinationPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to copy log file {logFile}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively process subdirectories
|
||||
var subdirectories = Directory.GetDirectories(sourceDir);
|
||||
foreach (var subdir in subdirectories)
|
||||
{
|
||||
var dirName = Path.GetFileName(subdir);
|
||||
var newRelativePath = string.IsNullOrEmpty(relativePath) ? dirName : Path.Combine(relativePath, dirName);
|
||||
CopyLogFilesFromDirectory(subdir, newRelativePath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restart scope exe.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
applyTo: "**/*.cs,**/*.cpp,**/*.c,**/*.h,**/*.hpp"
|
||||
---
|
||||
# Common – shared libraries guidance (concise)
|
||||
|
||||
Scope
|
||||
- Logging, IPC, settings, DPI, telemetry, utilities consumed by multiple modules.
|
||||
|
||||
Guidelines
|
||||
- Avoid breaking public headers/APIs; if changed, search & update all callers.
|
||||
- Coordinate ABI-impacting struct/class layout changes; keep binary compatibility.
|
||||
- Watch perf in hot paths (hooks, timers, serialization); avoid avoidable allocations.
|
||||
- Ask before adding third‑party deps or changing serialization formats.
|
||||
|
||||
Acceptance
|
||||
- No unintended ABI breaks, no noisy logs, new non-obvious symbols briefly commented.
|
||||
@@ -31,11 +31,11 @@
|
||||
<!-- The following sections assume that the machine we're building on is always x64. That means we won't be able to run/inspect arm64 executables, therefore we must always execute x64 generator. -->
|
||||
|
||||
<Target Name="PostBuildAction" AfterTargets="Build" Outputs="$(GeneratedDSCModule)" Condition="'$(Platform)'!='ARM64'">
|
||||
<Exec Command=""$(OutDir)$(AssemblyName).exe" "..\..\..\x64\$(Configuration)\WinUI3Apps\PowerToys.Settings.UI.Lib.dll" $(GeneratedDSCModule) $(GeneratedDSCManifest)" />
|
||||
<Exec Command=""$(OutDir)$(AssemblyName).exe" "$(SolutionDir)x64\$(Configuration)\WinUI3Apps\PowerToys.Settings.UI.Lib.dll" $(GeneratedDSCModule) $(GeneratedDSCManifest)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent" Condition="'$(Platform)'=='ARM64'">
|
||||
<Exec Command=""$(MSBuildToolsPath)\msbuild.exe" PowerToys.sln -p:Configuration="$(Configuration)" -p:Platform="x64" -verbosity:m -t:DSC\PowerToys_Settings_DSC_Schema_Generator" WorkingDirectory="..\..\..\" />
|
||||
<Exec Command=""$(MSBuildToolsPath)\msbuild.exe" PowerToys.sln -p:Configuration="$(Configuration)" -p:Platform="x64" -verbosity:m -t:DSC\PowerToys_Settings_DSC_Schema_Generator" WorkingDirectory="$(SolutionDir)" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4188\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4188\build\Microsoft.Windows.SDK.BuildTools.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
@@ -147,13 +141,7 @@
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4188\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4188\build\Microsoft.Windows.SDK.BuildTools.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
@@ -165,19 +153,7 @@
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4188\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4188\build\Microsoft.Windows.SDK.BuildTools.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4188\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4188\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.8.250907003\build\native\Microsoft.WindowsAppSDK.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -4,14 +4,5 @@
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.26100.4188" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK" version="1.8.250907003" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Base" version="1.8.250831001" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Foundation" version="1.8.250906002" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.WinUI" version="1.8.250906003" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Runtime" version="1.8.250907003" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.DWrite" version="1.8.25090401" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.InteractiveExperiences" version="1.8.250906004" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Widgets" version="1.8.250904007" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.AI" version="1.8.37" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.SDK.BuildTools.MSIX" version="1.7.20250829.1" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK" version="1.7.250513003" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -5,7 +5,6 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:winuiex="using:WinUIEx"
|
||||
Title="PowerToys.ScreenRuler"
|
||||
IsAlwaysOnTop="True"
|
||||
IsMaximizable="False"
|
||||
IsMinimizable="False"
|
||||
@@ -251,7 +250,6 @@
|
||||
<ToggleButton
|
||||
Name="btnBounds"
|
||||
x:Uid="BtnBounds"
|
||||
AutomationProperties.AutomationId="Button_Bounds"
|
||||
Click="BoundsTool_Click"
|
||||
Content=""
|
||||
KeyboardAcceleratorPlacementMode="Auto"
|
||||
@@ -269,7 +267,6 @@
|
||||
<ToggleButton
|
||||
Name="btnSpacing"
|
||||
x:Uid="BtnSpacing"
|
||||
AutomationProperties.AutomationId="Button_Spacing"
|
||||
Click="MeasureTool_Click"
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
@@ -287,7 +284,6 @@
|
||||
<ToggleButton
|
||||
Name="btnHorizontalSpacing"
|
||||
x:Uid="BtnHorizontalSpacing"
|
||||
AutomationProperties.AutomationId="Button_SpacingHorizontal"
|
||||
Click="HorizontalMeasureTool_Click"
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
@@ -308,7 +304,6 @@
|
||||
<ToggleButton
|
||||
Name="btnVerticalSpacing"
|
||||
x:Uid="BtnVerticalSpacing"
|
||||
AutomationProperties.AutomationId="Button_SpacingVertical"
|
||||
Click="VerticalMeasureTool_Click"
|
||||
Style="{StaticResource ToggleButtonRadioButtonStyle}">
|
||||
<ToolTipService.ToolTip>
|
||||
@@ -329,7 +324,6 @@
|
||||
<AppBarSeparator />
|
||||
<Button
|
||||
x:Uid="BtnClosePanel"
|
||||
AutomationProperties.AutomationId="Button_Close"
|
||||
Click="ClosePanelTool_Click"
|
||||
Content=""
|
||||
Foreground="{StaticResource CloseButtonBackgroundPointerOver}">
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap rescap">
|
||||
|
||||
<Identity
|
||||
Name="d4d0f157-5c12-4390-9689-152b0c86a582"
|
||||
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
||||
Version="1.0.0.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="d4d0f157-5c12-4390-9689-152b0c86a582" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>ScreenRuler.UITests</DisplayName>
|
||||
<PublisherDisplayName>Microsoft</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="ScreenRuler.UITests"
|
||||
Description="ScreenRuler.UITests"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
@@ -1,23 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<PropertyGroup>
|
||||
<RootNamespace>PowerToys.ScreenRuler.UITests</RootNamespace>
|
||||
<AssemblyName>ScreenRuler.UITests</AssemblyName>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
<!-- This is a UI test, so don't run as part of MSBuild -->
|
||||
<RunVSTest>false</RunVSTest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\tests\ScreenRuler.UITests\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MSTest" />
|
||||
<ProjectReference Include="..\..\..\..\common\UITestAutomation\UITestAutomation.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace ScreenRuler.UITests
|
||||
{
|
||||
[TestClass]
|
||||
public class TestBounds : UITestBase
|
||||
{
|
||||
public TestBounds()
|
||||
: base(PowerToysModule.PowerToysSettings, WindowSize.Large)
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("ScreenRuler.BoundsTool")]
|
||||
[TestCategory("Spacing")]
|
||||
public void TestScreenRulerBoundsTool()
|
||||
{
|
||||
TestHelper.InitializeTest(this, "bounds test");
|
||||
TestHelper.PerformBoundsToolTest(this);
|
||||
TestHelper.CleanupTest(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,466 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace ScreenRuler.UITests
|
||||
{
|
||||
public static class TestHelper
|
||||
{
|
||||
private static readonly string[] ShortcutSeparators = { " + ", "+", " " };
|
||||
|
||||
// Button automation names from Resources.resw
|
||||
public const string BoundsButtonId = "Button_Bounds";
|
||||
public const string SpacingButtonName = "Button_Spacing";
|
||||
public const string HorizontalSpacingButtonName = "Button_SpacingHorizontal";
|
||||
public const string VerticalSpacingButtonName = "Button_SpacingVertical";
|
||||
public const string CloseButtonId = "Button_Close";
|
||||
|
||||
/// <summary>
|
||||
/// Performs common test initialization: navigate to settings, enable toggle, verify shortcut
|
||||
/// </summary>
|
||||
/// <param name="testBase">The test base instance</param>
|
||||
/// <param name="testName">Name of the test for assertions</param>
|
||||
/// <returns>The activation keys for the test</returns>
|
||||
public static Key[] InitializeTest(UITestBase testBase, string testName)
|
||||
{
|
||||
LaunchFromSetting(testBase);
|
||||
|
||||
var toggleSwitch = SetScreenRulerToggle(testBase, enable: true);
|
||||
Assert.IsTrue(
|
||||
toggleSwitch.IsOn,
|
||||
$"Screen Ruler toggle switch should be ON for {testName}");
|
||||
|
||||
var activationKeys = ReadActivationShortcut(testBase);
|
||||
Assert.IsNotNull(activationKeys, "Should be able to read activation shortcut");
|
||||
Assert.IsTrue(activationKeys.Length > 0, "Activation shortcut should contain at least one key");
|
||||
|
||||
return activationKeys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs common test cleanup: close ScreenRuler UI
|
||||
/// </summary>
|
||||
/// <param name="testBase">The test base instance</param>
|
||||
public static void CleanupTest(UITestBase testBase)
|
||||
{
|
||||
CloseScreenRulerUI(testBase);
|
||||
|
||||
// Ensure we're attached to settings after cleanup
|
||||
try
|
||||
{
|
||||
testBase.Session.Attach(PowerToysModule.PowerToysSettings);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore attachment errors - this is just cleanup
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigate to the Screen Ruler (Measure Tool) settings page
|
||||
/// </summary>
|
||||
public static void LaunchFromSetting(UITestBase testBase)
|
||||
{
|
||||
var screenRulers = testBase.Session.FindAll<NavigationViewItem>(By.AccessibilityId("ScreenRulerNavItem"));
|
||||
|
||||
if (screenRulers.Count == 0)
|
||||
{
|
||||
testBase.Session.Find<NavigationViewItem>(By.AccessibilityId("SystemToolsNavItem"), 5000).Click(msPostAction: 500);
|
||||
}
|
||||
|
||||
testBase.Session.Find<NavigationViewItem>(By.AccessibilityId("ScreenRulerNavItem"), 5000).Click(msPostAction: 500);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the Screen Ruler toggle switch to the specified state
|
||||
/// </summary>
|
||||
public static ToggleSwitch SetScreenRulerToggle(UITestBase testBase, bool enable)
|
||||
{
|
||||
var toggleSwitch = testBase.Session.Find<ToggleSwitch>(By.AccessibilityId("Toggle_ScreenRuler"), 5000);
|
||||
|
||||
if (toggleSwitch.IsOn != enable)
|
||||
{
|
||||
toggleSwitch.Click(msPreAction: 1000, msPostAction: 2000);
|
||||
}
|
||||
|
||||
if (toggleSwitch.IsOn != enable)
|
||||
{
|
||||
testBase.Session.SendKey(Key.Space, msPreAction: 0, msPostAction: 2000);
|
||||
}
|
||||
|
||||
return toggleSwitch;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the Screen Ruler toggle and verify its state
|
||||
/// </summary>
|
||||
/// <param name="testBase">The test base instance</param>
|
||||
/// <param name="enable">True to enable, false to disable</param>
|
||||
/// <param name="testName">Name of the test for assertion messages</param>
|
||||
public static void SetAndVerifyScreenRulerToggle(UITestBase testBase, bool enable, string testName)
|
||||
{
|
||||
var toggleSwitch = SetScreenRulerToggle(testBase, enable);
|
||||
Assert.AreEqual(
|
||||
enable,
|
||||
toggleSwitch.IsOn,
|
||||
$"Screen Ruler toggle switch should be {(enable ? "ON" : "OFF")} for {testName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the current activation shortcut from the ShortcutControl
|
||||
/// </summary>
|
||||
public static Key[] ReadActivationShortcut(UITestBase testBase)
|
||||
{
|
||||
var shortcutCard = testBase.Session.Find<Element>(By.AccessibilityId("Shortcut_ScreenRuler"), 5000);
|
||||
var shortcutButton = shortcutCard.Find<Element>(By.AccessibilityId("EditButton"), 5000);
|
||||
return ParseShortcutText(shortcutButton.HelpText);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse shortcut text like "Win + Ctrl + Shift + M" into Key array
|
||||
/// </summary>
|
||||
private static Key[] ParseShortcutText(string shortcutText)
|
||||
{
|
||||
if (string.IsNullOrEmpty(shortcutText))
|
||||
{
|
||||
return new Key[] { Key.Win, Key.Ctrl, Key.Shift, Key.M };
|
||||
}
|
||||
|
||||
var keys = new List<Key>();
|
||||
var parts = shortcutText.Split(ShortcutSeparators, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
var cleanPart = part.Trim().ToLowerInvariant();
|
||||
var key = cleanPart switch
|
||||
{
|
||||
"win" or "windows" => Key.Win,
|
||||
"ctrl" or "control" => Key.Ctrl,
|
||||
"shift" => Key.Shift,
|
||||
"alt" => Key.Alt,
|
||||
_ when cleanPart.Length == 1 && char.IsLetter(cleanPart[0]) &&
|
||||
cleanPart[0] >= 'a' && cleanPart[0] <= 'z' =>
|
||||
(Key)Enum.Parse(typeof(Key), cleanPart.ToUpperInvariant()),
|
||||
_ => (Key?)null,
|
||||
};
|
||||
|
||||
if (key.HasValue)
|
||||
{
|
||||
keys.Add(key.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return keys.Count > 0 ? keys.ToArray() : new Key[] { Key.Win, Key.Ctrl, Key.Shift, Key.M };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if ScreenRulerUI window is open
|
||||
/// </summary>
|
||||
public static bool IsScreenRulerUIOpen(UITestBase testBase) => testBase.IsWindowOpen("PowerToys.ScreenRuler");
|
||||
|
||||
/// <summary>
|
||||
/// Wait for ScreenRulerUI to reach the specified state within the timeout
|
||||
/// </summary>
|
||||
public static bool WaitForScreenRulerUIState(UITestBase testBase, bool shouldBeOpen, int timeoutMs = 5000, int pollingIntervalMs = 100)
|
||||
{
|
||||
var endTime = DateTime.Now.AddMilliseconds(timeoutMs);
|
||||
|
||||
while (DateTime.Now < endTime)
|
||||
{
|
||||
if (IsScreenRulerUIOpen(testBase) == shouldBeOpen)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Task.Delay(pollingIntervalMs).Wait();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wait for ScreenRulerUI to appear within the specified timeout
|
||||
/// </summary>
|
||||
public static bool WaitForScreenRulerUI(UITestBase testBase, int timeoutMs = 5000) =>
|
||||
WaitForScreenRulerUIState(testBase, shouldBeOpen: true, timeoutMs);
|
||||
|
||||
/// <summary>
|
||||
/// Wait for ScreenRulerUI to disappear within the specified timeout
|
||||
/// </summary>
|
||||
public static bool WaitForScreenRulerUIToDisappear(UITestBase testBase, int timeoutMs = 5000) =>
|
||||
WaitForScreenRulerUIState(testBase, shouldBeOpen: false, timeoutMs);
|
||||
|
||||
/// <summary>
|
||||
/// Close ScreenRulerUI if it's open
|
||||
/// </summary>
|
||||
public static void CloseScreenRulerUI(UITestBase testBase)
|
||||
{
|
||||
if (IsScreenRulerUIOpen(testBase))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Attach to ScreenRuler window before trying to find and click close button
|
||||
testBase.Session.Attach(PowerToysModule.ScreenRuler);
|
||||
var closeButton = testBase.Session.Find<Element>(By.AccessibilityId(CloseButtonId), 15000, true);
|
||||
closeButton?.Click();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If we can't find the close button, ignore - the window might have closed already
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Attach back to settings after closing
|
||||
try
|
||||
{
|
||||
testBase.Session.Attach(PowerToysModule.PowerToysSettings);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore attachment errors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a specific ScreenRulerUI button by its automation name
|
||||
/// </summary>
|
||||
public static Element? GetScreenRulerButton(UITestBase testBase, string buttonName, int timeoutMs = 1000)
|
||||
{
|
||||
return testBase.Session.Find<Element>(By.AccessibilityId(buttonName), timeoutMs, true);
|
||||
|
||||
/*
|
||||
try
|
||||
{
|
||||
// Attach to ScreenRuler window before trying to find buttons
|
||||
testBase.Session.Attach(PowerToysModule.ScreenRuler);
|
||||
return testBase.Session.Find<Element>(By.AccessibilityId(buttonName), timeoutMs, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Attach back to settings if needed for further operations
|
||||
// This ensures we don't break the test flow
|
||||
try
|
||||
{
|
||||
testBase.Session.Attach(PowerToysModule.PowerToysSettings);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore attachment errors - the calling code will handle as needed
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear the clipboard content using STA thread
|
||||
/// </summary>
|
||||
public static void ClearClipboard()
|
||||
{
|
||||
ExecuteInSTAThread(() => System.Windows.Forms.Clipboard.Clear());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get text content from clipboard using STA thread
|
||||
/// </summary>
|
||||
public static string GetClipboardText()
|
||||
{
|
||||
string result = string.Empty;
|
||||
ExecuteInSTAThread(() =>
|
||||
{
|
||||
if (System.Windows.Forms.Clipboard.ContainsText())
|
||||
{
|
||||
result = System.Windows.Forms.Clipboard.GetText();
|
||||
}
|
||||
});
|
||||
return result ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute an action in an STA thread with error handling
|
||||
/// </summary>
|
||||
private static void ExecuteInSTAThread(Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
var staThread = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore clipboard errors
|
||||
}
|
||||
});
|
||||
|
||||
staThread.SetApartmentState(ApartmentState.STA);
|
||||
staThread.Start();
|
||||
staThread.Join(TimeSpan.FromSeconds(5));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore clipboard errors
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate clipboard content contains valid spacing measurement for the specified type
|
||||
/// </summary>
|
||||
public static bool ValidateSpacingClipboardContent(string clipboardText, string spacingType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(clipboardText))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return spacingType switch
|
||||
{
|
||||
"Spacing" => Regex.IsMatch(clipboardText, @"\d+\s*[<5B>x×]\s*\d+"),
|
||||
"Horizontal Spacing" or "Vertical Spacing" => Regex.IsMatch(clipboardText, @"^\d+$"),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a complete spacing tool test operation
|
||||
/// </summary>
|
||||
public static void PerformSpacingToolTest(UITestBase testBase, string buttonId, string testName)
|
||||
{
|
||||
ClearClipboard();
|
||||
|
||||
// Launch ScreenRuler UI
|
||||
var activationKeys = ReadActivationShortcut(testBase);
|
||||
testBase.SendKeys(activationKeys);
|
||||
|
||||
Assert.IsTrue(
|
||||
WaitForScreenRulerUI(testBase, 2000),
|
||||
$"ScreenRulerUI should appear after pressing activation shortcut for {testName}: {string.Join(" + ", activationKeys)}");
|
||||
|
||||
// Attach to ScreenRuler window and click spacing button
|
||||
// testBase.Session.Attach(PowerToysModule.ScreenRuler);
|
||||
var spacingButton = testBase.Session.Find<Element>(By.AccessibilityId(buttonId), 15000, true);
|
||||
Assert.IsNotNull(spacingButton, $"{testName} button should be found");
|
||||
|
||||
spacingButton!.Click();
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
// Perform measurement action (stay attached to ScreenRuler for this)
|
||||
PerformMeasurementAction(testBase);
|
||||
|
||||
// Validate results
|
||||
ValidateClipboardResults(testName);
|
||||
|
||||
// Cleanup - this will handle session attachment properly
|
||||
CloseScreenRulerUI(testBase);
|
||||
Assert.IsTrue(
|
||||
WaitForScreenRulerUIToDisappear(testBase, 2000),
|
||||
$"{testName}: ScreenRulerUI should close after calling CloseScreenRulerUI");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a bounds tool test operation
|
||||
/// </summary>
|
||||
public static void PerformBoundsToolTest(UITestBase testBase)
|
||||
{
|
||||
ClearClipboard();
|
||||
|
||||
var activationKeys = ReadActivationShortcut(testBase);
|
||||
testBase.SendKeys(activationKeys);
|
||||
|
||||
Assert.IsTrue(
|
||||
WaitForScreenRulerUI(testBase, 2000),
|
||||
$"ScreenRulerUI should appear after pressing activation shortcut: {string.Join(" + ", activationKeys)}");
|
||||
|
||||
// Attach to ScreenRuler window and click bounds button
|
||||
// testBase.Session.Attach(PowerToysModule.ScreenRuler);
|
||||
var boundsButton = testBase.Session.Find<Element>(By.AccessibilityId(BoundsButtonId), 15000, true);
|
||||
Assert.IsNotNull(boundsButton, "Bounds button should be found");
|
||||
|
||||
boundsButton.Click();
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
// Perform drag operation to create 100x100 box (stay attached to ScreenRuler)
|
||||
var currentPos = testBase.GetMousePosition();
|
||||
int startX = currentPos.Item1;
|
||||
int startY = currentPos.Item2 + 200;
|
||||
|
||||
testBase.MoveMouseTo(startX, startY);
|
||||
Task.Delay(200).Wait();
|
||||
|
||||
// Drag operation
|
||||
testBase.Session.PerformMouseAction(MouseActionType.LeftDown);
|
||||
Task.Delay(100).Wait();
|
||||
|
||||
testBase.MoveMouseTo(startX + 99, startY + 99);
|
||||
Task.Delay(200).Wait();
|
||||
|
||||
testBase.Session.PerformMouseAction(MouseActionType.LeftUp);
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
// Dismiss selection
|
||||
testBase.Session.PerformMouseAction(MouseActionType.RightClick);
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
// Validate results
|
||||
string clipboardText = GetClipboardText();
|
||||
Assert.IsFalse(string.IsNullOrEmpty(clipboardText), "Clipboard should contain measurement data");
|
||||
Assert.IsTrue(
|
||||
clipboardText.Contains("100 × 100") || clipboardText.Contains("100 x 100"),
|
||||
$"Clipboard should contain '100 x 100', but contained: '{clipboardText}'");
|
||||
|
||||
// Cleanup - this will handle session attachment properly
|
||||
CloseScreenRulerUI(testBase);
|
||||
Assert.IsTrue(
|
||||
WaitForScreenRulerUIToDisappear(testBase, 2000),
|
||||
"ScreenRulerUI should close after calling CloseScreenRulerUI");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a measurement action (move mouse and click)
|
||||
/// </summary>
|
||||
private static void PerformMeasurementAction(UITestBase testBase)
|
||||
{
|
||||
var currentPos = testBase.GetMousePosition();
|
||||
int startX = currentPos.Item1;
|
||||
int startY = currentPos.Item2 + 200;
|
||||
|
||||
testBase.MoveMouseTo(startX, startY);
|
||||
Task.Delay(200).Wait();
|
||||
|
||||
testBase.Session.PerformMouseAction(MouseActionType.LeftClick);
|
||||
Task.Delay(500).Wait();
|
||||
|
||||
testBase.Session.PerformMouseAction(MouseActionType.RightClick);
|
||||
Task.Delay(500).Wait();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate clipboard results for spacing tests
|
||||
/// </summary>
|
||||
private static void ValidateClipboardResults(string testName)
|
||||
{
|
||||
string clipboardText = GetClipboardText();
|
||||
Assert.IsFalse(string.IsNullOrEmpty(clipboardText), $"{testName}: Clipboard should contain measurement data");
|
||||
|
||||
bool containsValidPattern = ValidateSpacingClipboardContent(clipboardText, testName);
|
||||
Assert.IsTrue(
|
||||
containsValidPattern,
|
||||
$"{testName}: Clipboard should contain valid spacing measurement, but contained: '{clipboardText}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace ScreenRuler.UITests
|
||||
{
|
||||
[TestClass]
|
||||
public class TestShortcutActivation : UITestBase
|
||||
{
|
||||
public TestShortcutActivation()
|
||||
: base(PowerToysModule.PowerToysSettings, WindowSize.Large)
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("ScreenRuler.ShortcutActivation")]
|
||||
[TestCategory("Activation")]
|
||||
public void TestScreenRulerShortcutActivation()
|
||||
{
|
||||
var activationKeys = TestHelper.InitializeTest(this, "activation test");
|
||||
|
||||
// Test 1: Press the activation shortcut and verify the toolbar appears
|
||||
SendKeys(activationKeys);
|
||||
bool screenRulerAppeared = TestHelper.WaitForScreenRulerUI(this, 1000);
|
||||
Assert.IsTrue(
|
||||
screenRulerAppeared,
|
||||
$"ScreenRulerUI should appear after pressing activation shortcut: {string.Join(" + ", activationKeys)}");
|
||||
|
||||
// Test 2: Press the activation shortcut again and verify the toolbar disappears
|
||||
SendKeys(activationKeys);
|
||||
bool screenRulerDisappeared = TestHelper.WaitForScreenRulerUIToDisappear(this, 1000);
|
||||
Assert.IsTrue(
|
||||
screenRulerDisappeared,
|
||||
$"ScreenRulerUI should disappear after pressing activation shortcut again: {string.Join(" + ", activationKeys)}");
|
||||
|
||||
// Test 3: Disable Screen Ruler and verify that the activation shortcut no longer activates the utility
|
||||
// Ensure we're attached to settings UI before toggling
|
||||
Session.Attach(PowerToysModule.PowerToysSettings);
|
||||
TestHelper.SetAndVerifyScreenRulerToggle(this, enable: false, "disabled state test");
|
||||
|
||||
// Try to activate with shortcut while disabled
|
||||
SendKeys(activationKeys);
|
||||
Task.Delay(1000).Wait();
|
||||
Assert.IsFalse(
|
||||
TestHelper.IsScreenRulerUIOpen(this),
|
||||
"ScreenRulerUI should not appear when Screen Ruler is disabled");
|
||||
|
||||
// Test 4: Enable Screen Ruler and press the activation shortcut and verify the toolbar appears
|
||||
// Ensure we're attached to settings UI before toggling
|
||||
Session.Attach(PowerToysModule.PowerToysSettings);
|
||||
TestHelper.SetAndVerifyScreenRulerToggle(this, enable: true, "re-enabled state test");
|
||||
|
||||
SendKeys(activationKeys);
|
||||
screenRulerAppeared = TestHelper.WaitForScreenRulerUI(this, 1000);
|
||||
Assert.IsTrue(
|
||||
screenRulerAppeared,
|
||||
$"ScreenRulerUI should appear after re-enabling and pressing activation shortcut: {string.Join(" + ", activationKeys)}");
|
||||
|
||||
// Test 5: Verify the utility can be closed via the cleanup method
|
||||
TestHelper.CloseScreenRulerUI(this);
|
||||
bool screenRulerClosed = TestHelper.WaitForScreenRulerUIToDisappear(this, 1000);
|
||||
Assert.IsTrue(
|
||||
screenRulerClosed,
|
||||
"ScreenRulerUI should close after calling CloseScreenRulerUI");
|
||||
|
||||
TestHelper.CleanupTest(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace ScreenRuler.UITests
|
||||
{
|
||||
[TestClass]
|
||||
public class TestSpacing : UITestBase
|
||||
{
|
||||
public TestSpacing()
|
||||
: base(PowerToysModule.PowerToysSettings, WindowSize.Large)
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("ScreenRuler.SpacingTool")]
|
||||
[TestCategory("Spacing")]
|
||||
public void TestScreenRulerSpacingTool()
|
||||
{
|
||||
TestHelper.InitializeTest(this, "spacing test");
|
||||
TestHelper.PerformSpacingToolTest(this, TestHelper.SpacingButtonName, "Spacing");
|
||||
TestHelper.CleanupTest(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace ScreenRuler.UITests
|
||||
{
|
||||
[TestClass]
|
||||
public class TestSpacingHorizontal : UITestBase
|
||||
{
|
||||
public TestSpacingHorizontal()
|
||||
: base(PowerToysModule.PowerToysSettings, WindowSize.Large)
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("ScreenRuler.HorizontalSpacingTool")]
|
||||
[TestCategory("Spacing")]
|
||||
public void TestScreenRulerHorizontalSpacingTool()
|
||||
{
|
||||
TestHelper.InitializeTest(this, "horizontal spacing test");
|
||||
TestHelper.PerformSpacingToolTest(this, TestHelper.HorizontalSpacingButtonName, "Horizontal Spacing");
|
||||
TestHelper.CleanupTest(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace ScreenRuler.UITests
|
||||
{
|
||||
[TestClass]
|
||||
public class TestSpacingVertical : UITestBase
|
||||
{
|
||||
public TestSpacingVertical()
|
||||
: base(PowerToysModule.PowerToysSettings, WindowSize.Large)
|
||||
{
|
||||
}
|
||||
|
||||
[TestMethod("ScreenRuler.VerticalSpacingTool")]
|
||||
[TestCategory("Spacing")]
|
||||
public void TestScreenRulerVerticalSpacingTool()
|
||||
{
|
||||
TestHelper.InitializeTest(this, "vertical spacing test");
|
||||
TestHelper.PerformSpacingToolTest(this, TestHelper.VerticalSpacingButtonName, "Vertical Spacing");
|
||||
TestHelper.CleanupTest(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="ScreenRuler.UITests.app"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10.
|
||||
It is necessary to support features in unpackaged applications, for example the custom titlebar implementation.
|
||||
For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
@@ -49,23 +49,23 @@ namespace MouseUtils.UITests
|
||||
settings.BackgroundColor = "000000";
|
||||
settings.SpotlightColor = "FFFFFF";
|
||||
|
||||
var foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
var foundCustom = this.Find<Custom>("Find My Mouse");
|
||||
Assert.IsNotNull(foundCustom);
|
||||
|
||||
if (CheckAnimationEnable(ref foundCustom))
|
||||
{
|
||||
foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
foundCustom = this.Find<Custom>("Find My Mouse");
|
||||
}
|
||||
|
||||
if (foundCustom != null)
|
||||
{
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
|
||||
SetFindMyMouseActivationMethod(ref foundCustom, "Press Left Control twice");
|
||||
Assert.IsNotNull(foundCustom, "Find My Mouse group not found.");
|
||||
SetFindMyMouseAppearanceBehavior(ref foundCustom, ref settings);
|
||||
|
||||
var excludedApps = foundCustom.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseExcludedApps));
|
||||
var excludedApps = foundCustom.Find<TextBlock>("Excluded apps");
|
||||
if (excludedApps != null)
|
||||
{
|
||||
excludedApps.Click();
|
||||
@@ -115,23 +115,23 @@ namespace MouseUtils.UITests
|
||||
settings.BackgroundColor = "FF0000";
|
||||
settings.SpotlightColor = "0000FF";
|
||||
|
||||
var foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
var foundCustom = this.Find<Custom>("Find My Mouse");
|
||||
Assert.IsNotNull(foundCustom);
|
||||
|
||||
if (CheckAnimationEnable(ref foundCustom))
|
||||
{
|
||||
foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
foundCustom = this.Find<Custom>("Find My Mouse");
|
||||
}
|
||||
|
||||
if (foundCustom != null)
|
||||
{
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
|
||||
SetFindMyMouseActivationMethod(ref foundCustom, "Press Left Control twice");
|
||||
Assert.IsNotNull(foundCustom, "Find My Mouse group not found.");
|
||||
SetFindMyMouseAppearanceBehavior(ref foundCustom, ref settings);
|
||||
|
||||
var excludedApps = foundCustom.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseExcludedApps));
|
||||
var excludedApps = foundCustom.Find<TextBlock>("Excluded apps");
|
||||
if (excludedApps != null)
|
||||
{
|
||||
excludedApps.Click();
|
||||
@@ -170,27 +170,27 @@ namespace MouseUtils.UITests
|
||||
settings.AnimationDuration = "0";
|
||||
settings.BackgroundColor = "000000";
|
||||
settings.SpotlightColor = "FFFFFF";
|
||||
var foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
var foundCustom = this.Find<Custom>("Find My Mouse");
|
||||
|
||||
Assert.IsNotNull(foundCustom);
|
||||
|
||||
if (CheckAnimationEnable(ref foundCustom))
|
||||
{
|
||||
foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
foundCustom = this.Find<Custom>("Find My Mouse");
|
||||
}
|
||||
|
||||
if (foundCustom != null)
|
||||
{
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(false);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(false);
|
||||
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
SetFindMyMouseActivationMethod(ref foundCustom, "Press Left Control twice");
|
||||
Assert.IsNotNull(foundCustom);
|
||||
SetFindMyMouseAppearanceBehavior(ref foundCustom, ref settings);
|
||||
|
||||
var excludedApps = foundCustom.Find<Group>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseExcludedApps));
|
||||
var excludedApps = foundCustom.Find<TextBlock>("Excluded apps");
|
||||
if (excludedApps != null)
|
||||
{
|
||||
excludedApps.Click();
|
||||
@@ -212,14 +212,14 @@ namespace MouseUtils.UITests
|
||||
VerifySpotlightAppears(ref settings);
|
||||
|
||||
// [Test Case] Disable FindMyMouse. Verify the overlay no longer appears when you press Left Ctrl twice
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(false);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(false);
|
||||
Task.Delay(1000).Wait();
|
||||
ActivateSpotlight(ref settings);
|
||||
|
||||
VerifySpotlightDisappears(ref settings);
|
||||
|
||||
// [Test Case] Press Left Ctrl twice and verify the overlay appears
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
Task.Delay(2000).Wait();
|
||||
ActivateSpotlight(ref settings);
|
||||
VerifySpotlightAppears(ref settings);
|
||||
@@ -240,27 +240,27 @@ namespace MouseUtils.UITests
|
||||
settings.AnimationDuration = "0";
|
||||
settings.BackgroundColor = "000000";
|
||||
settings.SpotlightColor = "FFFFFF";
|
||||
var foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
var foundCustom = this.Find<Custom>("Find My Mouse");
|
||||
|
||||
Assert.IsNotNull(foundCustom);
|
||||
|
||||
if (CheckAnimationEnable(ref foundCustom))
|
||||
{
|
||||
foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
foundCustom = this.Find<Custom>("Find My Mouse");
|
||||
}
|
||||
|
||||
if (foundCustom != null)
|
||||
{
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(false);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(false);
|
||||
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
SetFindMyMouseActivationMethod(ref foundCustom, "Press Left Control twice");
|
||||
Assert.IsNotNull(foundCustom);
|
||||
SetFindMyMouseAppearanceBehavior(ref foundCustom, ref settings);
|
||||
|
||||
var excludedApps = foundCustom.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseExcludedApps));
|
||||
var excludedApps = foundCustom.Find<TextBlock>("Excluded apps");
|
||||
if (excludedApps != null)
|
||||
{
|
||||
excludedApps.Click();
|
||||
@@ -282,14 +282,14 @@ namespace MouseUtils.UITests
|
||||
VerifySpotlightAppears(ref settings);
|
||||
|
||||
// [Test Case] Disable FindMyMouse. Verify the overlay no longer appears when you press Left Ctrl twice
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(false);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(false);
|
||||
Task.Delay(1000).Wait();
|
||||
ActivateSpotlight(ref settings);
|
||||
|
||||
VerifySpotlightDisappears(ref settings);
|
||||
|
||||
// [Test Case] Press Left Ctrl twice and verify the overlay appears
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
Task.Delay(2000).Wait();
|
||||
ActivateSpotlight(ref settings);
|
||||
VerifySpotlightAppears(ref settings);
|
||||
@@ -310,17 +310,17 @@ namespace MouseUtils.UITests
|
||||
settings.AnimationDuration = "0";
|
||||
settings.BackgroundColor = "000000";
|
||||
settings.SpotlightColor = "FFFFFF";
|
||||
var foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
var foundCustom = this.Find<Custom>("Find My Mouse");
|
||||
if (foundCustom != null)
|
||||
{
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
|
||||
// foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(false);
|
||||
// foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(false);
|
||||
SetFindMyMouseActivationMethod(ref foundCustom, "Press Left Control twice");
|
||||
Assert.IsNotNull(foundCustom, "Find My Mouse group not found.");
|
||||
|
||||
// SetFindMyMouseAppearanceBehavior(ref foundCustom, ref settings);
|
||||
var excludedApps = foundCustom.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseExcludedApps));
|
||||
var excludedApps = foundCustom.Find<TextBlock>("Excluded apps");
|
||||
if (excludedApps != null)
|
||||
{
|
||||
excludedApps.Click();
|
||||
@@ -340,7 +340,7 @@ namespace MouseUtils.UITests
|
||||
// VerifySpotlightSettings(ref settings);
|
||||
|
||||
// [Test Case] Disable FindMyMouse. Verify the overlay no longer appears when you press Left Ctrl twice
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(false);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(false);
|
||||
Task.Delay(2000).Wait();
|
||||
Session.SendKey(Key.LCtrl, 0, 0);
|
||||
Task.Delay(100).Wait();
|
||||
@@ -382,6 +382,9 @@ namespace MouseUtils.UITests
|
||||
|
||||
var colorBackground = this.GetPixelColorString(location.Item1 + radius + 50, location.Item2 + radius + 50);
|
||||
Assert.AreEqual("#" + settings.BackgroundColor, colorBackground);
|
||||
|
||||
var colorBackground2 = this.GetPixelColorString(location.Item1 + radius + 100, location.Item2 + radius + 100);
|
||||
Assert.AreEqual("#" + settings.BackgroundColor, colorBackground2);
|
||||
}
|
||||
|
||||
private void ActivateSpotlight(ref FindMyMouseSettings settings)
|
||||
@@ -424,7 +427,7 @@ namespace MouseUtils.UITests
|
||||
private void SetFindMyMouseActivationMethod(ref Custom? foundCustom, string method)
|
||||
{
|
||||
Assert.IsNotNull(foundCustom);
|
||||
var groupActivation = foundCustom.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseActivationMethod));
|
||||
var groupActivation = foundCustom.Find<TextBlock>("Activation method");
|
||||
if (groupActivation != null)
|
||||
{
|
||||
groupActivation.Click();
|
||||
@@ -453,17 +456,17 @@ namespace MouseUtils.UITests
|
||||
private void SetFindMyMouseAppearanceBehavior(ref Custom foundCustom, ref FindMyMouseSettings settings)
|
||||
{
|
||||
Assert.IsNotNull(foundCustom);
|
||||
var groupAppearanceBehavior = foundCustom.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseAppearanceBehavior));
|
||||
var groupAppearanceBehavior = foundCustom.Find<TextBlock>("Appearance & behavior");
|
||||
if (groupAppearanceBehavior != null)
|
||||
{
|
||||
// groupAppearanceBehavior.Click();
|
||||
if (foundCustom.FindAll(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseOverlayOpacity)).Count == 0)
|
||||
if (foundCustom.FindAll<Slider>("Overlay opacity (%)").Count == 0)
|
||||
{
|
||||
groupAppearanceBehavior.Click();
|
||||
}
|
||||
|
||||
// Set the BackGround color
|
||||
var backgroundColor = foundCustom.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseBackgroundColor));
|
||||
var backgroundColor = foundCustom.Find<Group>("Background color");
|
||||
Assert.IsNotNull(backgroundColor);
|
||||
|
||||
var button = backgroundColor.Find<Button>(By.XPath(".//Button"));
|
||||
@@ -502,7 +505,7 @@ namespace MouseUtils.UITests
|
||||
button.Click();
|
||||
|
||||
// Set the Spotlight color
|
||||
var spotlightColor = foundCustom.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseSpotlightColor));
|
||||
var spotlightColor = foundCustom.Find<Group>("Spotlight color");
|
||||
Assert.IsNotNull(spotlightColor);
|
||||
|
||||
var spotlightColorButton = spotlightColor.Find<Button>(By.XPath(".//Button"));
|
||||
@@ -542,7 +545,7 @@ namespace MouseUtils.UITests
|
||||
spotlightColorButton.Click(false, 500, 1500);
|
||||
|
||||
// Set the overlay opacity to overlayOpacity%
|
||||
var overlayOpacitySlider = foundCustom.Find<Slider>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseOverlayOpacity));
|
||||
var overlayOpacitySlider = foundCustom.Find<Slider>("Overlay opacity (%)");
|
||||
Assert.IsNotNull(overlayOpacitySlider);
|
||||
Assert.IsNotNull(settings.OverlayOpacity);
|
||||
int overlayOpacityValue = int.Parse(settings.OverlayOpacity, CultureInfo.InvariantCulture);
|
||||
@@ -551,7 +554,7 @@ namespace MouseUtils.UITests
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// Set the Fade Initial zoom to 0
|
||||
var spotlightInitialZoomSlider = foundCustom.Find<Slider>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseSpotlightZoom));
|
||||
var spotlightInitialZoomSlider = foundCustom.Find<Slider>("Spotlight initial zoom");
|
||||
Assert.IsNotNull(spotlightInitialZoomSlider);
|
||||
Task.Delay(1000).Wait();
|
||||
spotlightInitialZoomSlider.QuickSetValue(int.Parse(settings.InitialZoom, CultureInfo.InvariantCulture));
|
||||
@@ -559,8 +562,7 @@ namespace MouseUtils.UITests
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
//// Change the edit value
|
||||
var spotlightRadius = foundCustom.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseSpotlightRadius));
|
||||
var spotlightRadiusEdit = spotlightRadius.Find<TextBox>(By.AccessibilityId("InputBox"));
|
||||
var spotlightRadiusEdit = foundCustom.Find<TextBox>("Spotlight radius (px) Minimum5");
|
||||
Assert.IsNotNull(spotlightRadiusEdit);
|
||||
Task.Delay(1000).Wait();
|
||||
spotlightRadiusEdit.SetText(settings.Radius);
|
||||
@@ -568,12 +570,11 @@ namespace MouseUtils.UITests
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// Set the duration to 0 ms
|
||||
var spotlightAnimationDuration = foundCustom.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseAnimationDuration));
|
||||
var spotlightAnimationDurationEdit = spotlightAnimationDuration.Find<TextBox>(By.AccessibilityId("InputBox"));
|
||||
Assert.IsNotNull(spotlightAnimationDurationEdit);
|
||||
var spotlightAnimationDuration = foundCustom.Find<TextBox>("Animation duration (ms) Minimum0");
|
||||
Assert.IsNotNull(spotlightAnimationDuration);
|
||||
Task.Delay(1000).Wait();
|
||||
spotlightAnimationDurationEdit.SetText(settings.AnimationDuration);
|
||||
Assert.AreEqual(settings.AnimationDuration, spotlightAnimationDurationEdit.Text);
|
||||
spotlightAnimationDuration.SetText(settings.AnimationDuration);
|
||||
Assert.AreEqual(settings.AnimationDuration, spotlightAnimationDuration.Text);
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// groupAppearanceBehavior.Click();
|
||||
@@ -621,19 +622,19 @@ namespace MouseUtils.UITests
|
||||
this.Session.SetMainWindowSize(WindowSize.Large);
|
||||
|
||||
// Goto Hosts File Editor setting page
|
||||
if (this.FindAll(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseUtilitiesNavItem)).Count == 0)
|
||||
if (this.FindAll<NavigationViewItem>("Mouse utilities", 10000).Count == 0)
|
||||
{
|
||||
// Expand Advanced list-group if needed
|
||||
this.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.InputOutputNavItem)).Click();
|
||||
this.Find<NavigationViewItem>("Input / Output").Click();
|
||||
}
|
||||
|
||||
if (reload)
|
||||
{
|
||||
this.Find<NavigationViewItem>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.KeyboardManagerNavItem)).Click();
|
||||
this.Find<NavigationViewItem>("Keyboard Manager").Click();
|
||||
}
|
||||
|
||||
Task.Delay(1000).Wait();
|
||||
this.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseUtilitiesNavItem)).Click();
|
||||
this.Find<NavigationViewItem>("Mouse utilities").Click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.
|
||||
|
||||
@@ -24,10 +24,10 @@ namespace MouseUtils.UITests
|
||||
public void TestEnableMouseHighlighter()
|
||||
{
|
||||
LaunchFromSetting();
|
||||
var foundCustom0 = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
var foundCustom0 = this.Find<Custom>("Find My Mouse");
|
||||
if (foundCustom0 != null)
|
||||
{
|
||||
foundCustom0.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(false);
|
||||
foundCustom0.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -42,11 +42,11 @@ namespace MouseUtils.UITests
|
||||
settings.FadeDelay = "0";
|
||||
settings.FadeDuration = "90";
|
||||
|
||||
var foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighter));
|
||||
var foundCustom = this.Find<Custom>("Mouse Highlighter");
|
||||
if (foundCustom != null)
|
||||
{
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighterToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighterToggle)).Toggle(false);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Highlighter").Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Highlighter").Toggle(false);
|
||||
|
||||
var xy = Session.GetMousePosition();
|
||||
Session.MoveMouseTo(xy.Item1, xy.Item2 - 100);
|
||||
@@ -54,7 +54,7 @@ namespace MouseUtils.UITests
|
||||
Session.PerformMouseAction(MouseActionType.ScrollDown);
|
||||
Session.PerformMouseAction(MouseActionType.ScrollDown);
|
||||
Session.PerformMouseAction(MouseActionType.ScrollDown);
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighterToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Highlighter").Toggle(true);
|
||||
|
||||
// Change the shortcut key for MouseHighlighter
|
||||
// [TestCase]Change activation shortcut and test it
|
||||
@@ -107,7 +107,7 @@ namespace MouseUtils.UITests
|
||||
VerifyMouseHighlighterNotAppears(ref settings, "rightClick");
|
||||
|
||||
// [Test Case] Disable Mouse Highlighter and verify that the module is not activated when you press the activation shortcut.
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighterToggle)).Toggle(false);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Highlighter").Toggle(false);
|
||||
xy = Session.GetMousePosition();
|
||||
Session.MoveMouseTo(xy.Item1 - 100, xy.Item2);
|
||||
|
||||
@@ -119,7 +119,7 @@ namespace MouseUtils.UITests
|
||||
|
||||
// [Test Case] With left mouse button pressed, drag the mouse and verify the highlight is dragged with the pointer.
|
||||
// [Test Case] With right mouse button pressed, drag the mouse and verify the highlight is dragged with the pointer.
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighterToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Highlighter").Toggle(true);
|
||||
xy = Session.GetMousePosition();
|
||||
Session.MoveMouseTo(xy.Item1 - 100, xy.Item2);
|
||||
|
||||
@@ -143,10 +143,10 @@ namespace MouseUtils.UITests
|
||||
public void TestMouseHighlighterDifferentSettings()
|
||||
{
|
||||
LaunchFromSetting();
|
||||
var foundCustom0 = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
var foundCustom0 = this.Find<Custom>("Find My Mouse");
|
||||
if (foundCustom0 != null)
|
||||
{
|
||||
foundCustom0.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(false);
|
||||
foundCustom0.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -161,11 +161,11 @@ namespace MouseUtils.UITests
|
||||
settings.FadeDelay = "0";
|
||||
settings.FadeDuration = "90";
|
||||
|
||||
var foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighter));
|
||||
var foundCustom = this.Find<Custom>("Mouse Highlighter");
|
||||
if (foundCustom != null)
|
||||
{
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighterToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighterToggle)).Toggle(false);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Highlighter").Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Highlighter").Toggle(false);
|
||||
|
||||
var xy = Session.GetMousePosition();
|
||||
Session.MoveMouseTo(xy.Item1, xy.Item2 - 100);
|
||||
@@ -173,7 +173,7 @@ namespace MouseUtils.UITests
|
||||
Session.PerformMouseAction(MouseActionType.ScrollDown);
|
||||
Session.PerformMouseAction(MouseActionType.ScrollDown);
|
||||
Session.PerformMouseAction(MouseActionType.ScrollDown);
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighterToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Highlighter").Toggle(true);
|
||||
|
||||
// Change the shortcut key for MouseHighlighter
|
||||
// [TestCase] Test the different settings and verify they apply - Change activation shortcut and test it
|
||||
@@ -387,7 +387,7 @@ namespace MouseUtils.UITests
|
||||
private void SetColor(ref Custom foundCustom, string colorName = "Primary button highlight color", string colorValue = "000000", string opacity = "0")
|
||||
{
|
||||
Assert.IsNotNull(foundCustom);
|
||||
var groupAppearanceBehavior = foundCustom.Find<Group>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighterAppearanceBehavior));
|
||||
var groupAppearanceBehavior = foundCustom.Find<TextBlock>("Appearance & behavior");
|
||||
if (groupAppearanceBehavior != null)
|
||||
{
|
||||
if (foundCustom.FindAll<TextBox>("Fade duration (ms) Minimum0").Count == 0)
|
||||
@@ -439,7 +439,7 @@ namespace MouseUtils.UITests
|
||||
private void SetMouseHighlighterAppearanceBehavior(ref Custom foundCustom, ref MouseHighlighterSettings settings)
|
||||
{
|
||||
Assert.IsNotNull(foundCustom);
|
||||
var groupAppearanceBehavior = foundCustom.Find<Group>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseHighlighterAppearanceBehavior));
|
||||
var groupAppearanceBehavior = foundCustom.Find<TextBlock>("Appearance & behavior");
|
||||
if (groupAppearanceBehavior != null)
|
||||
{
|
||||
// groupAppearanceBehavior.Click();
|
||||
@@ -477,7 +477,7 @@ namespace MouseUtils.UITests
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail("MouseHighlighter Appearance & behavior group not found.");
|
||||
Assert.Fail("Appearance & behavior group not found.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,14 +485,14 @@ namespace MouseUtils.UITests
|
||||
{
|
||||
this.Session.SetMainWindowSize(WindowSize.Large);
|
||||
|
||||
// Goto Mouse utilities setting page
|
||||
if (this.FindAll(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseUtilitiesNavItem)).Count == 0)
|
||||
// Goto Hosts File Editor setting page
|
||||
if (this.FindAll<NavigationViewItem>("Mouse utilities").Count == 0)
|
||||
{
|
||||
// Expand Input / Output list-group if needed
|
||||
this.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.InputOutputNavItem)).Click();
|
||||
// Expand Advanced list-group if needed
|
||||
this.Find<NavigationViewItem>("Input / Output").Click();
|
||||
}
|
||||
|
||||
this.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseUtilitiesNavItem)).Click();
|
||||
this.Find<NavigationViewItem>("Mouse utilities").Click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.
|
||||
|
||||
@@ -29,11 +29,11 @@ namespace MouseUtils.UITests
|
||||
public void TestEnableMouseJump2()
|
||||
{
|
||||
LaunchFromSetting();
|
||||
var foundCustom0 = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
var foundCustom0 = this.Find<Custom>("Find My Mouse");
|
||||
if (foundCustom0 != null)
|
||||
{
|
||||
foundCustom0.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom0.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(false);
|
||||
foundCustom0.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
foundCustom0.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -45,10 +45,10 @@ namespace MouseUtils.UITests
|
||||
Session.PerformMouseAction(MouseActionType.ScrollDown);
|
||||
}
|
||||
|
||||
var foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseJump));
|
||||
var foundCustom = this.Find<Custom>("Mouse Jump");
|
||||
if (foundCustom != null)
|
||||
{
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseJumpToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Jump").Toggle(true);
|
||||
|
||||
var xy = Session.GetMousePosition();
|
||||
Session.MoveMouseTo(xy.Item1, xy.Item2 - 100);
|
||||
@@ -89,7 +89,7 @@ namespace MouseUtils.UITests
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// [TestCase] Enable Mouse Jump. Then - Disable Mouse Jump and verify that the module is not activated when you press the activation shortcut.
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseJumpToggle)).Toggle(false);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Jump").Toggle(false);
|
||||
Session.MoveMouseTo(screenCenter.CenterX, screenCenter.CenterY - 300, 500, 1000);
|
||||
Session.SendKeys(Key.Win, Key.Shift, Key.Z);
|
||||
Task.Delay(500).Wait();
|
||||
@@ -108,11 +108,11 @@ namespace MouseUtils.UITests
|
||||
public void TestEnableMouseJump3()
|
||||
{
|
||||
LaunchFromSetting();
|
||||
var foundCustom0 = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouse));
|
||||
var foundCustom0 = this.Find<Custom>("Find My Mouse");
|
||||
if (foundCustom0 != null)
|
||||
{
|
||||
foundCustom0.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(true);
|
||||
foundCustom0.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.FindMyMouseToggle)).Toggle(false);
|
||||
foundCustom0.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(true);
|
||||
foundCustom0.Find<ToggleSwitch>("Enable Find My Mouse").Toggle(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -124,10 +124,10 @@ namespace MouseUtils.UITests
|
||||
Session.PerformMouseAction(MouseActionType.ScrollDown);
|
||||
}
|
||||
|
||||
var foundCustom = this.Find<Custom>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseJump));
|
||||
var foundCustom = this.Find<Custom>("Mouse Jump");
|
||||
if (foundCustom != null)
|
||||
{
|
||||
foundCustom.Find<ToggleSwitch>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseJumpToggle)).Toggle(true);
|
||||
foundCustom.Find<ToggleSwitch>("Enable Mouse Jump").Toggle(true);
|
||||
|
||||
var xy = Session.GetMousePosition();
|
||||
Session.MoveMouseTo(xy.Item1, xy.Item2 - 100);
|
||||
@@ -215,23 +215,23 @@ namespace MouseUtils.UITests
|
||||
Session.SetMainWindowSize(WindowSize.Large);
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// Goto Mouse utilities setting page
|
||||
if (this.FindAll(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseUtilitiesNavItem)).Count == 0)
|
||||
// Goto Hosts File Editor setting page
|
||||
if (this.FindAll<NavigationViewItem>("Mouse utilities").Count == 0)
|
||||
{
|
||||
// Expand Input / Output list-group if needed
|
||||
this.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.InputOutputNavItem)).Click();
|
||||
// Expand Advanced list-group if needed
|
||||
this.Find<NavigationViewItem>("Input / Output").ClickCenter();
|
||||
Task.Delay(2000).Wait();
|
||||
}
|
||||
|
||||
// Goto Mouse utilities setting page
|
||||
if (this.FindAll(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseUtilitiesNavItem)).Count == 0)
|
||||
// Goto Hosts File Editor setting page
|
||||
if (this.FindAll<NavigationViewItem>("Mouse utilities").Count == 0)
|
||||
{
|
||||
RestartScopeExe();
|
||||
Session.SetMainWindowSize(WindowSize.Large);
|
||||
Task.Delay(1000).Wait();
|
||||
|
||||
// Expand Input / Output list-group if needed
|
||||
this.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.InputOutputNavItem)).Click();
|
||||
// Expand Advanced list-group if needed
|
||||
this.Find<NavigationViewItem>("Input / Output").ClickCenter();
|
||||
Task.Delay(2000).Wait();
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ namespace MouseUtils.UITests
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseUtilitiesNavItem)).Click();
|
||||
this.Find<NavigationViewItem>("Mouse utilities").Click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ namespace MouseUtils.UITests
|
||||
private void SetColor(ref Custom foundCustom, string colorName, string colorValue = "000000")
|
||||
{
|
||||
Assert.IsNotNull(foundCustom);
|
||||
var groupAppearanceBehavior = foundCustom.Find<Group>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MousePointerCrosshairsAppearanceBehavior));
|
||||
var groupAppearanceBehavior = foundCustom.Find<TextBlock>("Appearance & behavior");
|
||||
if (groupAppearanceBehavior != null)
|
||||
{
|
||||
// Set primary button highlight color
|
||||
@@ -277,7 +277,7 @@ namespace MouseUtils.UITests
|
||||
private void SetMousePointerCrosshairsAppearanceBehavior(ref Custom foundCustom, ref MousePointerCrosshairsSettings settings)
|
||||
{
|
||||
Assert.IsNotNull(foundCustom);
|
||||
var groupAppearanceBehavior = foundCustom.Find<Group>(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MousePointerCrosshairsAppearanceBehavior));
|
||||
var groupAppearanceBehavior = foundCustom.Find<TextBlock>("Appearance & behavior");
|
||||
if (groupAppearanceBehavior != null)
|
||||
{
|
||||
// groupAppearanceBehavior.Click();
|
||||
@@ -337,7 +337,7 @@ namespace MouseUtils.UITests
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail("MousePointerCrosshairs Appearance & behavior group not found.");
|
||||
Assert.Fail("Appearance & behavior group not found.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,16 +371,8 @@ namespace MouseUtils.UITests
|
||||
|
||||
public Custom? FindMouseUtilElement(MouseUtilsSettings.MouseUtils element)
|
||||
{
|
||||
string accessibilityId = element switch
|
||||
{
|
||||
MouseUtilsSettings.MouseUtils.FindMyMouse => MouseUtilsSettings.AccessibilityIds.FindMyMouse,
|
||||
MouseUtilsSettings.MouseUtils.MouseHighlighter => MouseUtilsSettings.AccessibilityIds.MouseHighlighter,
|
||||
MouseUtilsSettings.MouseUtils.MousePointerCrosshairs => MouseUtilsSettings.AccessibilityIds.MousePointerCrosshairs,
|
||||
MouseUtilsSettings.MouseUtils.MouseJump => MouseUtilsSettings.AccessibilityIds.MouseJump,
|
||||
_ => throw new ArgumentException($"Unknown MouseUtils element: {element}"),
|
||||
};
|
||||
|
||||
var foundCustom = this.Find<Custom>(By.AccessibilityId(accessibilityId));
|
||||
var elementName = MouseUtilsSettings.GetMouseUtilUIName(element);
|
||||
var foundCustom = this.Find<Custom>(elementName);
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
if (foundCustom != null)
|
||||
@@ -389,7 +381,7 @@ namespace MouseUtils.UITests
|
||||
}
|
||||
|
||||
Session.PerformMouseAction(MouseActionType.ScrollDown);
|
||||
foundCustom = this.Find<Custom>(By.AccessibilityId(accessibilityId));
|
||||
foundCustom = this.Find<Custom>(elementName);
|
||||
}
|
||||
|
||||
return foundCustom;
|
||||
@@ -399,14 +391,14 @@ namespace MouseUtils.UITests
|
||||
{
|
||||
Session.SetMainWindowSize(WindowSize.Large);
|
||||
|
||||
// Goto Mouse utilities setting page
|
||||
if (this.FindAll(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseUtilitiesNavItem)).Count == 0)
|
||||
// Goto Hosts File Editor setting page
|
||||
if (this.FindAll<NavigationViewItem>("Mouse utilities").Count == 0)
|
||||
{
|
||||
// Expand Input / Output list-group if needed
|
||||
this.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.InputOutputNavItem)).Click();
|
||||
// Expand Advanced list-group if needed
|
||||
this.Find<NavigationViewItem>("Input / Output").Click();
|
||||
}
|
||||
|
||||
this.Find(By.AccessibilityId(MouseUtilsSettings.AccessibilityIds.MouseUtilitiesNavItem)).Click();
|
||||
this.Find<NavigationViewItem>("Mouse utilities").Click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,48 +11,6 @@ namespace MouseUtils.UITests
|
||||
{
|
||||
public class MouseUtilsSettings
|
||||
{
|
||||
// Accessibility ID constants
|
||||
public static class AccessibilityIds
|
||||
{
|
||||
// Mouse Utils module IDs
|
||||
public const string FindMyMouse = "MouseUtils_FindMyMouseTestId";
|
||||
public const string MouseHighlighter = "MouseUtils_MouseHighlighterTestId";
|
||||
public const string MousePointerCrosshairs = "MouseUtils_MousePointerCrosshairsTestId";
|
||||
public const string MouseJump = "MouseUtils_MouseJumpTestId";
|
||||
|
||||
// ToggleSwitch IDs
|
||||
public const string FindMyMouseToggle = "MouseUtils_FindMyMouseToggleId";
|
||||
public const string MouseHighlighterToggle = "MouseUtils_MouseHighlighterToggleId";
|
||||
public const string MousePointerCrosshairsToggle = "MouseUtils_MousePointerCrosshairsToggleId";
|
||||
public const string MouseJumpToggle = "MouseUtils_MouseJumpToggleId";
|
||||
|
||||
// Find My Mouse UI Element IDs
|
||||
public const string FindMyMouseActivationMethod = "MouseUtils_FindMyMouseActivationMethodId";
|
||||
public const string FindMyMouseAppearanceBehavior = "MouseUtils_FindMyMouseAppearanceBehaviorId";
|
||||
public const string FindMyMouseExcludedApps = "MouseUtils_FindMyMouseExcludedAppsId";
|
||||
public const string FindMyMouseBackgroundColor = "MouseUtils_FindMyMouseBackgroundColorId";
|
||||
public const string FindMyMouseSpotlightColor = "MouseUtils_FindMyMouseSpotlightColorId";
|
||||
public const string FindMyMouseOverlayOpacity = "MouseUtils_FindMyMouseOverlayOpacityId";
|
||||
public const string FindMyMouseSpotlightZoom = "MouseUtils_FindMyMouseSpotlightZoomId";
|
||||
public const string FindMyMouseSpotlightRadius = "MouseUtils_FindMyMouseSpotlightRadiusId";
|
||||
public const string FindMyMouseAnimationDuration = "MouseUtils_FindMyMouseAnimationDurationId";
|
||||
|
||||
// Mouse Highlighter UI Element IDs
|
||||
public const string MouseHighlighterActivationShortcut = "MouseUtils_MouseHighlighterActivationShortcutId";
|
||||
public const string MouseHighlighterAppearanceBehavior = "MouseUtils_MouseHighlighterAppearanceBehaviorId";
|
||||
|
||||
// Mouse Pointer Crosshairs UI Element IDs
|
||||
public const string MousePointerCrosshairsAppearanceBehavior = "MouseUtils_MousePointerCrosshairsAppearanceBehaviorId";
|
||||
|
||||
// Mouse Jump UI Element IDs
|
||||
public const string MouseJumpActivationShortcut = "MouseUtils_MouseJumpActivationShortcutId";
|
||||
|
||||
// Navigation IDs
|
||||
public const string InputOutputNavItem = "InputOutputNavItem";
|
||||
public const string MouseUtilitiesNavItem = "MouseUtilitiesNavItem";
|
||||
public const string KeyboardManagerNavItem = "KeyboardManagerNavItem";
|
||||
}
|
||||
|
||||
// Mouse Utils Modules
|
||||
public enum MouseUtils
|
||||
{
|
||||
|
||||
@@ -121,8 +121,8 @@ FONT 8, "MS Shell Dlg", 0, 0, 0x0
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "OK",IDOK,166,306,50,14
|
||||
PUSHBUTTON "Cancel",IDCANCEL,223,306,50,14
|
||||
LTEXT "ZoomIt v9.01",IDC_VERSION,42,7,73,10
|
||||
LTEXT "Copyright © 2006-2025 Mark Russinovich",IDC_COPYRIGHT,42,17,166,8
|
||||
LTEXT "ZoomIt v9.0",IDC_VERSION,42,7,73,10
|
||||
LTEXT "Copyright <EFBFBD> 2006-2024 Mark Russinovich",IDC_COPYRIGHT,42,17,166,8
|
||||
CONTROL "<a HREF=""https://www.sysinternals.com"">Sysinternals - www.sysinternals.com</a>",IDC_LINK,
|
||||
"SysLink",WS_TABSTOP,42,26,150,9
|
||||
ICON "APPICON",IDC_STATIC,12,9,20,20
|
||||
|
||||
@@ -3525,10 +3525,6 @@ winrt::fire_and_forget StartRecordingAsync( HWND hWnd, LPRECT rcCrop, HWND hWndR
|
||||
}
|
||||
if( destFile == nullptr ) {
|
||||
|
||||
if (stream) {
|
||||
stream.Close();
|
||||
stream = nullptr;
|
||||
}
|
||||
co_await file.DeleteAsync();
|
||||
}
|
||||
else {
|
||||
@@ -3548,10 +3544,6 @@ winrt::fire_and_forget StartRecordingAsync( HWND hWnd, LPRECT rcCrop, HWND hWndR
|
||||
}
|
||||
else {
|
||||
|
||||
if (stream) {
|
||||
stream.Close();
|
||||
stream = nullptr;
|
||||
}
|
||||
co_await file.DeleteAsync();
|
||||
g_RecordingSession = nullptr;
|
||||
}
|
||||
@@ -4024,10 +4016,7 @@ LRESULT APIENTRY MainWndProc(
|
||||
// Now copy crop or copy+save
|
||||
if( LOWORD( wParam ) == SNIP_SAVE_HOTKEY )
|
||||
{
|
||||
// Hide cursor for screen capture
|
||||
ShowCursor(false);
|
||||
SendMessage( hWnd, WM_COMMAND, IDC_SAVE_CROP, ( zoomed ? 0 : SHALLOW_ZOOM ) );
|
||||
ShowCursor(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4059,6 +4048,12 @@ LRESULT APIENTRY MainWndProc(
|
||||
OutputDebug( L"Exiting liveDraw after snip\n" );
|
||||
SendMessage( hWnd, WM_KEYDOWN, VK_ESCAPE, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set wparam to 1 to exit without animation
|
||||
OutputDebug(L"Exiting zoom after snip\n" );
|
||||
SendMessage( hWnd, WM_HOTKEY, ZOOM_HOTKEY, SHALLOW_DESTROY );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5783,26 +5778,17 @@ LRESULT APIENTRY MainWndProc(
|
||||
|
||||
if( !g_DrawingShape ) {
|
||||
|
||||
// If the point has changed, draw a line to it
|
||||
if (prevPt.x != LOWORD(lParam) || prevPt.y != HIWORD(lParam)) {
|
||||
Gdiplus::Graphics dstGraphics(hdcScreenCompat);
|
||||
if ((GetWindowLong(g_hWndMain, GWL_EXSTYLE) & WS_EX_LAYERED) == 0)
|
||||
{
|
||||
dstGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
|
||||
}
|
||||
Gdiplus::Color color = ColorFromColorRef(g_PenColor);
|
||||
Gdiplus::Pen pen(color, static_cast<Gdiplus::REAL>(g_PenWidth));
|
||||
Gdiplus::GraphicsPath path;
|
||||
pen.SetLineJoin(Gdiplus::LineJoinRound);
|
||||
path.AddLine(prevPt.x, prevPt.y, LOWORD(lParam), HIWORD(lParam));
|
||||
dstGraphics.DrawPath(&pen, &path);
|
||||
}
|
||||
// Draw a dot at the current point, if the point hasn't changed
|
||||
else {
|
||||
MoveToEx(hdcScreenCompat, prevPt.x, prevPt.y, NULL);
|
||||
LineTo(hdcScreenCompat, LOWORD(lParam), HIWORD(lParam));
|
||||
InvalidateRect(hWnd, NULL, FALSE);
|
||||
Gdiplus::Graphics dstGraphics(hdcScreenCompat);
|
||||
if( ( GetWindowLong( g_hWndMain, GWL_EXSTYLE ) & WS_EX_LAYERED ) == 0 )
|
||||
{
|
||||
dstGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
|
||||
}
|
||||
Gdiplus::Color color = ColorFromColorRef(g_PenColor);
|
||||
Gdiplus::Pen pen(color, static_cast<Gdiplus::REAL>(g_PenWidth));
|
||||
Gdiplus::GraphicsPath path;
|
||||
pen.SetLineJoin(Gdiplus::LineJoinRound);
|
||||
path.AddLine(prevPt.x, prevPt.y, LOWORD(lParam), HIWORD(lParam));
|
||||
dstGraphics.DrawPath(&pen, &path);
|
||||
|
||||
prevPt.x = LOWORD( lParam );
|
||||
prevPt.y = HIWORD( lParam );
|
||||
|
||||
@@ -2,44 +2,28 @@
|
||||
# You can modify the rules from these initially generated values to suit your own policies.
|
||||
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference.
|
||||
|
||||
##################################################
|
||||
# Global settings
|
||||
##################################################
|
||||
|
||||
[*.{cs,vb}]
|
||||
tab_width = 4
|
||||
indent_size = 4
|
||||
end_of_line = crlf
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
file_header_template = Copyright (c) Microsoft Corporation\nThe Microsoft Corporation licenses this file to you under the MIT license.\nSee the LICENSE file in the project root for more information.
|
||||
|
||||
##################################################
|
||||
# C# specific formatting
|
||||
##################################################
|
||||
|
||||
[*.cs]
|
||||
# ----------------------------------------------
|
||||
# Core editorconfig formatting - indentation
|
||||
# ----------------------------------------------
|
||||
|
||||
file_header_template = Copyright (c) Microsoft Corporation\r\nThe Microsoft Corporation licenses this file to you under the MIT license.\r\nSee the LICENSE file in the project root for more information.
|
||||
|
||||
#Core editorconfig formatting - indentation
|
||||
|
||||
#use soft tabs (spaces) for indentation
|
||||
indent_style = space
|
||||
|
||||
#Formatting - new line options
|
||||
|
||||
#place else statements on a new line
|
||||
csharp_new_line_before_else = true
|
||||
#require braces to be on a new line for lambdas, methods, control_blocks, types, properties, and accessors (also known as "Allman" style)
|
||||
csharp_new_line_before_open_brace = all
|
||||
|
||||
# ----------------------------------------------
|
||||
# Formatting - organize using options
|
||||
# ----------------------------------------------
|
||||
#Formatting - organize using options
|
||||
|
||||
# sort System.* using directives alphabetically, and place them before other usings
|
||||
#sort System.* using directives alphabetically, and place them before other usings
|
||||
dotnet_sort_system_directives_first = true
|
||||
# Do not place System.* using directives before other using directives.
|
||||
dotnet_separate_import_directive_groups = false
|
||||
|
||||
# ----------------------------------------------
|
||||
# Formatting - spacing options
|
||||
# ----------------------------------------------
|
||||
#Formatting - spacing options
|
||||
|
||||
#require NO space between a cast and the value
|
||||
csharp_space_after_cast = false
|
||||
@@ -60,29 +44,17 @@ csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
|
||||
# ----------------------------------------------
|
||||
# Formatting - wrapping options
|
||||
# ----------------------------------------------
|
||||
#Formatting - wrapping options
|
||||
|
||||
#leave code block on separate lines
|
||||
csharp_preserve_single_line_blocks = true
|
||||
#put each statement on a separate line
|
||||
csharp_preserve_single_line_statements = false
|
||||
|
||||
##################################################
|
||||
# C# style rules
|
||||
##################################################
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - Code block preferences
|
||||
# ----------------------------------------------
|
||||
#Style - Code block preferences
|
||||
|
||||
#prefer curly braces even for one line of code
|
||||
csharp_prefer_braces = true:suggestion
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - expression bodied member options
|
||||
# ----------------------------------------------
|
||||
#Style - expression bodied member options
|
||||
|
||||
#prefer expression bodies for accessors
|
||||
csharp_style_expression_bodied_accessors = true:warning
|
||||
@@ -93,73 +65,55 @@ csharp_style_expression_bodied_methods = when_on_single_line:silent
|
||||
#prefer expression-bodied members for properties
|
||||
csharp_style_expression_bodied_properties = true:warning
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - expression level options
|
||||
# ----------------------------------------------
|
||||
#Style - expression level options
|
||||
|
||||
#prefer out variables to be declared before the method call
|
||||
csharp_style_inlined_variable_declaration = false:suggestion
|
||||
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - Expression-level preferences
|
||||
# ----------------------------------------------
|
||||
#Style - Expression-level preferences
|
||||
|
||||
#prefer default over default(T)
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
#prefer objects to be initialized using object initializers when possible
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - implicit and explicit types
|
||||
# ----------------------------------------------
|
||||
#Style - implicit and explicit types
|
||||
|
||||
#prefer var over explicit type in all cases, unless overridden by another code style rule
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
#prefer var is used to declare variables with built-in system types such as int
|
||||
csharp_style_var_for_built_in_types = true:warning
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
#prefer var when the type is already mentioned on the right-hand side of a declaration expression
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - language keyword and framework type options
|
||||
# ----------------------------------------------
|
||||
#Style - language keyword and framework type options
|
||||
|
||||
#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - Language rules
|
||||
# ----------------------------------------------
|
||||
|
||||
#Style - Language rules
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
|
||||
csharp_style_var_for_built_in_types = true:warning
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - modifier options
|
||||
# ----------------------------------------------
|
||||
#Style - modifier options
|
||||
|
||||
#prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods.
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - Modifier preferences
|
||||
# ----------------------------------------------
|
||||
#Style - Modifier preferences
|
||||
|
||||
#when this rule is set to a list of modifiers, prefer the specified ordering.
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,async,readonly,override,sealed,abstract,virtual:warning
|
||||
dotnet_style_readonly_field = true:warning
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - Pattern matching
|
||||
# ----------------------------------------------
|
||||
#Style - Pattern matching
|
||||
|
||||
#prefer pattern matching instead of is expression with type casts
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:warning
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - qualification options
|
||||
# ----------------------------------------------
|
||||
#Style - qualification options
|
||||
|
||||
#prefer events not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
@@ -169,26 +123,20 @@ dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
#prefer properties not to be prefaced with this. or Me. in Visual Basic
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - expression bodies
|
||||
# ----------------------------------------------
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
csharp_prefer_simple_using_statement = true:warning
|
||||
csharp_style_namespace_declarations = file_scoped:warning
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
|
||||
# ----------------------------------------------
|
||||
# Style - Miscellaneous preferences
|
||||
# ----------------------------------------------
|
||||
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
csharp_prefer_simple_using_statement = true:warning
|
||||
csharp_style_namespace_declarations = file_scoped:warning
|
||||
|
||||
[*.{cs,vb}]
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
tab_width = 4
|
||||
indent_size = 4
|
||||
end_of_line = crlf
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
@@ -198,13 +146,12 @@ dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
[*.{cs,vb}]
|
||||
|
||||
#Style - Unnecessary code rules
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:warning
|
||||
|
||||
##################################################
|
||||
# Naming rules
|
||||
##################################################
|
||||
|
||||
[*.{cs,vb}]
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
@@ -256,11 +203,7 @@ dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:warning
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
|
||||
# Diagnostic configuration
|
||||
|
||||
##################################################
|
||||
# Diagnostics
|
||||
##################################################
|
||||
|
||||
[*.{cs,vb}]
|
||||
# CS8305: Type is for evaluation purposes only and is subject to change or removal in future updates.
|
||||
dotnet_diagnostic.CS8305.severity = suggestion
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.3.183" />
|
||||
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4188" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.250907003" />
|
||||
<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.8" />
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
@@ -118,46 +117,36 @@ public partial class ContextMenuViewModel : ObservableObject,
|
||||
/// Generates a mapping of key -> command item for this particular item's
|
||||
/// MoreCommands. (This won't include the primary Command, but it will
|
||||
/// include the secondary one). This map can be used to quickly check if a
|
||||
/// shortcut key was pressed. In case there are duplicate keybindings, the first
|
||||
/// one is used and the rest are ignored.
|
||||
/// shortcut key was pressed
|
||||
/// </summary>
|
||||
/// <returns>a dictionary of KeyChord -> Context commands, for all commands
|
||||
/// that have a shortcut key set.</returns>
|
||||
private Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
|
||||
public Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
|
||||
{
|
||||
var result = new Dictionary<KeyChord, CommandContextItemViewModel>();
|
||||
|
||||
var menu = CurrentContextMenu;
|
||||
if (menu is null)
|
||||
if (CurrentContextMenu is null)
|
||||
{
|
||||
return result;
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach (var item in menu)
|
||||
{
|
||||
if (item is CommandContextItemViewModel cmd && cmd.HasRequestedShortcut)
|
||||
{
|
||||
var key = cmd.RequestedShortcut ?? new KeyChord(0, 0, 0);
|
||||
var added = result.TryAdd(key, cmd);
|
||||
if (!added)
|
||||
{
|
||||
Logger.LogWarning($"Ignoring duplicate keyboard shortcut {KeyChordHelpers.FormatForDebug(key)} on command '{cmd.Title ?? cmd.Name ?? "(unknown)"}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return CurrentContextMenu
|
||||
.OfType<CommandContextItemViewModel>()
|
||||
.Where(c => c.HasRequestedShortcut)
|
||||
.ToDictionary(
|
||||
c => c.RequestedShortcut ?? new KeyChord(0, 0, 0),
|
||||
c => c);
|
||||
}
|
||||
|
||||
public ContextKeybindingResult? CheckKeybinding(bool ctrl, bool alt, bool shift, bool win, VirtualKey key)
|
||||
{
|
||||
var keybindings = Keybindings();
|
||||
|
||||
// Does the pressed key match any of the keybindings?
|
||||
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrl, alt, shift, win, key, 0);
|
||||
if (keybindings.TryGetValue(pressedKeyChord, out var item))
|
||||
if (keybindings is not null)
|
||||
{
|
||||
return InvokeCommand(item);
|
||||
// Does the pressed key match any of the keybindings?
|
||||
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrl, alt, shift, win, key, 0);
|
||||
if (keybindings.TryGetValue(pressedKeyChord, out var item))
|
||||
{
|
||||
return InvokeCommand(item);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -51,36 +51,6 @@ public abstract partial class ExtensionObjectViewModel : ObservableObject
|
||||
DoOnUiThread(() => OnPropertyChanged(propertyName));
|
||||
}
|
||||
|
||||
protected void UpdateProperty(string propertyName1, string propertyName2)
|
||||
{
|
||||
DoOnUiThread(() =>
|
||||
{
|
||||
OnPropertyChanged(propertyName1);
|
||||
OnPropertyChanged(propertyName2);
|
||||
});
|
||||
}
|
||||
|
||||
protected void UpdateProperty(string propertyName1, string propertyName2, string propertyName3)
|
||||
{
|
||||
DoOnUiThread(() =>
|
||||
{
|
||||
OnPropertyChanged(propertyName1);
|
||||
OnPropertyChanged(propertyName2);
|
||||
OnPropertyChanged(propertyName3);
|
||||
});
|
||||
}
|
||||
|
||||
protected void UpdateProperty(params string[] propertyNames)
|
||||
{
|
||||
DoOnUiThread(() =>
|
||||
{
|
||||
foreach (var propertyName in propertyNames)
|
||||
{
|
||||
OnPropertyChanged(propertyName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void ShowException(Exception ex, string? extensionHint = null)
|
||||
{
|
||||
if (PageContext.TryGetTarget(out var pageContext))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
|
||||
@@ -9,11 +10,14 @@ namespace Microsoft.CmdPal.Core.ViewModels;
|
||||
|
||||
public partial class FiltersViewModel : ExtensionObjectViewModel
|
||||
{
|
||||
private readonly ExtensionObject<IFilters> _filtersModel;
|
||||
private readonly ExtensionObject<IFilters> _filtersModel = new(null);
|
||||
|
||||
public string CurrentFilterId { get; private set; } = string.Empty;
|
||||
[ObservableProperty]
|
||||
public partial string CurrentFilterId { get; set; } = string.Empty;
|
||||
|
||||
public IFilterItemViewModel[] Filters { get; private set; } = [];
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(ShouldShowFilters))]
|
||||
public partial IFilterItemViewModel[] Filters { get; set; } = [];
|
||||
|
||||
public bool ShouldShowFilters => Filters.Length > 0;
|
||||
|
||||
@@ -30,11 +34,23 @@ public partial class FiltersViewModel : ExtensionObjectViewModel
|
||||
if (_filtersModel.Unsafe is not null)
|
||||
{
|
||||
var filters = _filtersModel.Unsafe.GetFilters();
|
||||
Filters = BuildFilters(filters ?? []);
|
||||
UpdateProperty(nameof(Filters), nameof(ShouldShowFilters));
|
||||
Filters = filters.Select<IFilterItem, IFilterItemViewModel>(filter =>
|
||||
{
|
||||
var filterItem = filter as IFilter;
|
||||
if (filterItem != null)
|
||||
{
|
||||
var filterVM = new FilterItemViewModel(filterItem!, PageContext);
|
||||
filterVM.InitializeProperties();
|
||||
|
||||
CurrentFilterId = _filtersModel.Unsafe.CurrentFilterId ?? string.Empty;
|
||||
UpdateProperty(nameof(CurrentFilterId));
|
||||
return filterVM;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SeparatorViewModel();
|
||||
}
|
||||
}).ToArray();
|
||||
|
||||
CurrentFilterId = _filtersModel.Unsafe.CurrentFilterId;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -45,27 +61,7 @@ public partial class FiltersViewModel : ExtensionObjectViewModel
|
||||
}
|
||||
|
||||
Filters = [];
|
||||
UpdateProperty(nameof(Filters), nameof(ShouldShowFilters));
|
||||
|
||||
CurrentFilterId = string.Empty;
|
||||
UpdateProperty(nameof(CurrentFilterId));
|
||||
}
|
||||
|
||||
private IFilterItemViewModel[] BuildFilters(IFilterItem[] filters)
|
||||
{
|
||||
return [..filters.Select<IFilterItem, IFilterItemViewModel>(filter =>
|
||||
{
|
||||
if (filter is IFilter filterItem)
|
||||
{
|
||||
var filterItemViewModel = new FilterItemViewModel(filterItem!, PageContext);
|
||||
filterItemViewModel.InitializeProperties();
|
||||
return filterItemViewModel;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SeparatorViewModel();
|
||||
}
|
||||
})];
|
||||
}
|
||||
|
||||
public override void SafeCleanup()
|
||||
@@ -74,9 +70,9 @@ public partial class FiltersViewModel : ExtensionObjectViewModel
|
||||
|
||||
foreach (var filter in Filters)
|
||||
{
|
||||
if (filter is FilterItemViewModel filterItemViewModel)
|
||||
if (filter is FilterItemViewModel filterVM)
|
||||
{
|
||||
filterItemViewModel.SafeCleanup();
|
||||
filterVM.SafeCleanup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CmdPal.Core.ViewModels.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels;
|
||||
|
||||
public class GalleryGridPropertiesViewModel : IGridPropertiesViewModel
|
||||
{
|
||||
private readonly ExtensionObject<IGalleryGridLayout> _model;
|
||||
|
||||
public GalleryGridPropertiesViewModel(IGalleryGridLayout galleryGridLayout)
|
||||
{
|
||||
_model = new(galleryGridLayout);
|
||||
}
|
||||
|
||||
public bool ShowTitle { get; set; }
|
||||
|
||||
public bool ShowSubtitle { get; set; }
|
||||
|
||||
public void InitializeProperties()
|
||||
{
|
||||
var model = _model.Unsafe;
|
||||
if (model is null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
|
||||
ShowTitle = model.ShowTitle;
|
||||
ShowSubtitle = model.ShowSubtitle;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels;
|
||||
|
||||
public interface IGridPropertiesViewModel
|
||||
{
|
||||
void InitializeProperties();
|
||||
}
|
||||
@@ -45,10 +45,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
(!_isFetching) &&
|
||||
IsLoading == false;
|
||||
|
||||
public bool IsGridView { get; private set; }
|
||||
|
||||
public IGridPropertiesViewModel? GridProperties { get; private set; }
|
||||
|
||||
// Remember - "observable" properties from the model (via PropChanged)
|
||||
// cannot be marked [ObservableProperty]
|
||||
public bool ShowDetails { get; private set; }
|
||||
@@ -520,13 +516,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
|
||||
_isDynamic = model is IDynamicListPage;
|
||||
|
||||
IsGridView = model.GridProperties is not null;
|
||||
UpdateProperty(nameof(IsGridView));
|
||||
|
||||
GridProperties = LoadGridPropertiesViewModel(model.GridProperties);
|
||||
GridProperties?.InitializeProperties();
|
||||
UpdateProperty(nameof(GridProperties));
|
||||
|
||||
ShowDetails = model.ShowDetails;
|
||||
UpdateProperty(nameof(ShowDetails));
|
||||
|
||||
@@ -548,27 +537,9 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
model.ItemsChanged += Model_ItemsChanged;
|
||||
}
|
||||
|
||||
private IGridPropertiesViewModel? LoadGridPropertiesViewModel(IGridProperties? gridProperties)
|
||||
{
|
||||
if (gridProperties is IMediumGridLayout mediumGridLayout)
|
||||
{
|
||||
return new MediumGridPropertiesViewModel(mediumGridLayout);
|
||||
}
|
||||
else if (gridProperties is IGalleryGridLayout galleryGridLayout)
|
||||
{
|
||||
return new GalleryGridPropertiesViewModel(galleryGridLayout);
|
||||
}
|
||||
else if (gridProperties is ISmallGridLayout smallGridLayout)
|
||||
{
|
||||
return new SmallGridPropertiesViewModel(smallGridLayout);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void LoadMoreIfNeeded()
|
||||
{
|
||||
var model = _model.Unsafe;
|
||||
var model = this._model.Unsafe;
|
||||
if (model is null)
|
||||
{
|
||||
return;
|
||||
@@ -612,7 +583,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
{
|
||||
base.FetchProperty(propertyName);
|
||||
|
||||
var model = _model.Unsafe;
|
||||
var model = this._model.Unsafe;
|
||||
if (model is null)
|
||||
{
|
||||
return; // throw?
|
||||
@@ -620,20 +591,14 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
|
||||
switch (propertyName)
|
||||
{
|
||||
case nameof(GridProperties):
|
||||
IsGridView = model.GridProperties is not null;
|
||||
GridProperties = LoadGridPropertiesViewModel(model.GridProperties);
|
||||
GridProperties?.InitializeProperties();
|
||||
UpdateProperty(nameof(IsGridView));
|
||||
break;
|
||||
case nameof(ShowDetails):
|
||||
ShowDetails = model.ShowDetails;
|
||||
this.ShowDetails = model.ShowDetails;
|
||||
break;
|
||||
case nameof(PlaceholderText):
|
||||
_modelPlaceholderText = model.PlaceholderText;
|
||||
this._modelPlaceholderText = model.PlaceholderText;
|
||||
break;
|
||||
case nameof(SearchText):
|
||||
SearchText = model.SearchText;
|
||||
this.SearchText = model.SearchText;
|
||||
break;
|
||||
case nameof(EmptyContent):
|
||||
EmptyContent = new(new(model.EmptyContent), PageContext);
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CmdPal.Core.ViewModels.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels;
|
||||
|
||||
public class MediumGridPropertiesViewModel : IGridPropertiesViewModel
|
||||
{
|
||||
private readonly ExtensionObject<IMediumGridLayout> _model;
|
||||
|
||||
public MediumGridPropertiesViewModel(IMediumGridLayout mediumGridLayout)
|
||||
{
|
||||
_model = new(mediumGridLayout);
|
||||
}
|
||||
|
||||
public bool ShowTitle { get; set; }
|
||||
|
||||
public void InitializeProperties()
|
||||
{
|
||||
var model = _model.Unsafe;
|
||||
if (model is null)
|
||||
{
|
||||
return; // throw?
|
||||
}
|
||||
|
||||
ShowTitle = model.ShowTitle;
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.ComponentModel;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
|
||||
@@ -34,28 +32,12 @@ public interface IContextMenuContext : INotifyPropertyChanged
|
||||
/// that have a shortcut key set.</returns>
|
||||
public Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
|
||||
{
|
||||
var result = new Dictionary<KeyChord, CommandContextItemViewModel>();
|
||||
|
||||
var menu = MoreCommands;
|
||||
if (menu is null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var item in menu)
|
||||
{
|
||||
if (item is CommandContextItemViewModel cmd && cmd.HasRequestedShortcut)
|
||||
{
|
||||
var key = cmd.RequestedShortcut ?? new KeyChord(0, 0, 0);
|
||||
var added = result.TryAdd(key, cmd);
|
||||
if (!added)
|
||||
{
|
||||
Logger.LogWarning($"Ignoring duplicate keyboard shortcut {KeyChordHelpers.FormatForDebug(key)} on command '{cmd.Title ?? cmd.Name ?? "(unknown)"}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return MoreCommands
|
||||
.OfType<CommandContextItemViewModel>()
|
||||
.Where(c => c.HasRequestedShortcut)
|
||||
.ToDictionary(
|
||||
c => c.RequestedShortcut ?? new KeyChord(0, 0, 0),
|
||||
c => c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CmdPal.Core.ViewModels.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels;
|
||||
|
||||
public class SmallGridPropertiesViewModel : IGridPropertiesViewModel
|
||||
{
|
||||
private readonly ExtensionObject<ISmallGridLayout> _model;
|
||||
|
||||
public SmallGridPropertiesViewModel(ISmallGridLayout smallGridLayout)
|
||||
{
|
||||
_model = new(smallGridLayout);
|
||||
}
|
||||
|
||||
public void InitializeProperties()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -94,4 +94,16 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Just mark it as AOT compatible. Do not publish with AOT now. We need fully test before we really publish it as AOT enabled-->
|
||||
<!--<PropertyGroup>
|
||||
<SelfContained>true</SelfContained>
|
||||
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
--><!-- <DisableRuntimeMarshalling>true</DisableRuntimeMarshalling> --><!--
|
||||
<PublishAot>true</PublishAot>
|
||||
<EnableMsixTooling>true</EnableMsixTooling>
|
||||
</PropertyGroup>-->
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -42,8 +42,6 @@ public partial class SettingsModel : ObservableObject
|
||||
|
||||
public bool IgnoreShortcutWhenFullscreen { get; set; }
|
||||
|
||||
public bool AllowExternalReload { get; set; }
|
||||
|
||||
public Dictionary<string, ProviderSettings> ProviderSettings { get; set; } = [];
|
||||
|
||||
public Dictionary<string, CommandAlias> Aliases { get; set; } = [];
|
||||
|
||||
@@ -38,16 +38,6 @@ public partial class SettingsViewModel : INotifyPropertyChanged
|
||||
}
|
||||
}
|
||||
|
||||
public bool AllowExternalReload
|
||||
{
|
||||
get => _settings.AllowExternalReload;
|
||||
set
|
||||
{
|
||||
_settings.AllowExternalReload = value;
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowAppDetails
|
||||
{
|
||||
get => _settings.ShowAppDetails;
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<Rectangle
|
||||
Height="1"
|
||||
Margin="-16,-12,-12,-12"
|
||||
Fill="{ThemeResource MenuFlyoutSeparatorBackground}" />
|
||||
Fill="{ThemeResource MenuFlyoutSeparatorThemeBrush}" />
|
||||
</DataTemplate>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -68,14 +68,11 @@
|
||||
<ComboBox
|
||||
Name="FiltersComboBox"
|
||||
x:Uid="FiltersComboBox"
|
||||
MinWidth="200"
|
||||
VerticalAlignment="Center"
|
||||
ItemTemplateSelector="{StaticResource FilterTemplateSelector}"
|
||||
ItemsSource="{x:Bind ViewModel.Filters, Mode=OneWay}"
|
||||
PlaceholderText="Filters"
|
||||
PreviewKeyDown="FiltersComboBox_PreviewKeyDown"
|
||||
SelectedValue="{x:Bind ViewModel.CurrentFilterId, Mode=OneWay}"
|
||||
SelectedValuePath="Id"
|
||||
SelectionChanged="FiltersComboBox_SelectionChanged"
|
||||
Style="{StaticResource ComboBoxStyle}"
|
||||
Visibility="{x:Bind ViewModel.ShouldShowFilters, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Controls;
|
||||
|
||||
public sealed partial class IconMarginConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
// Only include a margin if there is text to separate from the icon.
|
||||
var text = value as string;
|
||||
return string.IsNullOrEmpty(text) ? new Thickness(0) : new Thickness(0, 0, 4, 0);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) => throw new NotImplementedException();
|
||||
}
|
||||
@@ -131,11 +131,6 @@ public sealed partial class SearchBar : UserControl,
|
||||
WeakReferenceMessenger.Default.Send<OpenContextMenuMessage>(new OpenContextMenuMessage(null, null, null, ContextMenuFilterLocation.Bottom));
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (ctrlPressed && e.Key == VirtualKey.I)
|
||||
{
|
||||
// Today you learned that Ctrl+I in a TextBox will insert a tab
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == VirtualKey.Escape)
|
||||
{
|
||||
if (string.IsNullOrEmpty(FilterBox.Text))
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
<Thickness x:Key="TagPadding">4,2,4,2</Thickness>
|
||||
<Thickness x:Key="TagBorderThickness">1</Thickness>
|
||||
|
||||
<local:IconMarginConverter x:Key="IconMarginConverter" />
|
||||
|
||||
<Style BasedOn="{StaticResource DefaultTagStyle}" TargetType="local:Tag" />
|
||||
|
||||
<Style x:Key="DefaultTagStyle" TargetType="local:Tag">
|
||||
@@ -73,7 +71,7 @@
|
||||
x:Name="PART_Icon"
|
||||
Grid.Column="0"
|
||||
Height="12"
|
||||
Margin="{Binding Text, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource IconMarginConverter}}"
|
||||
Margin="0,0,4,0"
|
||||
SourceKey="{TemplateBinding Icon}" />
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// 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.CodeAnalysis;
|
||||
using Microsoft.CmdPal.Core.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
@@ -15,7 +14,6 @@ internal sealed partial class FilterTemplateSelector : DataTemplateSelector
|
||||
|
||||
public DataTemplate? Separator { get; set; }
|
||||
|
||||
[DynamicDependency(DynamicallyAccessedMemberTypes.All, "Microsoft.UI.Xaml.Controls.ComboBoxItem", "Microsoft.WinUI")]
|
||||
protected override DataTemplate? SelectTemplateCore(object item, DependencyObject dependencyObject)
|
||||
{
|
||||
DataTemplate? dataTemplate = Default;
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CmdPal.Core.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.CmdPal.UI;
|
||||
|
||||
internal sealed partial class GridItemTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
public IGridPropertiesViewModel? GridProperties { get; set; }
|
||||
|
||||
public DataTemplate? Small { get; set; }
|
||||
|
||||
public DataTemplate? Medium { get; set; }
|
||||
|
||||
public DataTemplate? Gallery { get; set; }
|
||||
|
||||
protected override DataTemplate? SelectTemplateCore(object item, DependencyObject dependencyObject)
|
||||
{
|
||||
DataTemplate? dataTemplate = Medium;
|
||||
|
||||
if (GridProperties is SmallGridPropertiesViewModel)
|
||||
{
|
||||
dataTemplate = Small;
|
||||
}
|
||||
else if (GridProperties is MediumGridPropertiesViewModel)
|
||||
{
|
||||
dataTemplate = Medium;
|
||||
}
|
||||
else if (GridProperties is GalleryGridPropertiesViewModel)
|
||||
{
|
||||
dataTemplate = Gallery;
|
||||
}
|
||||
|
||||
return dataTemplate;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
x:Class="Microsoft.CmdPal.UI.ListPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cmdpalUI="using:Microsoft.CmdPal.UI"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
|
||||
xmlns:coreViewModels="using:Microsoft.CmdPal.Core.ViewModels"
|
||||
@@ -12,11 +11,8 @@
|
||||
xmlns:help="using:Microsoft.CmdPal.UI.Helpers"
|
||||
xmlns:local="using:Microsoft.CmdPal.UI"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
xmlns:viewModels="using:Microsoft.CmdPal.UI.ViewModels"
|
||||
x:Name="PageRoot"
|
||||
Background="Transparent"
|
||||
DataContext="{x:Bind ViewModel, Mode=OneWay}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
@@ -27,7 +23,6 @@
|
||||
IsSourceGrouped="True"
|
||||
Source="{x:Bind ViewModel.Items, Mode=OneWay}" />-->
|
||||
|
||||
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||
<converters:StringVisibilityConverter
|
||||
x:Key="StringVisibilityConverter"
|
||||
EmptyValue="Collapsed"
|
||||
@@ -44,14 +39,6 @@
|
||||
ToolTipService.ToolTip="{x:Bind ToolTip, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
|
||||
<cmdpalUI:GridItemTemplateSelector
|
||||
x:Key="GridItemTemplateSelector"
|
||||
x:DataType="coreViewModels:ListItemViewModel"
|
||||
Gallery="{StaticResource GalleryGridItemViewModelTemplate}"
|
||||
GridProperties="{x:Bind ViewModel.GridProperties}"
|
||||
Medium="{StaticResource MediumGridItemViewModelTemplate}"
|
||||
Small="{StaticResource SmallGridItemViewModelTemplate}" />
|
||||
|
||||
<!-- https://learn.microsoft.com/windows/apps/design/controls/itemsview#specify-the-look-of-the-items -->
|
||||
<DataTemplate x:Key="ListItemViewModelTemplate" x:DataType="coreViewModels:ListItemViewModel">
|
||||
<Grid
|
||||
@@ -115,145 +102,6 @@
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Grid item templates for visual grid representation -->
|
||||
<DataTemplate x:Key="SmallGridItemViewModelTemplate" x:DataType="coreViewModels:ListItemViewModel">
|
||||
<StackPanel
|
||||
Width="60"
|
||||
Height="60"
|
||||
Padding="8,16"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.Name="{x:Bind Title}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="8"
|
||||
Orientation="Vertical"
|
||||
ToolTipService.ToolTip="{x:Bind Title}">
|
||||
|
||||
<cpcontrols:IconBox
|
||||
x:Name="GridIconBorder"
|
||||
Width="28"
|
||||
Height="28"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{ThemeResource TextFillColorPrimary}"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="MediumGridItemViewModelTemplate" x:DataType="coreViewModels:ListItemViewModel">
|
||||
<StackPanel
|
||||
Width="100"
|
||||
Height="100"
|
||||
Padding="8,16"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.Name="{x:Bind Title}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="8"
|
||||
Orientation="Vertical"
|
||||
ToolTipService.ToolTip="{x:Bind Title}">
|
||||
|
||||
<cpcontrols:IconBox
|
||||
x:Name="GridIconBorder"
|
||||
Width="36"
|
||||
Height="36"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
CharacterSpacing="12"
|
||||
FontSize="14"
|
||||
Foreground="{ThemeResource TextFillColorPrimary}"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
|
||||
<TextBlock
|
||||
x:Name="TitleTextBlock"
|
||||
MaxHeight="40"
|
||||
Margin="0,8,0,4"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
CharacterSpacing="12"
|
||||
FontSize="12"
|
||||
Text="{x:Bind Title}"
|
||||
TextAlignment="Center"
|
||||
TextTrimming="WordEllipsis"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding ElementName=PageRoot, Path=DataContext.GridProperties.ShowTitle, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="GalleryGridItemViewModelTemplate" x:DataType="coreViewModels:ListItemViewModel">
|
||||
<StackPanel
|
||||
Width="160"
|
||||
Margin="4"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.Name="{x:Bind Title}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="4"
|
||||
Orientation="Vertical"
|
||||
ToolTipService.ToolTip="{x:Bind Title}">
|
||||
|
||||
<Grid
|
||||
Width="160"
|
||||
Height="160"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Viewbox
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
Stretch="UniformToFill"
|
||||
StretchDirection="Both">
|
||||
<cpcontrols:IconBox
|
||||
CornerRadius="4"
|
||||
Foreground="{ThemeResource TextFillColorPrimary}"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Padding="4" Orientation="Vertical">
|
||||
<TextBlock
|
||||
x:Name="TitleTextBlock"
|
||||
MaxWidth="152"
|
||||
MaxHeight="40"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
CharacterSpacing="12"
|
||||
FontSize="14"
|
||||
Foreground="{ThemeResource TextFillColorPrimary}"
|
||||
Text="{x:Bind Title}"
|
||||
TextAlignment="Center"
|
||||
TextTrimming="WordEllipsis"
|
||||
TextWrapping="NoWrap" />
|
||||
<TextBlock
|
||||
x:Name="SubTitleTextBlock"
|
||||
MaxWidth="152"
|
||||
MaxHeight="40"
|
||||
Margin="0,4,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
CharacterSpacing="11"
|
||||
FontSize="11"
|
||||
Foreground="{ThemeResource TextFillColorTertiary}"
|
||||
Text="{x:Bind Subtitle}"
|
||||
TextAlignment="Center"
|
||||
TextTrimming="WordEllipsis"
|
||||
TextWrapping="NoWrap" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</Page.Resources>
|
||||
|
||||
<Grid>
|
||||
@@ -262,49 +110,34 @@
|
||||
TargetType="x:Boolean"
|
||||
Value="{x:Bind ViewModel.ShowEmptyContent, Mode=OneWay}">
|
||||
<controls:Case Value="False">
|
||||
<controls:SwitchPresenter
|
||||
HorizontalAlignment="Stretch"
|
||||
TargetType="x:Boolean"
|
||||
Value="{x:Bind ViewModel.IsGridView, Mode=OneWay}">
|
||||
<controls:Case Value="False">
|
||||
<ListView
|
||||
x:Name="ItemsList"
|
||||
Padding="0,2,0,0"
|
||||
ContextCanceled="Items_OnContextCanceled"
|
||||
ContextRequested="Items_OnContextRequested"
|
||||
DoubleTapped="Items_DoubleTapped"
|
||||
IsDoubleTapEnabled="True"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="Items_ItemClick"
|
||||
ItemTemplate="{StaticResource ListItemViewModelTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.FilteredItems, Mode=OneWay}"
|
||||
RightTapped="Items_RightTapped"
|
||||
SelectionChanged="Items_SelectionChanged">
|
||||
<ListView.ItemContainerTransitions>
|
||||
<TransitionCollection />
|
||||
</ListView.ItemContainerTransitions>
|
||||
</ListView>
|
||||
</controls:Case>
|
||||
<controls:Case Value="True">
|
||||
<GridView
|
||||
x:Name="ItemsGrid"
|
||||
Padding="8"
|
||||
ContextCanceled="Items_OnContextCanceled"
|
||||
ContextRequested="Items_OnContextRequested"
|
||||
DoubleTapped="Items_DoubleTapped"
|
||||
IsDoubleTapEnabled="True"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="Items_ItemClick"
|
||||
ItemTemplateSelector="{StaticResource GridItemTemplateSelector}"
|
||||
ItemsSource="{x:Bind ViewModel.FilteredItems, Mode=OneWay}"
|
||||
RightTapped="Items_RightTapped"
|
||||
SelectionChanged="Items_SelectionChanged">
|
||||
<GridView.ItemContainerTransitions>
|
||||
<TransitionCollection />
|
||||
</GridView.ItemContainerTransitions>
|
||||
</GridView>
|
||||
</controls:Case>
|
||||
</controls:SwitchPresenter>
|
||||
<ListView
|
||||
x:Name="ItemsList"
|
||||
Padding="0,2,0,0"
|
||||
ContextCanceled="ItemsList_OnContextCanceled"
|
||||
ContextRequested="ItemsList_OnContextRequested"
|
||||
DoubleTapped="ItemsList_DoubleTapped"
|
||||
IsDoubleTapEnabled="True"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="ItemsList_ItemClick"
|
||||
ItemTemplate="{StaticResource ListItemViewModelTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.FilteredItems, Mode=OneWay}"
|
||||
SelectionChanged="ItemsList_SelectionChanged">
|
||||
<ListView.ItemContainerTransitions>
|
||||
<TransitionCollection />
|
||||
</ListView.ItemContainerTransitions>
|
||||
<!--<ListView.GroupStyle>
|
||||
<GroupStyle HidesIfEmpty="True">
|
||||
<GroupStyle.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock
|
||||
Margin="0,16,0,0"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{Binding Key, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
</GroupStyle.HeaderTemplate>
|
||||
</GroupStyle>
|
||||
</ListView.GroupStyle>-->
|
||||
</ListView>
|
||||
</controls:Case>
|
||||
<controls:Case Value="True">
|
||||
<StackPanel
|
||||
@@ -337,5 +170,6 @@
|
||||
</StackPanel>
|
||||
</controls:Case>
|
||||
</controls:SwitchPresenter>
|
||||
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -13,7 +13,6 @@ using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
@@ -39,21 +38,13 @@ public sealed partial class ListPage : Page,
|
||||
public static readonly DependencyProperty ViewModelProperty =
|
||||
DependencyProperty.Register(nameof(ViewModel), typeof(ListViewModel), typeof(ListPage), new PropertyMetadata(null, OnViewModelChanged));
|
||||
|
||||
private ListViewBase ItemView
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewModel?.IsGridView == true ? ItemsGrid : ItemsList;
|
||||
}
|
||||
}
|
||||
|
||||
public ListPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.NavigationCacheMode = NavigationCacheMode.Disabled;
|
||||
this.ItemView.Loaded += Items_Loaded;
|
||||
this.ItemView.PreviewKeyDown += Items_PreviewKeyDown;
|
||||
this.ItemView.PointerPressed += Items_PointerPressed;
|
||||
this.ItemsList.Loaded += ItemsList_Loaded;
|
||||
this.ItemsList.PreviewKeyDown += ItemsList_PreviewKeyDown;
|
||||
this.ItemsList.PointerPressed += ItemsList_PointerPressed;
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
@@ -64,11 +55,11 @@ public sealed partial class ListPage : Page,
|
||||
}
|
||||
|
||||
if (e.NavigationMode == NavigationMode.Back
|
||||
|| (e.NavigationMode == NavigationMode.New && ItemView.Items.Count > 0))
|
||||
|| (e.NavigationMode == NavigationMode.New && ItemsList.Items.Count > 0))
|
||||
{
|
||||
// Upon navigating _back_ to this page, immediately select the
|
||||
// first item in the list
|
||||
ItemView.SelectedIndex = 0;
|
||||
ItemsList.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
// RegisterAll isn't AOT compatible
|
||||
@@ -99,6 +90,7 @@ public sealed partial class ListPage : Page,
|
||||
{
|
||||
ViewModel?.SafeCleanup();
|
||||
CleanupHelper.Cleanup(this);
|
||||
Bindings.StopTracking();
|
||||
}
|
||||
|
||||
// Clean-up event listeners
|
||||
@@ -108,7 +100,7 @@ public sealed partial class ListPage : Page,
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS is too aggressive at pruning methods bound in XAML")]
|
||||
private void Items_ItemClick(object sender, ItemClickEventArgs e)
|
||||
private void ItemsList_ItemClick(object sender, ItemClickEventArgs e)
|
||||
{
|
||||
if (e.ClickedItem is ListItemViewModel item)
|
||||
{
|
||||
@@ -131,9 +123,9 @@ public sealed partial class ListPage : Page,
|
||||
}
|
||||
}
|
||||
|
||||
private void Items_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
|
||||
private void ItemsList_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
|
||||
{
|
||||
if (ItemView.SelectedItem is ListItemViewModel vm)
|
||||
if (ItemsList.SelectedItem is ListItemViewModel vm)
|
||||
{
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
if (!settings.SingleClickActivates)
|
||||
@@ -144,10 +136,10 @@ public sealed partial class ListPage : Page,
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS is too aggressive at pruning methods bound in XAML")]
|
||||
private void Items_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
private void ItemsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var vm = ViewModel;
|
||||
var li = ItemView.SelectedItem as ListItemViewModel;
|
||||
var li = ItemsList.SelectedItem as ListItemViewModel;
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
vm?.UpdateSelectedItemCommand.Execute(li);
|
||||
@@ -162,12 +154,12 @@ public sealed partial class ListPage : Page,
|
||||
// here, then in Page_ItemsUpdated trying to select that cached item if
|
||||
// it's in the list (otherwise, clear the cache), but that seems
|
||||
// aggressively BODGY for something that mostly just works today.
|
||||
if (ItemView.SelectedItem is not null)
|
||||
if (ItemsList.SelectedItem is not null)
|
||||
{
|
||||
ItemView.ScrollIntoView(ItemView.SelectedItem);
|
||||
ItemsList.ScrollIntoView(ItemsList.SelectedItem);
|
||||
|
||||
// Automation notification for screen readers
|
||||
var listViewPeer = Microsoft.UI.Xaml.Automation.Peers.ListViewAutomationPeer.CreatePeerForElement(ItemView);
|
||||
var listViewPeer = Microsoft.UI.Xaml.Automation.Peers.ListViewAutomationPeer.CreatePeerForElement(ItemsList);
|
||||
if (listViewPeer is not null && li is not null)
|
||||
{
|
||||
var notificationText = li.Title;
|
||||
@@ -180,37 +172,10 @@ public sealed partial class ListPage : Page,
|
||||
}
|
||||
}
|
||||
|
||||
private void Items_RightTapped(object sender, RightTappedRoutedEventArgs e)
|
||||
private void ItemsList_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is FrameworkElement element &&
|
||||
element.DataContext is ListItemViewModel item)
|
||||
{
|
||||
if (ItemView.SelectedItem != item)
|
||||
{
|
||||
ItemView.SelectedItem = item;
|
||||
}
|
||||
|
||||
ViewModel?.UpdateSelectedItemCommand.Execute(item);
|
||||
|
||||
var pos = e.GetPosition(element);
|
||||
|
||||
_ = DispatcherQueue.TryEnqueue(
|
||||
() =>
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<OpenContextMenuMessage>(
|
||||
new OpenContextMenuMessage(
|
||||
element,
|
||||
Microsoft.UI.Xaml.Controls.Primitives.FlyoutPlacementMode.BottomEdgeAlignedLeft,
|
||||
pos,
|
||||
ContextMenuFilterLocation.Top));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void Items_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Find the ScrollViewer in the ItemView (ItemsList or ItemsGrid)
|
||||
var listViewScrollViewer = FindScrollViewer(this.ItemView);
|
||||
// Find the ScrollViewer in the ListView
|
||||
var listViewScrollViewer = FindScrollViewer(this.ItemsList);
|
||||
|
||||
if (listViewScrollViewer is not null)
|
||||
{
|
||||
@@ -242,25 +207,25 @@ public sealed partial class ListPage : Page,
|
||||
// And then have these commands manipulate that state being bound to the UI instead
|
||||
// We may want to see how other non-list UIs need to behave to make this decision
|
||||
// At least it's decoupled from the SearchBox now :)
|
||||
if (ItemView.SelectedIndex < ItemView.Items.Count - 1)
|
||||
if (ItemsList.SelectedIndex < ItemsList.Items.Count - 1)
|
||||
{
|
||||
ItemView.SelectedIndex++;
|
||||
ItemsList.SelectedIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemView.SelectedIndex = 0;
|
||||
ItemsList.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(NavigatePreviousCommand message)
|
||||
{
|
||||
if (ItemView.SelectedIndex > 0)
|
||||
if (ItemsList.SelectedIndex > 0)
|
||||
{
|
||||
ItemView.SelectedIndex--;
|
||||
ItemsList.SelectedIndex--;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemView.SelectedIndex = ItemView.Items.Count - 1;
|
||||
ItemsList.SelectedIndex = ItemsList.Items.Count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +235,7 @@ public sealed partial class ListPage : Page,
|
||||
{
|
||||
ViewModel?.InvokeItemCommand.Execute(null);
|
||||
}
|
||||
else if (ItemView.SelectedItem is ListItemViewModel item)
|
||||
else if (ItemsList.SelectedItem is ListItemViewModel item)
|
||||
{
|
||||
ViewModel?.InvokeItemCommand.Execute(item);
|
||||
}
|
||||
@@ -282,7 +247,7 @@ public sealed partial class ListPage : Page,
|
||||
{
|
||||
ViewModel?.InvokeSecondaryCommandCommand.Execute(null);
|
||||
}
|
||||
else if (ItemView.SelectedItem is ListItemViewModel item)
|
||||
else if (ItemsList.SelectedItem is ListItemViewModel item)
|
||||
{
|
||||
ViewModel?.InvokeSecondaryCommandCommand.Execute(item);
|
||||
}
|
||||
@@ -318,19 +283,19 @@ public sealed partial class ListPage : Page,
|
||||
//
|
||||
// It's important to do this here, because once there's no selection
|
||||
// (which can happen as the list updates) we won't get an
|
||||
// ItemView_SelectionChanged again to give us another chance to change
|
||||
// ItemsList_SelectionChanged again to give us another chance to change
|
||||
// the selection from null -> something. Better to just update the
|
||||
// selection once, at the end of all the updating.
|
||||
if (ItemView.SelectedItem is null)
|
||||
if (ItemsList.SelectedItem is null)
|
||||
{
|
||||
ItemView.SelectedIndex = 0;
|
||||
ItemsList.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
// Always reset the selected item when the top-level list page changes
|
||||
// its items
|
||||
if (!sender.IsNested)
|
||||
{
|
||||
ItemView.SelectedIndex = 0;
|
||||
ItemsList.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +304,7 @@ public sealed partial class ListPage : Page,
|
||||
var prop = e.PropertyName;
|
||||
if (prop == nameof(ViewModel.FilteredItems))
|
||||
{
|
||||
Debug.WriteLine($"ViewModel.FilteredItems {ItemView.SelectedItem}");
|
||||
Debug.WriteLine($"ViewModel.FilteredItems {ItemsList.SelectedItem}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,12 +328,12 @@ public sealed partial class ListPage : Page,
|
||||
return null;
|
||||
}
|
||||
|
||||
private void Items_OnContextRequested(UIElement sender, ContextRequestedEventArgs e)
|
||||
private void ItemsList_OnContextRequested(UIElement sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
var (item, element) = e.OriginalSource switch
|
||||
{
|
||||
// caused by keyboard shortcut (e.g. Context menu key or Shift+F10)
|
||||
SelectorItem selectorItem => (ItemView.ItemFromContainer(selectorItem) as ListItemViewModel, selectorItem),
|
||||
ListViewItem listViewItem => (ItemsList.ItemFromContainer(listViewItem) as ListItemViewModel, listViewItem),
|
||||
|
||||
// caused by right-click on the ListViewItem
|
||||
FrameworkElement { DataContext: ListItemViewModel itemViewModel } frameworkElement => (itemViewModel, frameworkElement),
|
||||
@@ -381,9 +346,9 @@ public sealed partial class ListPage : Page,
|
||||
return;
|
||||
}
|
||||
|
||||
if (ItemView.SelectedItem != item)
|
||||
if (ItemsList.SelectedItem != item)
|
||||
{
|
||||
ItemView.SelectedItem = item;
|
||||
ItemsList.SelectedItem = item;
|
||||
}
|
||||
|
||||
ViewModel?.UpdateSelectedItemCommand.Execute(item);
|
||||
@@ -406,14 +371,14 @@ public sealed partial class ListPage : Page,
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void Items_OnContextCanceled(UIElement sender, RoutedEventArgs e)
|
||||
private void ItemsList_OnContextCanceled(UIElement sender, RoutedEventArgs e)
|
||||
{
|
||||
_ = DispatcherQueue.TryEnqueue(() => WeakReferenceMessenger.Default.Send<CloseContextMenuMessage>());
|
||||
}
|
||||
|
||||
private void Items_PointerPressed(object sender, PointerRoutedEventArgs e) => _lastInputSource = InputSource.Pointer;
|
||||
private void ItemsList_PointerPressed(object sender, PointerRoutedEventArgs e) => _lastInputSource = InputSource.Pointer;
|
||||
|
||||
private void Items_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
|
||||
private void ItemsList_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
|
||||
{
|
||||
if (e.Key is VirtualKey.Enter or VirtualKey.Space)
|
||||
{
|
||||
|
||||
@@ -521,21 +521,6 @@ public sealed partial class MainWindow : WindowEx,
|
||||
WeakReferenceMessenger.Default.Send<OpenSettingsMessage>(new());
|
||||
return;
|
||||
}
|
||||
else if (uri.StartsWith("x-cmdpal://reload", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var settings = App.Current.Services.GetService<SettingsModel>();
|
||||
if (settings?.AllowExternalReload == true)
|
||||
{
|
||||
Logger.LogInfo("External Reload triggered");
|
||||
WeakReferenceMessenger.Default.Send<ReloadCommandsMessage>(new());
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogInfo("External Reload is disabled");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
|
||||
<PropertyGroup Condition="'$(CIBuild)'=='true'">
|
||||
<GenerateAppxPackageOnBuild>true</GenerateAppxPackageOnBuild>
|
||||
<AppxBundle>Never</AppxBundle>
|
||||
<AppxPackageTestDir>$(OutputPath)\AppPackages\Microsoft.CmdPal.UI_$(Version)_Test\</AppxPackageTestDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -327,6 +327,11 @@
|
||||
x:Name="FiltersDropDown"
|
||||
HorizontalAlignment="Right"
|
||||
CurrentPageViewModel="{x:Bind ViewModel.CurrentPage, Mode=OneWay}" />
|
||||
<Grid.Transitions>
|
||||
<TransitionCollection>
|
||||
<RepositionThemeTransition />
|
||||
</TransitionCollection>
|
||||
</Grid.Transitions>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
<RepositionThemeTransition IsStaggeringEnabled="False" />
|
||||
</StackPanel.ChildrenTransitions>-->
|
||||
|
||||
<!-- 'Activation' section -->
|
||||
|
||||
<TextBlock x:Uid="ActivationSettingsHeader" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsExpander
|
||||
@@ -68,8 +66,6 @@
|
||||
</ComboBox>
|
||||
</controls:SettingsCard>
|
||||
|
||||
<!-- 'Behavior' section -->
|
||||
|
||||
<TextBlock x:Uid="BehaviorSettingsHeader" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="Settings_GeneralPage_ShowAppDetails_SettingsCard" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
@@ -88,16 +84,7 @@
|
||||
<ToggleSwitch IsOn="{x:Bind viewModel.ShowSystemTrayIcon, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<!-- 'For Developers' section -->
|
||||
|
||||
<TextBlock x:Uid="ForDevelopersSettingsHeader" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsCard x:Uid="Settings_GeneralPage_AllowExternalReload_SettingsCard" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind viewModel.AllowExternalReload, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<!-- 'About' section -->
|
||||
|
||||
<!-- Example 'About' section -->
|
||||
<TextBlock x:Uid="AboutSettingsHeader" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
<controls:SettingsExpander x:Uid="Settings_GeneralPage_About_SettingsExpander" HeaderIcon="{ui:BitmapIcon Source=ms-appx:///Assets/StoreLogo.png}">
|
||||
|
||||
@@ -441,13 +441,4 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<data name="NavigationPaneOpened" xml:space="preserve">
|
||||
<value>Navigation page opened</value>
|
||||
</data>
|
||||
<data name="Settings_GeneralPage_AllowExternalReload_SettingsCard.Header" xml:space="preserve">
|
||||
<value>Enable external reload</value>
|
||||
</data>
|
||||
<data name="Settings_GeneralPage_AllowExternalReload_SettingsCard.Description" xml:space="preserve">
|
||||
<value>Trigger reload of the extension externally with the x-cmdpal://reload command</value>
|
||||
</data>
|
||||
<data name="ForDevelopersSettingsHeader.Text" xml:space="preserve">
|
||||
<value>For Developers</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -3,15 +3,9 @@
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup>
|
||||
<PathToRoot>..\..\..\..\</PathToRoot>
|
||||
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.8.250907003</WasdkNuget>
|
||||
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.7.250513003</WasdkNuget>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<CppWinRTOptimized>true</CppWinRTOptimized>
|
||||
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
|
||||
@@ -206,12 +200,6 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(MSBuildThisFileDirectory)..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
@@ -222,18 +210,6 @@
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props'))" />
|
||||
<Error Condition="!Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Base.1.8.250831001\build\native\Microsoft.WindowsAppSDK.Base.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Foundation.1.8.250906002\build\native\Microsoft.WindowsAppSDK.Foundation.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.WinUI.1.8.250906003\build\native\Microsoft.WindowsAppSDK.WinUI.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.Runtime.1.8.250907003\build\native\Microsoft.WindowsAppSDK.Runtime.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.DWrite.1.8.25090401\build\Microsoft.WindowsAppSDK.DWrite.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.InteractiveExperiences.1.8.250906004\build\native\Microsoft.WindowsAppSDK.InteractiveExperiences.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', 'Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
|
||||
@@ -4,14 +4,4 @@
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.2903.40" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK" version="1.8.250907003" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Base" version="1.8.250831001" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Foundation" version="1.8.250906002" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.WinUI" version="1.8.250906003" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Runtime" version="1.8.250907003" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.DWrite" version="1.8.25090401" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.InteractiveExperiences" version="1.8.250906004" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Widgets" version="1.8.250904007" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.AI" version="1.8.37" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.SDK.BuildTools.MSIX" version="1.7.20250829.1" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.08535 3C7.29127 2.4174 7.84689 2 8.5 2H11.5C12.1531 2 12.7087 2.4174 12.9146 3H14.5C15.3284 3 16 3.67157 16 4.5V16.5C16 17.3284 15.3284 18 14.5 18H5.5C4.67157 18 4 17.3284 4 16.5V4.5C4 3.67157 4.67157 3 5.5 3H7.08535ZM8.5 3C8.22386 3 8 3.22386 8 3.5C8 3.77614 8.22386 4 8.5 4H11.5C11.7761 4 12 3.77614 12 3.5C12 3.22386 11.7761 3 11.5 3H8.5ZM7.08535 4H5.5C5.22386 4 5 4.22386 5 4.5V16.5C5 16.7761 5.22386 17 5.5 17H14.5C14.7761 17 15 16.7761 15 16.5V4.5C15 4.22386 14.7761 4 14.5 4H12.9146C12.7087 4.5826 12.1531 5 11.5 5H8.5C7.84689 5 7.29127 4.5826 7.08535 4Z" fill="#D0D0D0"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 695 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.08535 3C7.29127 2.4174 7.84689 2 8.5 2H11.5C12.1531 2 12.7087 2.4174 12.9146 3H14.5C15.3284 3 16 3.67157 16 4.5V16.5C16 17.3284 15.3284 18 14.5 18H5.5C4.67157 18 4 17.3284 4 16.5V4.5C4 3.67157 4.67157 3 5.5 3H7.08535ZM8.5 3C8.22386 3 8 3.22386 8 3.5C8 3.77614 8.22386 4 8.5 4H11.5C11.7761 4 12 3.77614 12 3.5C12 3.22386 11.7761 3 11.5 3H8.5ZM7.08535 4H5.5C5.22386 4 5 4.22386 5 4.5V16.5C5 16.7761 5.22386 17 5.5 17H14.5C14.7761 17 15 16.7761 15 16.5V4.5C15 4.22386 14.7761 4 14.5 4H12.9146C12.7087 4.5826 12.1531 5 11.5 5H8.5C7.84689 5 7.29127 4.5826 7.08535 4Z" fill="#212121"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 695 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.08535 3C7.29127 2.4174 7.84689 2 8.5 2H11.5C12.1531 2 12.7087 2.4174 12.9146 3H14.5C15.3284 3 16 3.67157 16 4.5V9H15V4.5C15 4.22386 14.7761 4 14.5 4H12.9146C12.7087 4.5826 12.1531 5 11.5 5H8.5C7.84689 5 7.29127 4.5826 7.08535 4H5.5C5.22386 4 5 4.22386 5 4.5V16.5C5 16.7761 5.22386 17 5.5 17H9.03544C9.08595 17.3531 9.18915 17.6891 9.33682 18H5.5C4.67157 18 4 17.3284 4 16.5V4.5C4 3.67157 4.67157 3 5.5 3H7.08535ZM8.5 3C8.22386 3 8 3.22386 8 3.5C8 3.77614 8.22386 4 8.5 4H11.5C11.7761 4 12 3.77614 12 3.5C12 3.22386 11.7761 3 11.5 3H8.5ZM10 12.5C10 11.1193 11.1193 10 12.5 10H16.5C17.8807 10 19 11.1193 19 12.5V16.5C19 17.0095 18.8476 17.4835 18.5858 17.8787L15.5607 14.8536C14.9749 14.2678 14.0251 14.2678 13.4393 14.8536L10.4142 17.8787C10.1524 17.4835 10 17.0095 10 16.5V12.5ZM17 12.75C17 12.3358 16.6642 12 16.25 12C15.8358 12 15.5 12.3358 15.5 12.75C15.5 13.1642 15.8358 13.5 16.25 13.5C16.6642 13.5 17 13.1642 17 12.75ZM11.1213 18.5858C11.5165 18.8476 11.9905 19 12.5 19H16.5C17.0095 19 17.4835 18.8476 17.8787 18.5858L14.8536 15.5607C14.6583 15.3654 14.3417 15.3654 14.1464 15.5607L11.1213 18.5858Z" fill="#D0D0D0"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.08535 3C7.29127 2.4174 7.84689 2 8.5 2H11.5C12.1531 2 12.7087 2.4174 12.9146 3H14.5C15.3284 3 16 3.67157 16 4.5V9H15V4.5C15 4.22386 14.7761 4 14.5 4H12.9146C12.7087 4.5826 12.1531 5 11.5 5H8.5C7.84689 5 7.29127 4.5826 7.08535 4H5.5C5.22386 4 5 4.22386 5 4.5V16.5C5 16.7761 5.22386 17 5.5 17H9.03544C9.08595 17.3531 9.18915 17.6891 9.33682 18H5.5C4.67157 18 4 17.3284 4 16.5V4.5C4 3.67157 4.67157 3 5.5 3H7.08535ZM8.5 3C8.22386 3 8 3.22386 8 3.5C8 3.77614 8.22386 4 8.5 4H11.5C11.7761 4 12 3.77614 12 3.5C12 3.22386 11.7761 3 11.5 3H8.5ZM10 12.5C10 11.1193 11.1193 10 12.5 10H16.5C17.8807 10 19 11.1193 19 12.5V16.5C19 17.0095 18.8476 17.4835 18.5858 17.8787L15.5607 14.8536C14.9749 14.2678 14.0251 14.2678 13.4393 14.8536L10.4142 17.8787C10.1524 17.4835 10 17.0095 10 16.5V12.5ZM17 12.75C17 12.3358 16.6642 12 16.25 12C15.8358 12 15.5 12.3358 15.5 12.75C15.5 13.1642 15.8358 13.5 16.25 13.5C16.6642 13.5 17 13.1642 17 12.75ZM11.1213 18.5858C11.5165 18.8476 11.9905 19 12.5 19H16.5C17.0095 19 17.4835 18.8476 17.8787 18.5858L14.8536 15.5607C14.6583 15.3654 14.3417 15.3654 14.1464 15.5607L11.1213 18.5858Z" fill="#212121"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.08535 3C7.29127 2.4174 7.84689 2 8.5 2H11.5C12.1531 2 12.7087 2.4174 12.9146 3H14.5C15.3284 3 16 3.67157 16 4.5V10.337L15.3698 8.89819C15.2826 8.69904 15.1554 8.52562 15 8.38568V4.5C15 4.22386 14.7761 4 14.5 4H12.9146C12.7087 4.5826 12.1531 5 11.5 5H8.5C7.84689 5 7.29127 4.5826 7.08535 4H5.5C5.22386 4 5 4.22386 5 4.5V16.5C5 16.7761 5.22386 17 5.5 17H9.08561C8.9672 17.3338 8.97447 17.6857 9.08567 18H5.5C4.67157 18 4 17.3284 4 16.5V4.5C4 3.67157 4.67157 3 5.5 3H7.08535ZM8.5 3C8.22386 3 8 3.22386 8 3.5C8 3.77614 8.22386 4 8.5 4H11.5C11.7761 4 12 3.77614 12 3.5C12 3.22386 11.7761 3 11.5 3H8.5ZM14.4538 9.2994C14.3741 9.11744 14.1942 8.99992 13.9956 9C13.797 9.00008 13.6172 9.11776 13.5376 9.29979L10.0417 17.2998C9.93114 17.5528 10.0466 17.8476 10.2997 17.9582C10.5527 18.0687 10.8475 17.9533 10.958 17.7002L12.138 15H15.859L17.0419 17.7006C17.1527 17.9535 17.4475 18.0688 17.7005 17.958C17.9534 17.8472 18.0687 17.5523 17.9579 17.2994L14.4538 9.2994ZM15.421 14H12.575L13.9963 10.7474L15.421 14Z" fill="#D0D0D0"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.08535 3C7.29127 2.4174 7.84689 2 8.5 2H11.5C12.1531 2 12.7087 2.4174 12.9146 3H14.5C15.3284 3 16 3.67157 16 4.5V10.337L15.3698 8.89819C15.2826 8.69904 15.1554 8.52562 15 8.38568V4.5C15 4.22386 14.7761 4 14.5 4H12.9146C12.7087 4.5826 12.1531 5 11.5 5H8.5C7.84689 5 7.29127 4.5826 7.08535 4H5.5C5.22386 4 5 4.22386 5 4.5V16.5C5 16.7761 5.22386 17 5.5 17H9.08561C8.9672 17.3338 8.97447 17.6857 9.08567 18H5.5C4.67157 18 4 17.3284 4 16.5V4.5C4 3.67157 4.67157 3 5.5 3H7.08535ZM8.5 3C8.22386 3 8 3.22386 8 3.5C8 3.77614 8.22386 4 8.5 4H11.5C11.7761 4 12 3.77614 12 3.5C12 3.22386 11.7761 3 11.5 3H8.5ZM14.4538 9.2994C14.3741 9.11744 14.1942 8.99992 13.9956 9C13.797 9.00008 13.6172 9.11776 13.5376 9.29979L10.0417 17.2998C9.93114 17.5528 10.0466 17.8476 10.2997 17.9582C10.5527 18.0687 10.8475 17.9533 10.958 17.7002L12.138 15H15.859L17.0419 17.7006C17.1527 17.9535 17.4475 18.0688 17.7005 17.958C17.9534 17.8472 18.0687 17.5523 17.9579 17.2994L14.4538 9.2994ZM15.421 14H12.575L13.9963 10.7474L15.421 14Z" fill="#212121"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 2C6.89543 2 6 2.89543 6 4V14C6 15.1046 6.89543 16 8 16H14C15.1046 16 16 15.1046 16 14V4C16 2.89543 15.1046 2 14 2H8ZM7 4C7 3.44772 7.44772 3 8 3H14C14.5523 3 15 3.44772 15 4V14C15 14.5523 14.5523 15 14 15H8C7.44772 15 7 14.5523 7 14V4ZM4 6.00001C4 5.25973 4.4022 4.61339 5 4.26758V14.5C5 15.8807 6.11929 17 7.5 17H13.7324C13.3866 17.5978 12.7403 18 12 18H7.5C5.567 18 4 16.433 4 14.5V6.00001Z" fill="#D0D0D0"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 526 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 2C6.89543 2 6 2.89543 6 4V14C6 15.1046 6.89543 16 8 16H14C15.1046 16 16 15.1046 16 14V4C16 2.89543 15.1046 2 14 2H8ZM7 4C7 3.44772 7.44772 3 8 3H14C14.5523 3 15 3.44772 15 4V14C15 14.5523 14.5523 15 14 15H8C7.44772 15 7 14.5523 7 14V4ZM4 6.00001C4 5.25973 4.4022 4.61339 5 4.26758V14.5C5 15.8807 6.11929 17 7.5 17H13.7324C13.3866 17.5978 12.7403 18 12 18H7.5C5.567 18 4 16.433 4 14.5V6.00001Z" fill="#212121"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 526 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 4C6 2.89543 6.89543 2 8 2H11.5858C11.9836 2 12.3651 2.15804 12.6464 2.43934L16.5607 6.35355C16.842 6.63486 17 7.01639 17 7.41421V14C17 15.1046 16.1046 16 15 16H8C6.89543 16 6 15.1046 6 14V4ZM8 3C7.44772 3 7 3.44772 7 4V14C7 14.5523 7.44772 15 8 15H15C15.5523 15 16 14.5523 16 14V8H12.5C11.6716 8 11 7.32843 11 6.5V3H8ZM12 3.20711V6.5C12 6.77614 12.2239 7 12.5 7H15.7929L12 3.20711ZM4 5C4 4.44772 4.44772 4 5 4V14C5 15.6569 6.34315 17 8 17L15 17C15 17.5523 14.5523 18 14 18H7.93939C5.76373 18 4 16.2363 4 14.0606V5Z" fill="#D0D0D0"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 648 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 4C6 2.89543 6.89543 2 8 2H11.5858C11.9836 2 12.3651 2.15804 12.6464 2.43934L16.5607 6.35355C16.842 6.63486 17 7.01639 17 7.41421V14C17 15.1046 16.1046 16 15 16H8C6.89543 16 6 15.1046 6 14V4ZM8 3C7.44772 3 7 3.44772 7 4V14C7 14.5523 7.44772 15 8 15H15C15.5523 15 16 14.5523 16 14V8H12.5C11.6716 8 11 7.32843 11 6.5V3H8ZM12 3.20711V6.5C12 6.77614 12.2239 7 12.5 7H15.7929L12 3.20711ZM4 5C4 4.44772 4.44772 4 5 4V14C5 15.6569 6.34315 17 8 17L15 17C15 17.5523 14.5523 18 14 18H7.93939C5.76373 18 4 16.2363 4 14.0606V5Z" fill="#212121"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 648 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.49751 7.4966C9.04842 7.4966 9.49502 7.05 9.49502 6.4991C9.49502 5.94819 9.04842 5.50159 8.49751 5.50159C7.9466 5.50159 7.5 5.94819 7.5 6.4991C7.5 7.05 7.9466 7.4966 8.49751 7.4966ZM5 6C5 4.34315 6.34315 3 8 3H14C15.6569 3 17 4.34315 17 6V12C17 13.6569 15.6569 15 14 15H8C6.34315 15 5 13.6569 5 12V6ZM8 4C6.89543 4 6 4.89543 6 6V12C6 12.3709 6.10097 12.7182 6.27692 13.016L9.79085 9.50207C10.4586 8.83427 11.5414 8.83427 12.2092 9.50207L15.7231 13.016C15.899 12.7182 16 12.3709 16 12V6C16 4.89543 15.1046 4 14 4H8ZM15.016 13.7231L11.502 10.2092C11.2248 9.9319 10.7752 9.9319 10.498 10.2092L6.98403 13.7231C7.28178 13.899 7.6291 14 8 14H14C14.3709 14 14.7182 13.899 15.016 13.7231ZM12 17C12.8885 17 13.6868 16.6138 14.2361 16H7.5C5.68782 16 4.1973 14.6228 4.01807 12.8579C4.00612 12.7402 4 12.6208 4 12.5V5.76392C3.38625 6.31324 3 7.11152 3 8.00002V12.5C3 14.9853 5.01472 17 7.5 17H12Z" fill="#D0D0D0"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1017 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.49751 7.4966C9.04842 7.4966 9.49502 7.05 9.49502 6.4991C9.49502 5.94819 9.04842 5.50159 8.49751 5.50159C7.9466 5.50159 7.5 5.94819 7.5 6.4991C7.5 7.05 7.9466 7.4966 8.49751 7.4966ZM5 6C5 4.34315 6.34315 3 8 3H14C15.6569 3 17 4.34315 17 6V12C17 13.6569 15.6569 15 14 15H8C6.34315 15 5 13.6569 5 12V6ZM8 4C6.89543 4 6 4.89543 6 6V12C6 12.3709 6.10097 12.7182 6.27692 13.016L9.79085 9.50207C10.4586 8.83427 11.5414 8.83427 12.2092 9.50207L15.7231 13.016C15.899 12.7182 16 12.3709 16 12V6C16 4.89543 15.1046 4 14 4H8ZM15.016 13.7231L11.502 10.2092C11.2248 9.9319 10.7752 9.9319 10.498 10.2092L6.98403 13.7231C7.28178 13.899 7.6291 14 8 14H14C14.3709 14 14.7182 13.899 15.016 13.7231ZM12 17C12.8885 17 13.6868 16.6138 14.2361 16H7.5C5.68782 16 4.1973 14.6228 4.01807 12.8579C4.00612 12.7402 4 12.6208 4 12.5V5.76392C3.38625 6.31324 3 7.11152 3 8.00002V12.5C3 14.9853 5.01472 17 7.5 17H12Z" fill="#212121"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1017 B |
@@ -1,12 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.ClipboardHistory.Helpers;
|
||||
|
||||
internal enum PrimaryAction
|
||||
{
|
||||
Default,
|
||||
Paste,
|
||||
Copy,
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.CmdPal.Ext.ClipboardHistory.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
@@ -27,22 +26,10 @@ internal sealed class SettingsManager : JsonSettingsManager, ISettingOptions
|
||||
Resources.settings_confirm_delete_description!,
|
||||
true);
|
||||
|
||||
private readonly ChoiceSetSetting _primaryAction = new(
|
||||
Namespaced(nameof(PrimaryAction)),
|
||||
Resources.settings_primary_action_title!,
|
||||
Resources.settings_primary_action_description!,
|
||||
[
|
||||
new ChoiceSetSetting.Choice(Resources.settings_primary_action_default!, PrimaryAction.Default.ToString("G")),
|
||||
new ChoiceSetSetting.Choice(Resources.settings_primary_action_paste!, PrimaryAction.Paste.ToString("G")),
|
||||
new ChoiceSetSetting.Choice(Resources.settings_primary_action_copy!, PrimaryAction.Copy.ToString("G"))
|
||||
]);
|
||||
|
||||
public bool KeepAfterPaste => _keepAfterPaste.Value;
|
||||
|
||||
public bool DeleteFromHistoryRequiresConfirmation => _confirmDelete.Value;
|
||||
|
||||
public PrimaryAction PrimaryAction => Enum.TryParse<PrimaryAction>(_primaryAction.Value, out var action) ? action : PrimaryAction.Default;
|
||||
|
||||
private static string SettingsJsonPath()
|
||||
{
|
||||
var directory = Utilities.BaseSettingsPath("Microsoft.CmdPal");
|
||||
@@ -58,7 +45,6 @@ internal sealed class SettingsManager : JsonSettingsManager, ISettingOptions
|
||||
|
||||
Settings.Add(_keepAfterPaste);
|
||||
Settings.Add(_confirmDelete);
|
||||
Settings.Add(_primaryAction);
|
||||
|
||||
// Load settings from file upon initialization
|
||||
LoadSettings();
|
||||
|
||||
@@ -6,7 +6,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.ClipboardHistory;
|
||||
|
||||
internal static class Icons
|
||||
internal sealed class Icons
|
||||
{
|
||||
internal static IconInfo CopyIcon { get; } = new("\xE8C8");
|
||||
|
||||
@@ -17,21 +17,4 @@ internal static class Icons
|
||||
internal static IconInfo DeleteIcon { get; } = new("\uE74D");
|
||||
|
||||
internal static IconInfo ClipboardListIcon { get; } = IconHelpers.FromRelativePath("Assets\\ClipboardHistory.svg");
|
||||
|
||||
internal static IconInfo Clipboard { get; } = Create("ic_fluent_clipboard_20_regular");
|
||||
|
||||
internal static IconInfo ClipboardImage { get; } = Create("ic_fluent_clipboard_image_20_regular");
|
||||
|
||||
internal static IconInfo ClipboardLetter { get; } = Create("ic_fluent_clipboard_letter_20_regular");
|
||||
|
||||
internal static IconInfo Copy { get; } = Create(" ic_fluent_copy_20_regular");
|
||||
|
||||
internal static IconInfo DocumentCopy { get; } = Create("ic_fluent_document_copy_20_regular");
|
||||
|
||||
internal static IconInfo ImageCopy { get; } = Create("ic_fluent_image_copy_20_regular");
|
||||
|
||||
private static IconInfo Create(string name)
|
||||
{
|
||||
return IconHelpers.FromRelativePaths($"Assets\\Icons\\{name}.light.svg", $"Assets\\Icons\\{name}.dark.svg");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,41 +39,5 @@
|
||||
<Content Update="Assets\ClipboardHistory.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_clipboard_20_regular.dark.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_clipboard_20_regular.light.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_clipboard_image_20_regular.dark.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_clipboard_image_20_regular.light.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_clipboard_letter_20_regular.dark.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_clipboard_letter_20_regular.light.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_copy_20_regular.dark.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_copy_20_regular.light.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_document_copy_20_regular.dark.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_document_copy_20_regular.light.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_image_copy_20_regular.dark.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Icons\ic_fluent_image_copy_20_regular.light.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -3,8 +3,14 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.CmdPal.Common.Commands;
|
||||
using Microsoft.CmdPal.Ext.ClipboardHistory.Commands;
|
||||
using Microsoft.CmdPal.Ext.ClipboardHistory.Helpers;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
@@ -35,8 +41,126 @@ public class ClipboardItem
|
||||
}
|
||||
|
||||
[MemberNotNullWhen(true, nameof(ImageData))]
|
||||
internal bool IsImage => ImageData is not null;
|
||||
private bool IsImage => ImageData is not null;
|
||||
|
||||
[MemberNotNullWhen(true, nameof(Content))]
|
||||
internal bool IsText => !string.IsNullOrEmpty(Content);
|
||||
private bool IsText => !string.IsNullOrEmpty(Content);
|
||||
|
||||
public static List<string> ShiftLinesLeft(List<string> lines)
|
||||
{
|
||||
// Determine the minimum leading whitespace
|
||||
var minLeadingWhitespace = lines
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line))
|
||||
.Min(line => line.TakeWhile(char.IsWhiteSpace).Count());
|
||||
|
||||
// Check if all lines have at least that much leading whitespace
|
||||
if (lines.Any(line => line.TakeWhile(char.IsWhiteSpace).Count() < minLeadingWhitespace))
|
||||
{
|
||||
return lines; // Return the original lines if any line doesn't have enough leading whitespace
|
||||
}
|
||||
|
||||
// Remove the minimum leading whitespace from each line
|
||||
var shiftedLines = lines.Select(line => line.Substring(minLeadingWhitespace)).ToList();
|
||||
|
||||
return shiftedLines;
|
||||
}
|
||||
|
||||
public static List<string> StripLeadingWhitespace(List<string> lines)
|
||||
{
|
||||
// Determine the minimum leading whitespace
|
||||
var minLeadingWhitespace = lines
|
||||
.Min(line => line.TakeWhile(char.IsWhiteSpace).Count());
|
||||
|
||||
// Remove the minimum leading whitespace from each line
|
||||
var shiftedLines = lines.Select(line =>
|
||||
line.Length >= minLeadingWhitespace
|
||||
? line.Substring(minLeadingWhitespace)
|
||||
: line).ToList();
|
||||
|
||||
return shiftedLines;
|
||||
}
|
||||
|
||||
public ListItem ToListItem()
|
||||
{
|
||||
ListItem listItem;
|
||||
|
||||
List<DetailsElement> metadata = [];
|
||||
metadata.Add(new DetailsElement()
|
||||
{
|
||||
Key = "Copied on",
|
||||
Data = new DetailsLink(Item.Timestamp.DateTime.ToString(DateTimeFormatInfo.CurrentInfo)),
|
||||
});
|
||||
|
||||
var deleteConfirmationCommand = new ConfirmableCommand()
|
||||
{
|
||||
Command = new DeleteItemCommand(this),
|
||||
ConfirmationTitle = Properties.Resources.delete_confirmation_title!,
|
||||
ConfirmationMessage = Properties.Resources.delete_confirmation_message!,
|
||||
IsConfirmationRequired = () => Settings.DeleteFromHistoryRequiresConfirmation,
|
||||
};
|
||||
var deleteContextMenuItem = new CommandContextItem(deleteConfirmationCommand)
|
||||
{
|
||||
IsCritical = true,
|
||||
RequestedShortcut = KeyChords.DeleteEntry,
|
||||
};
|
||||
|
||||
if (IsImage)
|
||||
{
|
||||
var iconData = new IconData(ImageData);
|
||||
var heroImage = new IconInfo(iconData, iconData);
|
||||
listItem = new(new CopyCommand(this, ClipboardFormat.Image))
|
||||
{
|
||||
// Placeholder subtitle as there’s no BitmapImage dimensions to retrieve
|
||||
Title = "Image Data",
|
||||
Details = new Details()
|
||||
{
|
||||
HeroImage = heroImage,
|
||||
Title = GetDataType(),
|
||||
Body = Timestamp.ToString(CultureInfo.InvariantCulture),
|
||||
Metadata = metadata.ToArray(),
|
||||
},
|
||||
MoreCommands = [
|
||||
new CommandContextItem(new PasteCommand(this, ClipboardFormat.Image, Settings)),
|
||||
new Separator(),
|
||||
deleteContextMenuItem,
|
||||
],
|
||||
};
|
||||
}
|
||||
else if (IsText)
|
||||
{
|
||||
var splitContent = Content.Split("\n");
|
||||
var head = splitContent.AsSpan(0, Math.Min(3, splitContent.Length)).ToArray().ToList();
|
||||
var preview2 = string.Join(
|
||||
"\n",
|
||||
StripLeadingWhitespace(head));
|
||||
|
||||
listItem = new(new CopyCommand(this, ClipboardFormat.Text))
|
||||
{
|
||||
Title = preview2,
|
||||
|
||||
Details = new Details
|
||||
{
|
||||
Title = GetDataType(),
|
||||
Body = $"```text\n{Content}\n```",
|
||||
Metadata = metadata.ToArray(),
|
||||
},
|
||||
MoreCommands = [
|
||||
new CommandContextItem(new PasteCommand(this, ClipboardFormat.Text, Settings)),
|
||||
new Separator(),
|
||||
deleteContextMenuItem,
|
||||
],
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
listItem = new(new NoOpCommand())
|
||||
{
|
||||
Title = "Unknown",
|
||||
Subtitle = GetDataType(),
|
||||
Details = new Details { Title = GetDataType() },
|
||||
};
|
||||
}
|
||||
|
||||
return listItem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ internal sealed partial class ClipboardHistoryListPage : ListPage
|
||||
var item = clipboardHistory[i];
|
||||
if (item is not null)
|
||||
{
|
||||
listItems.Add(new ClipboardListItem(item, _settingsManager));
|
||||
listItems.Add(item.ToListItem());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.CmdPal.Common.Commands;
|
||||
using Microsoft.CmdPal.Ext.ClipboardHistory.Commands;
|
||||
using Microsoft.CmdPal.Ext.ClipboardHistory.Helpers;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.ClipboardHistory.Models;
|
||||
|
||||
internal sealed partial class ClipboardListItem : ListItem
|
||||
{
|
||||
private readonly SettingsManager _settingsManager;
|
||||
private readonly ClipboardItem _item;
|
||||
|
||||
private readonly CommandContextItem _deleteContextMenuItem;
|
||||
private readonly CommandContextItem? _pasteCommand;
|
||||
private readonly CommandContextItem? _copyCommand;
|
||||
private readonly Lazy<Details> _lazyDetails;
|
||||
|
||||
public override IDetails? Details
|
||||
{
|
||||
get => _lazyDetails.Value;
|
||||
set
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public ClipboardListItem(ClipboardItem item, SettingsManager settingsManager)
|
||||
{
|
||||
_item = item;
|
||||
_settingsManager = settingsManager;
|
||||
_settingsManager.Settings.SettingsChanged += SettingsOnSettingsChanged;
|
||||
|
||||
_lazyDetails = new(() => CreateDetails());
|
||||
|
||||
var deleteConfirmationCommand = new ConfirmableCommand
|
||||
{
|
||||
Command = new DeleteItemCommand(_item),
|
||||
ConfirmationTitle = Properties.Resources.delete_confirmation_title!,
|
||||
ConfirmationMessage = Properties.Resources.delete_confirmation_message!,
|
||||
IsConfirmationRequired = () => _settingsManager.DeleteFromHistoryRequiresConfirmation,
|
||||
};
|
||||
_deleteContextMenuItem = new CommandContextItem(deleteConfirmationCommand)
|
||||
{
|
||||
IsCritical = true,
|
||||
RequestedShortcut = KeyChords.DeleteEntry,
|
||||
};
|
||||
|
||||
if (item.IsImage)
|
||||
{
|
||||
Title = "Image";
|
||||
|
||||
_pasteCommand = new CommandContextItem(new PasteCommand(_item, ClipboardFormat.Image, _settingsManager));
|
||||
_copyCommand = new CommandContextItem(new CopyCommand(_item, ClipboardFormat.Image));
|
||||
}
|
||||
else if (item.IsText)
|
||||
{
|
||||
var splitContent = _item.Content?.Split("\n") ?? [];
|
||||
var head = splitContent.Take(3);
|
||||
var preview2 = string.Join(
|
||||
"\n",
|
||||
StripLeadingWhitespace(head));
|
||||
|
||||
Title = preview2;
|
||||
|
||||
_pasteCommand = new CommandContextItem(new PasteCommand(_item, ClipboardFormat.Text, _settingsManager));
|
||||
_copyCommand = new CommandContextItem(new CopyCommand(_item, ClipboardFormat.Text));
|
||||
}
|
||||
else
|
||||
{
|
||||
_pasteCommand = null;
|
||||
_copyCommand = null;
|
||||
}
|
||||
|
||||
RefreshCommands();
|
||||
}
|
||||
|
||||
private void SettingsOnSettingsChanged(object sender, Settings args)
|
||||
{
|
||||
RefreshCommands();
|
||||
}
|
||||
|
||||
private void RefreshCommands()
|
||||
{
|
||||
if (_item is { IsText: false, IsImage: false })
|
||||
{
|
||||
MoreCommands = [_deleteContextMenuItem];
|
||||
Icon = _settingsManager.PrimaryAction == PrimaryAction.Paste ? Icons.Clipboard : Icons.Copy;
|
||||
}
|
||||
|
||||
switch (_settingsManager.PrimaryAction)
|
||||
{
|
||||
case PrimaryAction.Paste:
|
||||
Command = _pasteCommand?.Command;
|
||||
MoreCommands =
|
||||
[
|
||||
_copyCommand!,
|
||||
new Separator(),
|
||||
_deleteContextMenuItem,
|
||||
];
|
||||
|
||||
if (_item.IsText)
|
||||
{
|
||||
Icon = Icons.ClipboardLetter;
|
||||
}
|
||||
else if (_item.IsImage)
|
||||
{
|
||||
Icon = Icons.ClipboardImage;
|
||||
}
|
||||
else
|
||||
{
|
||||
Icon = Icons.ClipboardImage;
|
||||
}
|
||||
|
||||
break;
|
||||
case PrimaryAction.Default:
|
||||
case PrimaryAction.Copy:
|
||||
default:
|
||||
Command = _copyCommand?.Command;
|
||||
MoreCommands =
|
||||
[
|
||||
_pasteCommand!,
|
||||
new Separator(),
|
||||
_deleteContextMenuItem,
|
||||
];
|
||||
|
||||
if (_item.IsText)
|
||||
{
|
||||
Icon = Icons.DocumentCopy;
|
||||
}
|
||||
else if (_item.IsImage)
|
||||
{
|
||||
Icon = Icons.ImageCopy;
|
||||
}
|
||||
else
|
||||
{
|
||||
Icon = Icons.Copy;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private Details CreateDetails()
|
||||
{
|
||||
IDetailsElement[] metadata =
|
||||
[
|
||||
new DetailsElement
|
||||
{
|
||||
Key = "Copied on",
|
||||
Data = new DetailsLink(_item.Timestamp.DateTime.ToString(DateTimeFormatInfo.CurrentInfo)),
|
||||
}
|
||||
];
|
||||
|
||||
if (_item.IsImage)
|
||||
{
|
||||
var iconData = new IconData(_item.ImageData);
|
||||
var heroImage = new IconInfo(iconData);
|
||||
return new Details
|
||||
{
|
||||
Title = _item.GetDataType(),
|
||||
HeroImage = heroImage,
|
||||
Metadata = metadata,
|
||||
};
|
||||
}
|
||||
|
||||
if (_item.IsText)
|
||||
{
|
||||
return new Details
|
||||
{
|
||||
Title = _item.GetDataType(),
|
||||
Body = $"```text\n{_item.Content}\n```",
|
||||
Metadata = metadata,
|
||||
};
|
||||
}
|
||||
|
||||
return new Details { Title = _item.GetDataType() };
|
||||
}
|
||||
|
||||
private static List<string> StripLeadingWhitespace(IEnumerable<string> lines)
|
||||
{
|
||||
// Determine the minimum leading whitespace
|
||||
var minLeadingWhitespace = lines
|
||||
.Min(static line => line.TakeWhile(char.IsWhiteSpace).Count());
|
||||
|
||||
// Remove the minimum leading whitespace from each line
|
||||
var shiftedLines = lines.Select(line =>
|
||||
line.Length >= minLeadingWhitespace
|
||||
? line[minLeadingWhitespace..]
|
||||
: line).ToList();
|
||||
|
||||
return shiftedLines;
|
||||
}
|
||||
}
|
||||
@@ -212,50 +212,5 @@ namespace Microsoft.CmdPal.Ext.ClipboardHistory.Properties {
|
||||
return ResourceManager.GetString("settings_keep_after_paste_title", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy to Clipboard.
|
||||
/// </summary>
|
||||
public static string settings_primary_action_copy {
|
||||
get {
|
||||
return ResourceManager.GetString("settings_primary_action_copy", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Default (Copy to Clipboard).
|
||||
/// </summary>
|
||||
public static string settings_primary_action_default {
|
||||
get {
|
||||
return ResourceManager.GetString("settings_primary_action_default", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Primary action (Enter key).
|
||||
/// </summary>
|
||||
public static string settings_primary_action_description {
|
||||
get {
|
||||
return ResourceManager.GetString("settings_primary_action_description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Paste.
|
||||
/// </summary>
|
||||
public static string settings_primary_action_paste {
|
||||
get {
|
||||
return ResourceManager.GetString("settings_primary_action_paste", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Primary action.
|
||||
/// </summary>
|
||||
public static string settings_primary_action_title {
|
||||
get {
|
||||
return ResourceManager.GetString("settings_primary_action_title", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,19 +168,4 @@
|
||||
<data name="delete_confirmation_message" xml:space="preserve">
|
||||
<value>Are you sure you want to delete this item from clipboard history? This action cannot be undone.</value>
|
||||
</data>
|
||||
<data name="settings_primary_action_title" xml:space="preserve">
|
||||
<value>Primary action</value>
|
||||
</data>
|
||||
<data name="settings_primary_action_description" xml:space="preserve">
|
||||
<value>Primary action (Enter key)</value>
|
||||
</data>
|
||||
<data name="settings_primary_action_default" xml:space="preserve">
|
||||
<value>Default (Copy to Clipboard)</value>
|
||||
</data>
|
||||
<data name="settings_primary_action_paste" xml:space="preserve">
|
||||
<value>Paste</value>
|
||||
</data>
|
||||
<data name="settings_primary_action_copy" xml:space="preserve">
|
||||
<value>Copy to Clipboard</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -30,7 +30,7 @@ internal sealed class ContextMenuHelper
|
||||
|
||||
// Hide menu if Explorer.exe is the shell process or the process name is ApplicationFrameHost.exe
|
||||
// In the first case we would crash the windows ui and in the second case we would kill the generic process for uwp apps.
|
||||
if (!windowData.Process.IsShellProcess && !(windowData.Process.IsUwpAppFrameHost && string.Equals(windowData.Process.Name, "ApplicationFrameHost.exe", StringComparison.OrdinalIgnoreCase))
|
||||
if (!windowData.Process.IsShellProcess && !(windowData.Process.IsUwpApp && string.Equals(windowData.Process.Name, "ApplicationFrameHost.exe", StringComparison.OrdinalIgnoreCase))
|
||||
&& !(windowData.Process.IsFullAccessDenied && SettingsManager.Instance.HideKillProcessOnElevatedProcesses))
|
||||
{
|
||||
contextMenu.Add(new CommandContextItem(new EndTaskCommand(windowData))
|
||||
|
||||
@@ -23,7 +23,7 @@ internal sealed class WindowProcess
|
||||
/// <summary>
|
||||
/// An indicator if the window belongs to an 'Universal Windows Platform (UWP)' process
|
||||
/// </summary>
|
||||
private readonly bool _isUwpAppFrameHost;
|
||||
private readonly bool _isUwpApp;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the id of the process
|
||||
@@ -42,8 +42,7 @@ internal sealed class WindowProcess
|
||||
{
|
||||
try
|
||||
{
|
||||
// Process.Responding doesn't work on UWP apps
|
||||
return ProcessType.Kind == ProcessPackagingKind.UwpApp || Process.GetProcessById((int)ProcessID).Responding;
|
||||
return Process.GetProcessById((int)ProcessID).Responding;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
@@ -77,7 +76,7 @@ internal sealed class WindowProcess
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the window belongs to an 'Universal Windows Platform (UWP)' process
|
||||
/// </summary>
|
||||
public bool IsUwpAppFrameHost => _isUwpAppFrameHost;
|
||||
internal bool IsUwpApp => _isUwpApp;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this is the shell process or not
|
||||
@@ -135,12 +134,9 @@ internal sealed class WindowProcess
|
||||
internal WindowProcess(uint pid, uint tid, string name)
|
||||
{
|
||||
UpdateProcessInfo(pid, tid, name);
|
||||
ProcessType = ProcessPackagingInspector.Inspect((int)pid);
|
||||
_isUwpAppFrameHost = string.Equals(Name, "ApplicationFrameHost.exe", StringComparison.OrdinalIgnoreCase);
|
||||
_isUwpApp = string.Equals(Name, "ApplicationFrameHost.exe", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public ProcessPackagingInfo ProcessType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates the process information of the <see cref="WindowProcess"/> instance.
|
||||
/// </summary>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
|
||||
|
||||
#pragma warning disable SA1649, CA1051, CA1707, CA1028, CA1714, CA1069, SA1402
|
||||
@@ -98,25 +98,6 @@ public static partial class NativeMethods
|
||||
[DllImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetFirmwareType(ref FirmwareType FirmwareType);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool OpenProcessToken(SafeProcessHandle processHandle, TokenAccess desiredAccess, out SafeAccessTokenHandle tokenHandle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool GetTokenInformation(
|
||||
SafeAccessTokenHandle tokenHandle,
|
||||
TOKEN_INFORMATION_CLASS tokenInformationClass,
|
||||
out int tokenInformation,
|
||||
int tokenInformationLength,
|
||||
out int returnLength);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "GetPackageFullName")]
|
||||
internal static extern int GetPackageFullName(
|
||||
SafeProcessHandle hProcess,
|
||||
ref uint packageFullNameLength,
|
||||
StringBuilder? packageFullName);
|
||||
}
|
||||
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "These are the names used by win32.")]
|
||||
@@ -402,7 +383,7 @@ public enum ShowWindowCommand
|
||||
|
||||
/// <summary>
|
||||
/// Displays a window in its most recent size and position. This value
|
||||
/// is similar to <see cref="ShowWindowCommand.Normal"/>, except
|
||||
/// is similar to <see cref="Win32.ShowWindowCommand.Normal"/>, except
|
||||
/// the window is not activated.
|
||||
/// </summary>
|
||||
ShowNoActivate = 4,
|
||||
@@ -420,14 +401,14 @@ public enum ShowWindowCommand
|
||||
|
||||
/// <summary>
|
||||
/// Displays the window as a minimized window. This value is similar to
|
||||
/// <see cref="ShowWindowCommand.ShowMinimized"/>, except the
|
||||
/// <see cref="Win32.ShowWindowCommand.ShowMinimized"/>, except the
|
||||
/// window is not activated.
|
||||
/// </summary>
|
||||
ShowMinNoActive = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Displays the window in its current size and position. This value is
|
||||
/// similar to <see cref="ShowWindowCommand.Show"/>, except the
|
||||
/// similar to <see cref="Win32.ShowWindowCommand.Show"/>, except the
|
||||
/// window is not activated.
|
||||
/// </summary>
|
||||
ShowNA = 8,
|
||||
@@ -1119,14 +1100,3 @@ public enum SIGDN : uint
|
||||
FILESYSPATH = 0x80058000,
|
||||
URL = 0x80068000,
|
||||
}
|
||||
|
||||
internal enum TOKEN_INFORMATION_CLASS
|
||||
{
|
||||
TokenIsAppContainer = 29,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum TokenAccess : uint
|
||||
{
|
||||
TOKEN_QUERY = 0x0008,
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
|
||||
|
||||
internal sealed record ProcessPackagingInfo(
|
||||
int Pid,
|
||||
ProcessPackagingKind Kind,
|
||||
bool HasPackageIdentity,
|
||||
bool IsAppContainer,
|
||||
string? PackageFullName,
|
||||
int? LastError
|
||||
);
|
||||
@@ -1,123 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
|
||||
|
||||
internal static class ProcessPackagingInspector
|
||||
{
|
||||
#pragma warning disable SA1310 // Field names should not contain underscore
|
||||
private const int ERROR_INSUFFICIENT_BUFFER = 122;
|
||||
private const int APPMODEL_ERROR_NO_PACKAGE = 15700;
|
||||
#pragma warning restore SA1310 // Field names should not contain underscore
|
||||
|
||||
/// <summary>
|
||||
/// Inspect a process by PID and classify its packaging.
|
||||
/// </summary>
|
||||
public static ProcessPackagingInfo Inspect(int pid)
|
||||
{
|
||||
var hProcess = NativeMethods.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, pid);
|
||||
using var process = new SafeProcessHandle(hProcess, true);
|
||||
if (process.IsInvalid)
|
||||
{
|
||||
return new ProcessPackagingInfo(
|
||||
pid,
|
||||
ProcessPackagingKind.Unknown,
|
||||
HasPackageIdentity: false,
|
||||
IsAppContainer: false,
|
||||
PackageFullName: null,
|
||||
LastError: Marshal.GetLastPInvokeError());
|
||||
}
|
||||
|
||||
// 1) Check package identity
|
||||
var hasPackage = TryGetPackageFullName(process, out var packageFullName, out _);
|
||||
|
||||
// 2) If packaged, check AppContainer -> strict UWP
|
||||
var isAppContainer = false;
|
||||
int? tokenErr = null;
|
||||
if (hasPackage)
|
||||
{
|
||||
isAppContainer = TryIsAppContainer(process, out tokenErr);
|
||||
}
|
||||
|
||||
var kind =
|
||||
!hasPackage ? ProcessPackagingKind.UnpackagedWin32 :
|
||||
isAppContainer ? ProcessPackagingKind.UwpApp :
|
||||
ProcessPackagingKind.PackagedWin32;
|
||||
|
||||
return new ProcessPackagingInfo(
|
||||
pid,
|
||||
kind,
|
||||
HasPackageIdentity: hasPackage,
|
||||
IsAppContainer: isAppContainer,
|
||||
PackageFullName: packageFullName,
|
||||
LastError: null);
|
||||
}
|
||||
|
||||
private static bool TryGetPackageFullName(SafeProcessHandle hProcess, out string? packageFullName, out int? lastError)
|
||||
{
|
||||
packageFullName = null;
|
||||
lastError = null;
|
||||
|
||||
uint len = 0;
|
||||
var rc = NativeMethods.GetPackageFullName(hProcess, ref len, null);
|
||||
if (rc == APPMODEL_ERROR_NO_PACKAGE)
|
||||
{
|
||||
return false; // no package identity
|
||||
}
|
||||
|
||||
if (rc != ERROR_INSUFFICIENT_BUFFER && rc != 0)
|
||||
{
|
||||
lastError = rc;
|
||||
return false; // unexpected error
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder((int)len);
|
||||
rc = NativeMethods.GetPackageFullName(hProcess, ref len, sb);
|
||||
if (rc == 0)
|
||||
{
|
||||
packageFullName = sb.ToString();
|
||||
return true;
|
||||
}
|
||||
|
||||
lastError = rc;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryIsAppContainer(SafeProcessHandle hProcess, out int? lastError)
|
||||
{
|
||||
lastError = null;
|
||||
|
||||
if (!NativeMethods.OpenProcessToken(hProcess, TokenAccess.TOKEN_QUERY, out var token))
|
||||
{
|
||||
lastError = Marshal.GetLastPInvokeError();
|
||||
return false; // can't decide; treat as not-UWP for classification
|
||||
}
|
||||
|
||||
using (token)
|
||||
{
|
||||
if (!NativeMethods.GetTokenInformation(
|
||||
token,
|
||||
TOKEN_INFORMATION_CLASS.TokenIsAppContainer,
|
||||
out var val,
|
||||
sizeof(int),
|
||||
out _))
|
||||
{
|
||||
lastError = Marshal.GetLastPInvokeError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return val != 0; // true => AppContainer (UWP)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowWalker.Helpers;
|
||||
|
||||
internal enum ProcessPackagingKind
|
||||
{
|
||||
Unknown = 0,
|
||||
UnpackagedWin32,
|
||||
PackagedWin32,
|
||||
UwpApp,
|
||||
}
|
||||
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
@@ -88,11 +88,11 @@ public static class ServiceHelper
|
||||
];
|
||||
}
|
||||
|
||||
IconInfo icon = Icons.PlayIcon;
|
||||
IconInfo icon = Icons.GreenCircleIcon;
|
||||
switch (s.Status)
|
||||
{
|
||||
case ServiceControllerStatus.Stopped:
|
||||
icon = Icons.StopIcon;
|
||||
icon = Icons.RedCircleIcon;
|
||||
break;
|
||||
case ServiceControllerStatus.Running:
|
||||
break;
|
||||
|
||||