Commit Graph

9343 Commits

Author SHA1 Message Date
Muyuan Li (from Dev Box)
514d593dd9 [PowerScripts] Move parameter prompt to a WinUI 3 helper process
The parameter prompt was an in-process WinForms dialog in PowerScripts.Host.
Keyboard Manager launches the Host hidden and actively hides every window the
Host process owns (ChordKeyboardHandler HideProgram), so the dialog was spawned
then immediately hidden -- pressing a KBM hotkey bound to a prompt-enabled
script appeared to do nothing.

Fix + native UI in one change: render the prompt in a separate WinUI 3 helper,
PowerScripts.PromptUI (self-contained, unpackaged Windows App SDK). A child
process's window is outside KBM's reach, so the prompt shows reliably while the
Host stays silent -- and it now matches PowerToys' WinUI 3 / Fluent design
(ComboBox / ToggleSwitch / NumberBox / TextBox, accent Run button, themed).

- PowerScripts.PromptUI: new WinUI 3 app. Reads a PromptSpec from --spec (temp
  JSON), builds a control per parameter, writes chosen values to --out; exit 0 =
  confirmed, 2 = cancelled/closed. Brings itself to the foreground and centers.
- Host: PromptLauncher serializes the spec, launches the helper, waits, reads
  back values. Resolves the helper next to the Host, via POWERSCRIPTS_PROMPTUI,
  or by discovering the prompt project's bin for in-repo runs; degrades to
  defaults if it can't be found. Program.cs calls PromptLauncher instead of the
  old dialog; WinForms dependency and ParameterPromptDialog removed.
- README: document the WinUI 3 prompt helper and control mapping.

Core tests 32/32. Verified end-to-end: Host launched hidden spawns the visible
WinUI 3 prompt; confirming passes values through to the script.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-09 17:15:28 +08:00
Muyuan Li (from Dev Box)
6bf15961a0 [PowerScripts] Add optional prompted script parameters
Adds an opt-in parameter-prompt feature: a script may declare typed parameters
in its manifest and set promptForParameters=true. When set, the Host shows a
small dialog before running so the user picks/enters values, which are passed to
the script (PowerShell -Name value, Python kwargs). When omitted, no UI shows
and behavior is unchanged (parameters only via --set).

- Manifest: ScriptParameter gains a 'choice' type (with options), Label,
  Description; add manifest-level promptForParameters. Validated in
  ManifestValidator (known types, choice needs options, default within options,
  int min/max, unique names).
- Host: ParameterPromptDialog (WinForms) builds a control per parameter
  (choice->dropdown, bool->checkbox, int->numeric, string->textbox); wired into
  the run path with a --no-prompt bypass. list --json now exposes
  promptForParameters. Main is [STAThread]; Host enables WinForms.
- Samples: greet (PowerShell) and py_greet (Python) demonstrating
  choice+string+bool prompted parameters.

Core tests 32/32; parameter values verified reaching PowerShell via --set, and
the prompt dialog verified rendering for the run path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-07 18:04:34 +08:00
Muyuan Li (from Dev Box)
fe13577c8d [PowerScripts] Fix context menu not rendering (use ExtendedSubCommandsKey)
The Explorer cascading submenu registered an empty 'SubCommands' value with an
inline \shell subkey. On Windows 11 an empty SubCommands frequently renders
nothing, so the PowerScripts submenu never appeared even though the keys were
present.

Switch to the documented per-user cascade pattern: the verb points at an
'ExtendedSubCommandsKey' (HKCU\\Software\\Classes\\PowerScripts.Cascade.<ext>)
whose \shell subtree holds the child commands. Uninstall now also removes the
cascade key. Fixed the remaining 'PowerScript' -> 'PowerScripts' doc reference.

Verified: after shell-install the .txt/.md verbs carry ExtendedSubCommandsKey
(no SubCommands) and the cascade command trees resolve to the Host run command.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-06 12:08:11 +08:00
Muyuan Li (from Dev Box)
aa9b94d0cf [PowerScripts] Fix stale id/folder-name doc comment
The manifest Id doc comment still claimed the id must match the containing
folder name, contradicting the implemented decoupling (ManifestValidator
ignores folderName; ScriptRegistry enforces id uniqueness). Correct it to
describe id as a portable identity independent of the folder, so scripts can
be renamed or relocated for sharing without changing identity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-06 11:51:03 +08:00
Muyuan Li (from Dev Box)
85228635fc [PowerScripts] Fix enabled gate, menu label, add Python samples
Fixes three issues reported during e2e testing of the PowerScripts prototype:

1. Enabled gate was inert after any PowerToys launch. The C++ runner rewrites
   settings.json's enabled block from its registered-module list on launch,
   dropping the PowerScripts key (PowerScripts is not yet a registered runner
   module). The gate treated the absent key as OFF, so the context menu, KBM
   hotkeys and Advanced Paste all went dead. The module's own config.json
   enabled flag (owned solely by this module, never touched by the runner) is
   now authoritative; an absent settings.json key falls back to enabled. The
   Settings toggle writes both settings.json (for the UI) and config.json
   (authoritative + restart-durable). Explicit false still disables all
   surfaces persistently.

2. Explorer right-click menu label was "PowerScript" (singular) in the
   registry-based ShellRegistration; corrected to "PowerScripts".

3. Added dedicated Python samples: py_uppercase_files (file / context menu,
   powerscript_from_files_to_files) and py_beep (system / Keyboard Manager,
   powerscript_from_none_to_none).

Core tests 27/27; Host, Core, Settings.UI and AdvancedPaste build clean;
enabled gate, both Python samples, and the context-menu registration verified
end-to-end.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-06 11:47:37 +08:00
Muyuan Li (from Dev Box)
12769727ca [PowerScripts] Add Python runtime + Advanced Paste surface
Extend PowerScripts so a script authored once runs from every surface,
now including Python and Advanced Paste.

Core/Host:
- Add Python runtime (Windows + WSL) driven by the convention
  powerscript_from_<input>_to_<output>; a bundled _runner.py bridges a
  JSON stdin/stdout transform protocol.
- Add PythonSettings (mode/windows/wsl/timeout) persisted in the module
  config.json python section (merge-preserving with scriptsRoot).
- ScriptExecutor delegates Python scripts to PythonRuntime.
- Host gains a `transform` command (JSON in/out) shared by all surfaces
  and enriches `list --json` with each script's transform contract.
- Sample Python PowerScript: samples/uppercase (text -> text).

Settings UI:
- PowerScripts page exposes a Python runtime section: mode combo
  (Disabled/Windows/WSL), interpreter path (with browse), and a WSL
  distribution combo populated from `wsl -l -q`. Config writes now
  preserve all sections.

Advanced Paste:
- New PowerScriptsService enumerates advancedPaste-surface scripts via
  the host and runs one as a clipboard text transform.
- PasteFormats.PowerScript + per-script PasteFormat factory; formats are
  populated in the options list and dispatched in PasteFormatExecutor.
- Scripts only appear when PowerScripts is enabled (host also gates), so
  disabling the module makes them inert everywhere.

Tests: add PythonConventionTests (parser); Core suite 27/27.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-06 11:19:03 +08:00
Muyuan Li (from Dev Box)
944ae41cf7 [PowerScripts] Rename context menu to "PowerScripts" + central enabled gate
- Explorer context-menu title now reads "PowerScripts" (was "PowerScript").
- Add ModuleState, a single runtime enabled gate read from PowerToys
  settings.json (enabled.PowerScripts). PowerScripts.Host.exe `run` and
  `shell-menu` consult it, so when the module is disabled every binding
  (Keyboard Manager hotkeys, the context menu, and any future module that
  shells out to the host) becomes inert without being deleted or rewritten;
  re-enabling restores them. Missing settings file (standalone/dev/test) or a
  corrupt file fails open; an absent key means off (module default).
  POWERSCRIPTS_IGNORE_ENABLED=1 bypasses the gate for tests/dev.
- Add ModuleStateTests (5) covering enabled/disabled/absent/missing/corrupt.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-03 14:27:06 +08:00
Muyuan Li (from Dev Box)
97ba9b8ec5 [PowerScripts] KBM: dedicated PowerScript action in new editor
Present PowerScript hotkeys as a first-class action in the Keyboard Manager
editor instead of raw run-program cards:

- Add PowerScriptShortcut model + dedicated "PowerScripts" section in MainPage
  that lists "runs PowerScript: <name>" with its own edit/toggle/delete flow.
- LoadPowerScriptShortcuts filters RunProgram mappings whose program is
  PowerScripts.Host.exe; LoadProgramShortcuts now skips them.
- On save, record trust for the script (Host trust approve <id>) and run
  non-interactively (run <id> --no-consent) so the engine-launched hidden Host
  never blocks on a consent dialog and the hotkey actually fires.
- Add catalog helpers ApproveTrust/IsPowerScriptProgramPath/ParseScriptId/
  GetScriptName.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-03 11:42:25 +08:00
Muyuan Li (from Dev Box)
1cbc5d6fdb [PowerScripts] Fix greyed-out Save for PowerScript hotkey mappings
The new Keyboard Manager editor's UnifiedMappingControl.IsInputComplete()
had no case for ActionType.PowerScript, so it fell through to `false` and
the Save button was permanently disabled when mapping a shortcut to a
PowerScript. Add the PowerScript completion rule (a script must be
selected) and the missing PowerScript case in SetActionType so a saved
PowerScript mapping round-trips to the correct action type when edited.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-03 11:22:39 +08:00
Muyuan Li (from Dev Box)
24ce23fa12 [PowerScripts] Decouple script id from folder + add trust-on-first-use gate
Two prototype improvements toward a shareable, safe script catalogue:

Catalogue-readiness (id decoupled from folder):
- Script `id` is now the portable identity; the id-must-equal-folder-name
  rule is removed so a shared/downloaded script keeps its id in any folder.
- Registry enforces id uniqueness across the catalogue (duplicate id is
  reported and skipped rather than silently shadowed).
- Manifest gains optional provenance fields: publisher, version, source.

Capability safety (trust-on-first-use):
- New ScriptIntegrity content hash (SHA-256 over entry body + kind +
  declared capabilities) and a persisted TrustStore (trust.json).
- Host `run` now gates every execution (the single choke point for context
  menu, KBM and agents): untrusted scripts prompt a native consent dialog
  showing name/publisher/source/capabilities/path; editing the body or
  escalating capabilities invalidates trust and re-prompts.
- `--no-consent` / POWERSCRIPTS_NO_CONSENT refuses instead of prompting
  (for non-interactive/agent callers); new `trust list|approve|revoke`
  subcommands; `list --json` exposes a `trusted` flag.
- Settings page shows a read-only Trust status row per script.

Tests: id decoupling, duplicate-id rejection, integrity stability/
invalidation, and trust-store round-trip (16/16 Core tests pass).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-01 16:53:48 +08:00
Muyuan Li (from Dev Box)
6d4a1dee6e [PowerScripts] Make the new KBM editor's PowerScript action e2e-ready
The new Keyboard Manager editor (KeyboardManagerEditorUI) already exposes a
PowerScript action, but on a Debug build it couldn't locate PowerScripts.Host.exe
(it isn't copied next to the editor), so the picker came up empty.

- PowerScriptsCatalog.ResolveHostPath: add the same dev-bin fallback the Settings
  view-model uses (walk up from the editor's base dir and probe
  src\modules\PowerScripts\PowerScripts.Host\bin\{Debug,Release}). The editor can
  now enumerate system scripts and resolve the host path for the saved RunProgram
  mapping in a dev build.
- Add kbm-e2e.ps1: a self-contained end-to-end helper that forces the new editor
  (useNewEditor=true), opens it to assign a hotkey to a system PowerScript, then
  runs KeyboardManagerEngine standalone so the hotkey actually fires
  Host.exe run <id> — no full runner required.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-30 11:38:48 +08:00
Muyuan Li (from Dev Box)
cd327dda07 [PowerScripts] Make Settings page a read-only script catalogue
The manifest.json is the single source of truth for a script's trigger
extensions, surfaces and capabilities. Drop the in-Settings extensions editor
(which only rewrote the manifest via the host) and instead show that
information read-only, so the UI reflects the manifest rather than duplicating
authoring of it.

- PowerScriptListItem: replace the editable ExtensionsText with read-only
  display projections (ExtensionsDisplay/SurfacesDisplay/CapabilitiesDisplay/
  RuntimeDisplay); surface Runtime/Surfaces/Capabilities from list --json.
- PowerScriptsPage.xaml: each script expander now lists Trigger file types
  (file scripts), Runtime, Surfaces and Capabilities as read-only rows.
- Remove SetScriptExtensions / ApplyExtensionsButton_Click. The host
  set-extensions command remains as a CLI/agent capability.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-30 11:08:27 +08:00
Muyuan Li (from Dev Box)
54bd07c08d [PowerScripts] Add Win11 modern context-menu handler (IExplorerCommand)
Legacy registry verbs only appear under "Show more options" on Windows 11.
This adds a self-contained IExplorerCommand COM server (sparse MSIX package)
that surfaces a top-level "PowerScript" entry with a dynamic submenu of the
file scripts matching the current selection.

- PowerScripts.Host: new `shell-menu --files` command emitting tab-separated
  id/name lines for matching file scripts (no JSON parser needed in native code).
- PowerScriptsContextMenu: WRL ClassicCom DLL (dllmain.cpp, dll.def) with a
  top-level command (GetState runs Host shell-menu, caches matches, hides when
  none), an IEnumExplorerCommand enumerator, and per-script items whose Invoke
  runs `Host run <id> --files <path>`. Host located next to the DLL.
- AppxManifest.xml registers the verb (ItemType Type="*", runtime visibility),
  build.cmd compiles via cl.exe, register.ps1 builds+publishes Host+deploys+
  registers the unsigned package (Add-AppxPackage -Register, Developer Mode).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-30 10:40:55 +08:00
Muyuan Li (from Dev Box)
35ccc7658d PowerScripts: let users edit a file script's trigger extensions in Settings
Add a per-script "Trigger on file types" editor (a SettingsExpander with
an editable extensions box + Apply) on the PowerScripts page for file
scripts. Applying calls a new host command, set-extensions <id> --ext
<.md .txt ...>, which rewrites the manifest's input.extensions via the
shared serializer, then re-registers the Explorer right-click submenu
(uninstall old verbs first so a changed extension leaves nothing stale).
list --json now surfaces input.extensions so the box shows current values.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 16:03:42 +08:00
Muyuan Li (from Dev Box)
b58b2f1a4c PowerScripts: locate the Host exe from in-repo dev builds
The Settings page lists scripts by shelling out to PowerScripts.Host.exe,
but a dev build never copies the Host next to Settings, so the list was
always empty even when the default scripts folder had scripts. Walk up
from the Settings base directory and probe the Host project's bin output
(Debug/Release) as a fallback, in addition to the existing next-to-exe
and %LOCALAPPDATA% locations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 14:49:17 +08:00
Muyuan Li (from Dev Box)
0188c1ac69 PowerScripts: let users choose the scripts folder from Settings
Add a "Scripts folder" card to the PowerScripts page with Browse/Reset.
The chosen path is persisted to the shared config.json, and Core's
ResolveScriptsRoot now reads it (explicit > env > config > default) so
every surface (Settings list, Explorer context menu, KBM run) honors the
same folder. Selecting a folder reloads the list and re-registers the
context-menu entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 11:39:08 +08:00
Muyuan Li (from Dev Box)
11bda2709b PowerScripts: add ModuleTitle/Description strings to fix blank Dashboard
The Dashboard builds every module tile via resourceLoader.GetString of
the module's ModuleTitle key, which throws COMException "NamedResource
Not Found" for a missing key and aborts BuildModuleList, blanking the
Home page. Add the PowerScripts.ModuleTitle/ModuleDescription resources.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-26 11:38:57 +08:00
Muyuan Li (from Dev Box)
a618b2f2f9 PowerScripts: update README with implemented-surface table and e2e demo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-25 16:30:43 +08:00
Muyuan Li (from Dev Box)
3cdbca3fa6 PowerScripts: add Settings module page listing scripts + enable toggle
- Add ModuleType.PowerScripts and Enabled.PowerScripts plumbing (EnabledModules,
  ModuleHelper, ModuleGpoHelper, App.GetPage)
- Add PowerScripts Settings nav item + page (NavigablePage) that lists installed
  scripts via 'PowerScripts.Host.exe list --json' and shows an enable toggle
- Enable toggle wires the Explorer context menu directly (Host shell-install/
  shell-uninstall), so the prototype is functional without a runner module DLL

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-25 16:28:58 +08:00
Muyuan Li (from Dev Box)
be711d12bf PowerScripts: add 'PowerScript' action to Keyboard Manager editor
Adds a new 'PowerScript' action type in the KBM editor's mapping control. The
picker lists system PowerScripts (via PowerScripts.Host.exe list --json) and saves
an ordinary RunProgram mapping invoking 'Host.exe run <id>', so a hotkey can launch
a PowerScript. Editor stays decoupled from PowerScripts assemblies by shelling out
to the Host CLI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-25 16:15:53 +08:00
Muyuan Li (from Dev Box)
29ca6328f9 PowerScripts: add convert_md_to_txt + volume_up samples and context-menu registration
- Add two e2e sample scripts: convert_md_to_txt (file/.md) and volume_up (system)
- Add Host shell-install/shell-uninstall: registry-driven 'PowerScript' cascading
  submenu under SystemFileAssociations\\<ext>\\shell, one sub-verb per matching script
- Switch PowerScripts.Host TFM to net10.0-windows for registry access

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-25 15:50:41 +08:00
Muyuan Li (from Dev Box)
af2c3c61cd [PowerScripts] Add prototype module: core, host CLI, samples, tests
Introduces a prototype of the PowerScripts module (write a script once,
surface it across PowerToys). Includes:
- PowerScripts.Core: manifest schema, validation, registry, executor
- PowerScripts.Host: list/run/kbm CLI (shared invocation + KBM RunProgram mapping)
- PowerScripts.Core.Tests: MSTest unit tests (9 passing)
- Two sample scripts (system-snapshot, sha256-checksum) and README

Surfaces prioritized: Explorer right-click + Keyboard Manager. Build is
isolated from the repo (local Directory.Build.props/Packages/nuget.config)
while prototyping; remove to adopt standard PowerToys build rules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-25 15:31:41 +08:00
Clint Rutkas
a864d421fc [Keyboard Manager] Fix stuck modifiers and dropped key-to-text remaps (#48571)
## Summary
Fixes stuck modifier keys and silently-dropped remaps on Keyboard
Manager's **single key → text** path, and adds unit coverage (including
a mockable injection-failure seam).

## What this changes
1. **Insert a dummy key event before releasing held modifiers.**
Releasing a lone Win or Alt key-up otherwise triggers the Start Menu /
menu bar. The dummy key absorbs it so the release is inert. The dummy +
releases are only injected when a modifier is actually held.
2. **Accept `WM_SYSKEYDOWN` as well as `WM_KEYDOWN`.** While Alt is held
the system delivers `WM_SYSKEYDOWN`, so the previous `WM_KEYDOWN`-only
guard silently dropped the remap whenever Alt was down.
3. **Route `Helpers::SendTextInput` through `InputInterface`** instead
of calling Win32 `SendInput` directly. Besides making the path mockable,
this stops the existing unit tests from injecting real keystrokes into
the OS during a test run. Text is still flushed per character to
preserve the existing batching workaround.
4. **Never re-press released modifiers.** Once a modifier key-up is
injected, `GetAsyncKeyState` reports it as up, so re-pressing risks
leaving it stuck if the user let go during injection. Leaving it
released is always safe.

## Testing
- New `MockedInput` failure seam (`SetSendVirtualInputShouldFail`).
- `RemappedKey_ShouldPassOriginalKeyThrough_WhenInjectionFails` —
verifies the original key is passed through when injection fails (the
core stuck-key behavior, previously untestable because the mock always
succeeded).
-
`HandleSingleKeyToTextRemapEvent_ShouldFireAndReleaseAlt_WhenAltIsHeld`
— covers fix #2 by asserting the remap still fires (and releases the
held Alt) when the key arrives as `WM_SYSKEYDOWN`.
- Full Keyboard Manager engine suite: **98/98 passing**, Release x64,
against current `main`.

This is one of a small set of related "stuck key" hardening fixes; each
stands alone.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 20:10:35 -07:00
Mike Griese
3331bdf02a CmdPal: add support for compact mode (#48801)
This is a bear of a PR. Watch out.
This PR adds support for compact mode to the command palette. In compact
mode, the results of the command palette window are collapsed by
default. And the only thing that is visible is the search bar. When the
user types, the window is expanded only just enough to show the
available results[^1]



https://github.com/user-attachments/assets/fd11bbc9-1173-426f-8f44-b513baf2ac5f



This is made possible by a fairly annoyingly substantial refactoring to
how our windowing is done. Animating the size or bounds of an HWND on
Windows is not fun. With pretty much any XAML application, you're going
to get at least one frame of blackness when you resize your window. The
trick then is to create an experience where it looks like your
application is resizing, but the HWND never actually resizes.

So the main bulk of this PR is actually just refactoring our window
handling. Our `MainWindow` class now becomes a dummy holder of _some
content_, and most of the main content is moved into the
`CmdPalMainControl` class. `MainWindow`'s job then is to handle a
transparent window that hosts some XAML content inside of it, and
pretend that content is the real bounds of the window. We need to fake
our NCHITTEST results, so that the edges of the XAML content act like
they're the edge of the actual HWND. We need to hide our actual window
frame and shadow, but then also re-create them in XAML around our
content.
Previously we've done work like this using a single full screen
transparent window with XAML content inside of it. However that has the
downside of not allowing the XAML content to be movable across different
monitors. By faking out the NCHITTEST results, we allow users to resize
and move the window using the normal user32 move size loop.
Our HWND is also cropped (with SetWindowRgn to the bounds of the shadow
around our XAML content. We need to include the shadow in the hit
testable region, because if we don't, then the shadow will be visibly
cropped on the edges.

In compact mode, instead of centering our window in the middle of the
monitor, the user can set a relative height where the search box opens
on that monitor. This defaults to about 60% up from the bottom of the
monitor, so that there's room for the results to expand downwards and
feel centered within the screen. This position is a setting, so users
can customize it to whatever they like.

I've also added a developer only debug build only internal setting,
which allows you to see the actual frame of our HWND. This makes it
easier to visually debug where the bounds of the window are and
understand a little bit more about the layout of our application. This
setting and functionality is disabled in release builds.

<img width="1334" height="1164" alt="cmdpal-compact-diagram"
src="https://github.com/user-attachments/assets/cb1c273d-37cc-4cb7-8680-e1878aa20c9c"
/>

Closes #38423


[^1]: with some caveats: pages with details expand fully always.
2026-06-24 22:35:37 +00:00
Michael Jolley
9ee0c7259b CmdPal: Dock Auto-hide (#48565)
This pull request introduces a new "Auto-hide" feature for the dock,
allowing users to collapse the dock until they hover over its screen
edge. The changes include updates to the settings model, UI,
localization resources, and automated tests to support and verify this
new functionality.

**Show me:**


https://github.com/user-attachments/assets/689625e8-9050-4a54-9c4b-9e303a3da63a

**Conflicted?**

"What if I have Taskbar and Dock on the same side and both with
auto-hide turned on?"

<img width="1437" height="264" alt="Screenshot 2026-06-14 144814"
src="https://github.com/user-attachments/assets/bd037a11-0653-4b9a-bd21-625aca03b901"
/>


Closes #46239

---------

Co-authored-by: root <root@io.bbq>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 16:39:58 -05:00
Boliang Zhang
7e877558b9 Add powertoys-module-verification agent skill (#48717)
## Summary of the Pull Request

Adds a new **GitHub Copilot Agent Skill**,
`powertoys-module-verification`, under `.github/skills/`. It packages
the workflow, drive techniques, helper scripts, and per-module reference
data an AI agent uses to verify a single PowerToys module's
release-checklist items end-to-end (each checkbox → a structured PASS /
FAIL / BLOCKED verdict with evidence).

This is **docs/automation tooling only** — no product code, binaries, or
end-user strings are touched.

## PR Checklist

- [ ] Closes: #xxx
- [x] **Communication:** Internal tooling for release sign-off; happy to
adjust scope/placement based on review.
- [x] **Tests:** N/A — documentation/skill bundle only (no product code
paths). The 12 bundled `.ps1` helpers are agent utilities, not part of
the product build/test.
- [x] **Localization:** N/A — no end-user-facing strings.
- [x] **New binaries:** N/A — no binaries added.
- [x] **Dev docs:** This PR *is* developer-facing documentation/tooling.

## Detailed Description of the Pull Request / Additional comments

Layout follows the repo's Agent Skill guidelines
(`.github/instructions/agent-skills.instructions.md`) and matches the
existing skills under `.github/skills/`:

```
.github/skills/powertoys-module-verification/
├── SKILL.md            # single entry doc (name/description/license frontmatter)
├── LICENSE.txt         # Apache 2.0 (matches existing skills)
├── scripts/            # 12 PowerShell helper utilities used by the agent
└── references/
    ├── winapp-ui-testing.md         # UIA-mechanics prerequisite doc
    ├── pre-flight.md / reporting-format.md / environment-setup.md / explorer-context-menu-flow.md
    ├── modules/                     # per-module verification profiles
    └── release-checklist/           # per-module checklists + index
```

Notes for reviewers:
- **`references/winapp-ui-testing.md`** is adapted from the
`winui-ui-testing` skill in
[microsoft/win-dev-skills](https://github.com/microsoft/win-dev-skills)
(MIT, © Microsoft Corporation and Contributors), with PowerToys-specific
edits. Provenance is recorded in the file header. Its skill frontmatter
was intentionally stripped so it is treated as a reference doc, not a
separately-discovered skill.
- **Checklist scope:** only modules already verified end-to-end (with a
sign-off report) are included for now — Environment Variables, File
Locksmith, Image Resizer, New+, Peek, PowerRename. Remaining modules'
checklists will be added as each is verified.
- No existing files are modified; this is purely additive under
`.github/skills/`.

## Validation Steps Performed

- Validated the bundle against the Agent Skill checklist in
`.github/instructions/agent-skills.instructions.md`: valid `name` (≤64
chars) + `description` + `license` frontmatter; `SKILL.md` body under
the 500-line guidance; single `SKILL.md`; `scripts/` + `references/`
resource buckets; all resource references use relative paths.
- Verified internal cross-references resolve after the migration (no
stale `helpers/`, `Winapp-SKILL.md`, or absolute-path tokens;
`src/modules/...` source citations left intact).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 13:45:26 -07:00
Mike Griese
386a16ff94 Revert "[CmdPal][Dock] Fix performance meter showing '???' after restart" (#48835)
Reverts microsoft/PowerToys#48682

I'm quite sure that OP did not build or test these changes, and they
should not have merged.
2026-06-24 14:21:10 -05:00
Michael Jolley
ada75d040a CmdPal: Hide uninstall option for system apps (#48804)
Command Palette currently shows the "Uninstall" context menu option for
system apps like Windows Settings, Registry Editor, and Task Manager.
Users can accidentally trigger uninstall on packages that should not be
removable. This PR hides the uninstall option for system apps.

It's probably not a perfect solution, but seemed to catch all I tried to
test.

Fixes #46826

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 13:52:12 -05:00
Michael Jolley
086bd06eaf CmdPal: Accurate GPU usage in Dock (#48710)
Closes #48677.

## Root cause
`GPUStats.GetData()` summed the cooked `Utilization Percentage` value of
every `engtype=3D` GPU-Engine performance-counter instance for a given
physical adapter. Each instance is a `(process, engine)` pair. Summing
across processes for a single engine is correct (gives total engine
utilization), but summing across **multiple 3D engines** on the same
adapter compounds them and produces values >100% (the 104%/118%
screenshots in the issue). The displayed value `sum / 100` therefore
exceeded 1.0, and the chart fed the raw inflated `sum` directly.

## Fix
Mirroring the bounded-counter approach used for CPU in #46381:

1. Bucket cooked values by `(physId, engineId)` rather than just
`physId`.
2. Reduce per-adapter to the **maximum** engine utilization (what Task
Manager surfaces as the overall GPU number).
3. Clamp the per-adapter value to `[0, 100]` before storing it as a 0–1
fraction in `Data.Usage` and pushing to the chart.
4. Defensive checks: skip `NaN` / `Infinity` / negative cooked values,
and skip instances whose engine id can't be parsed.

Co-authored-by: root <root@io.bbq>
2026-06-24 11:32:52 -05:00
Michael Jolley
205ae601ce CmdPal: Fix bookmark dock bands disappearing on restart (#48092)
## Summary

Bookmarks pinned to the CmdPal dock disappear after a restart.

## Root Cause

`BookmarksCommandProvider` did not override `GetCommandItem(string id)`.
When `InitializeCommands` in `CommandProviderWrapper` processes pinned
dock band settings, the fallback path calls
`provider.GetCommandItem(commandId)`, which hit the base-class no-op
returning `null`. Any bookmark band that `GetDockBands()` failed to
return (due to a race, transient file error, or exception) was
irreversibly lost from the dock.

## Fix

Added `GetCommandItem` override to `BookmarksCommandProvider`. Given a
`"Bookmarks.Launch.{guid}"` ID, it:

1. Parses the GUID suffix
2. Looks up the `BookmarkData` in `_bookmarksManager` (under lock)
3. Constructs a `BookmarkListItem` (with `asBand: true`) and wraps it in
a `WrappedDockItem`

Uses `BookmarkTitle` (maps to `_bookmark.Name`, set synchronously in the
constructor) rather than `Title` (set asynchronously after
classification completes), matching the pattern used by
`AllAppsCommandProvider`, `SystemCommandExtensionProvider`, and others.

Fixes #47576

Co-authored-by: root <root@io.bbq>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 11:32:08 -05:00
Michael Jolley
80f2b9b07d CmdPal: Fix 1px gap between dock window and screen edge (#48091) 2026-06-24 08:41:37 -05:00
Copilot
5f1b496bf2 Shortcut Guide: Rename Win+Q to "Open Click to Do" for Copilot+ PCs (#48439)
Win+Q and Win+S were both labeled "Open search" in Shortcut Guide. On
Copilot+ PCs, Win+Q launches Click to Do — not Search — so the duplicate
label was misleading.

## Changes

- `+WindowsNT.Shell.en-US.yml`: Renamed Win+Q entry from `Open search` →
`Open Click to Do` with description `On Copilot+ PCs`; Win+S retains
`Open search`

## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

The Windows key shortcuts manifest had two entries with identical names
(`Open search`) mapped to Win+Q and Win+S respectively. On Copilot+ PCs,
Win+Q opens Click to Do, not Search. The Win+Q entry is corrected to
`Open Click to Do` with a `On Copilot+ PCs` description to scope its
applicability.

## Validation Steps Performed

- Visually reviewed the YAML diff to confirm only the Win+Q entry name
and description changed; Win+S entry is unchanged.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-24 10:44:07 +00:00
Ingo Kodba
a2218b3c3b [KeyboardManager] Fix sticky Ctrl caused by stale AltGr flag (#46672)
## Summary

Fixes #46693

- The `static bool isAltRightKeyInvoked` flag in
`HandleShortcutRemapEvent` is set when AltGr (RAlt+LCtrl) is pressed,
but only reset inside Case 1's else branch — which requires a shortcut
to be actively invoked (`isShortcutInvoked == true`)
- If the user presses and releases AltGr when **no shortcut is active**,
the flag stays `true` permanently across all future calls
- Once stale, the flag blocks modifier key restoration and state resets
at 13 locations throughout the function (lines 646, 670, 791, 800, 866,
880, 889, 907, 927, 978, 996), and causes LCtrl key-up events to `break`
out of the handler loop (line 620-622) instead of being properly
processed
- This makes LCtrl permanently stuck for any shortcut remap that uses
LCtrl as a modifier

## Fix

Reset `isAltRightKeyInvoked` when `VK_RMENU` (Right Alt) is released,
regardless of whether a shortcut is currently invoked. This is added as
an `else if` right after the existing flag-set condition.

## Test plan

- [ ] Configure a shortcut remap using LCtrl (e.g. LCtrl+Y → Backspace)
- [ ] Press and release AltGr without triggering any shortcut
- [ ] Use the LCtrl shortcut — verify Ctrl does not become stuck
- [ ] Verify AltGr-based shortcuts still work correctly
- [ ] Verify normal AltGr character input (e.g. AltGr+Q for @ on German
layout) is unaffected

---------

Co-authored-by: fluffyspace <fluffyspace@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-24 10:42:54 +00:00
Clint Rutkas
47335149f3 [Settings] Extract HandleNavigationFailure and test all null permutations (#48410)
## Summary

Follow-up to #48409. That PR rewrote
`ShellViewModel.Frame_NavigationFailed` to set `e.Handled = true` and
log instead of re-throwing, but the unit tests it added only covered the
`GetPageDisplayName` formatting helper. The actual contract that matters
- "this handler must never throw, regardless of which fields on
`NavigationFailedEventArgs` happen to be null" - was not directly
testable because `NavigationFailedEventArgs` is a sealed WinRT type that
cannot be constructed from MSTest.

## Change

Tiny refactor: split the failure-handling logic out of
`Frame_NavigationFailed` into a pure static
`HandleNavigationFailure(Type sourcePageType, Exception exception)`. The
WinUI-shaped handler now just sets `Handled = true` and delegates.

This makes the "must not throw" invariant testable in isolation - no
WinUI Frame, no Microsoft.UI.Xaml.Navigation types needed.

## Tests

Added four new cases under `ShellViewModelTests`, exercising all four
`(SourcePageType, Exception)` null permutations:

| `sourcePageType` | `exception` |
| - | - |
| null | null |
| typeof(...) | null |
| null | new Exception(...) |
| typeof(...) | new Exception(...) |

Each test simply calls the helper and relies on MSTest's default "if it
throws, the test fails" behavior. Any future change that re-introduces
an unguarded dereference of `e.SourcePageType` or `e.Exception` will
turn the corresponding test red.

## Validation

All six tests pass:

```
Passed GetPageDisplayName_ReturnsFullName_ForKnownType
Passed GetPageDisplayName_ReturnsPlaceholder_ForNullType
Passed HandleNavigationFailure_DoesNotThrow_ForNullInputs
Passed HandleNavigationFailure_DoesNotThrow_ForNullException
Passed HandleNavigationFailure_DoesNotThrow_ForNullPageType
Passed HandleNavigationFailure_DoesNotThrow_ForBothInputsPresent
Total tests: 6, Passed: 6
```

`PowerToys.Settings.csproj` and `Settings.UI.UnitTests.csproj` both
build clean (Release|x64).

## Note

This PR is stacked on top of #48409 (same branch lineage). If #48409 is
merged first this PR will rebase cleanly to a small diff on
`ShellViewModel.cs` + the additional test cases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 10:02:08 +02:00
dependabot[bot]
5c63486dcb build(deps): bump actions/checkout from 6 to 7 (#48743)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to
7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>block checking out fork pr for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the
minor-actions-dependencies group across 1 directory by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2458">actions/checkout#2458</a></li>
<li>Bump flatted from 3.3.1 to 3.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2460">actions/checkout#2460</a></li>
<li>Bump js-yaml from 4.1.0 to 4.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2461">actions/checkout#2461</a></li>
<li>Bump <code>@​actions/core</code> and
<code>@​actions/tool-cache</code> and Remove uuid by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2459">actions/checkout#2459</a></li>
<li>upgrade module to esm and update dependencies by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2463">actions/checkout#2463</a></li>
<li>Bump the minor-npm-dependencies group across 1 directory with 3
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2462">actions/checkout#2462</a></li>
<li>getting ready for checkout v7 release by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2464">actions/checkout#2464</a></li>
<li>update error wording by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2467">actions/checkout#2467</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.3...v7.0.0">https://github.com/actions/checkout/compare/v6.0.3...v7.0.0</a></p>
<h2>v6.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Update changelog by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2357">actions/checkout#2357</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>Update changelog for v6.0.3 by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2446">actions/checkout#2446</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/yaananth"><code>@​yaananth</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.3">https://github.com/actions/checkout/compare/v6...v6.0.3</a></p>
<h2>v6.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Add orchestration_id to git user-agent when ACTIONS_ORCHESTRATION_ID
is set by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2355">actions/checkout#2355</a></li>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.1...v6.0.2">https://github.com/actions/checkout/compare/v6.0.1...v6.0.2</a></p>
<h2>v6.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Update all references from v5 and v4 to v6 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2314">actions/checkout#2314</a></li>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
<li>Clarify v6 README by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2328">actions/checkout#2328</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.1">https://github.com/actions/checkout/compare/v6...v6.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>v7.0.0</h2>
<ul>
<li>Block checking out fork PR for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the
minor-actions-dependencies group across 1 directory by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2458">actions/checkout#2458</a></li>
<li>Bump flatted from 3.3.1 to 3.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2460">actions/checkout#2460</a></li>
<li>Bump js-yaml from 4.1.0 to 4.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2461">actions/checkout#2461</a></li>
<li>Bump <code>@​actions/core</code> and
<code>@​actions/tool-cache</code> and Remove uuid by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2459">actions/checkout#2459</a></li>
<li>upgrade module to esm and update dependencies by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2463">actions/checkout#2463</a></li>
<li>Bump the minor-npm-dependencies group across 1 directory with 3
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2462">actions/checkout#2462</a></li>
</ul>
<h2>v6.0.3</h2>
<ul>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<h2>v6.0.2</h2>
<ul>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<h2>v6.0.1</h2>
<ul>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
</ul>
<h2>v6.0.0</h2>
<ul>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
</ul>
<h2>v5.0.1</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<h2>v5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>v4.3.1</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<h2>v4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9c091bb21b"><code>9c091bb</code></a>
update error wording (<a
href="https://redirect.github.com/actions/checkout/issues/2467">#2467</a>)</li>
<li><a
href="1044a6dea9"><code>1044a6d</code></a>
getting ready for checkout v7 release (<a
href="https://redirect.github.com/actions/checkout/issues/2464">#2464</a>)</li>
<li><a
href="f0282184c7"><code>f028218</code></a>
Bump the minor-npm-dependencies group across 1 directory with 3 updates
(<a
href="https://redirect.github.com/actions/checkout/issues/2462">#2462</a>)</li>
<li><a
href="d914b262ff"><code>d914b26</code></a>
upgrade module to esm and update dependencies (<a
href="https://redirect.github.com/actions/checkout/issues/2463">#2463</a>)</li>
<li><a
href="537c7ef99c"><code>537c7ef</code></a>
Bump <code>@​actions/core</code> and <code>@​actions/tool-cache</code>
and Remove uuid (<a
href="https://redirect.github.com/actions/checkout/issues/2459">#2459</a>)</li>
<li><a
href="130a169078"><code>130a169</code></a>
Bump js-yaml from 4.1.0 to 4.2.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2461">#2461</a>)</li>
<li><a
href="7d09575332"><code>7d09575</code></a>
Bump flatted from 3.3.1 to 3.4.2 (<a
href="https://redirect.github.com/actions/checkout/issues/2460">#2460</a>)</li>
<li><a
href="0f9f3aa320"><code>0f9f3aa</code></a>
Bump actions/publish-immutable-action (<a
href="https://redirect.github.com/actions/checkout/issues/2458">#2458</a>)</li>
<li><a
href="f9e715a95f"><code>f9e715a</code></a>
block checking out fork pr for pull_request_target and workflow_run (<a
href="https://redirect.github.com/actions/checkout/issues/2454">#2454</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/checkout/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=6&new-version=7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-24 09:51:55 +02:00
Gordon Lam
bf6dbd8865 feat(Advanced Paste): Add setting to show/hide AI paste section (#45242)
## Summary of the Pull Request

Adds a new "Show AI paste section" setting to Advanced Paste that allows
users to hide the AI paste input box from the Advanced Paste window.
This addresses user requests for a cleaner UI when the AI paste feature
is not needed or desired.

## PR Checklist

- [x] Closes: #32967
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

This PR implements a new boolean setting `ShowAIPaste` that controls the
visibility of the AI paste input box (PromptBox) in the Advanced Paste
window.

### Changes Made

**Settings UI Library:**
- `src/settings-ui/Settings.UI.Library/AdvancedPasteProperties.cs` -
Added `ShowAIPaste` property with JSON serialization

**Settings UI:**
- `src/settings-ui/Settings.UI/ViewModels/AdvancedPasteViewModel.cs` -
Added view model property with change notification
-
`src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPastePage.xaml`
- Added checkbox setting in the UI Behavior section
- `src/settings-ui/Settings.UI/Strings/en-us/Resources.resw` - Added
localized strings for header and description

**Advanced Paste Module:**
- `src/modules/AdvancedPaste/AdvancedPaste/Helpers/IUserSettings.cs` -
Added interface property
- `src/modules/AdvancedPaste/AdvancedPaste/Helpers/UserSettings.cs` -
Implemented setting loading from properties
-
`src/modules/AdvancedPaste/AdvancedPaste/ViewModels/OptionsViewModel.cs`
- Added `ShowAIPasteSection` property combining user setting with GPO
policy
-
`src/modules/AdvancedPaste/AdvancedPaste/AdvancedPasteXAML/Pages/MainPage.xaml`
- Bound PromptBox visibility to new property

**Tests:**
-
`src/modules/AdvancedPaste/AdvancedPaste.UnitTests/Mocks/IntegrationTestUserSettings.cs`
- Added mock property
-
`src/modules/AdvancedPaste/UITest-AdvancedPaste/TestFiles/settings.json`
- Updated test settings file

### Behavior
- Default value is `true` (AI paste section visible) to maintain
backward compatibility
- The setting respects GPO policy - if AI is disabled by GPO, the
section will be hidden regardless of user preference
- Setting is persisted in the Advanced Paste settings JSON file

## Validation Steps Performed

- [x] Verified setting appears in Settings UI under Advanced Paste →
UI Behavior
- [x] Verified toggling the setting hides/shows the AI paste input box
in the Advanced Paste window
- [x] Verified setting persists after closing and reopening Settings
- [x] Verified default value is `true` (visible) for new installations
- [x] Verified existing unit tests pass with updated mock

Fixes #32967

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-06-24 15:43:23 +08:00
Deryl Fabiensyah
3c942ae356 Quick Accent: Add ¡ and ¿ to ! and ? quick accent menu (#20618) (#48599)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR addresses issue #20618 by adding the inverted exclamation mark
(**¡**) to the **!** key (`VK_1`) and the inverted question mark (**¿**)
to the **?** key (`VK_SLASH_`) for both Spanish (`SP`) and Catalan
(`CA`) character mappings in Quick Accent.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #20618
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

Adds the inverted punctuation marks `¡` (inverted exclamation mark) and
`¿` (inverted question mark) to the character mappings of Spanish (`SP`)
and Catalan (`CA`) languages in `CharacterMappings.cs`.
- `LetterKey.VK_1` (`!`) now maps to `¡`
- `LetterKey.VK_SLASH_` (`?`) now maps to `¿`

This enables quick accent popups when pressing these respective keys,
aligning with the expected behavior for these languages.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

1. Verified character mapping changes build successfully.
2. Verified that the PowerToys CI pipeline checks completed
successfully.
2026-06-24 12:07:10 +08:00
Mario Hewardt
be4c3a1afa ZoomIt: add WebP/JPG screenshot encoder (#48818)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Add webp and jpg support for screenshots.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-06-23 15:48:34 -07:00
Clint Rutkas
968a7ac4b6 [Peek] Stop fail-fast in AppWindow.Closing path; reset cached preview-handler factories on release (#48564)
## Summary

Harden Peek's `AppWindow.Closing` path so a stale cached preview-handler
factory can't fail-fast the Peek process. Also clean up the matching
path in RegistryPreview.

## Background

Spotted while reading through Peek's `MainWindow` teardown sequence and
the `ShellPreviewHandlerPreviewer` cache for an unrelated review of how
Peek manages out-of-process preview-handler lifetimes.

The Peek `MainWindow` subscribes to `AppWindow.Closing`. The handler
doesn't actually close the window — it sets `args.Cancel = true` and
calls `Uninitialize()`, which in turn calls
`ShellPreviewHandlerPreviewer.ReleaseHandlerFactories()`.

`ReleaseHandlerFactories()` looked like this:

```csharp
public static void ReleaseHandlerFactories()
{
    foreach (var factory in HandlerFactories.Values)
    {
        try { Marshal.FinalReleaseComObject(factory); } catch { }
    }
}
```

Two problems:

1. The static `HandlerFactories` dictionary is never cleared. After
`FinalReleaseComObject`, the entries still point at separated RCWs. A
subsequent activation that races with this cleanup (or a second close in
the same process) can pick up the dead RCW from the cache.
2. The cached factory had `LockServer(true)` called on it when it was
first cached, but the matching `LockServer(false)` was never paired.

Any managed exception that escapes a WinRT event callback is projected
back to CFlat as a failed HRESULT and the CsWinRT dispatcher fail-fasts
the process. So a single `InvalidComObjectException` (HRESULT
0x80131527) thrown out of `Uninitialize()` is enough to terminate Peek.

## Changes

* **`ShellPreviewHandlerPreviewer.ReleaseHandlerFactories`** — snapshot
then clear the dictionary up front so that a subsequent call (or a
concurrent `LoadPreviewAsync`) can't pick up a stale RCW. Call
`LockServer(false)` before `FinalReleaseComObject` to mirror the
cache-time `LockServer(true)`. Both COM calls remain individually
wrapped because the RCW may already be unreachable during process
teardown.
* **`Peek.UI/MainWindow.xaml.cs` — `AppWindow_Closing`** — wrap the body
in try/catch + `Logger.LogError`. Any future exception in
`Uninitialize()` (or its callees) will now log instead of fail-fasting
the process.
* **`RegistryPreview/MainWindow.Events.cs` — `AppWindow_Closing`** —
same defensive try/catch, plus null-guard `jsonWindowPlacement` before
`SetNamedValue`. The placement dictionary can legitimately be null on
first run or after a corrupt placement file; previously that would NRE →
fail-fast.

## Risk

Low. The `ReleaseHandlerFactories` change matches the documented
`LockServer`/`FinalReleaseComObject` pairing and only widens the
lifetime window of the cache by `Clear()`-ing earlier; nothing in Peek
calls this method outside of teardown. The two try/catch wrappers
strictly add defense — the success path is unchanged.

## Validation

Spot-built locally; this repo's `dotnet restore` runtime-pack issue
(unrelated to this PR — same NU1102 pattern that's affecting other open
PRs) prevents a full `Build.cmd` here. The C++ side of Peek is
untouched.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---

ADO:
https://microsoft.visualstudio.com/DefaultCollection/OS/_workitems/edit/58765809/

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Boliang Zhang <122517415+LegendaryBlair@users.noreply.github.com>
2026-06-23 21:32:02 +08:00
Clint Rutkas
dd26d86580 [FancyZones] Fix stuck drag state and swallowed keys when a window is destroyed mid-drag (#48569)
## Summary
Fixes a class of "stuck drag" bugs in FancyZones where closing or
destroying a window **while it is being dragged** leaves FancyZones in a
half-dragging state — zone overlays stay on screen and subsequent
keystrokes (notably number keys) are swallowed or misrouted.

## What this changes
- **Subscribe to and dispatch `EVENT_OBJECT_DESTROY`.** `FancyZonesApp`
never subscribed to the destroy event, and the consumer's
`WM_PRIV_WINDOWDESTROYED` branch could therefore never fire. The event
is now registered and routed through `HandleWinHookEvent`.
- **Abort the drag (without snapping) when the dragged window is
destroyed.** On `WM_PRIV_WINDOWDESTROYED`, if the destroyed HWND is the
one being dragged, call the new `WindowMouseSnap::Abort()` (tears down
overlays/highlights/transparency) instead of `MoveSizeEnd()`, which
would try to snap the now-dead HWND and corrupt zone state. Dragging
state is then disabled.
- **Always clear dragging state in `MoveSizeEnd()`**, even when the
snapper was already null, so the state can't get stranded.
- **Require Win+Ctrl+Alt to switch layouts while dragging.** Previously
any digit switched layouts while `dragging` was true; if drag state was
stuck this "stole" number keys from the focused app. This is the
root-cause fix for the number-key-stealing symptom.
- **Only swallow the bare Shift key during a drag**, not `Shift+<other>`
combos, so real keystrokes are no longer eaten by an in-progress drag.

## Testing
- Builds Release x64 (FancyZones) clean against current `main`.
- Manually verified drag → close window mid-drag no longer leaves
overlays up or steals number keys. (FancyZones has no unit-test harness
for this path.)

This is one of a small set of related "stuck key / stuck state"
hardening fixes; each stands alone.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Muyuan Li <116717757+MuyuanMS@users.noreply.github.com>
2026-06-23 15:09:26 +02:00
Clint Rutkas
4771f15b6c [Runner] Harden centralized keyboard hook against stuck/ghost keys (#48570)
## Summary
Hardens the runner's centralized keyboard hook against stuck and "ghost"
key activations — cases where a hotkey action fires after the key was
already released, or a pending timer fires after the hook was torn down.

## What this changes
- **`vkCodePressed` is now `std::atomic<DWORD>`.** It is read/written
from the low-level hook callback and from the timer/teardown paths; the
plain `DWORD` was a data race.
- **Revalidate the key is still physically held before firing a held-key
timer.** The pressed-key timer callback now checks
`GetAsyncKeyState(virtualKey) & 0x8000` before invoking the action,
preventing ghost activations after the user has let go.
- **Tag the injected dummy `0xFF` key-up** with
`CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG` so the hook does not
reprocess its own synthetic event.
- **`Stop()` kills all pending pressed-key timers and resets
`vkCodePressed` before unhooking**, so a timer can't fire a callback
into a half-removed hook.

## Testing
- Builds Release x64 (runner / `PowerToys.exe`) clean against current
`main`.

This is one of a small set of related "stuck key" hardening fixes; each
stands alone.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 13:54:19 +02:00
Copilot
ed93fb585a Fix ZoomIt module description to eliminate Chinese translation repetition bug (#47370)
The ZoomIt module description contained `"snip screenshots"` — both
words map to the same Chinese term (截图), causing the translation system
to emit the garbled `"截图截图截图"` in the Chinese UI.

## Changes

- **`src/settings-ui/Settings.UI/Strings/en-us/Resources.resw`**:
Changed `"to snip screenshots to the clipboard or to a file"` → `"to
copy screenshots to the clipboard or to a file"` in both
`ZoomIt.ModuleDescription` and `Oobe_ZoomIt.Description`
- `copy` has an unambiguous, distinct Chinese translation (`复制`) with no
overlap with `截图`
- Consistent with the existing `ZoomIt_SnipGroup.Description` which
already uses `"Copy a selected area of the screen to the clipboard or to
a file"`

## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments

Before (zh-CN rendered):
> 还可以使用 Zoomlt 将屏幕**截图截图截图**剪贴板或文件中

After (expected zh-CN):
> 还可以使用 ZoomIt 将截图**复制到**剪贴板或文件中

Root cause: `snip` (Windows snipping action) and `screenshots` are both
translated to `截图` by the localization pipeline, producing triple
repetition. Replacing `snip` with `copy` — already used in the adjacent
Snip group description — resolves the collision without changing the
functional meaning.

## Validation Steps Performed

- Verified both string keys (`ZoomIt.ModuleDescription`,
`Oobe_ZoomIt.Description`) updated in `en-us/Resources.resw`
- Confirmed no other occurrences of `"snip screenshots"` remain in the
file

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: MuyuanMS <116717757+MuyuanMS@users.noreply.github.com>
2026-06-23 10:00:27 +00:00
Niels Laute
c3bec3935a Docs cleanup (#48813)
## Summary

Removes outdated/unused documentation and asset files:

- **`doc/unofficialInstallMethods.md`** — removed.
- **`doc/planning/`** — removed entire folder (`awake.md`,
`FancyZonesBacklog.md`, `PowerToysBacklog.md`,
`ShortcutGuideBacklog.md`).
- **`doc/images/icons/Video Conference Mute.png`** — removed (unused
module icon, not referenced anywhere in the repo).

Verified there are no remaining references to any of the removed files
across tracked sources (checked literal and `%20`-encoded paths).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 09:19:27 +00:00
Gordon Lam
334d1c8054 Validate cached installer filename from UpdateState.json in the updater (#48741)
## Summary of the Pull Request

`PowerToys.Update` reads `downloadedInstallerFilename` from the
persisted `UpdateState.json` and combines it with the `Updates` folder
to locate the installer to run. If that cached state is stale,
corrupted, or otherwise unexpected, the stored value could contain path
separators or an absolute path, which would make the updater look for
the installer outside the `Updates` folder.

This PR validates that the cached value is a plain filename and that the
resolved path stays inside the `Updates` folder before using it;
otherwise the update is treated as unavailable. The normal update flow
(a bare asset filename produced by the download step) is unaffected.

## PR Checklist

- [ ] **Communication:** I've discussed this with core contributors
already.
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** No end-user-facing strings added
- [x] **Dev docs:** N/A
- [x] **New binaries:** None

## Detailed Description of the Pull Request / Additional comments

- The filename check is factored into an inline helper
`updating::IsSafeDownloadedInstallerFilename` in
`src/common/updating/updateLifecycle.h` (next to the other inline update
helpers) so it can be unit-tested without a project reference.
- `ObtainInstaller` in `src/Update/PowerToys.Update.cpp` now calls that
helper and additionally confirms, via `weakly_canonical`, that the
resolved installer path's parent is the `Updates` directory.
- No behavior change for normal installer filenames, so the regular
update flow does not regress.

## Validation Steps Performed

- Added `IsSafeDownloadedInstallerFilenameTests` to `Updating.UnitTests`
covering normal filenames, empty values, parent-directory components,
nested path components, and absolute/drive-relative/UNC paths.
- Built `Updating.UnitTests` (Debug x64): 0 warnings, 0 errors.
- Ran the full `Updating.UnitTests` suite: 36/36 passed (30 existing + 6
new).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 15:01:25 +08:00
Niels Laute
5c16c97db5 [Settings] Fix FancyZones page scroll bounce at Excluded apps (#47937)
## Summary

Fixes #25353 — the FancyZones Settings page bounces / jumps when the
user scrolls down to the bottom (the **Excluded apps** expander).
Several closed dupes report the same behavior: #31500, #34259, #30164,
#45173, #32099, #32361.

## Root cause

The Excluded-apps `TextBox` (lines 283-305 of `FancyZonesPage.xaml`)
forced its own inner `ScrollViewer` to be permanently enabled with a
visible scrollbar, nested inside the page-level `ScrollViewer` provided
by `SettingsPageControl`:

```xml
ScrollViewer.IsVerticalRailEnabled="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Enabled"
```

The expander is `IsExpanded="True"` and sits at the very bottom of the
page, so when you wheel-scroll down the page the pointer ends up over
the TextBox. The TextBox''s inner scroller intercepts the wheel events;
when it has nothing left to scroll the event bubbles back to the outer
page scroller, which tries to over-scroll past content end. The result
is the bounce/jump visible in the videos on the issue.

The unbounded `MinHeight="160"` (with no `MaxHeight`) made it worse,
because the box can grow as users type, triggering layout re-measures
during scrolling.

## Fix

Minimal change to the same TextBox:

- Drop `ScrollViewer.IsVerticalRailEnabled` and
`ScrollViewer.VerticalScrollMode` — `AcceptsReturn="True"` already wires
up the inner scroller correctly.
- Change `ScrollViewer.VerticalScrollBarVisibility` from `Visible` to
`Auto`, so the inner scroller only competes with the outer one when
there is actual overflow to scroll.
- Add `MaxHeight="320"` so the box cannot keep growing as the user
types.

## Validation

- Builds clean (`tools\build\build.cmd` from
`src\settings-ui\Settings.UI`, arm64 Debug, exit 0, 0 errors).
- The same nested-scroller pattern exists on 9 other Settings pages
(AlwaysOnTop, GrabAndMove, MouseUtils, MouseWithoutBorders, PowerAccent,
PowerLauncher, ShortcutGuide). Keeping this PR atomic to the page called
out in #25353; happy to follow up with a sibling PR for those if
reviewers want them in the same pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 14:35:13 +08:00
Boliang Zhang
a255ece641 [File Locksmith] Fix crash (0xc000027b) when a listed process's image file no longer exists (#48719)
## Summary of the Pull Request

`PidToIconConverter.Convert` called `Icon.ExtractAssociatedIcon(path)`
without a guard. When a running process's image path is non-empty but
the file no longer exists on disk, the call throws
`FileNotFoundException`. The converter runs per-row while the process
`ListView` virtualizes, so the exception reached
`App_UnhandledException` (which only logs and never sets `e.Handled =
true`) and WinUI 3 fast-failed the whole app (`0xc000027b`).

This is routinely triggered by self-updating software that deletes its
old versioned directory while the old process keeps running — e.g.
Windows Defender (`SenseAPZ`, `MsMpEng`, `MpDefenderCoreService` under
versioned `...\Platform\<ver>\` / `...\DataCollection\<ver>\` paths).
Right-clicking a drive root enumerates every process and reliably
includes such a stale-path process, so the crash is easy to hit in
normal use.

The fix wraps the icon extraction in a try/catch and falls through to
the existing placeholder `BitmapImage`, logging a warning — mirroring
the exception handling already present in `MainViewModel.WatchProcess`.

## PR Checklist

- [x] Closes: #48693
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass — no existing test harness
covers this WinUI converter path; validated manually (steps below)
- [x] **Localization:** All end-user-facing strings can be localized —
n/a; the only new string is a developer log warning, not end-user UI
- [x] **Dev docs:** Added/updated — n/a
- [x] **New binaries:** Added on the required places — n/a; no new
binaries

## Detailed Description of the Pull Request / Additional comments


`src/modules/FileLocksmith/FileLocksmithUI/Converters/PidToIconConverter.cs`:

```csharp
if (!string.IsNullOrEmpty(y))
{
    try
    {
        icon = Icon.ExtractAssociatedIcon(y);
    }
    catch (Exception ex)
    {
        // The process image path can be non-empty but no longer exist on disk
        // (e.g. self-updating software that deletes its old versioned directory while
        // the old process is still running). ExtractAssociatedIcon then throws and,
        // because this converter runs per-row during ListView virtualization, the
        // exception would otherwise reach App_UnhandledException and fast-fail the app.
        // Fall through to the placeholder icon instead of crashing.
        Logger.LogWarning($"Couldn't extract the icon for '{y}'. {ex}");
    }
}
```

(+ `using ManagedCommon;` — already a project reference; `Logger` is
used identically in `App.xaml.cs`.)

Scope note: this keeps to the targeted converter guard. I deliberately
did **not** also blanket-set `e.Handled = true` in
`App_UnhandledException`, since that would mask unrelated genuine
crashes; the converter guard fully addresses this crash.

## Validation Steps Performed

1. Reproduced on the installed 0.100 build: right-click `C:\` → **Unlock
with File Locksmith** → scroll the list → crash (`0xc000027b`, faulting
module `Microsoft.UI.Xaml.dll`; the FileLocksmith log shows an unhandled
`FileNotFoundException` for `...\SenseAPZ.exe` in
`MainPage...ProcessBindings` / `PidToIconConverter`). Reproduced twice.
2. Built `FileLocksmithUI` (x64/Release) with the fix — 0 warnings / 0
errors.
3. Ran the produced exe on `C:\` and scrolled ~40× over the same list
(which includes the stale `SenseAPZ` row):
   - No crash; the process stayed alive and responsive.
- The log shows the new warning firing for the exact `...\SenseAPZ.exe`
path, confirming the catch branch executed on the previously-fatal row.
   - 0 unhandled exceptions in the session.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 14:33:06 +08:00
Clint Rutkas
106c970c8c Fix full rebuild: upgrade CalculatorEngineCommon to C++20 coroutines (#48790)
Remove _SILENCE_EXPERIMENTAL_COROUTINE_DEPRECATION_WARNINGS and upgrade
LanguageStandard from stdcpp17 to stdcpp20 so that <coroutine> is used
instead of the removed <experimental/coroutine> header on VS 2026.

<img width="946" height="348" alt="image"
src="https://github.com/user-attachments/assets/53392fd8-1a81-4852-9913-d84575f2f3e1"
/>

was part of https://github.com/microsoft/PowerToys/pull/48102 prior

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 00:16:59 +01:00
Mike Griese
ff8c1dbf85 Dock: Add a teachingtip to docks while pinning (#48726)
When you're pinning something to the dock with the dialog, I have _no_
idea what display is 1,2,3,4. That's meaningless to me.

This attempts to resolve that by adding a teachingtip to each dock while
pinning. When we open that pin to dock dialog, we'll display the
teachingtips, and dismiss them when the dialog is closed.

That way folks have at least some indication of where each display is
when pinning.
2026-06-22 16:54:55 -05:00
Michael Jolley
cd7465e22a CmdPal: Refactor TopLevelCommandManager to use IExtensionService implementations (#48417)
## Summary

The `TopLevelCommandManager` handles **alot.** And by "alot" I mean too
much. In preparation for future types of extensions, this PR attempts to
pull out the methods for loading/managing extensions to individual
`IExtensionService`s.

These `ExtensionService`s will be injected the `TopLevelCommandManager`
via dependency injection. It will iterate through them asking them to
load their extensions. During that process, they will surface
`ICommandProvider`s back to the `TopLevelCommandManager` for display in
Command Palette.

Currently, there are two types of `IExtensionService`s:
`BuiltInExtensionService` and `WinRTExtensionService`.

- The `BuiltInExtensionService` receives all `ICommandProvider`s
registered with DI.
- The `WinRTExtensionService` manages out-of-process WinRT AppExtension
providers.

## Additional Changes

- **Circular DI dependency resolved**: `BuiltInsCommandProvider` no
longer depends on `IRootPageService`.
Previously, it required the `IRootPageService` solely for the dock
command to open Command Palette (using the RootPage as its command.)
Now, it uses a new `GoHomeDockCommand` which returns
`CommandResult.GoHome()` with the existing `onBeforeShowConfirmation`
callback to show the palette at the dock button position.
  
 Also, fixes #48643

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 16:51:12 -05:00
Niels Laute
502dc40aa4 [Shortcut Guide] Prevent overlay crash on section navigation (#48448) (#48481)
## Summary of the Pull Request

Shortcut Guide overlay crashes and closes when navigating between
sidebar sections (e.g. clicking PowerToys, then clicking the Windows
icon to come back). Repro and crash logs in #48448. Crash logs in #48441
show the same propagation path plus a follow-up access violation in
coreclr, indicating exceptions that escape local catches.

This PR fixes the immediate navigation race and adds broader crash
hardening so future exceptions on the UI/background threads are logged
instead of tearing down the overlay.

### Navigation-race fix (commit 1)

Root cause: `WindowSelector_SelectionChanged` calls
`App.TaskBarWindow.Activate()` and then `SetWindowPosition()`
synchronously. `Activate()` runs a reentrant `Window_Activated` →
`BringToFront` → `TaskbarWindow.Activated` chain that can leave
`App.TaskBarWindow.AppWindow` momentarily null, so `SetWindowPosition`
throws `NullReferenceException`.

Because the initial `SelectedItem = MenuItems[0]` is set from
`SetNavItems`, the NRE bubbles up into `InitializeNavItemsAsync`'s catch
block — which sets `_closeType = "InitializationFailed"` and closes the
window. That matches both user-visible symptoms: the overlay "flashes
and disappears" (#48441) on open and "closes when clicking the Windows
icon" (#48448).

Edits in
`src/modules/ShortcutGuide/ShortcutGuide.Ui/ShortcutGuideXAML/MainWindow.xaml.cs`:

- **`SetWindowPosition`**: null-guard `App.TaskBarWindow?.AppWindow` and
skip the taskbar-overlap height adjustment when it is not currently
observable. Wrap the body in `try`/`catch` with `Logger.LogError` so any
future positioning hiccup keeps the previous layout instead of taking
down the overlay.
- **`WindowSelector_SelectionChanged`**: null-guard
`App.TaskBarWindow?.Hide()` / `Activate()` and wrap the body in
`try`/`catch`. This breaks the propagation path that lets a navigation
exception reach `InitializeNavItemsAsync`'s "fatal init failure" branch.

### Crash hardening (commit 2)

Additional defensive changes to cover other unguarded paths surfaced
while reviewing #48441:

- **`App.xaml.cs`**: register `App.UnhandledException`,
`AppDomain.CurrentDomain.UnhandledException`, and
`TaskScheduler.UnobservedTaskException` so a stray exception (e.g. an IO
failure during a fire-and-forget UI handler, or a background `Task`
fault) gets logged instead of tearing the process down with an access
violation in coreclr. Mirrors what Peek, AdvancedPaste, and CmdPal
already do.
- **`App.OnLaunched`**: wrap the launch sequence in `try`/`catch` and
exit cleanly with an error log on failure (`LoadData` / `MainWindow` /
`TaskbarWindow` ctors and `Activate` are all reachable failure points).
- **`App.LoadData`**: broaden the `Pinned.json` deserialize catch to
also handle `IOException` / `UnauthorizedAccessException`, and guard the
round-trip `SaveSettings` call as best-effort with a warning log.
- **`PinnedShortcutsHelper.Save`**: catch `IOException` /
`UnauthorizedAccessException` / `JsonException` and log; `Pin` / `Unpin`
runs from a synchronous UI handler so an unguarded `File.WriteAllText`
would tear down the overlay on any disk hiccup.
- **`TaskbarWindow.UpdateTasklistButtons`**: move the `AppWindow.Move`
calls inside the existing `try` block, null-guard
`App.MainWindow?.AppWindow` up front, and wrap the whole body so the
method (which runs from the ctor and from `Activated`) cannot tear the
overlay down when `MainWindow` is in a transient state.

## PR Checklist

- [x] Closes: #48448
- [x] Likely also fixes: #48441
- [x] **Communication:** Defensive fix to known crash paths; no API
change.
- [ ] **Tests:** No automated tests added — the failures are reentrancy
/ timing races that are hard to deterministically trigger in CI.
Validated with a synthetic repro (see below).
- [x] **Localization:** N/A — only logger strings.
- [x] **Dev docs:** N/A
- [x] **New binaries:** N/A

## Detailed Description of the Pull Request / Additional comments

The fix is intentionally defensive (rather than restructuring the
reentrant activation flow) because the legacy taskbar UIA enumeration
(`TasklistPositions.GetButtons`) on Windows 10 is what most reliably
widens the race window and is out of scope to redesign for a hotfix.

## Validation Steps Performed

- Build: `tools\build\build.cmd` from
`src\modules\ShortcutGuide\ShortcutGuide.Ui` — exit 0, errors log empty
for both commits.
- Synthetic repro: temporarily injected `throw new
NullReferenceException()` at the top of `SetWindowPosition` to exercise
the exact propagation path the reporter's log shows (`SetWindowPosition`
→ `SelectionChanged` → `set_SelectedItem` →
`InitializeNavItemsAsync.catch` → `Close("InitializationFailed")`).
- Before fix: overlay flashes and closes, log shows `Failed to
initialize navigation items.` with the NRE.
- After fix: overlay stays open, page navigates, log shows `Failed to
set Shortcut Guide window position; keeping previous layout.` from the
new `catch`.
- Did not reproduce the live race on a Win11 dev box; the reporter's
repro is Windows 10 19045 / Microsoft Store install where the legacy
taskbar UIA timing makes the reentrant chain more likely to expose the
null.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 11:00:25 +02:00