mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-08-29 10:09:43 +02:00
1a6a5e57b6e539d4512e957b992aba3a543c8362
9575 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3079a3c546 |
[EnvironmentVariables] Validation fixes, centralised validation, error message improvements (#46837)
## Summary of the Pull Request This fixes several critical validation issues with the Environment Variables utility, centralises the validation, guards registry writes, and improves error messages for validation failures. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #46763 <!-- - [ ] 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 - [x] **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 This PR fixes a reported critical vulnerability (#46763) where creating an environment variable with an equals sign in the name reportedly caused Windows to crash and enter a boot loop upon restarting. During the investigation of the issue, several other environment variable constraints were identified as missing, including there being no prevention of leading or trailing spaces in names (meaning variables could not be typed on the command line), no combined length checks and so on. This PR introduces a centralised, robust validation pipeline for UI and registry writes to prevent entering states which could corrupt the Windows environment block. ## Changes ### Centralised validation logic - All environment validation is now inside EnvironmentVariablesHelper.cs, rather than split between this code and the UI. - Both the UI (via model validate bindings) and backend registry writes now strictly evaluate against the same unified ruleset before applying changes or enabling/disabling controls. - Existing methods have been updated to report back their success or failure, to enable errors to be tracked more effectively. ### Blocked OS-breaking characters - In response to the user report, the equals character is now blocked from both Variable and Profile names. `=` being disallowed is [explicitly mentioned](https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables) in the Environment Variables Win32 documentation, so it's a surprise it wasn't caught previously. - All control characters (including `\0`, `\r` and `\n`) are also disallowed, both to protect the integrity of the environment block and the rendering of the strings in the UI. - Leading and trailing whitespace is rejected to prevent orphaned variables. ### Enforced Windows length constraints - Variable Names and Profile Names are restricted to 259 characters, to match the 260-character null-terminated string length limit in the Windows Environment Variables Editor (via sysdm.cpl) and RegEdit. To be clear: profile names may technically be longer, but we should choose to abide by this authoring tool limit to maintain compatibility with other editors. There was previously a 255-character limit on names in the code, and a comment indicating this was a registry limit, but that was incorrect and has been removed. The new limit constant is `MaxEnvironmentVariableNameAuthoringLength`. - In the prior code, there was no limit on the length of system variable names. This was incorrect. The limit for both System and User name fields is now the identical at 259 characters. - There is a length limit on the full environment variable entry `[VariableName]=[VariableValue]\0`, which is 32766 characters plus the null-terminator. This is now enforced and the constant is `MaxTotalEnvironmentVariableLength`. (There's no imposed limit on the number of environment variables.) ### Fixed User Profile backup "overflows" - Fixed a bug where a user could create a valid Profile Name and a valid environment variable name, but applying them would silently fail to apply the profile because the generated backup variable name `[VariableName]_PowerToys_[ProfileName]` exceeded the previous authoring limit of 255 characters. - Backup variables are excluded from the 259-character limit, as they are internal to the application, but the combined `[VariableName]=[VariableVavlue]\0` length is still strictly constrained to the 32767 environment variable length limit. There are now separate paths through the code to deal with backup variable persistence and validation. ### UI - If an applied user profile's name is now rejected because of the new rules (e.g. it contains `=`), the UI now shows a specific "Profile name is invalid" warning rather than the generic "not applicable" message from before, allowing the user to identify and fix the problem. - Fixed a small issue in the Add New Variable dialog where a vertical scrollbar was always present. There are other cases where this occurs, too, but I've left them for a future PR. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed New unit tests project added with coverage of the new validation functionality. Also, manual testing... Manual validation of each dialog: - Add variable - Edit variable - Add variable via Profile Edit dialog Test against: - `=` being in either the Variable Name or the Profile Name - A control character being present in the Variable Name or Profile Name - Either the Variable Name or Profile Name containing one or more trailing or leading whitespace characters - The length of the Variable Name being longer than 259 characters - The combined length of name + `=` + value being longer than 32766 characters The dialog tests can be confirmed by checking to see if the Save button is enabled: <img width="1099" height="843" alt="image" src="https://github.com/user-attachments/assets/685e561a-bd8d-4926-b9b2-a61dea4cc96a" /> Also confirm: - An invalid Profile Name is caught. This can be confirmed by: Editing the JSON file and adding an `=` character in the name: <img width="497" height="197" alt="image" src="https://github.com/user-attachments/assets/c6aa5d62-0672-499a-aac4-c639e8158b61" /> Then opening the application and trying to enable the profile: <img width="1117" height="371" alt="image" src="https://github.com/user-attachments/assets/bd887a44-5e65-4750-9c6f-9bf1b82a5ad6" /> Also confirm that in the Edit profile dialog, you can enable the profile, but the Save button is disabled: <img width="688" height="603" alt="image" src="https://github.com/user-attachments/assets/10d186d9-17a0-4210-93e3-23b1e2723f5f" /> - Confirm that control characters cannot be part of the Variable Name: First, run this from PowerShell, which adds a string containing the newline character to the clipboard: ```pwsh Set-Clipboard -Value "MyVar`nName" ``` Open the Add or Edit variable dialog and paste the value into the Name field. Confirm that the character is not pasted and the string truncates before it: <img width="1424" height="732" alt="image" src="https://github.com/user-attachments/assets/260ff728-57a2-438f-bb66-08d32a327b64" /> (For the null character specifically, use `Set-Clipboard -Value ("MyVar" + [char]0 + "Name")`.) - The initial dialog button state. Re-open the Add New variable dialog multiple times and confirm the Save button is disabled each time before making any input. - In the Add/Edit Variable dialogs, enter a valid variable name and then clear it, confirming that the Save button enables and disables correctly. ## Still outstanding There are some flaws I've found which I'm choosing to leave for now, mainly for expedience so the above issues can be prioritised: - Handling duplicate profile names - there is the potential there for duplicate variable names under identically-named profiles to conflict. - Profile JSON import is still not sanitised. These should be added in a future PR. |
||
|
|
1703e7ac09 |
[Build] Fix UTF-8 and output paths for local C++ builds (#49575)
## Summary of the Pull Request Fixes two local C++ build reliability problems: - Compiles all PowerToys C++ projects as UTF-8 through `Cpp.Build.props`, so builds do not depend on the active Windows code page. On code page 936, UTF-8 punctuation in BOM-less source files otherwise triggers C4819 and fails the build because warnings are treated as errors. - Uses `$(RepoRoot)` for Keyboard Manager repository paths and standardizes native/test output directories. This makes direct project builds find the resource conversion script and headers, places the Editor wrapper beside the WinUI app, and keeps the Engine test DLL under the repository test output directory. No runtime logic, end-user strings, dependencies, or binaries are added. ## PR Checklist - [x] Closes: #49573 - [x] Closes: #49574 - [x] **Communication:** Discussed the shared UTF-8 policy with a PowerToys collaborator in this PR - [x] **Tests:** Existing Keyboard Manager Engine tests pass; no new tests are needed for project-only changes - [x] **Localization:** No end-user-facing strings are changed - [x] **Dev docs:** No documentation changes are required for project configuration fixes - [x] **New binaries:** No new binaries are added - [x] **Documentation updated:** No user documentation changes are required ## Detailed Description of the Pull Request / Additional comments `Directory.Build.props` imports `Cpp.Build.props` for C++ projects. Defining `/utf-8 %(AdditionalOptions)` in its shared `ClCompile` settings makes source decoding deterministic across the native codebase and prevents future BOM-less UTF-8 source files from reintroducing the same locale-dependent failure. `/utf-8` explicitly sets both the source and execution character sets instead of suppressing C4819 or replacing valid Unicode text. `$(SolutionDir)` is only reliable when MSBuild is invoked through a solution. The repository's local build script builds `.vcxproj` files directly from their project directories, where `$(RepoRoot)` is the stable repository root property. The wrapper output now follows the existing `$(RepoRoot)$(Platform)\$(Configuration)\WinUI3Apps\` pattern used by other native WinUI dependencies. ## Validation Steps Performed All successful builds used the repository build scripts with `-Platform x64 -Configuration Debug`. - Ran `tools/build/build-essentials.cmd`: solution restore, Runner, and Settings all succeeded with empty errors logs. - Built `FancyZonesLib` successfully after it had failed with a resource-related CL exit during a full parallel build. - Built `WorkspacesModuleInterface` successfully, validating that existing UTF-16 BOM headers remain compatible with the shared option. - Built `ZoomItBreak` and `ZoomIt` successfully. - Built `KeyboardManagerEngineTest` successfully. - Built `KeyboardManagerEditor` and `KeyboardManagerEditorUI` successfully after the documented essentials prerequisite. - Confirmed the successful native build logs contain `/utf-8` compiler invocations and all corresponding `build.debug.x64.errors.log` files are empty. - Ran `vstest.console.exe` against the Keyboard Manager Engine test assembly: 103/103 passed. - Confirmed `PowerToys.KeyboardManagerEditorLibraryWrapper.dll` is emitted to `x64/Debug/WinUI3Apps`. - Confirmed `KeyboardManager.Engine.UnitTests.dll` is emitted to `x64/Debug/tests/KeyboardManagerEngine`. - Previously manually verified the x64 Debug PowerToys build can open Keyboard Manager Editor without 0x8007007E. A full `PowerToys.slnx` x64 Debug build was attempted twice. The first attempt exhausted the remaining 62 MB of disk space. After clearing 52.46 GB of ignored build outputs, the second attempt still exceeded the machine's temporary disk/commit limits (`CL.exe` exit `0xC000012D` and an out-of-space cppwinrt write). Before that resource failure, the log contained 4,642 `/utf-8` command entries and no character-set diagnostics. The full configuration matrix is left to PR CI rather than bypassing normal build settings locally. --------- Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> |
||
|
|
6bb16d014b |
[Settings][Image Resizer] Edit/add presets in a ContentDialog instead of a Flyout (#49161)
## Summary of the Pull Request Replaces the inline preset-edit **Flyout** on the Image Resizer settings page with a **ContentDialog**, matching the add/edit pattern already used on the **Color Picker** page. This aligns the experience with the Windows 11 / Fluent paradigm and fixes preset settings being saved on every intermediate change. Editing now happens on a **working copy** of the preset (`ImageSize.Clone()`), which is committed only when the user presses **Save/Update**. As a side effect, the intermediate width/height spinner changes no longer persist `settings.json` / `sizes.json` on every value change — resolving #36938. The per-row **delete** action moves from an inline trash button into a **"..." (More options)** `MenuFlyout`, again matching the Color Picker page. Historically this editing was a Flyout rather than a ContentDialog due to known `ContentDialog` / `XamlRoot` issues back when Settings was a UWP app. Now that Settings is on WinUI 3 / Windows App SDK, `ContentDialog` works reliably (as Color Picker's `ColorFormatDialog` demonstrates), so the original constraint no longer applies. https://github.com/user-attachments/assets/bf71b0a9-c3f8-4078-95c7-c7ee9dc7b24b ## PR Checklist - [x] Closes: #49157 - [x] Closes: #36938 - [ ] **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 (added to `Resources.resw`; reused existing keys for the delete menu) - [ ] **Dev docs:** Added/updated - [x] **New binaries:** None added ## Detailed Description of the Pull Request / Additional comments - **Dialog:** Clicking a preset card (or **Add new size**) opens an `EditSizeDialog` `ContentDialog`. Fields are bound with compiled `{x:Bind}` against a working-copy `EditingSize`. The dimensions field header is dynamic — **"Width"** when height is used, **"Size"** for aspect-ratio-preserving percentage scaling — so the label isn't misleading. The dialog is widened for a less cramped layout. - **Save semantics:** - `ImageSize.Clone()` — builds the editable working copy. - `ImageResizerViewModel.CreateNewImageSizeModel()` — builds a default-valued model for the add dialog without adding it to `Sizes`. - `ImageResizerViewModel.AddImageSize(ImageSize)` — commits a new preset with the next unique ID. - `ImageResizerViewModel.UpdateImageSize(original, updated)` — applies edited values back onto the original, temporarily detaching the per-item `PropertyChanged` save handler so it persists **once** instead of on every property. This is what fixes the "saved too often" behavior in #36938. - **Delete:** per-row `Button` → `MenuFlyout` with a Delete `MenuFlyoutItem`; the `ImageSize` is passed via `CommandParameter="{x:Bind}"` (robust inside a flyout popup) and the Yes/No confirmation dialog is preserved. ## Validation Steps Performed - Built `PowerToys.Settings` (x64/Debug) — clean (exit 0). - Ran the runner from this build and manually validated in Settings → Image Resizer: - **Add new size** opens the dialog pre-filled; Save adds the preset; Cancel discards. - **Editing** a preset in the dialog and pressing Cancel leaves the original untouched (working-copy clone). - Selecting **Percent** shows the **Size** header (not a misleading "Width"). - Spinning width/height inside the dialog no longer writes settings files on each change; a single save occurs on Update (#36938). - The **"..."** menu shows **Delete**, with the confirmation dialog intact. --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> |
||
|
|
d04ebff5e7 |
CmdPal: Use RepoRoot instead of SolutionDir (#49643)
As it turns out, the robots are unbelievably stupid. When they build our projects to verify their changes, they will often just build the .csproj that they changed rather than building it in the context of the solution. On the surface, this feels like a good idea. Only build the thing that changed. However, because they're not building it in the context of a solution, the MSBuild variable `$(SolutionDir)` doesn't get expanded to the actual directory of the solution. Instead, it just gets treated as the *path to the project*. This creates terrible recursive loops where the output of a project gets dumped relative to the project itself, and then that gets taken as input to the project's package outputs, and eventually you're gonna end up with a max path overrun. The very easy solution here is to just replace `$(SolutionDir)` with `$(RepoRoot)`. If we use that variable, then the dumb robots will still get the correct value for that variable when they build just a project. And for all the actual humans, everything will work exactly as it did before. |
||
|
|
10236ee8c7 |
[Quick Accent] Fix the accent bar's blank first frame and its under-measured width (#49633)
## Summary of the Pull Request Two defects in the WinUI 3 Quick Accent selector. They look unrelated but share a root: the overlay owns no layout of its own, so `MainWindow` sizes and shows it by hand — and both halves of that hand-rolled logic rest on an assumption that does not hold. * **#49489** — the bar appears blank, too wide and clipped on the right for a few frames, then snaps into place. A hidden WinUI 3 window renders nothing, so `ShowWindow(SW_SHOWNA)` puts the HWND on screen before the freshly rebuilt accent list has ever been laid out. * **#49488** — the window is sized narrower than its own content whenever a glyph is wider than the 48 DIP cell, so the list silently scrolls inside it and the trailing accents are pushed against the right edge. test result: https://github.com/user-attachments/assets/80d57aa8-5030-46c3-9ec8-6ed05ed00f03 ## PR Checklist - [x] Closes: #49489 - [x] Closes: #49488 - [x] **Communication:** bug fixes for two open, triaged issues in an existing module; no new feature surface - [x] **Tests:** added — 11 cases in `PowerAccent.Core.UnitTests` covering the new `Calculation.GetToolbarWidth`; the existing positioning/DPI suites are unaffected - [x] **Localization:** no new end-user-facing strings - [ ] **Dev docs:** N/A — the *Toolbar Sizing and Reveal* section was dropped from this PR; the reasoning lives in the code comments and in the commit messages instead - [x] **New binaries:** none — no new projects or outputs, so no `ESRPSigning_core.json`, `Product.wxs`, CI or release YML changes are needed - [ ] **Documentation updated:** N/A — internal rendering/layout fix with no user-facing behavior change beyond the bugs going away ## Detailed Description of the Pull Request / Additional comments ### #49489 — the blank, over-wide, clipped first frame The window is never actually repositioned or resized. Measuring the two frames in the issue shows the same HWND rect in both: identical left edge, and the bad frame's hard right cut sits exactly where the good frame's rounded corner plus its 24 DIP margin ends. What changes is the **content** — it is composed once from a stale layout, then re-laid-out. Two ordering problems produced that stale composition: 1. `TransientSurface` is `Collapsed` while hidden and is only flipped to `Visible` from the `Showing` event, which `TransparentWindow.RaiseShow` raises **after** `ShowWindow(SW_SHOWNA)`. The accent bar's subtree therefore provably has not been measured or arranged at the moment the HWND becomes visible. 2. The hide path called `ViewModel.Characters.Clear()` synchronously right after `Hide()` — but `Hide()` only *queues* the dismissal, so the still-visible window rendered an empty bar at the old width. That empty card is exactly what the next summon put back on screen. The fix mirrors what the WPF implementation did for the same symptom in #46593 (render off screen, then `SetWindowPos` into view), adapted to WinUI 3 where a hidden window does not render at all: * Show the bar with `Selector.Opacity = 0`, lay it out, and unveil it once `CompositionTarget.Rendering` confirms a couple of frames have elapsed. `Opacity = 0` still renders (unlike `Visibility.Collapsed`), which is exactly what is needed here. A 150 ms timeout backs it up — not because frames stop arriving (attaching a `Rendering` handler forces the UI thread to run every frame) but because the tick cadence carries no guarantee and can stop for a locked or fully occluded session; on that path the bar simply appears the way it used to, so it can never get stuck invisible. * Size the bar **twice** per summon: once before `Show`, and again after the first real layout pass. The first measurement runs while the surface is still `Collapsed` and, on the first summon of the process, before its template has ever been applied, so it can report less than the items need. The correction happens while the bar is still transparent, so it is never seen as a resize. * Leave the characters in the list on hide. The next summon clears and refills them anyway, and not clearing them removes the blank-bar frame at the source. * A generation counter drops a pending reveal when the summon is dismissed or superseded before its frame lands, and arming a new summon detaches the previous one's per-frame handler so it cannot unveil the new bar ahead of its own layout pass. ### #49488 — width derived from the item count instead of measured `MainWindow` computed the window width as `Characters.Count * 48`, while the XAML cell is `MinWidth="48"` — a *minimum*, not a fixed width. `ListViewItem` → `Grid MinWidth=48` with a `ContentPresenter Margin=12`, so a cell is `max(48, glyphWidth + 24)`: any glyph wider than 24 DIP (₹, ‰, ﷼, ៛, CJK fallbacks) grows its cell. With **All languages** selected, R and P each carry ~20 characters and the accumulated error is enough for the real content to overflow the window. The ListView's `ScrollViewer` (`HorizontalScrollMode="Enabled"`, `HorizontalScrollBarVisibility="Hidden"`) then absorbs the overflow invisibly, and `ScrollIntoView` starts scrolling a bar that should not scroll at all. The pre-migration WPF window used `SizeToContent="WidthAndHeight"` and only set `MaxWidth`, so the layout system measured the same item template and the window simply grew — which is why this never showed up before. `AppWindow` has no `SizeToContent` equivalent, and the migration replaced it with a constant model. Now: * `SelectorControl.MeasureContentWidthDip()` measures the list against an unbounded width and returns what the items actually need. Measuring explicitly, rather than reading a stale `DesiredSize`, addresses the concern recorded in the original comment: the bar is rebuilt on every summon while the window is still hidden, so no layout pass has run for the new items yet. * `Calculation.GetToolbarWidth()` — a pure function, hence the unit tests — floors that measurement at `itemCount * minItemWidth` (every cell is at least the minimum, so a list that could not be measured reports 0 and safely falls back to the old estimate instead of collapsing the bar), applies the description row's minimum width, and clamps to the display's usable width so long character sets still scroll on purpose. * The clamp's lower bound is `minItemWidth + chromeWidth` — one cell plus the space around it, the narrowest bar that can still draw a glyph — and its upper bound is `Math.Max(minItemWidth + chromeWidth, maxWidth)`, because a display narrower than that floor would otherwise invert the bounds and make `Math.Clamp` throw. `DescriptionMinWidthDip = 648` masked this bug whenever the Unicode description row was on and the character set short, which is likely why #49402 (description-row width) did not surface it. ## Validation Steps Performed * `PowerAccent.Core`, `PowerAccent.UI` and `PowerAccent.Core.UnitTests` build clean (Debug|x64). * `PowerAccent.Core.UnitTests`: 32/32 pass, including the 11 `GetToolbarWidth` cases — narrow glyphs hug the item count, wide glyphs win over the count estimate (the #49488 regression guard), the measurement winning by a single DIP, a partly realized list keeping the item-count floor, an unmeasured list falling back to the estimate, over-long content clamping to the display maximum, the description row widening a short bar but not a long one, the description minimum losing to a narrower display, and both ends of the clamp. The lower clamp bound was verified by mutation: rewriting it to `Math.Clamp(width, 0, ...)` fails only `GetToolbarWidth_EmptyList_FallsBackToOneCellPlusChrome`. --------- Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e542b82a2a |
[PowerAccent] Forward key-up after false activation (#49644)
## Summary of the Pull Request Quick Accent passes the owner letter's key-down to the rest of the low-level keyboard hook chain. When activation is canceled before the configured threshold, trigger-key modes currently swallow the matching key-up. This leaves downstream keyboard state reporting the letter as held and causes Keyboard Manager's shortcut-to-shortcut safety check to reject later remaps. This change forwards the owner letter's key-up on that false-start path, balancing the event pair for downstream hooks and applications. Successful Quick Accent activation behavior is unchanged. Partial fix: #38089 ## PR Checklist - [ ] Closes - [ ] **Communication:** Root cause, deterministic reproduction, and validation were posted on #38089; awaiting core-contributor review - [ ] **Tests:** No automated low-level keyboard-hook test seam is available; extensive manual validation is documented below - [x] **Localization:** No end-user-facing strings changed - [x] **Dev docs:** No developer documentation changes are required for this targeted bug fix - [x] **New binaries:** No new binaries were added - [ ] **Documentation updated:** No user-facing documentation change is required ## Detailed Description of the Pull Request / Additional comments The false-start path runs when the owner letter is released before Quick Accent's activation threshold. Its key-down was already allowed through by `OnKeyDown`, but `OnKeyUp` returned `true` for the Space/arrow activation modes. Returning `true` from the low-level hook prevents later hooks and the target application from receiving the release. Keyboard Manager intentionally checks that no unrelated key is held before applying a shortcut-to-shortcut remap. The missing release therefore makes several remaps stop together while both PowerToys processes remain responsive. It also explains why locking and unlocking the Windows session restores them: the stale keyboard state is reset. The fix is intentionally in Quick Accent rather than relaxing Keyboard Manager's safety check, which must continue to reject remaps when unrelated keys are genuinely held. Full captured evidence and source analysis: https://github.com/microsoft/PowerToys/issues/38089#issuecomment-5171089872 ## Validation Steps Performed - Built `PowerAccentKeyboardService` from current `main` in Release x64: 0 warnings, 0 errors. Spectre mitigation was disabled for the local build because the corresponding Visual Studio libraries were not installed. - Built and installed the same change against PowerToys 0.100.2 so the test DLL matched the installed release ABI. - Repeated dozens of false activations with E/N/O/Y by pressing Space and releasing the owner letter before the 500 ms threshold. - Interleaved successful Quick Accent selections to verify normal activation still worked. - Captured `GetAsyncKeyState` transitions and confirmed both the letter and Space changed from down to up; all sampled keys remained up after testing. - Continuously tested a Left Shift+O -> Left Alt+Tab Keyboard Manager remap; it remained functional throughout. - Completed an additional user soak test without recurrence; locking/unlocking was no longer required. |
||
|
|
e141d172c8 |
Modify PR branch filters in CI configuration (#49646)
Commented out branch filters for PRs to allow CI on stacked PRs. |
||
|
|
e5c63b2ea4 |
Dock: Remove our last 1px gap once and for all (#49641)
I guess if you set ExtendsContentIntoTitleBar, well, WinUI will offset your island by x,y=0,1. That's what happens if you don't actually set any titlebar content. * https://github.com/microsoft/microsoft-ui-xaml/blob/main/dxaml/xcp/components/WindowChrome/CWindowChrome.cpp#L202 * https://github.com/microsoft/microsoft-ui-xaml/blob/main/dxaml/xcp/components/WindowChrome/CWindowChrome.cpp#L171 * https://github.com/microsoft/microsoft-ui-xaml/blob/main/dxaml/xcp/components/WindowChrome/inc/CWindowChrome.h#L23 cause like, of course it does. I'm sure there are previous threads to xlink this too |
||
|
|
97aeab4e96 |
[Shortcut Guide] Add support for Greenshot (#49407)
## Summary of the Pull Request Adds a Shortcut Guide manifest for **Greenshot**. - **New manifest:** `src/modules/ShortcutGuide/ShortcutGuide.Ui/Assets/ShortcutGuide/Manifests/Greenshot.Greenshot.en-US.yml`: 32 shortcuts for `Greenshot.exe`, grouped into five sections: * **Capture:** Capture region, Capture last region, Capture window, Capture fullscreen, Capture Internet Explorer tab * **While selecting a region:** switch region/window mode, select a child window element, toggle magnifier, confirm selection, cancel capture * **Editor - draw:** rectangle/ellipse/line/arrow/freehand/highlight/obfuscate/crop/text/selection tools, enlarge screenshot, crop to visible elements, paste image from clipboard * **Editor - text:** insert line break, delete previous word, select all text, finish editing * **Editor - export:** save, save as, copy image to clipboard, print, e-mail - **No code changes.** The manifest is auto-included via the existing `Manifests/*.yml` glob in `ShortcutGuide.Ui.csproj`. - `BackgroundProcess: true`, matching the bundled PowerToys-itself manifest, since Greenshot's core value is its global capture hotkeys, which work regardless of the currently focused window. - Introduces a `<PrtScn>` token for the Print Screen key (not previously needed by any bundled manifest, since Greenshot's capture shortcuts are all built around it) alongside the existing `<Space>`, `<Enter>`, `<Esc>`, `<Backspace>`, `<PageDown>` named-key tokens. ## PR Checklist - [ ] **Closes:** #ISSUE_NUMBER - [ ] **Communication:** discussed in the linked issue - [ ] **Tests:** N/A for data; relies on the existing manifest deserialization path - [x] **Localization:** all end-user-facing strings can be localized - [ ] **Dev docs:** N/A, no schema changes - [ ] **New binaries:** N/A - [ ] **Documentation updated:** N/A - [x] **Local run:** see issue screenshot ## Detailed Description of the Pull Request / Additional comments The Shortcut Guide displays per-app shortcuts from YAML manifests, matched to the foreground window (or shown continuously for background processes) via `WindowFilter`/`BackgroundProcess`. Adding support for an app is purely additive: drop a `<PackageName>.<locale>.yml` file in the `Manifests` folder and it's picked up by the existing build glob and index generator. - `PackageName: Greenshot.Greenshot` is the WinGet package identifier; `WindowFilter: "Greenshot.exe"` is the process name (confirmed against a signed 1.3.315 build). - `Name: Greenshot` is the display name shown in the Shortcut Guide app picker. - Shortcut names follow the repo's sentence-case convention (capitalize only the first word plus proper nouns/product names). - Five shortcuts are marked `Recommended`: Capture region, Capture last region, Capture window, Save, Copy image to clipboard — the capture and export actions used most often. - Shortcut source: Greenshot's official help page (https://getgreenshot.org/help/), cross-checked against the unofficial `defkey.com` reference. ## Validation Steps Performed - **Source fidelity:** every shortcut and modifier combination matches the official Greenshot help page one-to-one; no unofficial-source shortcuts were added without confirming them against the official page. --- Closes #49406 --------- Co-authored-by: Korb <korwin+git@pm.me> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Muyuan Li <116717757+MuyuanMS@users.noreply.github.com> |
||
|
|
1980ca5ece |
[Runner][Interop] Authenticate Settings/Quick Access named-pipe clients before dispatch (CWE-732/CWE-862) (#49527)
## Summary of the Pull Request
The Runner is the **server** for the two-way named pipes it uses to talk
to `PowerToys.Settings.exe` and the Quick Access host, and it dispatched
privileged JSON commands (`killrunner`, `restart_elevation`,
`module_status`, `powertoys`, `language`, ...) **without authenticating
the caller**. When PowerToys runs elevated ("Run as administrator"), the
pipe DACL grants the shared **Logon SID**, so **any same-user Medium-IL
process could connect and inject commands** — a local privilege
escalation (CWE-732 / CWE-862). The pipe DACL cannot distinguish the
legitimate Medium-IL Settings child from a same-user attacker (identical
user SID, integrity level, and logon session), so this PR authenticates
the connecting process's **binary identity** before any dispatch.
## PR Checklist
- [x] **Tests:** Added/updated and all pass (native gate tests + C#
regression)
- [x] **Localization:** No new end-user-facing strings (only a
diagnostic runner log line)
- [x] **New binaries:** None — the new code compiles into the existing
`PowerToys.Interop` and `runner` binaries; tests were added to the
existing `Common.Utils.UnitTests` project
## Detailed Description of the Pull Request / Additional comments
New `src/common/interop/pipe_caller_auth.{h,cpp}` adds
`interop_auth::AuthenticateClient`, invoked from
`TwoWayPipeMessageIPC::handle_pipe_connection` **before** a message is
queued (fail-closed). A connecting client is accepted only if it is:
- under the **Runner-relative install directory**
(`get_module_folderpath()\WinUI3Apps`, so it adapts to installed and
dev-build layouts),
- an **allow-listed basename** (`PowerToys.Settings.exe` /
`PowerToys.QuickAccess.exe`),
- the Runner's **exact file version** (anti-downgrade), and
- **Microsoft Authenticode-signed**.
The signature is anchored to the **LOCAL MACHINE root store**
(`HCCE_LOCAL_MACHINE` +
`CertVerifyCertificateChainPolicy(AUTHENTICODE)`) rather than
`WinVerifyTrust`'s default user+machine union: the Runner runs as the
same user as a potential attacker and would otherwise trust a forged
signer added to `CurrentUser\Root`. Verdicts are cached per `(pid,
process-creation-time, policy)` with a short TTL so the check isn't
re-run on every message (each `send` opens a new connection). Rejections
are logged.
The gate is added via an **additive** `start(HANDLE, CallerPolicy)`
overload; the managed `start(nullptr)` path is unchanged (gate
disabled), so there is **no ABI break** to `PowerToys.Interop`.
`PIPE_REJECT_REMOTE_CLIENTS` is also set. In **Debug** builds only the
signature check is relaxed (directory/basename/version stay enforced) so
local unsigned builds still connect; the relaxation is compiled out of
Release.
**Scope:** this PR covers the two elevated Runner-server pipes (Settings
+ Quick Access), which are the actual EoP surface. The reverse
Runner->Settings response direction, the duplicated Workspaces
transport, and the AdvancedPaste/PowerDisplay module pipes are
intentionally out of scope and can be handled as follow-ups.
## Validation Steps Performed
**Automated**
- **Native unit tests** (`Common.Utils.UnitTests`,
`PipeCallerAuthTests`): legitimate self-caller accepted; wrong
basename/directory rejected with the reject-log callback firing; version
reading. 6/6 pass.
- **C# regression** (`Microsoft.Interop.Tests.TestSend`): managed
gate-disabled round-trip still works.
- **Builds:** runner Debug + Release, `PowerToys.Interop` Debug +
Release, and the test project all build/link clean.
**Official signed build (validates the Release-only signature path that
local Debug builds skip)**
- Queued the internal "PowerToys Signed YAML Release Build" for this
branch — **green** (`result: succeeded`). The produced installers are
Authenticode `Valid`, signer `Microsoft Corporation`.
**Manual testing on the signed installer (elevated Runner) — passed**
- Installed the signed build and ran the Runner **as administrator**.
Settings and Quick Access open and are fully functional; settings apply,
module toggles work, and the hotkey-conflict request/response
round-trips.
- **No** `Rejected unauthenticated ...` lines during legitimate use →
the genuine signed `PowerToys.Settings.exe` is accepted by the
machine-root signature + version + directory checks (verified in
`RunnerLogs\runner-log_*.log`, requests dispatched normally).
- **Security (negative) check:** a non-elevated `powershell.exe`
discovered the runner pipe via the pipe namespace and attempted
`{"killrunner":true}`; the write failed ("Pipe is broken") because the
Runner rejected the caller and disconnected before dispatch.
`PowerToys.exe` stayed running and logged: `Rejected unauthenticated
Settings pipe client: pid=... image='...\powershell.exe'
reason=bad-directory`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1d8f85ec-aaee-468a-9348-ba79b059cbaf
|
||
|
|
ba2e89c428 |
PowerDisplay: Fall back to persisted VCP values when a monitor read fails (#49445)
## Summary of the Pull Request On a monitor whose DDC/CI engine answers intermittently, every discovery pass starts from nothing. A panel that reported its brightness a minute ago can lose that control — or drop out of the flyout entirely — because one pass happened to fail. This persists every range-valid VCP value read off a monitor, keyed by its canonical DevicePath. In Maximum compatibility mode a later discovery falls back to that value when the hardware will not answer. Scope is intermittent failure, not permanent failure: the cache can only replay a value the hardware answered at least once, so a panel that never reads a code successfully sees no change. This partially addresses #49342. ## PR Checklist - [x] Closes: #49342 - [ ] **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 — this PR adds none - [ ] **Dev docs:** Added/updated - [x] **New binaries:** Added on the required places — none added, so no signing JSON, installer WXS or CI YML change is required - [ ] **Documentation updated** ## Detailed Description of the Pull Request / Additional comments ### What is stored `MonitorStateManager` implements `IKnownGoodVcpStore`, so the cache rides in the existing `monitor_state.json` next to the user's saved brightness rather than in a new file. Each entry is a `KnownGoodVcpFeature`: code, current, maximum, and when it was last read. Only range-valid observations are stored, so the common `current=0 / max=0` garbage reply never enters — it fails `VcpFeatureValue.IsValid`. Writes are not gated on Maximum compatibility mode, only reads are. A monitor that reads cleanly today can start failing after a cable or dock change, and a lazily populated cache would be empty on exactly the first pass that needs it. ### How a cached value is used `VcpDiscoveryEvidence.Reconcile` gains the cache as a third source alongside the parsed capabilities string and this pass's probe: | this pass | cache | result | | --- | --- | --- | | read succeeded | — | live value wins, cache refreshed | | replied, range unusable | hit | cached value applied, `MonitorReadFlags` left clear | | no reply | hit | cached value applied, `MonitorReadFlags` left clear | | code never probed (caps parsed) | hit | value applied only after one live read is attempted | The last row matters: on the caps-parsed path nothing has confirmed the cached value this pass, so the hardware is asked first. On the probe path it has already been asked, and re-reading would be pure I2C noise. `MonitorReadFlags` stays clear for anything the hardware did not answer, so a cached value never masquerades as an observation — which #49577 depends on, since it made the restore path write whenever the flag is unset. One consequence is worth naming: the flyout draws a slider at the cached position while `powerdisplay get` reports that setting as unknown, because `MonitorDtoProjector` gates on `supported && read`. ### Keeping the cache current `RefreshKnownGoodAfterWrite` restamps an entry after a successful `SetVCPFeature`, so a slider move cannot leave the cache holding the pre-write value. It refreshes only an entry a real read established, and only when the value was scaled against the maximum that entry holds — a monitor whose discovery read failed still carries a placeholder max, and writing that back would mis-scale every later write. `RemoveKnownGoodFeatures` clears the cache for monitors a settings reconciliation observably dropped, leaving the user's saved values alone. Cleanup is driven by an observed drop, never by absence from the rebuilt list: a missing or corrupt `settings.json` yields a defaults object indistinguishable from a real one, and pruning by absence would wipe every monitor not connected at that instant. A re-observation that changes nothing refreshes the in-memory timestamp but does not mark the file dirty, so a discovery pass no longer rewrites `monitor_state.json` for a moved timestamp alone. ## Validation Steps Performed - `PowerDisplay.Lib`, `PowerDisplay.Lib.UnitTests` and `PowerDisplay` built for x64 Debug with VS MSBuild — 0 errors, 0 warnings; `PowerDisplay.Lib.UnitTests.dll` under `vstest.console.exe`: **301 passed, 0 failed** - **Affected-hardware validation on the AOC Q27G3XMN is still pending.** That monitor, or an equivalent controllable DDC/CI setup, was not available locally. The paths this PR changes are reachable only on hardware whose capabilities string is unusable or whose VCP reads fail intermittently, so this is the main outstanding risk. --------- Co-authored-by: Yu Leng <yuleng@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Copilot-Session: 6ea38c04-6f68-4c42-91d9-8a03b49bdd81 |
||
|
|
37d8729ac3 |
FancyZones: apply edited custom layout spacing/sensitivity/zone count to active work areas immediately (#49433)
## Summary of the Pull Request When a **custom layout** is edited in the FancyZones editor while windows are already snapped to it, changes to the layout's *scalar* properties — **spacing between zones**, **highlight/activation sensitivity radius**, and **zone count** (for canvas layouts) — were **not applied to already-active work areas** until PowerToys (or FancyZones) was restarted. Only the grid **shape/edges** refreshed live. This PR makes those scalar edits take effect immediately on existing work areas, resolving the remaining gap in issue 44058. ## PR Checklist - [x] Closes: #44058 - [x] **Communication:** This addresses the behavior tracked in the linked issue. - [x] **Tests:** Added `EditedCustomLayoutSpacingRefreshesExistingWorkArea` regression test; existing FancyZones unit tests pass. - [x] **Localization:** No new end-user-facing strings. - [x] **Dev docs:** N/A (no public API or doc surface change). - [x] **New binaries:** None added. ## Detailed Description of the Pull Request / Additional comments ### Root cause For a **Custom**-type layout, `WorkArea::CalculateZoneSet` builds its `Layout` from `AppliedLayouts::GetDeviceLayout()`, which returns a snapshot from `applied-layouts.json`. The zone **shape** is read live from the `CustomLayouts` store, but the scalar properties (`spacing`, `sensitivityRadius`, and `zoneCount`) were taken from that **stale applied-layouts snapshot**. So when the editor updated the custom layout and fired `WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE`, the existing work areas re-laid-out their grid geometry but kept the *old* spacing/sensitivity/zone count. ### The fix In `WorkArea::CalculateZoneSet`, for Custom-type layouts, re-derive the scalar properties from the **live** `CustomLayouts` store instead of the stale snapshot: ```cpp if (const auto refreshed = CustomLayouts::instance().GetLayout(appliedLayout->uuid)) { appliedLayout = refreshed; } ``` `CustomLayouts::GetLayout` returns the canonical `LayoutData` used by the apply path (it derives grid zone count from `zoneCount()` and canvas zone count from `zones.size()`), so the refreshed values exactly match what a fresh apply would produce. **Why this is low-risk:** - Scoped strictly to **Custom** layouts; templated layouts (Grid/Columns/etc.) are untouched. - At initial apply-time, the live store and the applied-layouts snapshot are equal, so behavior is unchanged for the common case — only a genuine *edit* of an already-applied custom layout changes the outcome (which is the intended fix). This complements the editor-side `RefreshLayouts()` call (which refreshes zone shape) so that **all** properties of an edited custom layout now apply live. ## Validation Steps Performed **Automated:** Added `EditedCustomLayoutSpacingRefreshesExistingWorkArea` in `FancyZonesTests/UnitTests/WorkArea.Spec.cpp`. It creates a work area on a grid custom layout, asserts adjacent zones are flush, then edits the custom layout's spacing, re-initializes the layout via `InitLayout()`, and asserts the new spacing gap is present on the existing zones. Built the FancyZones unit tests and ran the `WorkArea` suite — all pass. **Manual (end-to-end):** 1. Create a **grid custom layout** in the FancyZones editor and apply it. 2. Snap a window into one of its zones. 3. Re-open the editor, edit the layout: change the **edge position** *and* the **space between zones** (and optionally sensitivity), then **Save**. 4. **Before this fix:** the zone edges move, but the spacing between snapped windows keeps the *old* gap until PowerToys is restarted. 5. **After this fix:** the new spacing (and sensitivity) are applied to the already-snapped/active work area immediately, with no restart. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19f7171d-0ca4-48dc-95ef-e50f505a9097 |
||
|
|
f4b3dcde03 |
PowerDisplay: Funnel both monitor-state saves through one locked write (#49629)
## Summary of the Pull Request
`MonitorStateManager` wrote `monitor_state.json` from two independent
paths: the debounced save used `File.WriteAllTextAsync`, `Dispose` used
`File.WriteAllText`. Both open the path with `FileShare.Read`, so
disposing while a debounced save had already passed its delay left the
two racing for the same handle — the loser was denied at `CreateFile`
and its payload was dropped whole, into a catch that only logged.
Both paths now go through one method that serializes and writes under a
single lock, and the file is published by rename instead of being
written in place.
## 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
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized —
this PR adds none
- [ ] **Dev docs:** Added/updated
- [x] **New binaries:** Added on the required places — none added, so no
signing JSON, installer WXS or CI YML change is required
- [ ] **Documentation updated**
## Detailed Description of the Pull Request / Additional comments
### The collision
`Dispose` disposes the debouncer before flushing, which cancels a
pending `Task.Delay` but cannot reach a save that has already passed it
and stopped observing the token. That save is inside
`File.WriteAllTextAsync` when `Dispose` reaches its own
`File.WriteAllText`. Both open with `FileMode.Create, FileAccess.Write,
FileShare.Read`, and Windows checks sharing in both directions, so the
second open fails with `ERROR_SHARING_VIOLATION`. The loser never gets a
handle and writes zero bytes — a torn or interleaved file was never
reachable, only a dropped write.
### Why the flush could actually be lost
A bare collision costs only a redundant write: both paths serialize the
same live `_states`, and `UpdateMonitorParameter` mutates it
synchronously before arming the debounce, so whichever writer wins
already has the user's latest value.
The case that loses data is narrower. The debounced save built its JSON
*before* the `await`, so:
1. the debounced save snapshots `{brightness: 60}` and opens the file;
2. the user moves a slider to 70 — `_states` is updated, a new debounce
is armed;
3. the user quits; `Dispose` snapshots `{brightness: 70}` and is denied
at `CreateFile`;
4. the async write completes, publishing 60.
70 is gone. The window is the few hundred microseconds the async write
holds the handle, but it is exactly the window in which the user is
quitting.
### The fix
Both paths call `WriteStateFile`, which takes `_writeLock` and does the
serialize-and-write inside it. `BuildStateJson` runs under the lock too,
so the last snapshot built is the one that lands — a writer that queues
behind another re-snapshots rather than replaying a stale payload.
The write is synchronous on both paths. `Dispose` has to flush without
awaiting, the file is a few hundred bytes, and the async API was the
only reason there were two write paths to collide in the first place.
That is also why the guard is a plain `lock` rather than a
`SemaphoreSlim`: with neither caller async there is no
blocking-on-an-async-method concern left to design around.
`Dispose` keeps its ordering — dispose the debouncer so nothing new is
scheduled, then flush if the state was dirty.
### Publishing by rename
The bytes go to a temp file and are renamed in, matching
`CrashDetectionScope` and `ProfileStore` in the same module. An in-place
write truncates at `CreateFile` before it writes anything, and two exit
paths never reach `Dispose` at all — `App.OnLaunched` registers
`TerminatePowerDisplayEvent` and the runner-exit watchdog, and both call
`Environment.Exit(0)` outright. An interrupted write there would leave a
zero-byte file, which `LoadStateFromDisk`'s catch turns into "no saved
state for *any* monitor" — total loss rather than the last change.
There is deliberately no `Flush(flushToDisk: true)` to go with it. The
threat here is process death, which the page cache survives, not power
loss; and this flush runs on the UI thread at shutdown, where a
`FlushFileBuffers` on a busy disk is the one change in this area a user
could actually feel.
### The dirty flag
`SaveStateToDisk` cleared `_isDirty` *after* the write. A change landing
between the snapshot and that assignment set the bit and had it
immediately cleared; `Dispose` then read `wasDirty == false`, cancelled
the debounce that change had scheduled, and skipped the flush — losing
exactly the last change this path exists to preserve. It is now cleared
before the snapshot and re-marked if the write throws, so a change that
lands mid-write either rides along in the snapshot or stays dirty.
### Testability
`MonitorStateManager` gains an internal constructor taking a state file
path, so tests can drive it against a temp directory instead of the real
LocalAppData location.
## Validation Steps Performed
- `PowerDisplay.Lib` and `PowerDisplay.Lib.UnitTests` built for x64
Debug with VS MSBuild; `PowerDisplay.Lib.UnitTests.dll` under
`vstest.console.exe`: **273 passed, 0 failed** (4 of them in
`MonitorStateSaveTests`)
- Removing `lock (_writeLock)` fails
`ConcurrentWrites_DoNotCollideOnTheStateFile` with the same "used by
another process" `IOException` the collision produces, so the test pins
the guard rather than the shape of the code
- `FailedWrite_LeavesTheExistingStateFileIntact` occupies the temp path
with a directory so the write fails at exactly the point an in-place
`File.WriteAllText` would already have truncated the published file;
against the previous in-place write the same test fails, since that
write would succeed and replace the file
- No end-to-end manual check was performed. The window is a few hundred
microseconds wide and only opens when a debounced save is mid-write at
the exact moment `Dispose` runs, so reproducing it by hand is unreliable
— the concurrency test drives the same contention deterministically
instead
### Known gap, not addressed here
`TerminatePowerDisplayEvent` and the runner-exit watchdog call
`Environment.Exit(0)` without ever running `Dispose`, so on those paths
up to a full `SaveDebounceMs` (2 s) of changes is dropped
unconditionally — no race required. That is a larger loss surface than
the one this PR closes, and the module already has the machinery to fix
it (`CrashDetectionScope` subscribes to `AppDomain.ProcessExit` through
an `IProcessExitHook` seam for precisely these paths). Left out to keep
this PR to one logical change; happy to open a follow-up issue.
Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
|
||
|
|
d2c53bf386 |
[ZoomIt] Add DemoMirror feature (#49607)
Mirror the screen, a selected region (Shift), or the window under the cursor (Alt) onto a second monitor - including the mouse pointer - so a demo can be shown on a presentation display without leaving the current view. Adds the native MirrorWindow implementation, a DemoMirror options tab (Ctrl+9 default, plus Track window region), and the corresponding Settings UI (ZoomIt page group, view model, properties, and resources). ## Summary of the Pull Request Adds a **DemoMirror** feature to ZoomIt. It mirrors the screen, a selected region (Shift), or the window under the cursor (Alt) onto a second monitor — including the mouse pointer — so a demo can be shown on a presentation display without leaving the current view. This introduces the native `MirrorWindow` implementation, a new DemoMirror options tab (default hotkey **Ctrl+9**, plus a **Track window region** option), and the corresponding Settings UI wiring (ZoomIt page group, view model, properties, and localized resources). ## PR Checklist - **Communication:** I've discussed this with core contributors already. - **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] ## Detailed Description of the Pull Request / Additional comments DemoMirror lets a presenter keep working on their primary display while a second monitor shows a live mirror of a chosen source. Three capture modes are supported via the DemoMirror hotkey (default **Ctrl+9**): - **Full screen** — `Ctrl+9`: mirrors the entire source screen. - **Region** — `Ctrl+Shift+9`: mirrors a user-selected rectangular region. - **Window** — `Ctrl+Alt+9`: mirrors the window currently under the cursor. With the **Track window region** option enabled, the mirror follows the window as it moves/resizes. The mirror includes the mouse pointer so pointer movement and clicks are visible on the presentation display. **Native (C++ / `PowerToys.ZoomIt.exe`)** - New `MirrorWindow.cpp` / `MirrorWindow.h` implementing the mirror capture/render window. Mirror windows use `WS_EX_NOACTIVATE | WS_EX_TRANSPARENT` so they never steal focus from the source. - `Zoomit.cpp`: registers the DemoMirror hotkeys and wires the start/stop handlers; the stop path checks `g_MirrorWindow.IsActive()` and stops unconditionally (cursor-independent). - `ZoomItSettings.h`: new `MirrorToggleKey` (default `Ctrl+9`) and `MirrorTrackWindow` settings, added to the `RegSettings[]` table. Record default kept distinct at `Ctrl+5`. - `resource.h` / `ZoomIt.rc`: new DemoMirror options tab and controls (`IDC_MIRROR_HOTKEY`, `IDC_MIRROR_TRACK_WINDOW`). - `CaptureFrameWait.*` and `SelectRectangle.*` updated to support the mirror capture/selection flow. - `ZoomItSettingsInterop/ZoomItSettings.cpp`: exposes the new settings across the interop bridge. **Settings UI (WinUI 3)** - New DemoMirror group on the ZoomIt page (`ZoomItPage.xaml`), backed by `ZoomItViewModel.cs` and `ZoomItProperties.cs`. - Localizable strings added to `Resources.resw`. **Conflict resolution notes** (rebased on top of upstream `main`): - Control-ID collision resolved by assigning distinct IDs (`IDC_MIRROR_HOTKEY`, `IDC_MIRROR_TRACK_WINDOW`). - `SelectRectangle` border-color: kept upstream `m_borderColor = borderColor;`. - `WM_USER` message-ID collision resolved by using `WM_USER_MIRROR_STOP = WM_USER + 113`. ## Validation Steps Performed Manually validated on a real dual-display setup (Surface laptop extended to an external monitor): - **Full screen** (`Ctrl+9`): source screen mirrored to the second monitor, including the mouse pointer. - **Region** (`Ctrl+Shift+9`): selected region mirrored correctly. - **Window** (`Ctrl+Alt+9`): window under the cursor mirrored; with **Track window region** enabled, the mirror follows the window. - **Stop/cancel**: DemoMirror stops reliably regardless of cursor position; mirror windows never take focus (`WS_EX_NOACTIVATE | WS_EX_TRANSPARENT`). - **Hotkey defaults**: confirmed Record (`Ctrl+5`) and DemoMirror (`Ctrl+9`) defaults are distinct and read independently from their own registry/settings values (no cross-contamination). - **Settings UI**: DemoMirror hotkey and Track window region options round-trip correctly through the Settings UI and the interop bridge. |
||
|
|
a64c400b7e |
[MouseWithoutBorders] Increase PBKDF2 key derivation iterations to 100,000 (#49600)
## Summary Increases the PBKDF2 iteration count used to derive the Mouse Without Borders AES-256 session key from 50,000 to 100,000, strengthening the derived key against brute-force attempts. ## Changes - `Encryption.cs`: `KeyDerivationIterations` 50,000 -> 100,000 (used by `GenLegalKey` via `Rfc2898DeriveBytes.Pbkdf2`). The unrelated SHA-512 stretch loop in `Get24BitHash` is deliberately left unchanged - it is not a `Rfc2898DeriveBytes` key derivation and drives the connection framing/identity value. ## Compatibility This changes the derived key, so all paired machines must run this version. Mouse Without Borders already requires the same version on every machine (it surfaces *"make sure you run the same version in all machines"* on a key/handshake mismatch), consistent with the per-connection salt/IV change in #48742. The existing key and settings are preserved and the key is derived fresh per connection, so **no re-pairing is needed once every machine is updated** - only a transient, self-healing failure during a mixed-version window. ## Validation - Built `MouseWithoutBorders` (Release | x64) - clean, exit 0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e47bf2c-ee54-4de6-8ce0-9b8dd67d4128 |
||
|
|
160492abcf |
docs(skills): recommend WindowEx for WinUI 3 migrations (#49303)
## Summary of the Pull Request Updates the WPF-to-WinUI 3 migration skill to make the established PowerToys windowing pattern explicit: - Default WinUI 3 top-level windows to `WinUIEx.WindowEx` or an existing PowerToys base derived from it, such as `TransparentWindow` for transient overlays. - Keep supported size, presenter, title bar, topmost, backdrop, and persistence behavior declarative in XAML instead of manual `AppWindow` / `OverlappedPresenter` code-behind. - Document the centrally managed `<PackageReference Include="WinUIEx" />`, WPF-to-`WindowEx` property mappings, and existing repository examples. - Add a value-converter decision guide that prefers `VisualStateManager`, direct `x:Bind` conversion, WinUI theme resources, and `CommunityToolkit.WinUI.Converters` over mechanically porting WPF converters. This follows the migration-skill feedback from @niels9001 in [PR #49174](https://github.com/microsoft/PowerToys/pull/49174#discussion_r3535181101). ## PR Checklist - [x] **Communication:** This change follows review feedback from a core contributor in PR #49174. - [x] **Tests:** The updated guidance passed 5/5 fresh agent migration scenarios. - [x] **Dev docs:** Added/updated. ## Detailed Description of the Pull Request / Additional comments `SKILL.md` now states the default PowerToys pattern and limits raw `AppWindow` / presenter code to behavior that `WindowEx` does not expose. The package mapping reference records the exact centrally managed dependency. The windowing reference adds a complete XAML example, a WPF-to-`WindowEx` mapping table, regular-window examples, and the `TransparentWindow` overlay exception. The XAML migration reference now also documents converter selection and reuse: control state belongs in `VisualState`s, count visibility can share one Toolkit `DoubleToVisibilityConverter` with `ConverterParameter=True`, and corner-radius converter resources come from `XamlControlsResources`. This is an atomic documentation-only change; no product code or dependencies are modified. ## Validation Steps Performed - Verified the documented `WindowEx` APIs and `TransparentWindow` inheritance against the repository and compiled WinUIEx assembly. - Verified all cited repository paths, the Markdown anchor, and central package management entry. - Ran five fresh current-branch agent scenarios; all selected `<PackageReference Include="WinUIEx" />` without a version, `WindowEx`, XAML-declared properties, and `CenterOnScreen()` only where required. - Ran a focused converter migration scenario before and after the guidance update; the updated skill selected `VisualState`s, one reusable Toolkit numeric converter, and existing WinUI corner-radius resources without custom converters. - Ran `git diff --check` with no errors. - Completed an independent read-only review with no findings. - Product builds and unit tests were not run because this change only updates agent guidance. --------- Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: fe9b24eb-99f0-43e8-aaa4-839f4579f6f9 Copilot-Session: d5afc36b-3356-46af-b8cb-071b87a64532 |
||
|
|
8f63402400 |
PowerDisplay: Adjust brightness by scrolling over the tray icon (#49446)
## Summary of the Pull Request Scrolling the mouse wheel over the Power Display tray icon adjusts brightness, without opening the flyout. - New **Tray icon mouse wheel** setting: `Off` / `Primary display` / `All displays`, defaulting to **`Off`**. It is scoped to the tray icon — the flyout sliders accept wheel input regardless, as they always have. The existing **Mouse wheel increment** setting supplies the per-notch step. - **Off by default.** The gesture consumes a wheel notch that would otherwise reach the window under the pointer, and acting on it installs a system-wide `WH_MOUSE_LL` hook. Neither is something an existing installation should acquire silently on upgrade. With the setting `Off` no hook is ever installed and no notch is ever consumed, so this PR changes no existing behaviour until the user opts in: 1958 insertions, 2 deletions, and both deletions are refactors of lines this feature reuses. - **No feedback UI.** Brightness is self-evidencing — you scroll and the screen changes — so the display itself is the feedback. The notification icon is untouched: same tooltip, same text, same legacy notification-icon protocol. ## PR Checklist - [x] Closes: #49410 - [ ] **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 - [x] **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 No new binaries or projects — everything lands in existing assemblies. Communication is unchecked because #49410 is still Needs-Triage. ## Detailed Description of the Pull Request / Additional comments ### Why a low-level hook The Shell does not forward `WM_MOUSEWHEEL` to a notification icon's callback window under any `NOTIFYICON_VERSION`, and a click-through overlay placed over the icon cannot receive wheel input either. `TrayIconMouseWheelListener` therefore installs a `WH_MOUSE_LL` hook — but only transiently, and only when it will act on the result: - Nothing is installed at all while the setting is `Off`, which is the default. - Installed in `EnsureHook()` when the UI thread confirms the pointer is inside the rectangle from `Shell_NotifyIconGetRect` **and** `CanAdjustBrightnessFromTrayWheel` says some monitor can accept a brightness write. - Removed in `DisarmCore()` as soon as either condition stops holding, the pointer leaves the rectangle, or the mode changes. - A notch is consumed (the hook proc returns non-zero) only while armed and only for points inside the armed rectangle, so a wheel event Power Display will not act on still reaches the window under the cursor. The hook runs on a dedicated background thread with its own message loop; the proc itself only enqueues a sample and posts a drain request. Deltas are marshalled to the UI thread in batches, and `WheelDeltaAccumulator` folds high-resolution deltas (precision wheels, touchpads) into whole notches. Each sample carries the hover generation it was captured under, so samples from a hover the UI thread has already retired are discarded rather than applied late. ### Hover detection The Shell sends `WM_MOUSEMOVE` to the icon's callback window while the pointer is over it. `TrayIconService.HandleTrayMouseMove` resolves the rectangle with `Shell_NotifyIconGetRect` and caches it for a second, because that message repeats for every pixel of travel. `TrayIconService` gains nothing else: no protocol change, no new hover UI, no polling. The rest of the file — and `MainWindow.xaml` — is untouched. ### Linked brightness While linked brightness is on, a notch has to move the whole group, so it goes through `MainViewModel.LinkedBrightness` rather than the individual monitor setters. The new master value is taken from the planner's value for the monitor the wheel named, **not** from the current master. The master is positional only — `SeedInitialLinkedBrightness` takes it from the lowest-numbered linked monitor and never writes hardware, and every monitor-list rebuild re-seeds it — so it can sit arbitrarily far from the monitor the wheel is aimed at. Stepping it relative to itself would apply a wrong-sized or wrong-signed change, and a master already clamped at 0/100 would swallow the notch while writing nothing at all. The setting description calls out that linked brightness widens the scope, so `Primary display` is not literally a single display while it is on. ### What is deliberately not here An earlier revision of this PR showed the target and percentage in a custom overlay as you scrolled. Doing that meant the standard Shell tooltip would not do (it cannot be shown on demand), which meant an own window, which meant suppressing the Shell tooltip so the two did not collide, which meant `NOTIFYICON_VERSION_4`, which changed the callback packing and made the app responsible for all hover text — including for keyboard and touch users, who never reach a cursor-anchored overlay and would have been left with no visible tooltip at all. That chain was about half the diff, for a readout that adds little on top of watching the screen change. It is gone. If a readout is wanted later it can be argued on its own merits, separately from this feature. The same revision also gated the flyout sliders on this setting. That bundled two unrelated things behind one switch — turning off tray scrolling would also have stopped the contrast and volume sliders responding to the wheel — so the setting is now scoped to the tray icon and named accordingly. An earlier revision also routed the tray **Exit** action through `Shutdown()`. That fixes a pre-existing teardown leak which has nothing to do with this feature, so it now lives in #49580 and is out of scope here. This branch does not depend on it: the hook thread is a background thread and the process is ending either way. ## Validation Steps Performed - Unit tests: `PowerDisplay.Lib.UnitTests` 215 passed, `Settings.UI.UnitTests` 165 passed. - Builds: `PowerDisplay` and Settings UI, x64 Debug, no warnings. - Automated coverage is in `PowerDisplay.Lib.UnitTests`: target selection per mode, wheel accumulation including negative deltas, partial notches and direction reversal, half-open rectangle containment, and settings serialization and round-trip for the new mode, including that a settings file predating the feature loads as `Off`. `Settings.UI.UnitTests` covers the view-model index mapping and pins the enum values to the ComboBox item order. - The Win32 glue in `TrayIconService` and `TrayIconMouseWheelListener` is not unit tested. Manual passes performed: scrolling over the icon in both modes, the icon parked in the notification overflow, high-resolution wheel input, brightness boundaries, live monitor refresh while hovering, tray icon hidden and re-enabled, Explorer restart, the context menu and left-click, `Off` stopping tray scrolling while the flyout sliders keep working, and confirming a notch that Power Display will not act on still reaches the window under the cursor. Not verified, needing hardware this branch has not been run on: - Multiple taskbars, where the tray icon is on a secondary display and `Primary display` mode adjusts a monitor the user may not be looking at. - Mixed-DPI setups, for the `Shell_NotifyIconGetRect` rectangle and the hook's physical-pixel hit test. --------- Co-authored-by: Yu Leng <yuleng@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Copilot-Session: 5d7f36fe-d175-4aa9-a3c7-b370d952d1d3 |
||
|
|
3cb3bdcd34 |
PowerDisplay: Reuse the values the max-compatibility probe already read (#49596)
## Summary of the Pull Request In Maximum compatibility mode, when a monitor's capabilities string is unusable, discovery probes each continuous VCP code directly to find out which ones the panel implements — and then **throws the values away**. `BuildMonitorFromPhysical` immediately re-reads every one of those codes. That doubles the I2C traffic on exactly the hardware that cannot take it, and the re-read is the one whose result the user actually sees: a panel that answered the probe a moment ago but fails the re-read shows its brightness slider parked at the never-read default instead of where the panel really is. This makes the probe's values survive into the build stage. Extracted from #49445, which bundles it with a persisted discovery cache it does not depend on. ## PR Checklist - [ ] Closes: #xxx — partially addresses #49342; the remaining cause is in #49445 - [ ] **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 — this PR adds none - [ ] **Dev docs:** Added/updated - [x] **New binaries:** Added on the required places — none added; no new project, so no signing JSON, installer WXS or CI YML change is required - [ ] **Documentation updated** ## Detailed Description of the Pull Request / Additional comments ### What the re-read costs Worth being precise about, because it is not the slider's *existence*: | decided by | set from | affected by a failed re-read | | --- | --- | --- | | slider visible (`MonitorViewModel.ShowBrightness`) | `Monitor.Capabilities`, via `UpdateMonitorCapabilitiesFromVcp` before the initializer runs | no | | slider position (`Monitor.CurrentBrightness`) | the read | yes — stays at the never-read default | | `powerdisplay get` reporting a live reading (`Monitor.ReadValues`) | the read | yes — reported as unknown | | relative `powerdisplay adjust` (`AdjustCommandExecutor`) | `Monitor.ReadValues` | yes — no before-value to adjust from | So the flyout keeps the control either way; what the second read decides is whether it is pointed anywhere real, and whether the CLI will admit to a value. Halving the transactions on a bus that is both slow and, on this hardware, unreliable is the other half of the win. ### The seam `FetchCapabilitiesWithFallbackAsync` used to return `(string capsString, VcpCapabilities? caps)` — capabilities only, no values. It now returns a `VcpDiscoveryEvidence`, which carries the same two things plus the values the probe already read and a flag for a handle that died mid-probe. `VcpDiscoveryEvidence.Reconcile` folds the probe observations into the parsed capabilities in one place: | observation | capabilities | value carried | | --- | --- | --- | | read succeeded | code marked supported | yes | | device replied, range unusable (e.g. `max=0`) | code marked supported | no — the initializer still owes it a read | | no reply | unchanged | no | | handle-class failure | everything discarded | — | The second row is why membership keys off `Replied` rather than the value being usable: an unimplemented code fails with `DDCCI_VCP_NOT_SUPPORTED` and never sets the flag, so a reply proves the opcode exists even when the reported range cannot scale a percentage. That is the same rule `BuildCapabilitiesFromProbe` used before this PR; it just moves next to the value handling. Like that method, `Reconcile` iterates the observations rather than `NativeConstants.ContinuousVcpCodes`, which `VcpFeatureProbeService` only takes as the default for its constructor-injected sweep list. That keeps a widened sweep from silently dropping a code that answered, but it is not sufficient on its own: the carried value is consumed only for codes `ContinuousVcpInitializer` walks, so widening the sweep still needs a matching edit there. The comment and `Reconcile_ProbedCodeOutsideTheDefaultSweepIsStillHonoured` both say so rather than claiming the seam alone covers it. On the normal path nothing changes: the probe only runs when the caps string is unusable, so `live` is empty and `Reconcile` is a pass-through. `Reconcile_ParsedCapabilitiesSurviveWhenNoProbeRan` pins that. ### Continuous-VCP initialization moves out of the controller `DdcCiController` carried six near-identical `Initialize*` methods. The three percent-scaled ones become **`ContinuousVcpInitializer`** — brightness, contrast, volume. It skips any code the evidence already has a value for, and returns `false` when a read fails with a handle-class error, because `Monitor.Handle` is captured once per discovery pass and never refreshed: a monitor kept alive on a dead handle would send every later read and write into the void. It reads through the `IVcpFeatureReader` seam introduced in #49579, so it is testable without hardware. The three discrete-enum ones — color preset, input source, power mode — stay in `DdcCiController`, unchanged. The probe sweeps only `NativeConstants.ContinuousVcpCodes`, so no discrete value is ever carried across the seam and extracting them would be a refactor this change does not need; see *What is deliberately left out*. Only the continuous stage discards the monitor. That is a policy choice, not a property of the stage: losing a whole display because `0xD6` answered badly is worse than showing it without a power control. `DdcCiController.TryGetVcpFeature` therefore still has three discovery callers plus `GetVcpFeatureAsync`, the runtime refresh path. ### Behaviour change outside Maximum compatibility mode **A handle-class error during continuous VCP initialization now discards the monitor.** Before, the failure was logged, the read flag left unset, and the monitor kept — so its handle reached `PhysicalMonitorHandleManager` and every later operation went to a handle already known to be dead. The cost is that the monitor stays out of the flyout until a rediscovery: `DisplayChangeWatcher` schedules one for device-arrival/removal and console-display-state notifications, and the flyout's Refresh button forces one on demand. Note this check is not on every path. A caps string that parses but advertises none of `0x10`/`0x12`/`0x62` leaves `ContinuousVcpInitializer` nothing to read and suppresses the probe, so such a monitor is still published with a handle no VCP read has exercised — and its first VCP read then happens in the discrete stage, which never discards. ### What is deliberately left out **Extracting the discrete-VCP initialization.** The probe sweeps only the continuous codes, so no discrete value is ever reused and moving `0x14`/`0x60`/`0xD6` out of the controller would be a drive-by refactor with no bearing on this change. It is worth doing on its own, where the added test coverage can be reviewed for what it is. **Remembering a probe value across discoveries.** A probe value is only useful for the pass that produced it. Carrying one forward — so a later failing pass can still show the control — is the persisted known-good cache in #49445, a much larger change with an open design question attached. This PR is complete without it. ## Validation Steps Performed - built `PowerDisplay.Lib.UnitTests` and `PowerDisplay` for x64 Debug with VS MSBuild — 0 errors, 0 warnings - ran `PowerDisplay.Lib.UnitTests.dll` with `vstest.console.exe`: **240 passed, 0 failed** — 16 of those cases are added here (8 in `ContinuousVcpInitializerTests`, 7 in `VcpDiscoveryEvidenceTests`, 1 in `DdcErrorClassifierTests`) - `VcpDiscoveryEvidenceTests` pins each row of the table above, plus that a probed code outside the default sweep is still honoured - `ContinuousVcpInitializerTests` pins that a probed code is never re-read (the reader is primed with a failure it must not reach), that a handle-class error stops the remaining codes, and that a feature-level refusal does not. `Initialize_EveryContinuousCodeIsReadAndApplied` walks the whole `ContinuousVcpCodes` array with a distinct range and percentage per feature, so a code added to that array without an arm in both `IsSupported` and `ApplyValue` fails rather than being silently skipped or silently discarded — checked by mutation: removing either volume switch arm fails that test and `Initialize_ProbedVolumeIsAppliedWithoutReadingAgain` - not covered by tests: the `DdcCiController` side of the contract — that `evidence.IsPhysicalMonitorUnavailable` skips the monitor and releases the physical, and that a `false` from `ContinuousVcpInitializer` does the same. That layer takes no injectable dependencies today - no hardware validation performed: this path is reachable only on a panel whose capabilities string is unusable, which needs an incomplete or unreliable DDC/CI implementation --------- Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> |
||
|
|
bb99c30edc |
New module: AltWindowCycle (#48281)
## Summary of the Pull Request Introduces a new utility: AltWindowCycle to quickly switch between windows from the same process using Alt + `. In release notes give @wzhudev coauthor credits as he also had an earlier PR It works like Alt + Tab, but scoped to the app you’re already in. Perfect for juggling multiple browser windows, terminals, or editor instances. https://github.com/user-attachments/assets/cd42f6af-fa5d-4f08-8f68-3c4e75c16d94 <img width="1835" height="971" alt="image" src="https://github.com/user-attachments/assets/adea59cb-6c8d-4b44-87e2-0a792c4c0b4f" /> ## PR Checklist - [x] Closes: https://github.com/microsoft/PowerToys/issues/278 - [ ] **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 This PR adds AltWindowCycle (in-proc module + Settings integration), then addresses follow-up check-spelling feedback without changing runtime behavior: - allow-list update for `ROOTOWNER` - comment text adjustment for forbidden-pattern compliance - local identifier rename (`wpx` → `whitePx`) for spelling compliance ## Validation Steps Performed - Verified `ROOTOWNER` is present in `.github/actions/spell-check/allow/code.txt` - Verified `wpx` is removed and updated occurrences in `src/modules/AltWindowCycle/AltWindowCycle.cpp` - Ran targeted diff/verification for both updated files - Ran final validation (code review + CodeQL trivial-change path) - Ran secret scan for changed files --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Clint Rutkas <crutkas@users.noreply.github.com> Copilot-Session: dd5080ea-5001-4efb-87f8-1e7218e10a4e |
||
|
|
331f88a1a0 |
CmdPal: bump to 0.12 (#49586)
title |
||
|
|
ffc839afea |
[PowerAccent] Fix injection hygiene and reset state on hide (#48572)
## Summary Keeps Quick Accent-injected keys from retriggering centralized shortcuts and clears native keyboard-listener state whenever the toolbar closes. ## What this changes - Tags backspace, Unicode, and arrow `SendInput` events with `dwExtraInfo = 0x110`, mirroring `CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG`. - Uses the existing `SendArrowKey(bool)` implementation as the single arrow-injection path, preserving `KEYEVENTF_EXTENDEDKEY` on key-down and key-up. - Checks the number of events sent by every `SendInput` call and logs incomplete sends. - Adds `ForceReset()` to the keyboard service WinRT API and invokes it from the core hide path immediately before `OnChangeDisplay(false)`. - Keeps listener state non-atomic because the low-level hook is installed on the WinUI thread and its callbacks execute on that same thread, as documented by `MainWindow.RunOnUiThread`. ## Testing - Built `PowerAccent.Core.csproj` in Release x64, including `PowerAccentKeyboardService`. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 122a9176-ce18-437c-8af4-c39f83fb2fa6 |
||
|
|
70e0fc2295 |
CmdPal: when expanding compact mode, don't be too tall (#49532)
If you open command palette on one display and resize its expanded size to be very tall, then you move command palette to a monitor that is not that tall and expand it, we will still expand our control to fit the full size of our HWND, which is taller than this new monitor. This PR fixes that by making sure to measure the size that's available on the current monitor and limit the max height of our control when we're expanding it, so that the bottom of the control always fits on the current monitor. Closes: not filed I don't think |
||
|
|
7d1dde7aa5 |
[ZoomIt] Port recording/editing features from Mac ZoomIt (trim editor, snip-to-clipboard, recording border) and fix video trim reliability (#49553)
## Summary of the Pull Request Ports several recording and editing features from the Sysinternals **Mac ZoomIt** into the Windows PowerToys ZoomIt module, and hardens the video **trim/save** pipeline against a sporadic "Failed to trim the video" failure. Highlights: - **Video trim editor — interior "Delete Region" editing.** In the post-recording trim dialog you can now select and delete interior segments (not just trim the head/tail). Includes red timeline overlays with drag grips, right-drag to select, `Delete` to remove, `Ctrl+Z` to undo, and `Esc` to cancel a pending selection. - **Reliable trim/render.** Fixed a sporadic *"Failed to trim the video"* error. The live capture pipeline produces **fragmented** MP4s (moof/mdat) that play in preview but fail `MediaComposition` render/seek with `0xC00DA7FC`. The render path now (a) sources resolution from the clip's encoding properties first, (b) retries transient failures (0×0 dimensions from a fragmented-MP4 metadata race, `!CanTranscode()`, post-remux render failure), and (c) remuxes fragmented MP4s to a standard seekable MP4 via `MediaTranscoder` before rendering. - **Snip → Copy to clipboard.** New ZoomIt setting to copy a snip directly to the clipboard. - **Recording border color.** The screen-recording selection border now uses a distinct color, and turns orange while recording is active. - **GIF recording robustness.** First-frame timeout so GIF capture doesn't hang when no frames arrive. - **Audio hardening.** Stereo downmix handling and defensive guards in the audio sample generator. - **Opt-in diagnostics.** Recording diagnostics (`[RecDiag]`) are gated behind a registry DWORD `HKCU\Software\Sysinternals\ZoomIt\EnableDebugTrace` (off by default), and all module debug output is prefixed with `[ZoomIt]` for easy filtering in DebugView. - **Fix:** GDI bitmap leak in the snip-to-clipboard path when `SetClipboardData` fails. ## PR Checklist - [ ] **Tests:** ZoomIt is native Win32/WinRT with no unit-test harness; validated manually (see Validation Steps) - [ ] - [x] **Localization:** All end-user-facing strings can be localized <!-- new strings added to Settings.UI en-us Resources.resw --> - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** N/A: no new binaries/projects - [ ] JSON for signing — N/A - [ ] WXS for installer — N/A - [ ] YML for CI pipeline — N/A - [ ] YML for signed pipeline — N/A - [ ] **Documentation updated:** N/A ## Detailed Description of the Pull Request / Additional comments Files changed (17): **ZoomIt module (native)** - `VideoRecordingSession.cpp/.h` — interior delete-region trim editor; render/trim reliability (resolution from clip encoding properties, retry loop, fragmented-MP4 → seekable remux); registry-gated `[RecDiag]` diagnostics. - `GifRecordingSession.cpp` — first-frame timeout / no-frames handling. - `AudioSampleGenerator.cpp` — stereo downmix + defensive guards. - `SelectRectangle.cpp/.h`, `PanoramaCapture.cpp` — recording border color parameter. - `Zoomit.cpp` — snip → clipboard workflow; GDI bitmap leak fix on `SetClipboardData` failure. - `ZoomItSettings.h`, `ZoomIt.h`, `ZoomIt.rc`, `resource.h` — new setting + "Delete Region" button + message id. - `pch.h` — `[ZoomIt]` debug-output prefix wrapper. **Settings UI** - `ZoomItProperties.cs`, `ZoomItViewModel.cs`, `ZoomItPage.xaml`, `Resources.resw` — "Copy snip to clipboard" setting and localized strings. Note: ZoomIt is a Sysinternals port kept in its upstream code style, so it is intentionally exempt from the repo `.clang-format` (changed lines follow the surrounding Sysinternals convention). ## Validation Steps Performed Manual validation (no automated ZoomIt harness): - **Trim reliability:** Recorded multiple clips and used Trim → Save repeatedly (including 3-clip compositions produced by Delete Region); render now succeeds consistently (previously failed sporadically with "Failed to trim the video"). - **Delete Region editor:** Right-drag to select an interior segment, `Delete` to remove, `Ctrl+Z` to undo, `Esc` to cancel; saved output reflects the removed segments. - **Snip → clipboard:** Enabled the new setting; snip is placed on the clipboard and pastes correctly. Verified no GDI handle leak when clipboard set fails. - **Recording border:** Verified border color and the orange active-recording state (full-monitor and region). - **GIF:** Confirmed capture no longer hangs when no frames arrive. - **Diagnostics:** With `EnableDebugTrace` unset, no `%TEMP%\ZoomIt_RecDiag.log` and no `[RecDiag]` output; with it set to `1`, `[ZoomIt] [RecDiag ...]` traces appear. - **Style checks:** XamlStyler (clean), StyleCop via building `Settings.UI.Library` and `PowerToys.Settings` (no `SA####` warnings), ZoomIt x64 Release builds with exit code 0. |
||
|
|
5803bc7ec5 |
BUILD: Fix the version.vcxproj FastUpToDate check (#49534)
This has been my personal enemy for a year now. VS will skip doing work for your build if it thinks everything is up-to- date. But this version project has been treated as dirty for a long time now. What that means is that incremental builds (READ: dev inner loop builds) end up building the world CONSTANTLY. Because VS thinks FOR SOME REASON that this project needs to rebuild. By setting the `Inputs`/`Outputs` for this `Target`, VS is smart enough to only re-run the task if the inputs actually changed since the last build. Tested by building the code, then building again, and observing that all the projects were successfully noted as up-to-date drive-by: fix some of the other `csproj` files for cmdpal. Closes #45296 |
||
|
|
4b3f961b12 |
[PowerDisplay] Run the tray Exit through Shutdown so teardown is not skipped (#49580)
## Summary of the Pull Request PowerDisplay's tray context menu **Exit** ended the process with `Environment.Exit(0)`, skipping the teardown that `App.Shutdown()` already performs. Point it at `Shutdown()` instead — a one-line change. What Exit was skipping: - `TrayIconService.Destroy()` — `Shell_NotifyIcon(NIM_DELETE)`, the icon and popup-menu handles, and restoring the subclassed window procedure. Without the `NIM_DELETE`, the notification area can keep showing a stale PowerDisplay icon until the Shell next validates it, which in practice is when the pointer passes over it. - `MainWindow.Dispose()` — which cancels the CLI named-pipe server's `CancellationTokenSource` and disposes the hotkey service, the message hook and `MainViewModel` (monitor manager, display-change watcher, per-monitor view models). `Environment.Exit` does not run finalizers, so none of that happened by another route. The named-pipe terminate message (`PowerDisplayTerminateAppMessage`) has always gone through `Shutdown()`, so this only makes the tray menu agree with a path that is already shipping. The tray menu command is dispatched from the subclassed main-window procedure, so it already runs on the UI thread that owns these objects, and `Shutdown()` still ends with `Environment.Exit(0)` — the process exits unconditionally either way. ## PR Checklist - [ ] Closes: #xxx — no filed issue. Found while working on #49410; split out so it can be reviewed on its own. - [ ] **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 — none added. The change is process-exit wiring inside `App.OnLaunched`, which has no test harness; validated manually. - [x] **Localization:** All end-user-facing strings can be localized — no new or changed strings. - [ ] **Dev docs:** Added/updated — no doc change warranted for a one-line teardown fix. - [ ] **New binaries:** Added on the required places — none. - [ ] **Documentation updated:** no user-facing behaviour change. ## Detailed Description of the Pull Request / Additional comments ### Deliberately not in scope Two other paths still call `Environment.Exit(0)` directly, and both are pre-existing and unchanged here: - The runner **Terminate** event (`Constants.TerminatePowerDisplayEvent()`) — the module-disable and PowerToys-exit path. Its callback is already marshalled to the UI thread by `NativeEventWaiter`, so it *could* be routed the same way, but adding teardown work to the runner's shutdown path should be validated against the runner's shutdown timeout on its own rather than riding along with a tray-menu fix. - The `RunnerHelper.WaitForPowerToysRunner` watchdog, whose callback runs on a background thread and would need marshalling to the UI thread first. Happy to follow up on either if reviewers would rather see them fixed together. ## Validation Steps Performed - Tray icon → right-click → **Exit**: PowerDisplay exits, the notification icon disappears immediately rather than lingering until hover. - Re-launch from PowerToys Settings after a tray Exit: the tray icon comes back once, not twice. - `powerdisplay` CLI still works after a launch/tray-Exit/launch cycle, confirming the named pipe was released rather than left to process teardown. - Existing terminate paths unchanged: disabling PowerDisplay in Settings and quitting PowerToys both still exit the process. Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> |
||
|
|
bc2d09abe8 |
PowerDisplay: Pace and retry the maximum-compatibility VCP probe (#49579)
## Summary of the Pull Request In Maximum compatibility mode, when a monitor's capabilities string is missing or unparsable, discovery falls back to probing each continuous VCP code directly. That probe issues **one** `GetVCPFeatureAndVCPFeatureReply` per code, back to back, and treats any failure as final. On a panel whose DDC/CI engine answers intermittently, a single transient I2C fault permanently drops that control for the whole discovery pass — and if every code happens to fault, the monitor disappears from the flyout entirely. This replaces the probe with `VcpFeatureProbeService`: - **paced** — 100 ms between transactions, instead of hammering the I2C bus back to back - **retried** — up to 3 attempts, but only for failures another attempt can plausibly get past - **classified** — `DdcErrorClassifier` decides what "transient" means, so the retry budget is not burned on a definitive `DDCCI_VCP_NOT_SUPPORTED` or on a dead physical-monitor handle - **aborted early** — a handle-class error stops the remaining codes rather than issuing more requests against a handle already known to be invalid Extracted from #49445, which bundles this with a persisted discovery cache and a discovery restructure it does not depend on. This piece stands alone and addresses one of the root causes in #49342 by itself. ## PR Checklist - [ ] Closes: #xxx — partially addresses #49342; the remaining causes are in #49445 - [ ] **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 — this PR adds none - [ ] **Dev docs:** Added/updated - [x] **New binaries:** Added on the required places — none added; no new project, so no signing JSON, installer WXS or CI YML change is required - [ ] **Documentation updated** ## Detailed Description of the Pull Request / Additional comments ### What is and is not retried `DdcErrorClassifier` names the DDC/CI error codes after `winerror.h` and splits them into two sets. `DdcErrorClassifierTests` pins both the membership of each set **and** the numeric value of every constant against `winerror.h`, so a typo cannot move production and tests together and leave the suite green. Retried — framing, arbitration and timing faults on the I2C bus: `I2C_ERROR_TRANSMITTING_DATA`, `I2C_ERROR_RECEIVING_DATA`, `DDCCI_INVALID_DATA`, `MCA_INTERNAL_ERROR`, `DDCCI_INVALID_MESSAGE_COMMAND`, `DDCCI_INVALID_MESSAGE_LENGTH`, `DDCCI_INVALID_MESSAGE_CHECKSUM`, `DDCCI_CURRENT_CURRENT_VALUE_GREATER_THAN_MAXIMUM_VALUE`, `ERROR_TIMEOUT`. Not retried, each for a stated reason recorded on the predicate: `DDCCI_VCP_NOT_SUPPORTED` is the device's final answer; `I2C_NOT_SUPPORTED` and `I2C_DEVICE_DOES_NOT_EXIST` are permanent bus-level facts; `MCA_INVALID_CAPABILITIES_STRING` belongs to the capabilities path, not to a VCP read; and the two handle-class codes must abort rather than retry. ### Behaviour preserved `FetchCapabilitiesWithFallbackAsync` keeps its signature and still returns `(string, VcpCapabilities?)`, so nothing outside the probe changes. `BuildCapabilitiesFromProbe` synthesizes the same shape `DdcCiNative.ProbeSupportedVcpFeatures` used to, and decides membership the same way: a code counts as supported when the device *replied*, not when the value was usable. A reply proves the opcode is implemented even if the reported range cannot scale a percentage — an unimplemented code fails with `DDCCI_VCP_NOT_SUPPORTED` instead. The set of probed codes moves from a private array in `DdcCiNative` to `NativeConstants.ContinuousVcpCodes`, where the follow-up work in #49445 also needs it. ### Cost The probe only runs in Maximum compatibility mode, and only when the capabilities string is already unusable — so this adds no I2C traffic to a monitor that parses normally. For a monitor that does reach it, the worst case grows from 3 transactions to 9 plus 900 ms of pacing, and it is bounded: a definitive refusal stops after one attempt, and a handle-class error stops the whole probe. ### What is deliberately left out The probe's values are still discarded — `BuildMonitorFromPhysical` re-reads each code immediately afterwards. Reusing them needs a carrier for the observed value, which is `VcpDiscoveryEvidence` in #49445. `VcpFeatureProbeService` already returns everything that needs (`VcpProbeObservation` carries the value, the attempt count and the last error); this PR simply does not consume it yet. ## Validation Steps Performed - built `PowerDisplay.Lib.UnitTests` for x64 Debug with VS MSBuild — 0 errors, 0 warnings - ran `PowerDisplay.Lib.UnitTests.dll` with `vstest.console.exe`: **223 passed, 0 failed** (186 on `main` + 37 added here) - `VcpFeatureProbeServiceTests` drives the pacing, the retry budget, the transient/definitive split, cancellation before and during the inter-transaction delay, a throwing native read, and that reads run off the caller's thread — all through an injected reader and an injected delay, so no hardware is needed - no hardware validation performed: reaching this path needs a panel whose capabilities string is unusable **and** whose VCP reads fail intermittently --------- Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> |
||
|
|
efc0258cda |
Validate the update installer before PowerToys.Update launches it (#48903)
## Summary PowerToys' self-updater downloads the installer into `%LOCALAPPDATA%\Microsoft\PowerToys\Updates` and then launches it from `PowerToys.Update.exe` (Stage 2). This makes that launch path more robust: - Open the downloaded installer with a read-only share so the file stays consistent while we inspect and run it. - Confirm it is a valid, Authenticode-signed **Microsoft** PowerToys installer (valid signing chain + Microsoft organization) before executing it. This single chokepoint covers both freshly downloaded and previously downloaded installers. - If the check does not pass, log and skip the launch instead of running an incomplete or invalid file. ## Implementation - Added `updating::verify_installer_trust` to the shared `common/updating` library (`installer.h` / `installer.cpp`): `WinVerifyTrust` for the signing chain, and `CryptQueryObject` / `CertGetNameString` to confirm the signer's organization is `Microsoft Corporation`. `Wintrust.lib` / `Crypt32.lib` are linked via `#pragma comment(lib, ...)`. - `InstallNewVersionStage2` opens the installer with `FILE_SHARE_READ`, verifies it, and keeps the handle open across `MsiInstallProductW` / the bootstrapper launch so the file stays stable during install. ## Validation - `ApplicationUpdate` and `PowerToys.Update` build clean (x64 Debug). - Existing updating unit tests pass (30/30). - Checked end-to-end against real binaries: a Microsoft Authenticode-signed binary is accepted; a corrupted copy and an unsigned file are both declined. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Muyuan Li <muyuanli@microsoft.com> Co-authored-by: Boliang Zhang (from Dev Box) <bozhang@microsoft.com> Copilot-Session: d168a794-8cce-483d-9c46-10787893dbe2 |
||
|
|
af5665eaa8 |
PowerDisplay: Always write the saved value when restoring monitor settings (#49577)
## Summary of the Pull Request `TryRestore` skipped writing a saved monitor value when it already equalled the value `MonitorViewModel` was showing. That displayed value is only an observation when the discovery-time VCP read succeeded. When the read failed it is a placeholder: | setting | value when the read failed | source | | --- | --- | --- | | brightness | `50` | `MonitorDiscoveryHelper` stamps it — *"Initial placeholder; overwritten if the VCP read succeeds"* | | contrast | `50` | `Monitor` backing-field default | | volume | `50` | `Monitor` backing-field default | | color temperature | `0x05` (6500K) | `Monitor` backing-field default | A saved value that happened to equal one of those silently suppressed the restore, and the monitor kept whatever it powered on with. `50` is the mid-slider value and `0x05` is the most common preset, so the coincidence is not rare. This drops the comparison: a restore now always writes. ## PR Checklist - [ ] Closes: #xxx — no issue; found while splitting up #49445 - [ ] **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 — none added; `TryRestore` is a private helper in the `PowerDisplay` app project, which has no test project - [x] **Localization:** All end-user-facing strings can be localized — this PR adds none - [ ] **Dev docs:** Added/updated - [x] **New binaries:** Added on the required places — none added; no new project, so no signing JSON, installer WXS or CI YML change is required - [ ] **Documentation updated** ## Detailed Description of the Pull Request / Additional comments ### Why remove the check rather than refine it The skip-if-equal check dates from PowerDisplay's first commit (#42642, where it read `// Restore brightness if different from current`); #47051 only refactored it into the shared `TryRestore` helper. It is day-one "obviously we shouldn't write twice" code, not a response to a reported problem. Removing it is correct by construction: with no skip branch there is no state in which a restore silently does nothing. Any narrower fix has to decide *when* the displayed value can be trusted, and gets that decision wrong in exactly the cases that are hardest to reproduce. ### Cost Two, both bounded: - **A redundant VCP write when the monitor already sits at the saved value.** Some panels surface a write on their OSD. Both paths that reach here are user-initiated: startup restore only runs when `RestoreSettingsOnStartup` is enabled, and a profile apply happens because the user invoked that profile. - **Time.** At most four writes per monitor, serialised on that monitor's I2C bus (~100 ms each). Monitors still run in parallel through the existing `Task.WhenAll`. The `isVisible` guard is untouched, so a monitor still never receives a write for a feature it does not expose — an unsupported VCP `0x14` is not written just because a profile carries a color temperature. Input source and power state are not restored here at all. ### If the redundant write turns out to matter The narrower fix is to keep the comparison and add one clause: also write when `(monitor.ReadValues & flag) != flag`, i.e. when the compared value was never read off the hardware. `MonitorReadFlags` already carries exactly that information, and `Monitor.ReadValues` is already maintained by the discovery-time `Initialize*` methods, so it is a small change on top of this one. I went with the simpler version first — happy to switch if a maintainer would rather keep the optimisation. ## Validation Steps Performed - built `PowerDisplay` and `PowerDisplay.Lib.UnitTests` for x64 Debug with VS MSBuild — 0 errors, 0 warnings - ran `PowerDisplay.Lib.UnitTests.dll` with `vstest.console.exe`: **186 passed, 0 failed** — unchanged from `main`; this PR touches only the app project and adds no tests - no hardware validation performed: the placeholder path this PR fixes is reachable only on a monitor whose VCP read fails during discovery Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> |
||
|
|
32f738bd45 |
PowerDisplay: Release physical-monitor handles that discovery abandons (#49578)
## Summary of the Pull Request `DdcCiController.DiscoverFromHandleAsync` abandons a physical monitor on three paths without destroying its handle. Handles only reach `PhysicalMonitorHandleManager` through monitors that were successfully built: the map is rebuilt from the returned monitor list, and its cleanup pass only destroys handles that were in the *previous* map. A handle dropped on an abandon path therefore never gets destroyed. A discovery runs on every display-topology change, so a monitor that keeps failing leaks one more handle per discovery for the process lifetime — a docking-station user accumulates them. Extracted from #49445, where the same fix is bundled with maximum-compatibility-mode work it does not depend on. ## PR Checklist - [ ] Closes: #xxx — no issue; extracted from #49445 - [ ] **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 — none added; rationale below - [x] **Localization:** All end-user-facing strings can be localized — this PR adds none - [ ] **Dev docs:** Added/updated - [x] **New binaries:** Added on the required places — none added; no new project, so no signing JSON, installer WXS or CI YML change is required - [ ] **Documentation updated** ## Detailed Description of the Pull Request / Additional comments ### The three leaking paths | path | before this PR | | --- | --- | | more physical monitors than `QueryDisplayConfig` entries for the GDI name | `break` leaves `physicals[i..]` unreleased — the whole tail, not just the current one | | capabilities unavailable | `continue` | | `BuildMonitorFromPhysical` returned null (construction failed, or it threw and was caught) | no `else` branch at all | `ReleaseAbandonedPhysical` is null-handle safe and swallows a failing `DestroyPhysicalMonitor` at warn level: one handle that cannot be destroyed must not take down the rest of the discovery pass. ### Why there are no tests Reaching these call sites means faking the whole native enumeration surface — `EnumDisplayMonitors`, `GetMonitorInfo`, `GetPhysicalMonitorsFromHMONITOR` — which is a larger seam than a one-file leak fix should introduce. The paths were verified by reading instead. Happy to add the seam if a maintainer would rather have it covered. ### Known remaining leaks, deliberately out of scope - `GetPhysicalMonitorsWithRetryAsync`'s retry loop discards a whole array of live handles when it retries after seeing NULL handles. - Cancellation unwinds `DiscoverMonitorsAsync` before `UpdateHandleMap` runs, so that pass's handles never enter the map and are never destroyed. Both predate this change and are better addressed separately. ## Validation Steps Performed - built `PowerDisplay.Lib` and `PowerDisplay.Lib.UnitTests` for x64 Debug with VS MSBuild — 0 errors, 0 warnings - ran `PowerDisplay.Lib.UnitTests.dll` with `vstest.console.exe`: **186 passed, 0 failed** — no new tests; this only confirms nothing regressed - no hardware validation performed: reaching an abandon path needs a monitor whose capabilities fetch fails or whose construction throws Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> |
||
|
|
135291d456 |
[Shortcut Guide] Add Less Than and greater than characters and fix crash if key is empty or invalid (#49562)
<!-- 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 - [x] Closes: #49558 <!-- - [ ] 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 - [x] **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 |
||
|
|
e6bbf4428e |
docs: add Quick Shell to third-party Run plugins (#49567)
## Summary Adds [Quick Shell](https://github.com/tonythethompson/QuickShell) to the community PowerToys Run plugins list. - **Plugin:** Quick Shell (`qs` keyword) - **Author:** [tonythethompson](https://github.com/tonythethompson) - **Description:** Open saved project folders in any terminal; shared shortcuts with the Quick Shell Command Palette extension ## Install - WinGet (bundled CmdPal + Run): `winget install tonythethompson.QuickShell` - Run-only ZIP: [`QuickShell.Run-x64.zip`](https://github.com/tonythethompson/QuickShell/releases/latest) / [`QuickShell.Run-ARM64.zip`](https://github.com/tonythethompson/QuickShell/releases/latest) - Run-only EXE: `QuickShellforRun-Setup-*-x64.exe` / `*-arm64.exe` from the same release Docs: https://github.com/tonythethompson/QuickShell/blob/master/docs/powertoys-run-plugin.md ## Validation - [x] Listed under General plugins - [x] Links to GitHub repo and author profile - [x] Release assets include Run plugin ZIP and installer Made with [Cursor](https://cursor.com) Co-authored-by: Anthony Thompson <> |
||
|
|
d72fa2ea6e |
Update Monaco Editor from 0.47.0 to 0.52.2 (#48415)
## Summary of the Pull Request Updates the vendored Monaco Editor from 0.47.0 (Mar 2024) to 0.52.2 (Dec 2024). ## PR Checklist - [x] **Communication:** Discussed in #46692 review - [x] **Tests:** Headless-browser smoke tests pass (syntax highlighting, custom languages, context-menu hack, addAction registration) - [x] **Dev docs:** No doc changes needed (update process unchanged) ## Detailed Description ### What changed | Area | Detail | |------|--------| | `src/Monaco/monacoSRC/min/` | Replaced with `monaco-editor@0.52.2` from npm | | NLS layout | `editor.main.nls.*.js` / `simpleWorker.nls.*.js` removed upstream → `vs/nls.messages.*.js` added | | New language | `typespec` shipped upstream (+1 language, 100→101 total) | | `monacoSpecialLanguages.js` | Inline grammar snapshots (cpp/xml/razor/vb/ini/shell) refreshed from 0.52.2 shipped files | | `monaco_languages.json` | Regenerated; all PowerToys custom languages + extension mappings intact | ### Supply-chain verification - npm tarball SHA-512 verified against registry SRI: `sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==` - Vendored tree hash-verified file-by-file (103 files, all match) ### Why 0.52.2 and not 0.55.1 (latest)? Monaco 0.53+ completely restructured the `min/` bundle: flat hashed chunks instead of per-language AMD modules, `vs/platform/actions/common/actions` removed, `vs/basic-languages/<id>/<id>` modules eliminated. PowerToys' `index.html` (context-menu stripping via MenuRegistry) and `monacoSpecialLanguages.js` (language cloning via AMD require) depend on these internals. **0.52.2 is the last release compatible without a glue-code rewrite.** The 0.55.x port is tracked separately. ## Validation Steps Performed - [x] Tarball SRI integrity verified against npm registry - [x] Vendored tree == tarball (SHA-256 per file, 103/103 match) - [x] `monacoSpecialLanguages.js` passes Node.js syntax check - [x] Headless smoke test (Edge via puppeteer-core): editor creates, tokenization paints (5+ classes), `addAction` entries register, `MenuRegistry` context-menu hack works - [x] Same smoke test passes identically on 0.47.0 baseline (no regressions) - [x] `monaco_languages.json`: 101 languages, all custom IDs present (reg, gitignore, srt, cppExt, xmlExt, txtExt, razorExt, vbExt, iniExt, shellExt) ## Related - Supersedes automation approach in #46692 (which has fatal bugs; will close separately) - 0.55.x port tracked as follow-up issue Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b6bd2181-eff3-4f2a-b25e-dcd1065ead6a |
||
|
|
d127511c7d |
Fix runner APPLICATION_HANG_QUIESCE: handle WM_ENDSESSION and skip blocking shutdown cleanup (#48363)
## Summary The runner WndProc (`tray_icon_window_proc`) does not handle `WM_QUERYENDSESSION` / `WM_ENDSESSION`, **and** its `WM_DESTROY` teardown performs blocking cross-process cleanup. Both contribute to the Watson failure `APPLICATION_HANG_QUIESCE_cfffffff_PowerToys.exe!run_message_loop` on OS shutdown, sign-out, or restart: 1. Without a `WM_ENDSESSION` handler, `DefWindowProc` returns `0` without posting a quit message, so `run_message_loop` stays parked in `GetMessageW` until the OS quiesce timeout (~5 s) force-terminates the process. 2. Even once teardown starts, `WM_DESTROY` calls `close_settings_window()`, which blocks up to 1.5 s on `WaitForSingleObject` against `PowerToys.Settings.exe` (`src/runner/settings_window.cpp:712`), plus `Shell_NotifyIcon(NIM_DELETE)` during Explorer teardown. The Windows [shutdown guidance](https://learn.microsoft.com/windows/win32/shutdown/shutting-down) is explicit that handlers must not block. This PR fixes both issues for the always-on runner. Rollout to module-owned windows is intentionally separate and tracked in #49539. > Supersedes #48378 (same Watson bucket) by combining its no-blocking-cleanup fix with a reusable helper and unit tests. The cleanup-skip insight is credited to @yeelam-gordon. Related (same failure class, different binary): #41260. ## Root cause `src/runner/tray_icon.cpp` → `tray_icon_window_proc` had no case for `WM_QUERYENDSESSION` / `WM_ENDSESSION`, and `WM_DESTROY` unconditionally ran cross-process cleanup. On a full Windows session end, the OS delivers `WM_ENDSESSION` to child applications and reaps them independently, so the runner's waits consume the quiesce budget without helping shutdown complete. ## Fix ### 1. Explicitly stateless helper in `src/common/utils/window.h` `handle_stateless_session_end_message`: - `WM_QUERYENDSESSION` → returns `TRUE`. The name makes clear that this helper is only for processes with no unsaved user state. - `WM_ENDSESSION(TRUE)` → calls `DestroyWindow(window)`, driving the existing `WM_DESTROY → PostQuitMessage(0)` path so `run_message_loop` unwinds. - `WM_ENDSESSION(FALSE)` → leaves the window alone because another application cancelled shutdown. - The optional `out_system_session_ending` flag is set only when the full Windows session is ending. `ENDSESSION_CLOSEAPP` still closes the runner but leaves the flag false so Restart Manager requests retain normal child-process cleanup. Stateful modules must implement their own save/permission behavior rather than adopt this helper. `tray_icon_window_proc` calls it at the top of dispatch and returns immediately when the message is handled. ### 2. Skip blocking cleanup only for a full Windows session end `WM_DESTROY` branches on `g_system_session_ending`: - **User-initiated close or Restart Manager `ENDSESSION_CLOSEAPP`:** unchanged full cleanup (`Shell_NotifyIcon(NIM_DELETE)`, `close_settings_window()`, and `QuickAccessHost::stop()`). - **Full OS shutdown, sign-out, or restart:** posts `WM_QUIT` without waiting on child processes the OS is already reaping in parallel. ### Scope and follow-up This PR intentionally fixes the highest-volume contributor: the always-on runner. Native module processes with their own windows/message loops require module-specific review before adopting the pattern; that inventory and rollout is tracked in #49539. ### Why not centralize handling inside `run_message_loop`? `WM_QUERYENDSESSION` / `WM_ENDSESSION` invoke the WndProc directly during `GetMessage`; they do not appear as a `MSG` returned to the loop. Handling must therefore live in, or be called from, each relevant WndProc. ## Tests 8 focused tests in `src/common/UnitTests-CommonUtils/Window.Tests.cpp`: | Test | Guards | |---|---| | `HandleStatelessSessionEndMessage_QueryEndSession_AllowsShutdown` | `WM_QUERYENDSESSION` returns `TRUE`. | | `HandleStatelessSessionEndMessage_EndSessionCancelled_DoesNotTearDown` | `WM_ENDSESSION(FALSE)` does not destroy the window. | | `HandleStatelessSessionEndMessage_EndSessionConfirmed_TearsDownAndExitsLoop` | `WM_ENDSESSION(TRUE)` destroys the window and exits before the longer timer fallback. | | `HandleStatelessSessionEndMessage_UnrelatedMessage_NotHandled` | Unrelated messages fall through untouched. | | `HandleStatelessSessionEndMessage_EndSessionConfirmed_SignalsSystemSessionEnding` | A full session end enables the no-wait teardown path. | | `HandleStatelessSessionEndMessage_CloseApp_DoesNotSignalSystemSessionEnding` | Restart Manager closes the window while retaining normal child cleanup. | | `HandleStatelessSessionEndMessage_EndSessionCancelled_DoesNotSignalSystemSessionEnding` | Cancelled shutdown does not flag teardown. | | `HandleStatelessSessionEndMessage_QueryEndSession_DoesNotSignalSystemSessionEnding` | The query phase does not flag teardown. | **Build:** `runner.vcxproj` and `UnitTests-CommonUtils.vcxproj` build clean (`x64|Release`). The 8 focused tests pass. ## Manual validation 1. Build PowerToys and start the runner. 2. Initiate a sign-off (`logoff`) or restart. 3. Confirm Event Viewer (`Windows Logs → Application`) shows no `Application Hang` event for `PowerToys.exe`. 4. Right-click tray → Exit: confirm Settings.exe and the Quick Access host shut down gracefully and no ghost tray icon remains. (#48378 additionally captured real logoff/restart runs showing `WM_ENDSESSION → WM_DESTROY` completing in 1–8 ms with no hang events—the same full-session path used here.) ## Quality checklist - [x] Linked work item: AB#55588441 - [x] Module follow-up: #49539 - [x] Cross-references #41260; supersedes #48378 - [x] Unit tests (8 in `Window.Tests.cpp`) - [x] No new binaries - [x] Localization: no end-user strings changed - [x] Shared helper documents its stateless contract Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8d70b986-081a-43dd-bbfd-7e6351baef7a |
||
|
|
6d89ade9ad |
Fix PT Run ThreadPool worker leak from stale query cancellation (#48394)
## Summary Fixes a ThreadPool worker leak in PowerToys Run that can eventually surface as `System.OutOfMemoryException` from `Thread.StartInternal` after rapid typing and repeated stale-query cancellation. Related: #36041 and duplicate reports #45704, #36587, #39942, #20264, and #8878. ## Root cause `MainViewModel.QueryResults` stored the active cancellation token in a mutable field. When a new query replaced that field, older workers could observe the new, non-cancelled token instead of the token belonging to their own query. The previous `CancellationTokenSource` was also disposed while its consumers could still be running. As stale queries accumulated, they continued invoking plugins and consuming ThreadPool workers until the process could no longer create another worker thread. ## Changes - Adds `QuerySession`, which owns one captured token and the complete task lifetime for a query. Superseded sessions are cancelled immediately and their token sources are disposed only after their work completes. - Uses a suspended session start so query state is published before workers can return results. - Adds generation checks before scheduling and applying work so superseded queries cannot enqueue stale plugin tasks or update current results. - Adds a per-plugin execution gate. Calls to the same plugin do not overlap, while unrelated plugins can execute independently; cancelled waiters do not occupy ThreadPool workers. - Preserves legacy `IResultUpdated` compatibility by correlating generation-0 events using `RawQuery`. - Preserves the original two-phase query contract: all non-delayed plugin queries complete and their results are applied before delayed queries start. Delayed queries remain globally parallel, and `noInitialResults` is computed from the complete non-delayed phase. - Cancels and performs a bounded wait for the active query during shutdown. ## Tests `Wox.Test`: **142/142 passing** locally. Coverage includes: - token ownership, cancellation, deferred disposal, shutdown timeout, and suspended session startup; - current-query generation matching and legacy generation-0 compatibility; - per-plugin execution gating and queued latest-query behavior; - deterministic verification that delayed queries cannot start until every non-delayed query completes. ## Manual validation 1. Hold a key in PowerToys Run for 10–15 seconds and confirm the PowerToys Run process thread count stabilizes instead of growing monotonically. 2. Exercise normal Calculator, file, web, and indexer queries. 3. Enable search query tuning and waiting for slow results; confirm results appear and final sorting completes. 4. Start a slow query and type again before it completes; only the newest query should update results. 5. Exit PowerToys with a query in flight; shutdown should complete cleanly without orphaned processes. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Copilot-Session: 54e1bb28-edae-496b-8211-0e1592ddc985 |
||
|
|
44fd627c3a |
Tighten IContextMenu::GetCommandString in Image Resizer (#48399)
## Summary Corrects `IContextMenu::GetCommandString` handling in the Image Resizer shell extension. ## Changes - `GCS_VERBW` copies the Unicode canonical verb with `StringCchCopyW`, preserving copy failures. - Only `GCS_VALIDATEA` and `GCS_VALIDATEW` return `S_OK`. - ANSI verb requests, help-text requests, and unknown request types return `E_NOTIMPL`. - ANSI string verbs are intentionally not advertised because `InvokeCommand` cannot execute them. - Updates spell-check expectations for the Windows constants used by this implementation. ## Validation The authoritative local versions of all three changed files are pushed together. A Windows build was not run in this Linux environment. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
0d335ffbbd |
Add Peek.Common unit tests (MathHelper, PathHelper) (#49105)
## Summary Adds a **Peek.Common.UnitTests** project (MSTest) with unit coverage for Peek.Common.Helpers: - **MathHelper.Modulo** — positive/zero results, negative-dividend wrap-around, large values, and the new non-positive-divisor guard. - **MathHelper.NumberOfDigits** — single/multi-digit, negative, and 9/10 & 99/100 boundary values. - **PathHelper.IsUncPath** — standard UNC, subfolders, dotted-server and IP hosts, plus negatives: drive-letter, relative, empty, HTTP URL, ile:// URI, single backslash, and null. Also adds a small correctness guard to MathHelper.Modulo: a non-positive divisor now throws ArgumentOutOfRangeException instead of silently throwing DivideByZeroException (b == 0) or returning a misleading result (b < 0). Registers the test project in `PowerToys.slnx` (ARM64 + x64). **37 tests pass** locally (x64 Debug). ## Context This is a clean, **tests-only split of #46684** (the Peek.Common portion), intentionally **without** the bundled global dependency bump from that PR. The PowerAccent.Core portion of #46684 was shipped separately in #49104. ## Test coverage | Area | Tests | |------|-------| | MathHelper.Modulo / NumberOfDigits | included | | PathHelper.IsUncPath | included | No production behavior changes beyond the Modulo argument guard, which is covered by the new tests. Co-authored-by: Clint Rutkas <crutkas@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> |
||
|
|
7afcb8ce42 |
Fixing a WindowBase warning during compile (#49049)
Removing a warning that pops up a lot. **With fix:** <img width="694" height="674" alt="image" src="https://github.com/user-attachments/assets/2a496935-0d4b-45e6-97f2-62b8d4004faa" /> **Without fix:** here it is commented out to show the warning. <img width="1033" height="654" alt="Screenshot 2026-06-30 111523" src="https://github.com/user-attachments/assets/5d8f5df9-3c45-4155-a995-4b666df894fd" /> Found conflicts between different versions of "WindowsBase" that could not be resolved. There was a conflict between "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" and "WindowsBase, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35". "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" was chosen because it was primary and "WindowsBase, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" was not. References which depend on "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" [C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\10.0.8\ref\net10.0\WindowsBase.dll]. C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\10.0.8\ref\net10.0\WindowsBase.dll Project file item includes which caused reference "C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\10.0.8\ref\net10.0\WindowsBase.dll". C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\10.0.8\ref/net10.0/WindowsBase.dll References which depend on or have been unified to "WindowsBase, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" []. C:\Users\crutkas\.nuget\packages\microsoft.web.webview2\1.0.3719.77\lib_manual\net5.0-windows10.0.17763.0\Microsoft.Web.WebView2.Wpf.dll Project file item includes which caused reference "C:\Users\crutkas\.nuget\packages\microsoft.web.webview2\1.0.3719.77\lib_manual\net5.0-windows10.0.17763.0\Microsoft.Web.WebView2.Wpf.dll". C:\Users\crutkas\.nuget\packages\microsoft.web.webview2\1.0.3719.77\buildTransitive\..\\lib_manual\net5.0-windows10.0.17763.0\Microsoft.Web.WebView2.Wpf.dll |
||
|
|
021ca6aee0 |
Add Runner C++ hotkey conflict unit test seed (#48352)
Adds the C++ counterpart to #48346: a focused Runner native unit-test seed for core hotkey conflict behavior. Why this one: - Runner is core infrastructure rather than another C# module test. - It adds the missing native C++ test-project path for Runner. - The seed test is deterministic and covers in-app hotkey conflict detection. - It keeps the active rollout to two PRs: one C# module-services PR (#48346) and one C++ core/runner PR. Validation: - `tools\build\build.ps1 -Platform x64 -Configuration Debug -Path src\runner\UnitTests` - `vstest.console.exe x64\Debug\tests\Runner\Runner.UnitTests.dll /Tests:HasConflict_TwoModulesSameHotkey_InAppConflict` → 1 passed --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
7f1cdece68 |
Update SharpCompress to 0.50.1 (#49520)
## Summary of the Pull Request Updates `SharpCompress` from **0.37.2** to **0.50.1** (latest listed stable) and migrates Peek's `ArchivePreviewer` to the renamed APIs. 0.37.2 is subject to [GHSA-6c8g-7p36-r338](https://github.com/advisories/GHSA-6c8g-7p36-r338) (moderate severity), which currently produces an `NU1902` warning on restore. This upgrade clears it. The bump also required a real behavioral fix: `.tar.gz` / `.tgz` previews break outright on 0.50.1 without it. Details below. ## PR Checklist - [ ] Closes: #xxx <!-- N/A: no tracking issue, this is a dependency/security bump --> - [ ] **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 <!-- See "Validation Steps Performed" - Peek has no unit test project today, so this was validated with a differential harness. Happy to add coverage if desired. --> - [x] **Localization:** All end-user-facing strings can be localized <!-- N/A: no strings added or changed --> - [ ] **Dev docs:** Added/updated <!-- N/A --> - [ ] **New binaries:** Added on the required places <!-- N/A: no new binaries. SharpCompress.dll already ships with Peek; only its version changes. --> - [ ] [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 <!-- N/A --> ## Detailed Description of the Pull Request / Additional comments Two files change: **`Directory.Packages.props`** - central version pin moves `0.37.2` to `0.50.1`. `Peek.FilePreviewer.csproj` needs no edit because its `PackageReference` is versionless under Central Package Management. **`src/modules/peek/Peek.FilePreviewer/Previewers/Archives/ArchivePreviewer.cs`** - the only SharpCompress consumer in the repo. ### API renames Verified by reflecting over the shipped 0.50.1 assembly rather than guessing: | 0.37.2 | 0.50.1 | |---|---| | `ArchiveFactory.Open(...)` | `ArchiveFactory.OpenArchive(...)` | | `ReaderFactory.Open(...)` | `ReaderFactory.OpenReader(...)` | | `IArchive.TotalUncompressSize` | `IArchive.TotalUncompressedSize` | `ArchiveEncoding`, `ReaderOptions.Forced`, and `IEntry.Key`/`Size`/`IsDirectory` are unchanged, so the existing zip CP437 encoding-probe logic ported over without modification. ### Behavioral fix: `.tar.gz` / `.tgz` The renames alone are not sufficient. On 0.50.1, `ArchiveFactory.OpenArchive` can no longer open a gzip-compressed tar as a random-access archive; it throws `ArchiveOperationException: Cannot determine compressed stream type`. On 0.37.2 the same call succeeded and returned `type=Tar`. I probed six alternatives before settling on a fix: `OpenArchive(path)`, `ExtensionHint="tar.gz"`, `ExtensionHint=".tar.gz"`, `LookForHeader=true`, the `FileInfo` overload, and `OpenReader`. Only `ReaderFactory.OpenReader` works. The branch is now forward-only through `OpenReader`, and the `OpenArchive` + `stream.Seek(0)` preamble is removed. This path is user-reachable, so the break would have shipped: `FileItem.Extension` returns `.gz` for `foo.tar.gz`, and `.gz` is in `_supportedFileTypes`, so Peek does preview these files. ### Incidental correctness fix While rewriting that branch, the reported size changes. The old code used `archive.TotalUncompressSize`, which for a `.tar.gz` reported the size of the intermediate **tar container** rather than the sum of the entries. It now accumulates `reader.Entry.Size`, so the footer count/size line is correct for these archives. ## Validation Steps Performed `Peek.FilePreviewer` builds clean (x64 Release) resolving SharpCompress 0.50.1. Peek has no unit test project, and the only archive coverage in `Peek.UITests` is `Peek.FilePreview.ZIPArchive`, which previews `TestAssets\7.zip` and asserts via screenshot comparison. There is no `.tar.gz` test asset, so nothing in the existing suite would have caught the regression above. Given that, I validated with a standalone differential harness that replicates `LoadPreviewAsync` verbatim and runs it against **both** 0.37.2 and 0.50.1 over the same set of archives, comparing entry names and sizes: | Archive | 0.37.2 | 0.50.1 | |---|---|---| | `test.zip` | `sub/nested.txt (19)`, `hello.txt (11)`, total 30 | identical | | `utf8.zip` | names correct | names correct | | `sjis.zip` | `日本語/テスト.txt` correct | identical | | `short.zip` | `caf‚.txt`, `na‹ve.md`, `a¤o.log` (mangled, detected windows-1252) | `café.txt`, `naïve.md`, `año.log` (correct, detected utf-8) | | `test.tar.gz` | opens, total 4096 (container size) | opens, total 30 (correct) | | `test.tar` | ok | ok | | `hello.gz` | ok | ok | All entry names and sizes match. 0.50.1 is strictly more correct on short non-ASCII entry names and on `.tar.gz` sizing. One subtle difference worth flagging for reviewers: on `utf8.zip`, 0.50.1 honors `ArchiveEncoding.Forced` even for UTF-8-flagged zips, so the strict CP437 round-trip no longer throws and `encodingDetermined` comes back `false` where it was `true` before. The decoded names are still correct, because charset detection then correctly identifies UTF-8. No tested case produced wrong output. Manual validation: previewed `.zip`, `.tar`, `.tar.gz`, and `.gz` files in Peek. `NOTICE.md` lists SharpCompress by name without a version, so it needs no update. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: cb1e58a5-de5b-420e-8153-ef9b15810211 |
||
|
|
130a77907b |
[Keyboard Manager] Build the WinUI 3 editor self-contained to fix launch crash (0xC0000409) (#49524)
## Summary of the Pull Request `PowerToys.KeyboardManagerEditorUI.exe` fail-fasts with `0xC0000409` (`STATUS_STACK_BUFFER_OVERRUN`) during `MainWindow` construction, so the new Keyboard Manager editor never opens. `KeyboardManagerEditorUI.csproj` was the **only WinUI 3 executable in the repo missing `<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>`**, so it was built framework-package-dependent and mixed two Windows App SDK provenances in one process. ## PR Checklist - [x] Closes: #49399 - [ ] **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 <!-- no user-facing strings added --> - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places <!-- no new binaries --> - [ ] **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 ### Root cause The reporter's WinDbg capture shows a first-chance `Core::ApiException` carrying `0x800704DF` (`ERROR_ALREADY_INITIALIZED`): ``` MainWindow.SetTitleBar -> Microsoft.UI.Xaml.Window.set_ExtendsContentIntoTitleBar -> Microsoft.UI.Input!InputNonClientPointerSourceWinRTStatics::GetForWindowIdHelper -> Microsoft.UI.Windowing.Core!RegisterWindowFeature -> Core::NamedApiObject::Init -> Core::ApiException ``` `ExtendsContentIntoTitleBar` is the **site**, not the cause — it is simply the first user statement that crosses XAML -> Windowing -> Input. `microsoft.windowsappsdk.foundation/*/buildTransitive/Microsoft.WindowsAppSDK.BootstrapCommon.targets` turns the bootstrapper on precisely when this project's shape is hit: ```xml <PropertyGroup Condition="'$(WindowsAppSdkBootstrapInitialize)'=='' and '$(WindowsAppSDKSelfContained)'!='true' and '$(WindowsPackageType)'=='None' and ('$(OutputType)'=='Exe' or '$(OutputType)'=='Winexe')"> <WindowsAppSdkBootstrapInitialize>true</WindowsAppSdkBootstrapInitialize> </PropertyGroup> ``` That compiles in `MddBootstrapAutoInitializer.cs`, which joins the machine-wide `Microsoft.WindowsAppRuntime` MSIX framework package to the process package graph before `Main`. Meanwhile the exe's own directory — `WinUI3Apps` — is first in the Win32 DLL search order and already contains a complete app-local Windows App SDK payload, deployed there by the other 14 self-contained apps. One process, two Windows App SDK provenances, and the one-time feature-type registration in `Microsoft.UI.Input` collides. The omission was easy to miss: the project imports `src\Common.SelfContained.props`, whose name suggests it covers this — but it only sets the **.NET** `<SelfContained>` property, which is unrelated. This also explains why the reporter could not shake it off: the framework package is machine state, so uninstall/reinstall and wiping `%LOCALAPPDATA%\Microsoft\PowerToys` change nothing. The classic C++ editor is unaffected because it uses WinUI 2 XAML Islands and ships no Windows App SDK at all. `PowerToys.Settings.exe` ran healthily in the same elevated session on the same day while doing strictly more title-bar work (it sets `ExtendsContentIntoTitleBar` twice and drives `InputNonClientPointerSource.GetForWindowId` on every `SizeChanged`) — because it *is* self-contained. ### Two additional defects fixed Both were found while investigating why the crash left no diagnostics at all: 1. **`App.xaml.cs` initialized the logger via fire-and-forget `Task.Run`** — the only one of ~30 `Logger.InitializeLogger` call sites in the repo to do so. That races window creation, and `Logger` has no buffering or replay (`Trace.WriteLine` straight through, listener attached in `InitializeLogger`), so anything logged before the listener is attached is lost permanently. This is why the user's bug report bundle contains a `WinUI3Editor` log for the day it worked and **no log file at all** for the day it crashed. Made synchronous, ordered to match `FileLocksmithXAML/App.xaml.cs`, plus a log line before the window is constructed. 2. **`MainWindow` never called `WindowHelpers.ForceTopBorder1PixelInsetOnWindows10`**, unlike the other PowerToys WinUI 3 module windows (AdvancedPaste, EnvironmentVariables, FileLocksmith, Hosts, ImageResizer, Peek, RegistryPreview, Settings). It is a no-op on Windows 11 and fixes the black top border from microsoft/microsoft-ui-xaml#6901 on Windows 10 — the OS this issue was reported against. Happy to drop this hunk if reviewers prefer a minimal diff. Deliberately **not** done: wrapping `new MainWindow()` in `try/catch`. The failure is a WIL `RaiseFailFastException`, which managed code cannot intercept; and swallowing managed exceptions there would leave a windowless zombie process still holding the runner's `m_hEditorProcess` handle, making the runner take its "editor already open" branch and breaking every subsequent launch. That is why #49477 cannot work. ### Repo-wide audit All 15 WinUI 3 executables (`UseWinUI=true` and `OutputType=WinExe`) were checked. **KeyboardManagerEditorUI was the only one missing the property**; the other 14 already set it. Also verified as correct and unchanged: the 7 WinUI class libraries (property is app-level, N/A), `runner.vcxproj` and `PowerRenameUI.vcxproj` (native exes, both already `true`), and `PowerToys.MeasureToolCore.vcxproj` / `FindMyMouse.vcxproj` (deliberately `false` — in-proc module DLLs whose host already establishes the self-contained context). There is no repo-level default or build guard for this property; it is hand-copied into 17 project files, which is how the hole opened. A `Directory.Build.targets` guard that errors when an unpackaged Windows App SDK executable omits it would prevent recurrence, but it would catch nothing today, so I left it out of this PR to keep the diff scoped. Happy to open it separately. ## Validation Steps Performed Built `KeyboardManagerEditorUI.csproj` (x64/Debug) and diffed the build output before and after the change: | | before | after | `PowerToys.Hosts.exe` (reference) | |---|---|---|---| | `obj\x64\Debug\Manifests\` (created only by `CreateWinRTRegistration`) | absent | **present** | present | | `activatableClass` registrations embedded in the exe | **0** | **1912** | 1912 | | assembly references `Microsoft.WindowsAppRuntime.Bootstrap.Net` / `MddBootstrap` | **yes** | **no** | no | The editor now resolves every `Microsoft.UI.*` activation app-locally through registration-free WinRT instead of the machine framework package, which removes the mixing hazard. **Not yet validated on Windows 10.** I do not have a Windows 10 19045 machine, so the crash repro itself is unverified end-to-end. The deployment-mode change is verified from build output as above; confirmation from the issue reporter would be valuable. A useful discriminator if anyone has the reporter's ProcDump dump: `lm v m Microsoft.UI.*` — if `Microsoft.UI.Input.dll` is listed twice from two different paths, the mechanism is confirmed directly. Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com> Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
837fe46ed3 |
Add Awake module services unit test seed (#48346)
Adds an Awake module-services unit-test seed for runtime state creation from timed settings. This is product/module coverage, not Settings UI model serialization.\n\nValidation:\n- Restored and built Awake.ModuleServices.UnitTests x64 Debug\n- Ran the filtered test CreateState_TimedSettings_ReturnsTimedStateWithDuration: 1 passed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
7ddfd2f3e0 |
[Updater] Open PowerToys handle before WM_CLOSE to avoid PID-recycle race (#46973)
Narrows this PR to @yeelam-gordon's review feedback. The wait-for-exit before launching the installer is **already in `main`** (landed separately), so the original change here is now redundant. What's **not** in main is the PID-recycle hazard Gordon flagged, so this PR applies just that fix: Open the PowerToys process handle **before** sending `WM_CLOSE`. PowerToys can exit inside its own `WM_CLOSE` handler, after which the OS may recycle its PID — opening by PID afterwards could then fail or attach to an unrelated process that reused it, and `WaitForSingleObject` would wait on the wrong thing. Holding the handle first anchors the kernel object to the original process, so PID reuse is impossible while we wait on it. Rebased onto latest `main` (resolves the previous merge conflict). Originally fixes #46966. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
e7b3346aff |
CmdPal: Improve performance of Window Walker extension (#49317)
## Summary of the Pull Request This PR improves performance of Window Walker, to make it faster (or at least make it look like it is faster). - Adds cached Window Walker list items and window snapshots for faster page loading. - Changes window enumeration to refresh asynchronously without blocking initial results. - Adds lazy, sequential icon loading with cached icon data. - Reuses existing list items when window metadata changes. - Fixes incorrect destruction of borrowed window icon handles. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #49315 <!-- - [ ] 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 |
||
|
|
346b498fb5 |
Shortcut Guide: Replace dual windows with single transparent overlay and add holding windows button (#48683)
## Summary Refactors Shortcut Guide from two separate `WindowEx` instances (`MainWindow` + `TaskbarWindow`) into a single full-monitor transparent `OverlayWindow` that hosts both surfaces as XAML UserControls. This enables shared animations and a more polished visual experience, and makes the taskbar shortcut indicators **edge-aware** for Windows 11's top/bottom/left/right taskbar positioning. https://github.com/user-attachments/assets/e40a25f6-4ab3-4073-b1a8-906ef7782877 <img width="507" height="968" alt="image" src="https://github.com/user-attachments/assets/2e06a3d9-32d9-482e-90fe-1f0f8a7d7598" /> ## Changes Closes: #48435 Closes #48491 Closes: #49200 Closes: #48552 (theme flash on Light/System theme + shortcut-list scroll flutter) Closes: #48773 ### Architecture - **OverlayWindow**: Single transparent host covering the full monitor work area, using `TransparentTintBackdrop` - **MainPaneControl**: The shortcut list pseudo-window, reusing the shared `TransientSurface` control for chrome (acrylic backdrop, theme shadow, rounded corners) - **TaskbarPaneControl + TaskbarIndicator**: Tooltip-style indicators with triangle tails, positioned above taskbar buttons ### Edge-aware taskbar indicators (Windows 11 top/bottom/left/right) - Detects the taskbar edge via the public, documented `SHAppBarMessage` / `ABM_GETTASKBARPOS` API (the same API CmdPal Dock uses) - Indicators lay out along the correct axis — horizontally for a top/bottom taskbar, vertically for a left/right taskbar — with the triangle tail always pointing toward the taskbar (4-direction tail + per-edge slide-in animation) - For a left/right taskbar, the main pane is inset so the order reads **taskbar | indicators | pane** - **Adaptive sizing**: each indicator's body size is derived from the actual measured UIA taskbar button rect, so the bubbles shrink when Windows uses small icons or combines buttons (many apps open). Uses the smallest button slot (clamped to a readable range) so neighbouring bubbles never overlap; the font scales with it ### Visual polish - Windows 11 system flyout entry/exit animations (slide + fade, ~367ms entrance / ~200ms exit with cubic easing) - Animation direction is position-aware (slides from left when left-aligned, from right when right-aligned) - Taskbar indicators slide in from the taskbar edge with the same timing - Close button on the main flyout title bar ### Robustness - Multi-monitor DPI handling via WM_DPICHANGED suppression (prevents double-scaling on cross-monitor moves) - Win11 phantom border elimination (comprehensive DWM/style stripping) - Click-outside-to-close with animated exit transition - Process lifetime fix (`Application.Current.Exit()` on close) ## Validation - Build clean (x64 Debug, exit 0, empty errors log) - Tested on multi-monitor mixed-DPI setup (150% + 100%) - Tested with the taskbar docked to each edge (top/bottom/left/right) and with small/combined taskbar icons --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Noraa Junker <noraa.junker@outlook.com> Co-authored-by: Clint Rutkas <clint@rutkas.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
d7afa69048 |
Fix _snwprintf_s size argument in BugReportTool EventViewer (#48398)
## Summary Caught while reading through `BugReportTool` for an unrelated review: the two `_snwprintf_s` calls in `EventViewer.cpp` pass `sizeof(buff)` as the buffer-size argument, but `buff` is a `wchar_t[1000]`. `_snwprintf_s` measures its size and count arguments in **wide characters**, not bytes, so the current code advertises a 2000-wchar destination for a buffer that only holds 1000. `cpp wchar_t buff[1000]; // 2000 bytes, 1000 wchars memset(buff, 0, sizeof(buff)); _snwprintf_s(buff, sizeof(buff), fmt, ...); // <-- 2000 passed as wchar count ` If the formatted output ever exceeds 1000 wchars, the Secure CRT bounds check fires (in debug) and - depending on which `_snwprintf_s` overload the compiler selects against the safe template - it can write past the end of the stack buffer in release. Neither format string here is likely to produce 1000+ characters in practice (one substitutes a process name, the other a channel name + integer), so this is more of a latent footgun than a known crash, but the bounds are simply wrong. ## Fix Use `_countof(buff)` for the size argument (which is what `_snwprintf_s` actually wants - element count, not byte count) and pass `_TRUNCATE` for the count so output is safely capped at 999 wchars plus the null terminator: `cpp _snwprintf_s(buff, _countof(buff), _TRUNCATE, fmt, ...); ` Applied to both `GetQuery` and `GetQueryByChannel`. ## Scope Searched the rest of the repo for the same pattern (`_snwprintf_s(buf, sizeof(...))` / `_snprintf_s(buf, sizeof(...))`) - these two call sites are the only occurrences in the codebase. ## Validation - `BugReportTool.sln` rebuilds clean locally (Release|x64) and produces `PowerToys.BugReportTool.exe`. - No behavior change on the happy path - both formats are well under 1000 wchars in normal use. ## Risk Low. Two-line change in a single utility that builds event-log queries for bug reports. Truncation on overflow is strictly safer than the prior behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
354a43bd8c |
[Deps] Update .NET packages from 10.0.9 to 10.0.10 (#49419)
## Summary of the Pull Request Updates the centrally pinned .NET 10 `Microsoft.*` packages in `Directory.Packages.props` from `10.0.9` to `10.0.10`. ## 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 Bumps the .NET 10 `Microsoft.*` package pins from `10.0.9` to `10.0.10` to match the latest servicing release. ## Validation Steps Performed Not run locally here; change is a package version bump only. Co-authored-by: Copilot <copilot@github.com> |
||
|
|
fc680d350f |
[Quick Accent] Fix window width when descriptions are disabled (#49402)
## Summary of the Pull Request Fixes Quick Accent clipping or horizontally shifting the last character when Unicode descriptions are disabled and the character list is short. The WinUI window width was calculated as `item count × 48 DIPs`, but the selector surface also has 24-DIP left and right margins and a 1-DIP border on each side. Those values reduced the usable list width. Fractional layout rounding at scaled display settings could then leave the viewport one physical pixel too narrow even after accounting for the nominal XAML dimensions. The sizing calculation now reads the surface's live horizontal margin and border thickness and includes them in the requested window width. It also adds a 1-DIP layout-rounding allowance so the character list is not truncated at fractional display scales. ## PR Checklist - [x] Closes: #49346 - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - The proposed root cause and approach were posted in the [contribution thread](https://github.com/microsoft/PowerToys/issues/28769#issuecomment-5013633279); maintainer confirmation is still pending. - [ ] **Tests:** Added/updated and all pass - No automated test was added because this fix connects runtime WinUI layout values and display scaling to the window-size calculation; a unit test that duplicated the XAML dimensions would not catch the integration regression. - [x] **Localization:** All end-user-facing strings can be localized - No strings changed. - [x] **Dev docs:** Added/updated - No developer documentation changes are needed for this focused layout correction. - [x] **New binaries:** Added on the required places - No binaries or projects were added. - [x] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries — not applicable - [x] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder — not applicable - [x] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects — not applicable - [x] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) — not applicable - [ ] **Documentation updated:** Not applicable; there is no user-facing behavior or documentation change. ## Detailed Description of the Pull Request / Additional comments `SelectorControl.xaml` gives the `TransientSurface` a `Margin=24,24,24,16`, and `DefaultTransientSurfaceStyle` supplies a 1-DIP border on each side. For the four-character reproduction in #49346, the previous calculation requested a 192-DIP window (`4 × 48`). After the 48 DIPs of horizontal surface margin, only 144 DIPs remained for the list, which is exactly three character cells. `SelectorControl` now exposes the computed left-plus-right surface margin and border thickness internally. `MainWindow.SizeAndPosition()` adds that live overhead to the character-driven width before applying the existing description minimum and monitor-width clamp. A further 1-DIP allowance covers fractional physical-pixel rounding at scaled display settings. With four characters, the calculation reserves the complete 192-DIP list width, the 50-DIP surface overhead, and the 1-DIP layout-rounding allowance. This leaves long-list scrolling, selected-character scrolling, description sizing, monitor clamping, DPI conversion, and window positioning unchanged. ## Validation Steps Performed - `git diff --check` passes. - Built `PowerAccent.UI` locally with Visual Studio 2026 in `Debug|x64`; the build completed successfully with 0 warnings and 0 errors. - Runtime-tested with Unicode descriptions disabled and only `SPECIAL` enabled. Holding `X` and pressing `Space` displayed all four mapped characters (`ẋ`, `×`, `ˣ`, `ₓ`) without clipping or scrolling. - Reproduced the one-pixel horizontal shift with all character sets enabled at 150% and 175% display scaling. - Retested the 1-DIP layout-rounding allowance at both 150% and 175%; all seven `F` characters remained stationary while cycling through the selection. - Verified the description minimum and maximum monitor-width clamp remain in the same order after the corrected content width is calculated. --------- Co-authored-by: Dave Rayment <dave.rayment@gmail.com> |
||
|
|
b69bfe7f86 |
CmdPal: Replace custom sign(x) function with built-in sgn(x) function (#49392)
## Summary of the Pull Request This PR allow use of built-in `sgn` function in exprtk in Calculator and uses it to implement `sign` function. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #49391 <!-- - [ ] 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 |
||
|
|
c87ef67103 |
CmdPal: Ensure visual state groups set properties exclusively (#49319)
## Summary of the Pull Request This PR updates DockItemControl to ensure that visual state groups exclusively set properties and don't overlap to prevent unexpected and undeterministic result. - TextVisibilityStates and TextAlignmentStates shared SubtitleText.Visibility - TextVisibilityStates and IconVisibilityStates shared ContentGrid.ColumnSpacing <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #47980 - [x] Closes: #49156 <!-- - [ ] 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 |
||
|
|
bc32d4216c |
CmdPal: Prevent selection from overriding ListView scrolling (#49354)
## Summary of the Pull Request This PR make ensuring selected item visibility on the list view optional and avoids it when user scrolls list view viewport manually (using scrollbar or mouse wheel), without touching selection. - Implicitly keep selection when using incrementel loading (incrementel loading) - Make ensuring the selected item is visible optional, and skip it when the user scrolls the ListView viewport using the scrollbar or mouse wheel <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #46592 <!-- - [ ] 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 |