Compare commits

..

20 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
c412e85cfc Switch AI model from gpt-4o-mini to gpt-4o for better classification accuracy
Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/0789f3f1-1c5e-4f3b-9d03-dd771793a01c

Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-18 11:24:22 +00:00
copilot-swe-agent[bot]
049cbccd21 Extract magic numbers to named constants per review feedback
Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/5188f8c6-4eea-4d6a-a1f5-44a10c0100d7

Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-18 11:21:47 +00:00
copilot-swe-agent[bot]
4308eb65a9 Add scheduled workflow for auto-labeling issues missing Product-* labels
Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/5188f8c6-4eea-4d6a-a1f5-44a10c0100d7

Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-18 11:20:55 +00:00
moooyo
5520ae4cfa [PowerDisplay] Fix startup restore, volume init, and identify window lifecycle (#47051)
<!-- 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
- **Volume initialization**: Read VCP 0x62 on monitor discovery so
`CurrentVolume` reflects actual hardware state instead of staying at the
50% default.
- **Brightness capability check**: Guard brightness init behind
`SupportsBrightness` flag, consistent with contrast/volume handling.
- **IdentifyWindow lifecycle**: Replace fire-and-forget `Task.Delay`
with `DispatcherQueueTimer` (UI-thread-safe, stoppable on dispose). Swap
`Activate`/`PositionOnDisplay` order to eliminate first-show flicker.
- **Startup restore fix**: Change `MonitorStateEntry` fields to `int?`
so unset values (`null`) aren't confused with zero — prevents writing
default 0% brightness/volume to hardware on startup.
- **Restore/profile apply refactor**: Push value validation down to
`Set*Async` (continuous → `Math.Clamp`, discrete → capabilities check),
extract unified `TryRestore` helper, remove redundant `IsValueInRange`
and `> 0` checks.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

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

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

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

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 08:41:14 +00:00
moooyo
beddc3b065 [ImageResizer] Fix JsonPropertyName forwarding in ObservableProperty generator (#47056)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This issue introduced by our recent WinUI 3 migration

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

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

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

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

Co-authored-by: Yu Leng <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4 <noreply@anthropic.com>
2026-04-17 15:20:45 +08:00
Niels Laute
088da21a70 Update default module states (#47027)
## Summary

- **Disable 7 modules by default** for new users: PowerToys Run, Crop
and Lock, Advanced Paste, Hosts File Editor, Registry Preview,
Environment Variables, Workspaces
- **Swap default hotkeys**: Command Palette now defaults to \Alt+Space\,
PowerToys Run now defaults to \Win+Alt+Space\
- Update unit test to reflect PowerLauncher default-off state

## Changes

| File | Change |
|------|--------|
| \EnabledModules.cs\ | Set 7 module defaults to off |
| \PowerLauncherProperties.cs\ | Default hotkey → \Win+Alt+Space\ |
| \SettingsModel.cs\ (CmdPal) | Default hotkey → \Alt+Space\ |
| \General.cs\ (test) | Assert PowerLauncher is false |

## Validation

- Existing unit test updated to match new defaults
- No ABI or IPC contract changes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-16 08:44:25 +02:00
Gordon Lam
befb5c672e Fix AdvancedPaste auto-copy failing on Electron/Chromium apps (#46486)
## Summary

Fixes #46485

AdvancedPaste's auto-copy feature fails on Electron/Chromium-based apps
(e.g. Microsoft Teams, VS Code, browsers) because `WM_COPY` is delivered
successfully but silently ignored by these apps.

## Problem

The auto-copy code sends `WM_COPY` via `SendMessageTimeout`. For
standard Win32 controls this works, but Electron apps accept the message
delivery without actually copying to clipboard. The code treated
successful delivery as success and **never fell back to `SendInput`
Ctrl+C**.

## Changes


**`src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp`**:

- **Changed retry logic**: Each attempt now tries both `WM_COPY` and
`SendInput` Ctrl+C. If `WM_COPY` is delivered but clipboard is
unchanged, it falls through to Ctrl+C instead of giving up.
- **Extracted `poll_clipboard_sequence()` helper**: Reusable clipboard
polling logic (checks `GetClipboardSequenceNumber` over N polls with
configurable delay).
- **Extracted `send_ctrl_c_input()` helper**: Sends Ctrl+C via
`SendInput` with `CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG`.
- **Improved logging**: Each strategy logs clearly whether it succeeded
or fell through, making future debugging easier.

## Validation

- [x] Manual testing with Microsoft Teams (Electron): auto-copy now
works for selected text
- [x] Standard Win32 apps (Notepad, etc.): `WM_COPY` still works on
first try, no regression
- [x] No new warnings or errors in build

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-16 10:49:40 +08:00
Niels Laute
578554d157 [Settings] Format last update check date with friendly relative dates (#46923)
## Summary

Formats the Last checked date on the General and Dashboard pages with
friendly relative strings instead of raw date/time output.

**Before:** Last checked: 4/12/2026 1:22:00 PM
**After:** Last checked: Today at 1:22 PM / Yesterday at 3:45 PM

### Changes

- Add LastCheckedDateTime property to UpdatingSettings exposing the
parsed DateTime
- Create FriendlyDateHelper in Settings.UI that formats Today/Yesterday
with localized resource strings, falling back to the full
culture-specific format for older dates
- Update GeneralViewModel and CheckUpdateControl to use the friendly
format
- Add localized resource strings General_LastCheckedDate_TodayAt and
General_LastCheckedDate_YesterdayAt

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-15 10:06:10 +02:00
Gordon Lam
e4f98897ce Add window positioning and sizing with Alt+mouse button (#47024)
Re-creation of #46817 from an internal branch to work around stale
code-scanning merge protection.

## Original PR
See #46817 for full context, discussion, and review history.

## Summary
This adds a new toy, GrabAndMove (previously WinPos), that allows
dragging (left click) or resizing (right click) of windows while the Alt
key is pressed.

Closes: #269

## PR Checklist
- [x] Communication: discussed with core contributors
- [ ] Tests: Added/updated and all pass
- [ ] Localization: All end-user-facing strings can be localized
- [ ] Dev docs: Added/updated

---------

Co-authored-by: foxmsft <foxmsft@hotmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Muyuan Li (from Dev Box) <muyuanli@microsoft.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Alex Mihaiuc <amihaiuc@microsoft.com>
2026-04-15 09:13:56 +02:00
Muyuan Li
be1e749574 Add telemetry support for CLI modules (#46872)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This PR adds comprehensive localization and telemetry support to the
modules with CLI (FileLocksmith, Awake, ImageResizer), improving user
experience for international users and enabling usage tracking for
product insights.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

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

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

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-15 14:14:12 +08:00
Niels Laute
dc57d22754 [Settings] Fix Dashboard layout and 1px alignment offset (#46922)
## Summary

Fixes layout issues on the Settings Dashboard page:

- **Scroll area fix**: The scroll area on the Home page extended far
beyond the content, leaving a large empty space below the modules list.
(By wrapping the quick launch / shortcuts cards into a `StackPanel` vs
separate `Grid.Rows`
- **Resizing fix**: On main, resizing states are not applied when making
the window smaller. This is now fixed.
- **1px alignment fix**: Fixed a 1-pixel vertical alignment mismatch on
the Dashboard shortcut conflict control.

Closes #45925
Closes #41523
2026-04-14 15:30:29 +02:00
moooyo
99ef5948b0 [PD] Fix thread safety, color temperature guard, and log accuracy (#47008)
Mark _disposed and _isDirty as volatile for correct cross-thread
visibility. Guard color temperature apply/restore behind
ShowColorTemperature to avoid writing unsupported VCP codes. Fix
misleading log message in Settings UI profile apply path.

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

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

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

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

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

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 08:49:54 +00:00
Niels Laute
218a01c1a9 Fix for back up folder path being clipped (#46920)
<!-- 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

Before:
<img width="661" height="530" alt="image"
src="https://github.com/user-attachments/assets/b77c12b2-481f-4f77-8f74-fa679331a604"
/>

After:
<img width="678" height="365" alt="image"
src="https://github.com/user-attachments/assets/ea997ab6-f1f5-4191-ac24-15885b2e19d3"
/>

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

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

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

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-14 10:23:58 +02:00
Niels Laute
1c7f3d832c [Text Extractor] Remove WPF-UI in favor of Fluent theming in WPF (#46218)
Replaces the `WPF-UI` dependency in Text Extractor with native WPF
Fluent theming (`ThemeMode="System"`), custom
`SubtleButtonStyle`/`SubtleToggleButtonStyle` control templates, and
Segoe Fluent Icons font — eliminating the third-party library while
retaining light/dark theme support.

## Summary of the Pull Request

- Drops `xmlns:ui` (WPF-UI) from `App.xaml` and `OCROverlay.xaml`
- Removes `Wpf.Ui.Appearance.SystemThemeWatcher.Watch()` call; replaced
by `ThemeMode="System"` on `<Application>`
- Defines inline `SubtleButtonStyle` and `SubtleToggleButtonStyle` using
WinUI-aligned resource brush names (`SubtleFillColorSecondaryBrush`,
`AccentFillColorDefaultBrush`, etc.)
- Replaces `<ui:SymbolIcon>` with `<TextBlock
FontFamily="{DynamicResource SymbolThemeFontFamily}">` using Unicode
glyph codes
- Background uses `SolidBackgroundFillColorBaseBrush` instead of
`ApplicationBackgroundBrush`

| Light | Dark |
|-------|------|
|
![light](https://github.com/user-attachments/assets/dc03fdb3-3ef4-4f18-8352-c58fbdd19dd5)
|
![dark](https://github.com/user-attachments/assets/38fdbd6a-53cb-410d-8486-92927019be2a)
|

## PR Checklist

- [ ] **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

Related: #46220

## Validation Steps Performed

Verified light and dark themes render correctly with proper accent
highlight on the active toggle button.

---------

Co-authored-by: Joe Finney <josephfinney@LIVE.COM>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-14 14:37:27 +08:00
moooyo
ff87dce4a4 [PD] Clean up PowerDisplay: fix resource leaks, remove dead code, and fix some bugs (#46979)
- Replace custom GetLastError P/Invoke with Marshal.GetLastWin32Error
and add SetLastError=true
- Fix resource leaks: dispose DpiSuppressor on window close, dispose
MonitorViewModels on refresh, destroy unused small icon handle, wrap WMI
outParams in using block
- Remove unused code: IProfileService, ColorTemperatureHelper,
ProfileHelper (Lib), CustomVcpValueMappingExtensions, IPCMessageAction,
UpdatePropertySilently, LocalizedCodeNameProvider, bring_to_front,
Constants.h
- Convert recursive MccsCapabilitiesParser.TryParseEntry to iterative
loop
- Simplify ProfileService to static class
- Use std::atomic for m_enabled flag in module interface
- Change default activation shortcut to Win+Ctrl+Shift+P
- Add null-coalescing fallback for ActivationShortcut property
- Add PowerDisplay to ModuleHelper name mapping
- Update GPO policy to target PowerToys 0.99.0
- Fix NamedPipeProcessor to break on pipe close and reduce log verbosity
- Add ShortcutControl workaround in Settings UI

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

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

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [x] **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

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

Co-authored-by: Yu Leng <yuleng@microsoft.com>
Co-authored-by: Claude Opus 4 <noreply@anthropic.com>
2026-04-13 18:00:04 +00:00
Jiří Polášek
758a60103c CmdPal: Include new transitive dependencies in SLNF (#46896)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

This PR adds new transitive dependencies to Command Palette’s SLNF (UI
tests -> UITestAutomation -> ...), and introduces a new SLNF that
excludes UI tests entirely, making it leaner.

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

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

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

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2026-04-13 11:47:25 -05:00
Copilot
f8cadbf7f0 Fix AlwaysOnTop sound playing when pin/unpin fails (#46910)
## Summary of the Pull Request

`ProcessCommand` played the pin/unpin sound unconditionally, regardless
of whether `SetWindowPos` succeeded. This caused spurious audio feedback
when targeting desktop, taskbar, task view, start menu, or elevated
windows from a non-elevated process.

Gate sound playback on actual state change:

```cpp
bool stateChanged = false;
// ...
if (UnpinTopmostWindow(window)) { stateChanged = true; /* ... */ }
// ...
if (PinTopmostWindow(window))   { stateChanged = true; /* ... */ }
// ...
if (stateChanged && AlwaysOnTopSettings::settings()->enableSound)
    m_sound.Play(soundType);
```

## PR Checklist

- [ ] **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

`PinTopmostWindow` and `UnpinTopmostWindow` already return `bool`
indicating success, and the existing code already branches on those
return values for bookkeeping and telemetry — but the sound playback at
the end of `ProcessCommand` ignored the result. Added a `stateChanged`
flag set only inside the success branches, then checked before calling
`m_sound.Play()`.

## Validation Steps Performed

- Verified that the `soundType` / `stateChanged` logic covers all four
paths: pin success, pin failure, unpin success, unpin failure.
- Code review passed with no comments.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-13 12:53:06 +02:00
Niels Laute
0819a6268b [CmdPal] Move dev docs to doc/devdocs/modules/cmdpal (#46926)
## Summary

Move Command Palette developer documentation from
\src/modules/cmdpal/doc\ to \doc/devdocs/modules/cmdpal\, consistent
with the location of other module dev docs.

Also updates the spell-check exclude path for the moved \.pdn\ file.

Points 2 and 3 from the issue (extension settings how-to and details
pane markdown documentation) are addressed in the windows-dev-docs-pr
repo.

Closes #38107

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-12 12:33:30 -05:00
Niels Laute
a31f82fcbd [CmdPal] Fix Window Walker 'Not Responding' tag illegible in dark mode (#46924)
## Summary

The 'Not Responding' tag in Window Walker used a hardcoded crimson
foreground color (rgb 220,20,60) that was illegible against the dark tag
background in dark mode.

**Fix:** Remove the hardcoded color override so the tag uses the default
theme-aware TagForeground brush, which is legible in both light and dark
modes.

Closes #40219

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-12 12:32:49 -05:00
Copilot
daeb2e1ef4 Fix CmdPal Calc extension unit test failure in non-English cultures (#46911)
## Summary of the Pull Request

`TrigModeSettingsTest` fails under cultures using `,` as decimal
separator (e.g., `de-DE`, `fr-FR`). Two root causes: the C++ calculator
engine's `ToWStringFullPrecision` doesn't pin the stream locale, and the
test classes don't set a deterministic thread culture.

## PR Checklist

- [x] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated

## Detailed Description of the Pull Request / Additional comments

**C++ locale fix** — `ExprtkEvaluator.cpp`: `std::wostringstream`
defaults to the global C++ locale, which can be changed to the system
locale by the runtime. Pin it to `std::locale::classic()` so the decimal
separator is always `.` across the WinRT boundary:

```cpp
std::wostringstream oss;
oss.imbue(std::locale::classic());
oss << std::fixed << std::setprecision(15) << value;
```

**Test culture setup** — `QueryTests.cs`, `QueryHelperTests.cs`: Added
`TestInitialize`/`TestCleanup` to set thread culture to `en-US`,
matching the existing pattern across all TimeDate test classes.

**Non-English culture test cases** — New
`TrigModeSettingsTest_NonEnglishCulture` parameterized over `de-DE` and
`fr-FR` verifies `outputUseEnglishFormat: true` produces `.`-separated
output regardless of `CurrentCulture`.

## Validation Steps Performed

- Code review passed with no actionable findings (naming convention
matches existing TimeDate test pattern across 7+ files)
- New `TrigModeSettingsTest_NonEnglishCulture` test exercises the exact
failure scenario from the issue

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-12 14:12:34 +02:00
186 changed files with 3888 additions and 2596 deletions

View File

@@ -328,9 +328,6 @@ MRUCMPPROC
MRUINFO
REGSTR
# Quick Accent
Ene
# Misc Win32 APIs and PInvokes
INVOKEIDLIST
MEMORYSTATUSEX
@@ -392,9 +389,5 @@ nostdin
engtype
Nonpaged
# Spell-check fragments
traies
udit
# XAML
Untargeted

View File

@@ -107,7 +107,7 @@
^src/common/sysinternals/Eula/
^src/modules/cmdpal/Tests/Microsoft\.CommandPalette\.Extensions\.Toolkit\.UnitTests/FuzzyMatcherComparisonTests.cs$
^src/modules/cmdpal/Tests/Microsoft\.CommandPalette\.Extensions\.Toolkit\.UnitTests/FuzzyMatcherDiacriticsTests.cs$
^src/modules/cmdpal/doc/initial-sdk-spec/list-elements-mock-002\.pdn$
^doc/devdocs/modules/cmdpal/initial-sdk-spec/list-elements-mock-002\.pdn$
^src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage\.cs$
^src/modules/cmdpal/Microsoft\.CmdPal\.UI/Settings/InternalPage\.SampleData\.cs$
^src/modules/cmdpal/Tests/Microsoft\.CmdPal\.Common\.UnitTests/.*\.TestData\.cs$

View File

@@ -791,6 +791,7 @@ lowlevel
LOWORD
lparam
LPBITMAPINFOHEADER
LPCFHOOKPROC
lpch
LPCITEMIDLIST
LPCLSID
@@ -832,6 +833,7 @@ lstrlen
LTEXT
LTRREADING
luid
LUMA
lusrmgr
LVal
LWA
@@ -850,6 +852,7 @@ MAPPEDTOSAMEKEY
MAPTOSAMESHORTCUT
MAPVK
MARKDOWNPREVIEWHANDLERCPP
MAXDWORD
MAXSHORTCUTSIZE
maxversiontested
MBM
@@ -914,6 +917,7 @@ MOUSEINPUT
MOVESIZEEND
MOVESIZESTART
MRM
MRT
mru
msc
mscorlib
@@ -1637,6 +1641,7 @@ tracelogging
tracerpt
trackbar
trafficmanager
traies
transicc
TRAYMOUSEMESSAGE
triaging
@@ -1657,6 +1662,7 @@ UBR
UCallback
ucrt
ucrtd
udit
uefi
uesc
UFlags
@@ -2299,6 +2305,7 @@ virama
vnd
vredraw
VSpeed
VSync
WASDK
WCRAPI
wft
@@ -2336,3 +2343,9 @@ YTimer
zamora
zonability
Zorder
LLMHF
RIGHTBUTTON
SIZEALL
grabandmove
GRABANDMOVEMODULEINTERFACE
INITCOMMONCONTROLSEX

View File

@@ -0,0 +1,232 @@
name: Scheduled Issue Product Labeling
on:
schedule:
- cron: "20 */6 * * *" # Every 6 hours at :20
workflow_dispatch: # Allow manual trigger
permissions:
models: read
issues: write
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
jobs:
label-issues:
runs-on: ubuntu-latest
steps:
- name: Label issues missing Product labels
uses: actions/github-script@v7
with:
script: |
// ── Product label mapping ──────────────────────────────────
// Canonical list of Product-* labels used in this repo,
// derived from .github/skills/release-note-generation/references/step2-labeling.md
const PRODUCT_LABELS = [
"Product-Advanced Paste",
"Product-Always on Top",
"Product-Awake",
"Product-ColorPicker",
"Product-Command not found",
"Product-Command Palette",
"Product-CropAndLock",
"Product-Cursor Wrap",
"Product-Environment Variables",
"Product-FancyZones",
"Product-File Explorer",
"Product-File Locksmith",
"Product-Find My Mouse",
"Product-Hosts",
"Product-Image Resizer",
"Product-Keyboard Manager",
"Product-LightSwitch",
"Product-Mouse Highlighter",
"Product-Mouse Jump",
"Product-Mouse Pointer Crosshairs",
"Product-Mouse Without Borders",
"Product-New+",
"Product-Peek",
"Product-PowerRename",
"Product-PowerToys Run",
"Product-Quick Accent",
"Product-Registry Preview",
"Product-Screen Ruler",
"Product-Settings",
"Product-Shortcut Guide",
"Product-Text Extractor",
"Product-Workspaces",
"Product-ZoomIt",
];
// Map from bug-report "Area(s) with issue?" dropdown values
// to Product-* labels (used as strong hints when the issue body
// contains the area dropdown answer).
const AREA_TO_LABEL = {
"Advanced Paste": "Product-Advanced Paste",
"Always on Top": "Product-Always on Top",
"Awake": "Product-Awake",
"ColorPicker": "Product-ColorPicker",
"Command not found": "Product-Command not found",
"Command Palette": "Product-Command Palette",
"Crop and Lock": "Product-CropAndLock",
"Environment Variables": "Product-Environment Variables",
"FancyZones": "Product-FancyZones",
"FancyZones Editor": "Product-FancyZones",
"File Locksmith": "Product-File Locksmith",
"File Explorer: Preview Pane": "Product-File Explorer",
"File Explorer: Thumbnail preview": "Product-File Explorer",
"Hosts File Editor": "Product-Hosts",
"Image Resizer": "Product-Image Resizer",
"Keyboard Manager": "Product-Keyboard Manager",
"Light Switch": "Product-LightSwitch",
"Mouse Utilities": "Product-Find My Mouse",
"Mouse Without Borders": "Product-Mouse Without Borders",
"New+": "Product-New+",
"Peek": "Product-Peek",
"PowerRename": "Product-PowerRename",
"PowerToys Run": "Product-PowerToys Run",
"Quick Accent": "Product-Quick Accent",
"Registry Preview": "Product-Registry Preview",
"Screen ruler": "Product-Screen Ruler",
"Shortcut Guide": "Product-Shortcut Guide",
"TextExtractor": "Product-Text Extractor",
"Workspaces": "Product-Workspaces",
"ZoomIt": "Product-ZoomIt",
};
// ── Helpers ────────────────────────────────────────────────
function hasProductLabel(labels) {
return labels.some((l) => l.name.startsWith("Product-"));
}
// Try to extract the area from the structured bug-report body
// (the "Area(s) with issue?" dropdown).
function extractAreaFromBody(body) {
if (!body) return null;
// The rendered issue body contains a heading followed by the selected values
const areaMatch = body.match(
/### Area\(s\) with issue\?\s*\n+(.+?)(?:\n###|\n\n|$)/s
);
if (!areaMatch) return null;
const areaText = areaMatch[1].trim();
if (areaText === "_No response_" || areaText === "General") return null;
// Could be comma-separated; take the first specific one
const areas = areaText.split(",").map((a) => a.trim());
for (const area of areas) {
if (AREA_TO_LABEL[area]) return AREA_TO_LABEL[area];
}
return null;
}
// Use GitHub Models to classify an issue when the dropdown area
// is not available or is "General".
const MAX_BODY_LENGTH = 3000; // Truncate body to stay within model token limits while keeping enough context
const MAX_COMPLETION_TOKENS = 60; // Enough for a Product-* label name with some margin
async function classifyWithAI(title, body) {
const truncatedBody = (body || "").slice(0, MAX_BODY_LENGTH);
const labelList = PRODUCT_LABELS.join("\n- ");
const prompt = `You are a GitHub issue triager for the microsoft/PowerToys repository.
Given the issue title and body below, determine which ONE Product label best fits.
Reply with ONLY the label name (e.g. "Product-FancyZones") or "UNKNOWN" if you cannot determine it.
Available labels:
- ${labelList}
Issue title: ${title}
Issue body:
${truncatedBody}`;
try {
const response = await fetch(
"https://models.github.ai/inference/chat/completions",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "openai/gpt-4o",
messages: [{ role: "user", content: prompt }],
max_tokens: MAX_COMPLETION_TOKENS,
temperature: 0,
}),
}
);
if (!response.ok) {
core.warning(`AI classification failed: ${response.status} ${response.statusText}`);
return null;
}
const data = await response.json();
const answer = data.choices?.[0]?.message?.content?.trim();
if (!answer || answer === "UNKNOWN") return null;
// Validate the answer is a known label
if (PRODUCT_LABELS.includes(answer)) return answer;
// Try fuzzy match (the model may include extra text)
const found = PRODUCT_LABELS.find((l) => answer.includes(l));
return found || null;
} catch (err) {
core.warning(`AI classification error: ${err.message}`);
return null;
}
}
// ── Main ───────────────────────────────────────────────────
const MAX_ISSUES = 50; // Process up to 50 issues per run
let labeled = 0;
let skipped = 0;
core.info("Searching for open issues with Needs-Triage but no Product-* label...");
// Paginate through open issues labeled Needs-Triage
for await (const response of github.paginate.iterator(
github.rest.issues.listForRepo,
{
owner: context.repo.owner,
repo: context.repo.repo,
state: "open",
labels: "Needs-Triage",
sort: "created",
direction: "desc",
per_page: 100,
}
)) {
for (const issue of response.data) {
if (labeled + skipped >= MAX_ISSUES) break;
// Skip pull requests (the API returns them too)
if (issue.pull_request) continue;
if (hasProductLabel(issue.labels)) continue;
core.info(`Processing #${issue.number}: ${issue.title}`);
// 1) Try structured area dropdown first (fast, no AI needed)
let label = extractAreaFromBody(issue.body);
// 2) Fall back to AI classification
if (!label) {
label = await classifyWithAI(issue.title, issue.body);
}
if (label) {
core.info(` → Applying "${label}" to #${issue.number}`);
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: [label],
});
labeled++;
} else {
core.info(` → Could not determine product label for #${issue.number}, skipping.`);
skipped++;
}
}
if (labeled + skipped >= MAX_ISSUES) break;
}
core.info(`Done. Labeled: ${labeled}, Skipped: ${skipped}`);

View File

@@ -250,6 +250,9 @@
"PowerToys.ZoomItModuleInterface.dll",
"PowerToys.ZoomItSettingsInterop.dll",
"PowerToys.GrabAndMove.exe",
"PowerToys.GrabAndMoveModuleInterface.dll",
"WinUI3Apps\\PowerToys.Settings.dll",
"WinUI3Apps\\PowerToys.Settings.exe",

View File

@@ -108,6 +108,7 @@ Thank you for using PowerToys!
| Microsoft.PowerToys.AwakeIndefinitelyKeepAwakeEvent | Triggered when the system is set to stay awake indefinitely. |
| Microsoft.PowerToys.AwakeNoKeepAwakeEvent | Occurs when Awake is turned off, allowing the computer to enter sleep mode. |
| Microsoft.PowerToys.AwakeTimedKeepAwakeEvent | Triggered when the system is kept awake for a specified time duration. |
| Microsoft.PowerToys.Awake_CLICommand | Triggered when an Awake CLI command is executed, logging the command name and success status. |
### Color Picker
@@ -204,6 +205,7 @@ Thank you for using PowerToys!
| Microsoft.PowerToys.FileLocksmith_Invoked | Occurs when File Locksmith is invoked. |
| Microsoft.PowerToys.FileLocksmith_InvokedRet | Triggered when File Locksmith invocation returns a result. |
| Microsoft.PowerToys.FileLocksmith_QueryContextMenuError | Occurs when there is an error querying the context menu for File Locksmith. |
| Microsoft.PowerToys.FileLocksmith_CLICommand | Triggered when a File Locksmith CLI command is executed, logging the operation mode (query, kill, query-wait, query-json, or help) and success status. |
### FileExplorerAddOns
@@ -258,6 +260,7 @@ Thank you for using PowerToys!
| Microsoft.PowerToys.ImageResizer_Invoked | Occurs when Image Resizer is invoked by the user. |
| Microsoft.PowerToys.ImageResizer_InvokedRet | Fires when the Image Resizer operation is completed and returns a result. |
| Microsoft.PowerToys.ImageResizer_QueryContextMenuError | Triggered when there is an error querying the context menu for Image Resizer. |
| Microsoft.PowerToys.ImageResizer_CLICommand | Triggered when an Image Resizer CLI command is executed, logging the command name and success status. |
### Keyboard Manager

View File

@@ -85,14 +85,6 @@
<ForceImportBeforeCppProps>$(RepoRoot)Cpp.Build.props</ForceImportBeforeCppProps>
</PropertyGroup>
<!-- Force all C# projects to reference these packages from NuGet so their 10.x versions
take precedence over the 9.x versions bundled in the .NET 9 runtime. Without this,
projects that don't transitively depend on these packages would get the runtime 9.x
version, causing deps.json version conflicts with projects that do. -->
<ItemGroup Condition="'$(MSBuildProjectExtension)' == '.csproj'">
<PackageReference Include="System.Diagnostics.EventLog" />
<PackageReference Include="System.Threading.Channels" />
</ItemGroup>
<ItemGroup Condition="'$(MSBuildProjectExtension)' == '.csproj' and '$(_IsSkippedTestProject)' != 'true'">
<PackageReference Include="StyleCop.Analyzers">

View File

@@ -42,26 +42,26 @@
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.10" />
<!-- Including Microsoft.Bcl.AsyncInterfaces to force version, since it's used by Microsoft.SemanticKernel. -->
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.5" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.10" />
<PackageVersion Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
<PackageVersion Include="Microsoft.Windows.CppWinRT" Version="2.0.250303.1" />
<PackageVersion Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.16" />
<PackageVersion Include="Microsoft.Extensions.AI" Version="10.4.1" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="10.4.1" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="10.0.5" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.5" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.5" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.5" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.5" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.5" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.5" />
<PackageVersion Include="Microsoft.Extensions.AI" Version="9.9.1" />
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="9.9.1-preview.1.25474.6" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.10" />
<PackageVersion Include="Microsoft.AI.Foundry.Local" Version="0.3.0" />
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.74.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.OpenAI" Version="1.74.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.AzureAIInference" Version="1.74.0-beta" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Google" Version="1.74.0-alpha" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.MistralAI" Version="1.74.0-alpha" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.74.0-alpha" />
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.66.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.OpenAI" Version="1.66.0" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.AzureAIInference" Version="1.66.0-beta" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Google" Version="1.66.0-alpha" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.MistralAI" Version="1.66.0-alpha" />
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.66.0-alpha" />
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.3179.45" />
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
@@ -89,11 +89,11 @@
<PackageVersion Include="MSTest" Version="$(MSTestVersion)" />
<PackageVersion Include="MSTest.TestFramework" Version="$(MSTestVersion)" />
<PackageVersion Include="NJsonSchema" Version="11.4.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="NLog" Version="5.2.8" />
<PackageVersion Include="NLog.Extensions.Logging" Version="5.3.8" />
<PackageVersion Include="NLog.Schema" Version="5.2.8" />
<PackageVersion Include="OpenAI" Version="2.9.1" />
<PackageVersion Include="OpenAI" Version="2.5.0" />
<PackageVersion Include="Polly.Core" Version="8.6.5" />
<PackageVersion Include="ReverseMarkdown" Version="4.1.0" />
<PackageVersion Include="RtfPipe" Version="2.0.7677.4303" />
@@ -113,27 +113,23 @@
<PackageVersion Include="System.Data.OleDb" Version="9.0.10" />
<!-- Package System.Data.SqlClient added to force it as a dependency of Microsoft.Windows.Compatibility to the latest version available at this time. -->
<PackageVersion Include="System.Data.SqlClient" Version="4.9.0" />
<!-- Package System.Diagnostics.EventLog force-pinned to 10.x to match other Microsoft.Extensions packages;
referenced by all C# projects (via Directory.Build.props) to override the 9.x version from the .NET runtime. -->
<PackageVersion Include="System.Diagnostics.EventLog" Version="10.0.5" />
<!-- Package System.Diagnostics.EventLog added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Data.OleDb but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.10" />
<!-- Package System.Diagnostics.PerformanceCounter added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.11. -->
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.10" />
<PackageVersion Include="System.ClientModel" Version="1.9.0" />
<PackageVersion Include="System.ClientModel" Version="1.7.0" />
<PackageVersion Include="System.Drawing.Common" Version="9.0.10" />
<PackageVersion Include="System.IO.Abstractions" Version="22.0.13" />
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="22.0.13" />
<PackageVersion Include="System.Management" Version="9.0.10" />
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Numerics.Tensors" Version="10.0.4" />
<!-- Including System.Threading.Channels to force version across all projects;
referenced by all C# projects (via Directory.Build.props) to override the 9.x version from the .NET runtime. -->
<PackageVersion Include="System.Threading.Channels" Version="10.0.4" />
<PackageVersion Include="System.Numerics.Tensors" Version="9.0.11" />
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
<PackageVersion Include="System.Reactive" Version="6.0.1" />
<PackageVersion Include="System.Runtime.Caching" Version="9.0.10" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="10.0.5" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="9.0.10" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.10" />
<PackageVersion Include="System.Text.Json" Version="10.0.5" />
<PackageVersion Include="System.Text.Json" Version="9.0.10" />
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageVersion Include="ToolGood.Words.Pinyin" Version="3.1.0.3" />
<PackageVersion Include="UnicodeInformation" Version="2.6.0" />

View File

@@ -791,10 +791,6 @@
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/peek/peek/peek.vcxproj" Id="a1425b53-3d61-4679-8623-e64a0d3d0a48" />
<Project Path="src/modules/peek/Peek.Common.UnitTests/Peek.Common.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
</Folder>
<Folder Name="/modules/PowerAccent/">
<Project Path="src/modules/poweraccent/PowerAccent.Core/PowerAccent.Core.csproj">
@@ -807,10 +803,6 @@
</Project>
<Project Path="src/modules/poweraccent/PowerAccentKeyboardService/PowerAccentKeyboardService.vcxproj" Id="c97d9a5d-206c-454e-997e-009e227d7f02" />
<Project Path="src/modules/poweraccent/PowerAccentModuleInterface/PowerAccentModuleInterface.vcxproj" Id="34a354c5-23c7-4343-916c-c52daf4fc39d" />
<Project Path="src/modules/poweraccent/PowerAccent.Core.UnitTests/PowerAccent.Core.UnitTests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
</Folder>
<Folder Name="/modules/PowerOCR/">
<Project Path="src/modules/PowerOCR/PowerOCR/PowerOCR.csproj">
@@ -1044,6 +1036,10 @@
<Project Path="src/modules/ZoomIt/ZoomItModuleInterface/ZoomItModuleInterface.vcxproj" Id="e4585179-2ac1-4d5f-a3ff-cfc5392f694c" />
<Project Path="src/modules/ZoomIt/ZoomItSettingsInterop/ZoomItSettingsInterop.vcxproj" Id="ca7d8106-30b9-4aec-9d05-b69b31b8c461" />
</Folder>
<Folder Name="/modules/GrabAndMove/">
<Project Path="src/modules/GrabAndMove/GrabAndMove/GrabAndMove.vcxproj" Id="568c4c30-2e3c-4c2c-a691-007362073765" />
<Project Path="src/modules/GrabAndMove/GrabAndMoveModuleInterface/GrabAndMoveModuleInterface.vcxproj" Id="2c3f7770-4e57-46b7-8dc1-7428a383d0db" />
</Folder>
<Folder Name="/settings-ui/">
<Project Path="src/settings-ui/QuickAccess.UI/PowerToys.QuickAccess.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
@@ -1108,6 +1104,8 @@
<BuildDependency Project="src/modules/launcher/Microsoft.Launcher/Microsoft.Launcher.vcxproj" />
<BuildDependency Project="src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMoveModuleInterface/GrabAndMoveModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMove/GrabAndMove.vcxproj" />
<BuildDependency Project="src/modules/powerrename/dll/PowerRenameExt.vcxproj" />
<BuildDependency Project="src/modules/powerrename/lib/PowerRenameLib.vcxproj" />
<BuildDependency Project="src/modules/previewpane/Common/PreviewHandlerCommon.csproj" />

View File

Before

Width:  |  Height:  |  Size: 497 KiB

After

Width:  |  Height:  |  Size: 497 KiB

View File

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 276 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 269 KiB

After

Width:  |  Height:  |  Size: 269 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 228 KiB

After

Width:  |  Height:  |  Size: 228 KiB

View File

Before

Width:  |  Height:  |  Size: 491 KiB

After

Width:  |  Height:  |  Size: 491 KiB

View File

Before

Width:  |  Height:  |  Size: 706 KiB

After

Width:  |  Height:  |  Size: 706 KiB

View File

Before

Width:  |  Height:  |  Size: 408 KiB

After

Width:  |  Height:  |  Size: 408 KiB

View File

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 384 KiB

View File

Before

Width:  |  Height:  |  Size: 493 KiB

After

Width:  |  Height:  |  Size: 493 KiB

View File

Before

Width:  |  Height:  |  Size: 492 KiB

After

Width:  |  Height:  |  Size: 492 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

View File

Before

Width:  |  Height:  |  Size: 311 KiB

After

Width:  |  Height:  |  Size: 311 KiB

View File

Before

Width:  |  Height:  |  Size: 297 KiB

After

Width:  |  Height:  |  Size: 297 KiB

View File

Before

Width:  |  Height:  |  Size: 284 KiB

After

Width:  |  Height:  |  Size: 284 KiB

View File

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 225 KiB

View File

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

View File

Before

Width:  |  Height:  |  Size: 890 KiB

After

Width:  |  Height:  |  Size: 890 KiB

View File

Before

Width:  |  Height:  |  Size: 858 KiB

After

Width:  |  Height:  |  Size: 858 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View File

@@ -28,6 +28,7 @@ namespace ExprtkCalculator::internal
std::wstring ToWStringFullPrecision(double value)
{
std::wostringstream oss;
oss.imbue(std::locale::classic());
oss << std::fixed << std::setprecision(15) << value;
return oss.str();
}

View File

@@ -36,6 +36,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredPowerDisplayEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredGrabAndMoveEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredGrabAndMoveEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredFancyZonesEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredFancyZonesEnabledValue());

View File

@@ -15,6 +15,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
static GpoRuleConfigured GetConfiguredLightSwitchEnabledValue();
static GpoRuleConfigured GetConfiguredPowerDisplayEnabledValue();
static GpoRuleConfigured GetConfiguredGrabAndMoveEnabledValue();
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();

View File

@@ -19,6 +19,7 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
static GpoRuleConfigured GetConfiguredLightSwitchEnabledValue();
static GpoRuleConfigured GetConfiguredPowerDisplayEnabledValue();
static GpoRuleConfigured GetConfiguredGrabAndMoveEnabledValue();
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();

View File

@@ -71,5 +71,10 @@ namespace PowerToys.GPOWrapperProjection
{
return (GpoRuleConfigured)PowerToys.GPOWrapper.GPOWrapper.GetConfiguredLightSwitchEnabledValue();
}
public static GpoRuleConfigured GetConfiguredGrabAndMoveEnabledValue()
{
return (GpoRuleConfigured)PowerToys.GPOWrapper.GPOWrapper.GetConfiguredGrabAndMoveEnabledValue();
}
}
}

View File

@@ -36,6 +36,7 @@ namespace ManagedCommon
ShortcutGuide,
PowerOCR,
Workspaces,
GrabAndMove,
ZoomIt,
GeneralSettings,
}

View File

@@ -145,6 +145,10 @@ namespace CommonSharedConstants
// Path to the events used by ZoomIt
const wchar_t ZOOMIT_REFRESH_SETTINGS_EVENT[] = L"Local\\PowerToysZoomIt-RefreshSettingsEvent-f053a563-d519-4b0d-8152-a54489c13324";
// Path to the events used by GrabAndMove
const wchar_t GRABANDMOVE_REFRESH_SETTINGS_EVENT[] = L"Local\\PowerToysGrabAndMove-RefreshSettingsEvent-a7b3c1d2-4e5f-6a7b-8c9d-0e1f2a3b4c5d";
const wchar_t GRABANDMOVE_EXIT_EVENT[] = L"Local\\PowerToysGrabAndMove-ExitEvent-b8c4d2e3-5f6a-7b8c-9d0e-1f2a3b4c5d6e";
const wchar_t ZOOMIT_EXIT_EVENT[] = L"Local\\PowerToysZoomIt-ExitEvent-36641ce6-df02-4eac-abea-a3fbf9138220";
const wchar_t ZOOMIT_ZOOM_EVENT[] = L"Local\\PowerToysZoomIt-ZoomEvent-1e4190d7-94bc-4ad5-adc0-9a8fd07cb393";
const wchar_t ZOOMIT_DRAW_EVENT[] = L"Local\\PowerToysZoomIt-DrawEvent-56338997-404d-4549-bd9a-d132b6766975";

View File

@@ -84,6 +84,7 @@ struct LogSettings
inline const static std::string zoomItLoggerName = "zoom-it";
inline const static std::string lightSwitchLoggerName = "light-switch";
inline const static std::string powerDisplayLoggerName = "powerdisplay";
inline const static std::string grabAndMoveLoggerName = "grabandmove";
inline const static int retention = 30;
std::wstring logLevel;
LogSettings();

View File

@@ -33,6 +33,7 @@ namespace powertoys_gpo
const std::wstring POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK = L"ConfigureEnabledUtilityCropAndLock";
const std::wstring POLICY_CONFIGURE_ENABLED_LIGHT_SWITCH = L"ConfigureEnabledUtilityLightSwitch";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_DISPLAY = L"ConfigureEnabledUtilityPowerDisplay";
const std::wstring POLICY_CONFIGURE_ENABLED_GRAB_AND_MOVE = L"ConfigureEnabledUtilityGrabAndMove";
const std::wstring POLICY_CONFIGURE_ENABLED_FANCYZONES = L"ConfigureEnabledUtilityFancyZones";
const std::wstring POLICY_CONFIGURE_ENABLED_FILE_LOCKSMITH = L"ConfigureEnabledUtilityFileLocksmith";
const std::wstring POLICY_CONFIGURE_ENABLED_SVG_PREVIEW = L"ConfigureEnabledUtilityFileExplorerSVGPreview";
@@ -317,6 +318,11 @@ namespace powertoys_gpo
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_POWER_DISPLAY);
}
inline gpo_rule_configured_t getConfiguredGrabAndMoveEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_GRAB_AND_MOVE);
}
inline gpo_rule_configured_t getConfiguredFancyZonesEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_FANCYZONES);

View File

@@ -29,6 +29,7 @@
<definition name="SUPPORTED_POWERTOYS_0_96_0" displayName="$(string.SUPPORTED_POWERTOYS_0_96_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_97_0" displayName="$(string.SUPPORTED_POWERTOYS_0_97_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_98_0" displayName="$(string.SUPPORTED_POWERTOYS_0_98_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_99_0" displayName="$(string.SUPPORTED_POWERTOYS_0_99_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1)"/>
</definitions>
</supportedOn>
@@ -152,7 +153,7 @@
</policy>
<policy name="ConfigureEnabledUtilityPowerDisplay" class="Both" displayName="$(string.ConfigureEnabledUtilityPowerDisplay)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityPowerDisplay">
<parentCategory ref="PowerToys" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_95_0" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_99_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>

View File

@@ -36,6 +36,7 @@
<string id="SUPPORTED_POWERTOYS_0_96_0">PowerToys version 0.96.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_97_0">PowerToys version 0.97.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_98_0">PowerToys version 0.98.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_99_0">PowerToys version 0.99.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1">From PowerToys version 0.64.0 until PowerToys version 0.87.1</string>
<string id="ConfigureAllUtilityGlobalEnabledStateDescription">This policy configures the enabled state for all PowerToys utilities.

View File

@@ -496,23 +496,119 @@ private:
if (!GetGUIThreadInfo(0, &gui_info))
{
Logger::warn(L"Auto-copy: GetGUIThreadInfo failed (error={})", GetLastError());
return false;
}
HWND target = gui_info.hwndFocus ? gui_info.hwndFocus : gui_info.hwndActive;
if (!target)
{
Logger::warn(L"Auto-copy: no focused or active window found");
return false;
}
DWORD_PTR result = 0;
return SendMessageTimeout(target,
WM_COPY,
0,
0,
SMTO_ABORTIFHUNG | SMTO_BLOCK,
50,
&result) != 0;
auto sendResult = SendMessageTimeout(target, WM_COPY, 0, 0, SMTO_ABORTIFHUNG | SMTO_BLOCK, 50, &result);
return sendResult != 0;
}
// Helper: poll clipboard sequence number for a change from initial_sequence.
// Returns true if the sequence number changed within the given number of polls.
bool poll_clipboard_sequence(DWORD initial_sequence, int poll_attempts, std::chrono::milliseconds poll_delay)
{
for (int poll = 0; poll < poll_attempts; ++poll)
{
if (GetClipboardSequenceNumber() != initial_sequence)
{
return true;
}
std::this_thread::sleep_for(poll_delay);
}
return false;
}
// Helper: send Ctrl+C via SendInput, releasing any held modifier keys first
// (the hotkey combination may still have modifiers physically pressed).
bool send_ctrl_c_input()
{
std::vector<INPUT> inputs;
// Release all modifier keys that are currently held down from the hotkey.
// Without this, the target app sees e.g. Win+Shift+Ctrl+C instead of just Ctrl+C.
try_inject_modifier_key_up(inputs, VK_LCONTROL);
try_inject_modifier_key_up(inputs, VK_RCONTROL);
try_inject_modifier_key_up(inputs, VK_LWIN);
try_inject_modifier_key_up(inputs, VK_RWIN);
try_inject_modifier_key_up(inputs, VK_LSHIFT);
try_inject_modifier_key_up(inputs, VK_RSHIFT);
try_inject_modifier_key_up(inputs, VK_LMENU);
try_inject_modifier_key_up(inputs, VK_RMENU);
// Ctrl down
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = VK_CONTROL;
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
// C down
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = 0x43; // C
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
// C up
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = 0x43; // C
input_event.ki.dwFlags = KEYEVENTF_KEYUP;
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
// Ctrl up
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = VK_CONTROL;
input_event.ki.dwFlags = KEYEVENTF_KEYUP;
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
// Restore modifiers that were held down
try_inject_modifier_key_restore(inputs, VK_LCONTROL);
try_inject_modifier_key_restore(inputs, VK_RCONTROL);
try_inject_modifier_key_restore(inputs, VK_LWIN);
try_inject_modifier_key_restore(inputs, VK_RWIN);
try_inject_modifier_key_restore(inputs, VK_LSHIFT);
try_inject_modifier_key_restore(inputs, VK_RSHIFT);
try_inject_modifier_key_restore(inputs, VK_LMENU);
try_inject_modifier_key_restore(inputs, VK_RMENU);
// Prevent Start Menu from activating after Win key release/restore
INPUT dummyEvent = {};
dummyEvent.type = INPUT_KEYBOARD;
dummyEvent.ki.wVk = 0xFF;
dummyEvent.ki.dwFlags = KEYEVENTF_KEYUP;
inputs.push_back(dummyEvent);
auto uSent = SendInput(static_cast<UINT>(inputs.size()), inputs.data(), sizeof(INPUT));
if (uSent != inputs.size())
{
DWORD errorCode = GetLastError();
auto errorMessage = get_last_error_message(errorCode);
Logger::error(L"SendInput failed for Ctrl+C. Expected to send {} inputs and sent only {}. {}", inputs.size(), uSent, errorMessage.has_value() ? errorMessage.value() : L"");
Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"input.SendInput");
return false;
}
return true;
}
bool send_copy_selection()
@@ -526,78 +622,30 @@ private:
for (int attempt = 0; attempt < copy_attempts; ++attempt)
{
const auto initial_sequence = GetClipboardSequenceNumber();
copy_succeeded = try_send_copy_message();
if (!copy_succeeded)
// Strategy 1: Try WM_COPY message (works for standard Win32 controls)
bool wm_copy_sent = try_send_copy_message();
if (wm_copy_sent)
{
std::vector<INPUT> inputs;
// send Ctrl+C (key downs and key ups)
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = VK_CONTROL;
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = 0x43; // C
// Avoid triggering detection by the centralized keyboard hook.
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = 0x43; // C
input_event.ki.dwFlags = KEYEVENTF_KEYUP;
// Avoid triggering detection by the centralized keyboard hook.
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = VK_CONTROL;
input_event.ki.dwFlags = KEYEVENTF_KEYUP;
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
auto uSent = SendInput(static_cast<UINT>(inputs.size()), inputs.data(), sizeof(INPUT));
if (uSent != inputs.size())
{
DWORD errorCode = GetLastError();
auto errorMessage = get_last_error_message(errorCode);
Logger::error(L"SendInput failed for Ctrl+C. Expected to send {} inputs and sent only {}. {}", inputs.size(), uSent, errorMessage.has_value() ? errorMessage.value() : L"");
Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"input.SendInput");
}
else
if (poll_clipboard_sequence(initial_sequence, clipboard_poll_attempts, clipboard_poll_delay))
{
copy_succeeded = true;
}
}
if (copy_succeeded)
// Strategy 2: If WM_COPY didn't work, try SendInput Ctrl+C (works for Electron, browsers, etc.)
if (!copy_succeeded)
{
bool sequence_changed = false;
for (int poll_attempt = 0; poll_attempt < clipboard_poll_attempts; ++poll_attempt)
const auto sequence_before_ctrl_c = GetClipboardSequenceNumber();
if (send_ctrl_c_input())
{
if (GetClipboardSequenceNumber() != initial_sequence)
if (poll_clipboard_sequence(sequence_before_ctrl_c, clipboard_poll_attempts, clipboard_poll_delay))
{
sequence_changed = true;
break;
copy_succeeded = true;
}
std::this_thread::sleep_for(clipboard_poll_delay);
}
copy_succeeded = sequence_changed;
}
if (copy_succeeded)
@@ -611,6 +659,11 @@ private:
}
}
if (!copy_succeeded)
{
Logger::warn(L"Auto-copy: all {} copy attempts failed — the target application did not update the clipboard after WM_COPY and Ctrl+C", copy_attempts);
}
return copy_succeeded;
}
@@ -977,6 +1030,7 @@ public:
{
if (!send_copy_selection())
{
Logger::warn(L"Auto-copy: failed to copy selection for custom action index {} — aborting action", custom_action_index);
return false;
}
}

View File

@@ -121,7 +121,7 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
if (argc < 2)
{
Logger::warn("No arguments provided");
return { 1, get_usage(strings) };
return { 1, get_usage(strings), L"help" };
}
bool json_output = false;
@@ -156,18 +156,18 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
catch (...)
{
Logger::error("Invalid timeout value");
return { 1, strings.GetString(IDS_ERROR_INVALID_TIMEOUT) };
return { 1, strings.GetString(IDS_ERROR_INVALID_TIMEOUT), L"query-wait" };
}
}
else
{
Logger::error("Timeout argument missing");
return { 1, strings.GetString(IDS_ERROR_TIMEOUT_ARG) };
return { 1, strings.GetString(IDS_ERROR_TIMEOUT_ARG), L"query-wait" };
}
}
else if (arg == L"--help")
{
return { 0, get_usage(strings) };
return { 0, get_usage(strings), L"help" };
}
else
{
@@ -178,7 +178,7 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
if (paths.empty())
{
Logger::error("No paths specified");
return { 1, strings.GetString(IDS_ERROR_NO_PATHS) };
return { 1, strings.GetString(IDS_ERROR_NO_PATHS), L"query" };
}
Logger::info("Processing {} paths", paths.size());
@@ -213,13 +213,13 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
{
Logger::warn("Timeout waiting for files to be unlocked");
ss << strings.GetString(IDS_TIMEOUT);
return { 1, ss.str() };
return { 1, ss.str(), L"query-wait" };
}
}
Sleep(200);
}
return { 0, ss.str() };
return { 0, ss.str(), L"query-wait" };
}
auto results = finder.find(paths);
@@ -244,5 +244,6 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
output_ss << get_text(results, strings);
}
return { 0, output_ss.str() };
std::wstring cmd_name = kill ? L"kill" : (json_output ? L"query-json" : L"query");
return { 0, output_ss.str(), cmd_name };
}

View File

@@ -8,6 +8,7 @@ struct CommandResult
{
int exit_code;
std::wstring output;
std::wstring command_name;
};
struct IProcessFinder

View File

@@ -1,6 +1,7 @@
#include "pch.h"
#include "CLILogic.h"
#include "FileLocksmithLib/FileLocksmith.h"
#include "FileLocksmithLib/Trace.h"
#include <iostream>
#include "resource.h"
#include <common/logger/logger.h>
@@ -47,6 +48,7 @@ struct RealStringProvider : IStringProvider
int wmain(int argc, wchar_t* argv[])
{
winrt::init_apartment();
Trace::RegisterProvider();
LoggerHelpers::init_logger(L"FileLocksmithCLI", L"", LogSettings::fileLocksmithLoggerName);
Logger::info("FileLocksmithCLI started");
@@ -65,7 +67,10 @@ int wmain(int argc, wchar_t* argv[])
Logger::info("Command succeeded");
}
Trace::CLICommand(result.command_name.c_str(), result.exit_code == 0);
std::wcout << result.output;
Trace::UnregisterProvider();
return result.exit_code;
}
#endif

View File

@@ -52,6 +52,7 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(1, argv, finder, terminator, strings);
Assert::AreEqual(1, result.exit_code);
Assert::AreEqual(std::wstring(L"help"), result.command_name);
}
TEST_METHOD(TestHelp)
@@ -64,6 +65,7 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(2, argv, finder, terminator, strings);
Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"help"), result.command_name);
}
TEST_METHOD(TestFindProcesses)
@@ -77,6 +79,7 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(2, argv, finder, terminator, strings);
Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"query"), result.command_name);
Assert::IsTrue(result.output.find(L"123") != std::wstring::npos);
Assert::IsTrue(result.output.find(L"process") != std::wstring::npos);
}
@@ -94,6 +97,7 @@ namespace FileLocksmithCLIUnitTests
Microsoft::VisualStudio::CppUnitTestFramework::Logger::WriteMessage(result.output.c_str());
Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"query-json"), result.command_name);
Assert::IsTrue(result.output.find(L"\"pid\"") != std::wstring::npos);
Assert::IsTrue(result.output.find(L"123") != std::wstring::npos);
}
@@ -109,6 +113,7 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(3, argv, finder, terminator, strings);
Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"kill"), result.command_name);
Assert::AreEqual((size_t)1, terminator.terminatedPids.size());
Assert::AreEqual((DWORD)123, terminator.terminatedPids[0]);
}
@@ -125,6 +130,7 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(5, argv, finder, terminator, strings);
Assert::AreEqual(1, result.exit_code);
Assert::AreEqual(std::wstring(L"query-wait"), result.command_name);
}
};
}

View File

@@ -49,3 +49,14 @@ void Trace::QueryContextMenuError(_In_ HRESULT hr) noexcept
TraceLoggingHResult(hr),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}
void Trace::CLICommand(_In_ PCWSTR commandName, _In_ bool successful) noexcept
{
TraceLoggingWriteWrapper(
g_hProvider,
"FileLocksmith_CLICommand",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingWideString(commandName, "CommandName"),
TraceLoggingBoolean(successful, "Successful"));
}

View File

@@ -11,4 +11,5 @@ public:
static void Invoked() noexcept;
static void InvokedRet(_In_ HRESULT hr) noexcept;
static void QueryContextMenuError(_In_ HRESULT hr) noexcept;
static void CLICommand(_In_ PCWSTR commandName, _In_ bool successful) noexcept;
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

View File

@@ -0,0 +1,102 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#include "../../../common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APP_ICON ICON "GrabAndMove.ico"
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
1 VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
END
END
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,197 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{568c4c30-2e3c-4c2c-a691-007362073765}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>GrabAndMove</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>GrabAndMove</ProjectName>
<TargetName>PowerToys.GrabAndMove</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(RepoRoot)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>
$(RepoRoot)src\common;
$(RepoRoot)src\common\SettingsAPI;
$(RepoRoot)src\;
%(AdditionalIncludeDirectories)
</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;UNICODE;_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;UNICODE;_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;UNICODE;_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;UNICODE;_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="GrabAndMove.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446D-23F7-4023-9BB3-8657F904AF99}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Image Include="GrabAndMove.ico" />
</ItemGroup>
<ItemGroup>
<Manifest Include="GrabAndMove.manifest" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="resource.h" />
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Resource Files">
<UniqueIdentifier>{195243ad-53ca-40c9-8879-b9efef4fc26d}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{9bdf974b-a58f-4af8-aed8-4882381f7172}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{0e19fd51-9939-4511-b8cb-d144c0e2a670}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Image Include="GrabAndMove.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="GrabAndMove.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
#include "pch.h"

View File

@@ -0,0 +1,14 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <commctrl.h>
#include <TraceLoggingProvider.h>
#include <limits>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

View File

@@ -0,0 +1,21 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by GrabAndMove.rc
//
#pragma once
#define IDI_APP_ICON 101
#define IDR_TRAY_MENU 102
#define IDM_EXIT 1001
#define WM_TRAY_ICON (WM_USER + 1)
//////////////////////////////
// Non-localizable
#define FILE_DESCRIPTION "PowerToys GrabAndMove"
#define INTERNAL_NAME "PowerToys.GrabAndMove"
#define ORIGINAL_FILENAME "PowerToys.GrabAndMove.exe"
// Non-localizable
//////////////////////////////

View File

@@ -0,0 +1,36 @@
#include <windows.h>
#include "resource.h"
#include "../../../common/version/version.h"
1 VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
END
END

View File

@@ -0,0 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{2c3f7770-4e57-46b7-8dc1-7428a383d0db}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>GrabAndMoveModuleInterface</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>GrabAndMoveModuleInterface</ProjectName>
<TargetName>PowerToys.GrabAndMoveModuleInterface</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(RepoRoot)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;GRABANDMOVEMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;GRABANDMOVEMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;GRABANDMOVEMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;GRABANDMOVEMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(RepoRoot)src\common\inc;$(RepoRoot)src\common\Telemetry;..\..\;$(RepoRoot)src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="trace.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">pch.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="trace.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="GrabAndMoveModuleInterface.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="$(RepoRoot)src\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(RepoRoot)deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,216 @@
#include "pch.h"
#include <interface/powertoy_module_interface.h>
#include "trace.h"
#include <common/logger/logger.h>
#include <common/SettingsAPI/settings_objects.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/utils/logger_helper.h>
#include <common/interop/shared_constants.h>
extern "C" IMAGE_DOS_HEADER __ImageBase;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Trace::RegisterProvider();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Trace::UnregisterProvider();
break;
}
return TRUE;
}
// The PowerToy name that will be shown in the settings.
const static wchar_t* MODULE_NAME = L"GrabAndMove";
// Add a description that will be shown in the module settings page.
const static wchar_t* MODULE_DESC = L"Move and resize windows with Alt+Drag (left button to move, right button to resize).";
class GrabAndMoveInterface : public PowertoyModuleIface
{
private:
bool m_enabled = false;
HANDLE m_process{ nullptr };
HANDLE m_reload_settings_event_handle{ nullptr };
HANDLE m_exit_event_handle{ nullptr };
public:
GrabAndMoveInterface()
{
LoggerHelpers::init_logger(L"GrabAndMove", L"ModuleInterface", LogSettings::grabAndMoveLoggerName);
m_reload_settings_event_handle = CreateDefaultEvent(CommonSharedConstants::GRABANDMOVE_REFRESH_SETTINGS_EVENT);
m_exit_event_handle = CreateDefaultEvent(CommonSharedConstants::GRABANDMOVE_EXIT_EVENT);
}
virtual const wchar_t* get_key() override
{
return L"GrabAndMove";
}
virtual void destroy() override
{
disable();
delete this;
}
virtual const wchar_t* get_name() override
{
return MODULE_NAME;
}
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
{
return powertoys_gpo::getConfiguredGrabAndMoveEnabledValue();
}
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
{
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
PowerToysSettings::Settings settings(hinstance, get_name());
settings.set_description(MODULE_DESC);
settings.set_overview_link(L"https://aka.ms/powertoys");
return settings.serialize_to_buffer(buffer, buffer_size);
}
virtual void set_config(const wchar_t* config) override
{
try
{
auto values = PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
values.save_to_settings_file();
// Signal the GrabAndMove process to reload settings
if (m_reload_settings_event_handle)
{
SetEvent(m_reload_settings_event_handle);
}
}
catch (const std::exception&)
{
Logger::error("[GrabAndMove] set_config: Failed to parse or apply config.");
}
}
virtual void enable()
{
Logger::info(L"Enabling GrabAndMove module...");
if (m_process && WaitForSingleObject(m_process, 0) == WAIT_TIMEOUT)
{
m_enabled = true;
Trace::Enable(true);
Logger::debug(L"GrabAndMove process already running.");
return;
}
if (m_process)
{
CloseHandle(m_process);
m_process = nullptr;
}
m_enabled = false;
unsigned long powertoys_pid = GetCurrentProcessId();
std::wstring args = std::to_wstring(powertoys_pid);
std::wstring exe_name = L"PowerToys.GrabAndMove.exe";
std::wstring resolved_path(MAX_PATH, L'\0');
DWORD result = SearchPathW(
nullptr,
exe_name.c_str(),
nullptr,
static_cast<DWORD>(resolved_path.size()),
resolved_path.data(),
nullptr);
if (result == 0 || result >= resolved_path.size())
{
Logger::error(
L"Failed to locate GrabAndMove executable named '{}' at location '{}'",
exe_name,
resolved_path.c_str());
return;
}
resolved_path.resize(result);
Logger::debug(L"Resolved executable path: {}", resolved_path);
std::wstring command_line = L"\"" + resolved_path + L"\" " + args;
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
if (!CreateProcessW(
resolved_path.c_str(),
command_line.data(),
nullptr,
nullptr,
TRUE,
0,
nullptr,
nullptr,
&si,
&pi))
{
Logger::error(L"Failed to launch GrabAndMove process. {}", get_last_error_or_default(GetLastError()));
return;
}
Logger::info(L"GrabAndMove process launched successfully (PID: {}).", pi.dwProcessId);
m_process = pi.hProcess;
m_enabled = true;
Trace::Enable(true);
CloseHandle(pi.hThread);
}
virtual void disable()
{
Logger::info("GrabAndMove disabling");
m_enabled = false;
if (m_exit_event_handle)
{
SetEvent(m_exit_event_handle);
}
if (m_process)
{
constexpr DWORD timeout_ms = 1500;
DWORD result = WaitForSingleObject(m_process, timeout_ms);
if (result == WAIT_TIMEOUT)
{
Logger::warn("GrabAndMove: Process didn't exit in time. Forcing termination.");
TerminateProcess(m_process, 0);
}
CloseHandle(m_process);
m_process = nullptr;
}
Trace::Enable(false);
}
virtual bool is_enabled() override
{
return m_enabled;
}
virtual bool is_enabled_by_default() const override
{
return false;
}
};
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new GrabAndMoveInterface();
}

View File

@@ -0,0 +1 @@
#include "pch.h"

View File

@@ -0,0 +1,9 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/utils/gpo.h>
#include <common/utils/winapi_error.h>
#include <shlwapi.h>
#include <shellapi.h>

View File

@@ -0,0 +1,12 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
//////////////////////////////
// Non-localizable
#define FILE_DESCRIPTION "GrabAndMove Module"
#define INTERNAL_NAME "GrabAndMove"
#define ORIGINAL_FILENAME "PowerToys.GrabAndMoveModuleInterface.dll"
// Non-localizable
//////////////////////////////

View File

@@ -0,0 +1,30 @@
#include "pch.h"
#include "trace.h"
#include <TraceLoggingProvider.h>
TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
"Microsoft.PowerToys",
// {38e8889b-9731-53f5-e901-e8a7c1753074}
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
TraceLoggingOptionProjectTelemetry());
void Trace::RegisterProvider()
{
TraceLoggingRegister(g_hProvider);
}
void Trace::UnregisterProvider()
{
TraceLoggingUnregister(g_hProvider);
}
void Trace::Enable(bool enabled) noexcept
{
TraceLoggingWrite(
g_hProvider,
"GrabAndMove_EnableGrabAndMove",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingBoolean(enabled, "Enabled"));
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <windows.h>
#include <TraceLoggingActivity.h>
#include <common/telemetry/ProjectTelemetry.h>
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);
class Trace
{
public:
static void RegisterProvider();
static void UnregisterProvider();
static void Enable(bool enabled) noexcept;
};

View File

@@ -17,7 +17,10 @@
<PackageReference Include="MSTest" />
<PackageReference Include="System.IO.Abstractions" />
<PackageReference Include="System.IO.Abstractions.TestingHelpers" />
<!-- System.Diagnostics.EventLog is now provided to all C# projects via Directory.Build.props -->
<PackageReference Include="System.Diagnostics.EventLog">
<!-- This package is a dependency of Microsoft.Extensions.Logging.EventLog, but we need to set it here so we can exclude the assets, so it doesn't conflict with the 8.0.1 dll coming from .NET SDK. -->
<ExcludeAssets>runtime</ExcludeAssets> <!-- Should already be present on .net sdk runtime, so we avoid the conflicting runtime version from nuget -->
</PackageReference>
<!-- HACK: CmdPal uses CommunityToolkit.Common directly. Align the version. -->
<PackageReference Include="CommunityToolkit.Common" />
</ItemGroup>

View File

@@ -3,16 +3,101 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PowerOCR"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Exit="Application_Exit"
ShutdownMode="OnExplicitShutdown"
Startup="Application_Startup">
Startup="Application_Startup"
ThemeMode="System">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Dark" />
<ui:ControlsDictionary />
</ResourceDictionary.MergedDictionaries>
<FontFamily x:Key="SymbolThemeFontFamily">Segoe Fluent Icons, Segoe MDL2 Assets</FontFamily>
<Style
x:Key="SubtleButtonStyle"
BasedOn="{StaticResource {x:Type Button}}"
TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
x:Name="Border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4"
SnapsToDevicePixels="True">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Focusable="False"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
<Setter Property="Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource TextFillColorDisabledBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="SubtleToggleButtonStyle"
BasedOn="{StaticResource {x:Type ToggleButton}}"
TargetType="ToggleButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border
x:Name="Border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4"
SnapsToDevicePixels="True">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Focusable="False"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
<Setter Property="Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource AccentFillColorDefaultBrush}" />
<Setter Property="Foreground" Value="{DynamicResource TextOnAccentFillColorPrimaryBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource TextFillColorDisabledBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -1,14 +1,12 @@
<Window
<Window
x:Class="PowerOCR.OCROverlay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:p="clr-namespace:PowerOCR.Properties"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
x:Name="TextExtractorWindow"
Title="TextExtractor"
ui:Design.Background="Transparent"
AllowsTransparency="True"
Background="Transparent"
Loaded="Window_Loaded"
@@ -22,26 +20,6 @@
WindowStyle="None"
mc:Ignorable="d">
<Window.Resources>
<Style BasedOn="{StaticResource DefaultToggleButtonStyle}" TargetType="{x:Type ToggleButton}">
<Setter Property="Margin" Value="4,0" />
<Setter Property="Padding" Value="0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="Background" Value="Transparent" />
</Style>
<Style BasedOn="{StaticResource DefaultButtonStyle}" TargetType="{x:Type Button}">
<Setter Property="Margin" Value="4,0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Padding" Value="0" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="Background" Value="Transparent" />
</Style>
</Window.Resources>
<Grid>
<Viewbox>
<Image x:Name="BackgroundImage" Stretch="UniformToFill" />
@@ -101,17 +79,11 @@
HorizontalAlignment="Center"
VerticalAlignment="Top"
d:Visibility="Visible"
Background="{DynamicResource ApplicationBackgroundBrush}"
Background="{DynamicResource SolidBackgroundFillColorBaseBrush}"
BorderBrush="{DynamicResource SurfaceStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="8"
Visibility="Collapsed">
<Border.Effect>
<DropShadowEffect
BlurRadius="32"
Opacity="0.28"
RenderingBias="Performance"
ShadowDepth="1" />
</Border.Effect>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Top"
@@ -133,35 +105,67 @@
</ComboBox>
<ToggleButton
x:Name="SingleLineToggleButton"
Width="32"
Height="32"
Margin="4,0"
Padding="0"
d:IsChecked="True"
AutomationProperties.Name="{x:Static p:Resources.ResultTextSingleLine}"
Click="SingleLineMenuItem_Click"
IsChecked="{Binding IsChecked, ElementName=SingleLineMenuItem, Mode=TwoWay}"
Style="{DynamicResource SubtleToggleButtonStyle}"
ToolTip="{x:Static p:Resources.ResultTextSingleLineShortcut}">
<ui:SymbolIcon FontSize="18" Symbol="SubtractSquare24" />
<TextBlock
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontSize="16"
Text="&#xF16E;" />
</ToggleButton>
<ToggleButton
x:Name="TableToggleButton"
Width="32"
Height="32"
Margin="4,0"
Padding="0"
d:IsChecked="True"
AutomationProperties.Name="{x:Static p:Resources.ResultTextTable}"
Click="TableToggleButton_Click"
IsChecked="{Binding IsChecked, ElementName=TableMenuItem, Mode=TwoWay}"
Style="{DynamicResource SubtleToggleButtonStyle}"
ToolTip="{x:Static p:Resources.ResultTextTableShortcut}">
<ui:SymbolIcon FontSize="18" Symbol="Table24" />
<TextBlock
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontSize="16"
Text="&#xE80A;" />
</ToggleButton>
<Button
x:Name="SettingsButton"
Width="32"
Height="32"
Margin="4,0"
Padding="0"
AutomationProperties.Name="{x:Static p:Resources.Settings}"
Click="SettingsMenuItem_Click"
Style="{DynamicResource SubtleButtonStyle}"
ToolTip="{x:Static p:Resources.Settings}">
<ui:SymbolIcon FontSize="18" Symbol="Settings24" />
<TextBlock
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontSize="16"
Text="&#xE713;" />
</Button>
<Button
x:Name="CancelButton"
Width="32"
Height="32"
Margin="4,0"
Padding="0"
AutomationProperties.Name="{x:Static p:Resources.Cancel}"
Click="CancelMenuItem_Click"
Style="{DynamicResource SubtleButtonStyle}"
ToolTip="{x:Static p:Resources.CancelShortcut}">
<ui:SymbolIcon FontSize="18" Symbol="Dismiss24" />
<TextBlock
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontSize="16"
Text="&#xE711;" />
</Button>
</StackPanel>
</Border>

View File

@@ -64,8 +64,6 @@ public partial class OCROverlay : Window
InitializeComponent();
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this, Wpf.Ui.Controls.WindowBackdropType.None);
PopulateLanguageMenu();
}

View File

@@ -31,7 +31,6 @@
<ItemGroup>
<PackageReference Include="System.ComponentModel.Composition" />
<PackageReference Include="System.Drawing.Common" />
<PackageReference Include="WPF-UI" />
</ItemGroup>
<ItemGroup>

View File

@@ -252,11 +252,13 @@ void AlwaysOnTop::ProcessCommand(HWND window)
}
Sound::Type soundType = Sound::Type::Off;
bool stateChanged = false;
bool topmost = IsTopmost(window);
if (topmost)
{
if (UnpinTopmostWindow(window))
{
stateChanged = true;
auto iter = m_topmostWindows.find(window);
if (iter != m_topmostWindows.end())
{
@@ -274,6 +276,7 @@ void AlwaysOnTop::ProcessCommand(HWND window)
{
if (PinTopmostWindow(window))
{
stateChanged = true;
soundType = Sound::Type::On;
AssignBorder(window);
@@ -281,7 +284,7 @@ void AlwaysOnTop::ProcessCommand(HWND window)
}
}
if (AlwaysOnTopSettings::settings()->enableSound)
if (stateChanged && AlwaysOnTopSettings::settings()->enableSound)
{
m_sound.Play(soundType);
}

View File

@@ -19,6 +19,7 @@ using Awake.Core;
using Awake.Core.Models;
using Awake.Core.Native;
using Awake.Properties;
using Awake.Telemetry;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Telemetry;
@@ -68,6 +69,7 @@ namespace Awake
if (parseResult.Errors.Count > 0)
{
// Shows errors and returns non-zero.
LogCLITelemetry(successful: false);
return rootCommand.Invoke(args);
}
@@ -96,6 +98,7 @@ namespace Awake
{
// Awake is already running - there is no need for us to process
// anything further
LogCLITelemetry(successful: false);
Exit(Core.Constants.AppName + " is already running! Exiting the application.", 1);
return 1;
}
@@ -103,6 +106,7 @@ namespace Awake
{
if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredAwakeEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
LogCLITelemetry(successful: false);
Exit("PowerToys.Awake tried to start with a group policy setting that disables the tool. Please contact your system administrator.", 1);
return 1;
}
@@ -125,7 +129,9 @@ namespace Awake
Bridge.GetPwrCapabilities(out _powerCapabilities);
Logger.LogInfo(JsonSerializer.Serialize(_powerCapabilities, _serializerOptions));
return await rootCommand.InvokeAsync(args);
var result = await rootCommand.InvokeAsync(args);
LogCLITelemetry(successful: result == 0);
return result;
}
}
}
@@ -216,6 +222,22 @@ namespace Awake
return rootCommand;
}
private static void LogCLITelemetry(bool successful)
{
try
{
PowerToysTelemetry.Log.WriteEvent(new AwakeCLICommandEvent
{
CommandName = "awake",
Successful = successful,
});
}
catch (Exception ex)
{
Logger.LogError($"Failed to log CLI telemetry: {ex.Message}");
}
}
private static void AwakeUnhandledExceptionCatcher(object sender, UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject is Exception exception)

View File

@@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Awake.Telemetry
{
/// <summary>
/// Telemetry event for Awake CLI command execution.
/// </summary>
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class AwakeCLICommandEvent : EventBase, IEvent
{
public AwakeCLICommandEvent()
{
EventName = "Awake_CLICommand";
CommandName = string.Empty;
}
/// <summary>
/// Gets or sets the name of the CLI command that was executed.
/// </summary>
public string CommandName { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the command executed successfully.
/// </summary>
public bool Successful { get; set; }
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}
}

View File

@@ -0,0 +1,57 @@
{
"solution": {
"path": "..\\..\\..\\PowerToys.slnx",
"projects": [
"src\\common\\CalculatorEngineCommon\\CalculatorEngineCommon.vcxproj",
"src\\common\\Common.UI.Controls\\Common.UI.Controls.csproj",
"src\\common\\ManagedCommon\\ManagedCommon.csproj",
"src\\common\\ManagedCsWin32\\ManagedCsWin32.csproj",
"src\\common\\ManagedTelemetry\\Telemetry\\ManagedTelemetry.csproj",
"src\\common\\interop\\PowerToys.Interop.vcxproj",
"src\\common\\version\\version.vcxproj",
"src\\modules\\cmdpal\\CmdPalKeyboardService\\CmdPalKeyboardService.vcxproj",
"src\\modules\\cmdpal\\CmdPalModuleInterface\\CmdPalModuleInterface.vcxproj",
"src\\modules\\cmdpal\\Microsoft.CmdPal.Common\\Microsoft.CmdPal.Common.csproj",
"src\\modules\\cmdpal\\Microsoft.CmdPal.UI.ViewModels\\Microsoft.CmdPal.UI.ViewModels.csproj",
"src\\modules\\cmdpal\\Microsoft.CmdPal.UI\\Microsoft.CmdPal.UI.csproj",
"src\\modules\\cmdpal\\Microsoft.Terminal.UI\\Microsoft.Terminal.UI.vcxproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Common.UnitTests\\Microsoft.CmdPal.Common.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.Apps.UnitTests\\Microsoft.CmdPal.Ext.Apps.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.Bookmarks.UnitTests\\Microsoft.CmdPal.Ext.Bookmarks.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.Calc.UnitTests\\Microsoft.CmdPal.Ext.Calc.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.ClipboardHistory.UnitTests\\Microsoft.CmdPal.Ext.ClipboardHistory.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.Registry.UnitTests\\Microsoft.CmdPal.Ext.Registry.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.RemoteDesktop.UnitTests\\Microsoft.CmdPal.Ext.RemoteDesktop.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.Shell.UnitTests\\Microsoft.CmdPal.Ext.Shell.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.System.UnitTests\\Microsoft.CmdPal.Ext.System.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.TimeDate.UnitTests\\Microsoft.CmdPal.Ext.TimeDate.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.UnitTestsBase\\Microsoft.CmdPal.Ext.UnitTestBase.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.WebSearch.UnitTests\\Microsoft.CmdPal.Ext.WebSearch.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.WindowWalker.UnitTests\\Microsoft.CmdPal.Ext.WindowWalker.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.UI.ViewModels.UnitTests\\Microsoft.CmdPal.UI.ViewModels.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.UITests\\Microsoft.CmdPal.UITests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CommandPalette.Extensions.Toolkit.UnitTests\\Microsoft.CommandPalette.Extensions.Toolkit.UnitTests.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Apps\\Microsoft.CmdPal.Ext.Apps.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Bookmark\\Microsoft.CmdPal.Ext.Bookmarks.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Calc\\Microsoft.CmdPal.Ext.Calc.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.ClipboardHistory\\Microsoft.CmdPal.Ext.ClipboardHistory.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Indexer\\Microsoft.CmdPal.Ext.Indexer.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.PerformanceMonitor\\Microsoft.CmdPal.Ext.PerformanceMonitor.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Registry\\Microsoft.CmdPal.Ext.Registry.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.RemoteDesktop\\Microsoft.CmdPal.Ext.RemoteDesktop.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Shell\\Microsoft.CmdPal.Ext.Shell.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.System\\Microsoft.CmdPal.Ext.System.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.TimeDate\\Microsoft.CmdPal.Ext.TimeDate.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WebSearch\\Microsoft.CmdPal.Ext.WebSearch.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WinGet\\Microsoft.CmdPal.Ext.WinGet.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WindowWalker\\Microsoft.CmdPal.Ext.WindowWalker.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WindowsServices\\Microsoft.CmdPal.Ext.WindowsServices.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WindowsSettings\\Microsoft.CmdPal.Ext.WindowsSettings.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WindowsTerminal\\Microsoft.CmdPal.Ext.WindowsTerminal.csproj",
"src\\modules\\cmdpal\\ext\\ProcessMonitorExtension\\ProcessMonitorExtension.csproj",
"src\\modules\\cmdpal\\ext\\SamplePagesExtension\\SamplePagesExtension.csproj",
"src\\modules\\cmdpal\\extensionsdk\\Microsoft.CommandPalette.Extensions.Toolkit\\Microsoft.CommandPalette.Extensions.Toolkit.csproj",
"src\\modules\\cmdpal\\extensionsdk\\Microsoft.CommandPalette.Extensions\\Microsoft.CommandPalette.Extensions.vcxproj"
]
}
}

View File

@@ -7,8 +7,14 @@
"src\\common\\ManagedCommon\\ManagedCommon.csproj",
"src\\common\\ManagedCsWin32\\ManagedCsWin32.csproj",
"src\\common\\ManagedTelemetry\\Telemetry\\ManagedTelemetry.csproj",
"src\\common\\SettingsAPI\\SettingsAPI.vcxproj",
"src\\common\\UITestAutomation\\UITestAutomation.csproj",
"src\\common\\interop\\PowerToys.Interop.vcxproj",
"src\\common\\logger\\logger.vcxproj",
"src\\common\\version\\version.vcxproj",
"src\\logging\\logging.vcxproj",
"src\\modules\\MouseUtils\\MouseJump.Common\\MouseJump.Common.csproj",
"src\\modules\\ZoomIt\\ZoomItSettingsInterop\\ZoomItSettingsInterop.vcxproj",
"src\\modules\\cmdpal\\CmdPalKeyboardService\\CmdPalKeyboardService.vcxproj",
"src\\modules\\cmdpal\\CmdPalModuleInterface\\CmdPalModuleInterface.vcxproj",
"src\\modules\\cmdpal\\Microsoft.CmdPal.Common\\Microsoft.CmdPal.Common.csproj",
@@ -51,7 +57,9 @@
"src\\modules\\cmdpal\\ext\\ProcessMonitorExtension\\ProcessMonitorExtension.csproj",
"src\\modules\\cmdpal\\ext\\SamplePagesExtension\\SamplePagesExtension.csproj",
"src\\modules\\cmdpal\\extensionsdk\\Microsoft.CommandPalette.Extensions.Toolkit\\Microsoft.CommandPalette.Extensions.Toolkit.csproj",
"src\\modules\\cmdpal\\extensionsdk\\Microsoft.CommandPalette.Extensions\\Microsoft.CommandPalette.Extensions.vcxproj"
"src\\modules\\cmdpal\\extensionsdk\\Microsoft.CommandPalette.Extensions\\Microsoft.CommandPalette.Extensions.vcxproj",
"src\\modules\\powerdisplay\\PowerDisplay.Models\\PowerDisplay.Models.csproj",
"src\\settings-ui\\Settings.UI.Library\\Settings.UI.Library.csproj"
]
}
}

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using Microsoft.CmdPal.Ext.Calc.Helper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -10,6 +11,25 @@ namespace Microsoft.CmdPal.Ext.Calc.UnitTests;
[TestClass]
public class QueryHelperTests
{
private CultureInfo originalCulture;
private CultureInfo originalUiCulture;
[TestInitialize]
public void Setup()
{
originalCulture = CultureInfo.CurrentCulture;
CultureInfo.CurrentCulture = new CultureInfo("en-us", false);
originalUiCulture = CultureInfo.CurrentUICulture;
CultureInfo.CurrentUICulture = new CultureInfo("en-us", false);
}
[TestCleanup]
public void CleanUp()
{
CultureInfo.CurrentCulture = originalCulture;
CultureInfo.CurrentUICulture = originalUiCulture;
}
[DataTestMethod]
[DataRow("2²", "4")]
[DataRow("2³", "8")]

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Linq;
using Microsoft.CmdPal.Ext.Calc.Helper;
using Microsoft.CmdPal.Ext.Calc.Pages;
@@ -14,6 +15,25 @@ namespace Microsoft.CmdPal.Ext.Calc.UnitTests;
[TestClass]
public class QueryTests : CommandPaletteUnitTestBase
{
private CultureInfo originalCulture;
private CultureInfo originalUiCulture;
[TestInitialize]
public void Setup()
{
originalCulture = CultureInfo.CurrentCulture;
CultureInfo.CurrentCulture = new CultureInfo("en-us", false);
originalUiCulture = CultureInfo.CurrentUICulture;
CultureInfo.CurrentUICulture = new CultureInfo("en-us", false);
}
[TestCleanup]
public void CleanUp()
{
CultureInfo.CurrentCulture = originalCulture;
CultureInfo.CurrentUICulture = originalUiCulture;
}
[DataTestMethod]
[DataRow("2+2", "4")]
[DataRow("5*3", "15")]
@@ -84,6 +104,40 @@ public class QueryTests : CommandPaletteUnitTestBase
Assert.IsTrue(result.Title.Contains(expected, System.StringComparison.Ordinal), $"Calc trigMode convert result isn't correct. Current result: {result.Title}");
}
[DataTestMethod]
[DataRow("sin(60)", "-0.30481", CalculateEngine.TrigMode.Radians, "de-DE")]
[DataRow("sin(60)", "0.866025", CalculateEngine.TrigMode.Degrees, "de-DE")]
[DataRow("sin(60)", "0.809016", CalculateEngine.TrigMode.Gradians, "de-DE")]
[DataRow("sin(60)", "-0.30481", CalculateEngine.TrigMode.Radians, "fr-FR")]
[DataRow("sin(60)", "0.866025", CalculateEngine.TrigMode.Degrees, "fr-FR")]
[DataRow("sin(60)", "0.809016", CalculateEngine.TrigMode.Gradians, "fr-FR")]
public void TrigModeSettingsTest_NonEnglishCulture(string input, string expected, CalculateEngine.TrigMode trigMode, string cultureName)
{
var previousCulture = CultureInfo.CurrentCulture;
var previousUiCulture = CultureInfo.CurrentUICulture;
try
{
CultureInfo.CurrentCulture = new CultureInfo(cultureName, false);
CultureInfo.CurrentUICulture = new CultureInfo(cultureName, false);
var settings = new Settings(trigUnit: trigMode, outputUseEnglishFormat: true);
var page = new CalculatorListPage(settings);
page.UpdateSearchText(string.Empty, input);
var result = page.GetItems().FirstOrDefault();
Assert.IsNotNull(result);
Assert.IsTrue(result.Title.Contains(expected, System.StringComparison.Ordinal), $"Calc trigMode convert result isn't correct for culture '{cultureName}'. Current result: {result.Title}");
}
finally
{
CultureInfo.CurrentCulture = previousCulture;
CultureInfo.CurrentUICulture = previousUiCulture;
}
}
[DataTestMethod]
[DataRow("2^64", "18446744073709551616", "0x10000000000000000")]
[DataRow("0-(2^64)", "-18446744073709551616", "-0x10000000000000000")]

View File

@@ -108,7 +108,6 @@ internal static class ResultHelper
tags.Add(new Tag
{
Text = Resources.windowwalker_NotResponding,
Foreground = ColorHelpers.FromRgb(220, 20, 60),
});
}

View File

@@ -7,7 +7,9 @@ using System.Globalization;
using System.Text;
using ImageResizer.Cli;
using ImageResizer.Cli.Telemetry;
using ManagedCommon;
using Microsoft.PowerToys.Telemetry;
namespace ImageResizerCLI;
@@ -37,14 +39,33 @@ internal static class Program
try
{
var executor = new ImageResizerCliExecutor();
return executor.Run(args);
int result = executor.Run(args);
LogCLITelemetry(executor.CommandName, result == 0);
return result;
}
catch (Exception ex)
{
CliLogger.Error($"Unhandled exception: {ex.Message}");
CliLogger.Error($"Stack trace: {ex.StackTrace}");
Console.Error.WriteLine($"Fatal error: {ex.Message}");
LogCLITelemetry("resize", successful: false);
return 1;
}
}
private static void LogCLITelemetry(string commandName, bool successful)
{
try
{
PowerToysTelemetry.Log.WriteEvent(new ImageResizerCLICommandEvent
{
CommandName = commandName,
Successful = successful,
});
}
catch (Exception ex)
{
CliLogger.Error($"Failed to log CLI telemetry: {ex.Message}");
}
}
}

View File

@@ -19,6 +19,11 @@ namespace ImageResizer.Cli
/// </summary>
public class ImageResizerCliExecutor
{
/// <summary>
/// Gets the name of the last CLI operation that was executed.
/// </summary>
public string CommandName { get; private set; } = "resize";
/// <summary>
/// Runs the CLI executor with the provided command-line arguments.
/// </summary>
@@ -37,18 +42,21 @@ namespace ImageResizer.Cli
}
CliOptions.PrintUsage();
CommandName = "error";
return 1;
}
if (cliOptions.ShowHelp)
{
CliOptions.PrintUsage();
CommandName = "help";
return 0;
}
if (cliOptions.ShowConfig)
{
CliOptions.PrintConfig(Settings.Default);
CommandName = "show-config";
return 0;
}
@@ -56,6 +64,7 @@ namespace ImageResizer.Cli
{
Console.WriteLine(Resources.CLI_NoInputFiles);
CliOptions.PrintUsage();
CommandName = "error";
return 1;
}

View File

@@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace ImageResizer.Cli.Telemetry
{
/// <summary>
/// Telemetry event for Image Resizer CLI command execution.
/// </summary>
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class ImageResizerCLICommandEvent : EventBase, IEvent
{
public ImageResizerCLICommandEvent()
{
EventName = "ImageResizer_CLICommand";
CommandName = string.Empty;
}
/// <summary>
/// Gets or sets the name of the CLI command that was executed.
/// </summary>
public string CommandName { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the command executed successfully.
/// </summary>
public bool Successful { get; set; }
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}
}

View File

@@ -18,7 +18,7 @@ namespace ImageResizer.Models
_scaleFormat ??= CompositeFormat.Parse(ResourceLoaderInstance.GetString("Input_AiScaleFormat"));
[ObservableProperty]
[JsonPropertyName("scale")]
[property: JsonPropertyName("scale")]
private int _scale = 2;
/// <summary>

View File

@@ -26,26 +26,26 @@ namespace ImageResizer.Models
};
[ObservableProperty]
[JsonPropertyName("Id")]
[property: JsonPropertyName("Id")]
private int _id;
private string _name;
[ObservableProperty]
[JsonPropertyName("fit")]
[property: JsonPropertyName("fit")]
[NotifyPropertyChangedFor(nameof(ShowHeight))]
private ResizeFit _fit = ResizeFit.Fit;
[ObservableProperty]
[JsonPropertyName("width")]
[property: JsonPropertyName("width")]
private double _width;
[ObservableProperty]
[JsonPropertyName("height")]
[property: JsonPropertyName("height")]
private double _height;
[ObservableProperty]
[JsonPropertyName("unit")]
[property: JsonPropertyName("unit")]
[NotifyPropertyChangedFor(nameof(ShowHeight))]
private ResizeUnit _unit = ResizeUnit.Pixel;

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