mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-07-10 04:20:23 +02:00
## Summary of the Pull Request Migrates the **Quick Accent (PowerAccent)** module's UI from WPF (`System.Windows.*`) to **WinUI 3 (Windows App SDK)**, following the pattern used by other migrated modules (ImageResizer, PowerDisplay). The accent selector is now a self-contained WinUI 3 app (`PowerToys.PowerAccent.exe`) shipped under `WinUI3Apps`, and `PowerAccent.Core` is UI-framework-agnostic. demo: https://github.com/user-attachments/assets/400c33ee-0fc0-491e-841b-a546438edf91 ## PR Checklist - [x] Closes: #48889 - [x] **Communication:** Tracked task (#48889) agreed with core contributors - [x] **Tests:** Added/updated and all pass — new `PowerAccent.Core.UnitTests` (21 tests for the positioning / DPI math); existing `PowerAccent.Common.UnitTests` unaffected - [x] **Localization:** No new localizable end-user strings — new accessibility metadata uses non-localized `AutomationProperties.AutomationId`, and the window title is the brand name `"Quick Accent"` (literal, matching ColorPicker) - [x] **Dev docs:** Updated `doc/devdocs/modules/quickaccent.md` - [x] **New binaries:** Added on the required places - [x] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json): the `WinUI3Apps\` PowerAccent payloads are listed in `ESRPSigning_core.json` - [x] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs): no manual `Product.wxs` entry — the self-contained `WinUI3Apps` output (exe + `.pri` + Windows App SDK runtime) is harvested by the `WinUI3ApplicationsFiles` glob (same as ImageResizer) - [x] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml): no change needed — `PowerAccent.Core.UnitTests` is discovered by the existing `**\*UnitTest*.dll` VSTest glob - [x] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml): covered by `ESRPSigning_core.json`; no `release.yml` change needed - [ ] **Documentation updated:** N/A — internal UI-framework migration with no user-facing behavior change ## Detailed Description of the Pull Request / Additional comments The migration spans three areas (tracked in #48889): **UI (WPF → WinUI 3)** - `PowerAccent.UI` is now a WinUI 3 app shell (custom `Program.Main`, `WindowsPackageType=None`, `WindowsAppSDKSelfContained=true`). - The accent selector is a non-activating `TransparentWindow` overlay shown with `SW_SHOWNA` (never steals focus). It is made always-on-top only while shown — the WinUIEx `WindowEx.IsAlwaysOnTop` property is toggled `true` on show / `false` on hide in `OnChangeDisplay` (matching the WPF original's `Topmost = isActive`), so the dormant, never-destroyed overlay does not pin a discrete GPU awake on hybrid-graphics laptops (issue #34849 / PR #41044). - The accent "pill" selection visual is reproduced with `VisualStateManager` (WinUI 3 has no `Style.Triggers`). - **WinUI 3 gotcha:** x:Bind on a Window-rooted XAML initializes only on `Window.Activated`, which never fires for this `SW_SHOWNA` overlay — so the selector calls `Bindings.Update()` after `InitializeComponent()`; without it the `ListView` renders empty. - **Theme:** the long-lived, never-activated process follows the system app theme automatically — `App.xaml` leaves `Application.RequestedTheme` unset, so WinUI re-resolves the `{ThemeResource}` brushes (and retints the acrylic) on a live light/dark switch with no manual `ThemeListener` needed. - **Layout parity with the WPF original:** the bar width hugs its content (`itemCount × 48`, clamped to the monitor width — computed, not measured, to avoid a racy `ListView` measure), and each cell pins `MinWidth=48` (WinUI's `ListViewItem` defaults to 88, which would otherwise leave wide gaps). - **Accessibility:** UIA window name + `AutomationId`s on the character list and description. **Dependency** - `PowerAccent.Core` no longer depends on WPF — it raises events and takes an injected UI-thread marshaller. - WinForms `SendKeys` → `SendInput` (CsWin32 P/Invoke); WPF-UI (Lepo) removed; language data moved to the UI-/WinRT-agnostic `PowerAccent.Common`. - MVVM via CommunityToolkit.Mvvm with `[ObservableProperty]` **partial properties** (WinRT-correct, clears MVVMTK0045). **CI / Build / Installer** - Signing config, WinUI3Apps glob harvest, and the new unit-test project — see the checklist above. ## Validation Steps Performed - **Build:** `x64 Debug` builds with **0 warnings / 0 errors**. - **Unit tests:** `PowerAccent.Core.UnitTests` — **21/21 pass** (9 anchor positions × DPI 1.0/1.5/2.0, the offset and negative-origin monitors, caret centering + edge clamping + flip-below). - **XamlStyler:** `PowerAccentXAML/MainWindow.xaml` passes the passive format check (CI mode). - **Manual (single monitor, Top-center, light theme):** - Accent popup appears with the full accent list rendered. - Bar hugs the characters and is centered; cell spacing matches the WPF original. - Switching the system theme (light/dark) is followed live by the popup. - With `show_description` enabled, the description row is wide (≥600px) and readable, with the accent bar centered above it. - **Remaining manual validation** (tracked in #48889): multi-monitor, per-monitor DPI, all 9 `toolbar_position` values, and high-contrast theme. --------- Co-authored-by: Yu Leng <yuleng@microsoft.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
145 lines
7.6 KiB
Markdown
145 lines
7.6 KiB
Markdown
# Quick Accent
|
|
|
|
|
|
[Public overview - Microsoft Learn](https://learn.microsoft.com/en-us/windows/powertoys/quick-accent)
|
|
|
|
## Quick Links
|
|
|
|
[All Issues](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen%20label%3A%22Product-Quick%20Accent%22)<br>
|
|
[Bugs](https://github.com/microsoft/PowerToys/issues?q=is%3Aopen%20label%3AIssue-Bug%20label%3A%22Product-Quick%20Accent%22)<br>
|
|
[Pull Requests](https://github.com/microsoft/PowerToys/pulls?q=is%3Apr+is%3Aopen+label%3A%22Product-Quick+Accent%22)
|
|
|
|
## Overview
|
|
|
|
Quick Accent (formerly known as Power Accent) is a PowerToys module that allows users to quickly insert accented characters by holding a key and pressing an activation key (like the Space key or arrow keys). For example, holding 'a' might display options like 'à', 'á', 'â', etc. This tool enhances productivity by streamlining the input of special characters without the need to memorize keyboard shortcuts.
|
|
|
|
## Architecture
|
|
|
|
The Quick Accent module consists of five projects:
|
|
|
|
```
|
|
poweraccent/
|
|
├── PowerAccent.Common/ # Language data, character mappings, LetterKey enum
|
|
├── PowerAccent.Core/ # Accent logic, settings, positioning, usage statistics
|
|
├── PowerAccent.UI/ # WinUI 3 character selector app (PowerToys.PowerAccent.exe)
|
|
├── PowerAccentKeyboardService/ # WinRT keyboard-hook component
|
|
└── PowerAccentModuleInterface/ # Native runner module DLL
|
|
```
|
|
|
|
### Module Interface (PowerAccentModuleInterface)
|
|
|
|
The Module Interface, implemented in `PowerAccentModuleInterface/dllmain.cpp`, is responsible for:
|
|
- Handling communication between PowerToys Runner and the PowerAccent process
|
|
- Managing module lifecycle (enable/disable/settings)
|
|
- Launching and terminating the PowerToys.PowerAccent.exe process
|
|
|
|
### Shared Data (PowerAccent.Common)
|
|
|
|
`PowerAccent.Common` holds the UI- and runtime-agnostic data the other projects share:
|
|
- The language / character-set definitions and per-letter accent mappings
|
|
- The managed `LetterKey` enum (kept in sync with the WinRT `LetterKey` in `PowerAccentKeyboardService/KeyboardListener.idl`)
|
|
|
|
It has no UI or WinRT dependencies and is unit-tested in isolation (`PowerAccent.Common.UnitTests`).
|
|
|
|
### Core Logic (PowerAccent.Core)
|
|
|
|
The Core component contains:
|
|
- Main accent character logic, consuming the language data from `PowerAccent.Common`
|
|
- Toolbar positioning math (9 anchor points with per-monitor DPI) and settings handling
|
|
- Management of special characters (currency, math symbols, etc.) and usage statistics
|
|
|
|
Core carries no UI-framework dependency: it raises events and accepts a UI-thread marshaller delegate instead of touching WPF/WinUI directly, and its positioning math is covered by `PowerAccent.Core.UnitTests`.
|
|
|
|
### UI Layer (PowerAccent.UI)
|
|
|
|
The UI component is a self-contained **WinUI 3 (Windows App SDK)** app, migrated from WPF.
|
|
It is responsible for:
|
|
- Displaying the accent toolbar — a non-activating, always-on-top `TransparentWindow` overlay shown with `SW_SHOWNA` so it never steals focus from the app being typed into
|
|
- Handling selection and the toolbar's sizing / positioning
|
|
- Following the system theme while the long-lived process runs
|
|
|
|
It builds to `PowerToys.PowerAccent.exe` together with its `.pri` and the bundled Windows App SDK runtime, all under the `WinUI3Apps` output folder.
|
|
|
|
### Keyboard Service (PowerAccentKeyboardService)
|
|
|
|
This component:
|
|
- Implements keyboard hooks to detect key presses
|
|
- Manages the trigger mechanism for displaying the accent toolbar
|
|
- Handles keyboard input processing
|
|
|
|
## Implementation Details
|
|
|
|
### Activation Mechanism
|
|
|
|
Quick Accent supports two activation styles, selected by the **Activation key** setting.
|
|
|
|
**Trigger-key modes** (`Left/Right arrow`, `Space`, or `Both` — the default):
|
|
1. A user presses and holds a character key (e.g., 'a')
|
|
2. User presses the trigger key
|
|
3. After a brief delay (around 300ms per setting), the accent toolbar appears
|
|
4. The user can select an accented variant using the trigger key
|
|
5. Upon releasing the keys, the selected accented character is inserted
|
|
|
|
**Press-and-hold mode** (`Press and hold the letter`, iOS/macOS style, opt-in):
|
|
1. A user presses and holds an accent-capable character key (e.g., 'a'); the base
|
|
letter is typed immediately
|
|
2. After the configured **Hold duration** (around 500ms per setting), the accent
|
|
toolbar appears automatically — no separate trigger key is required
|
|
3. The user navigates the options with the arrow keys or Space
|
|
4. Upon releasing the letter, the selected accent replaces the base letter; if no
|
|
option was selected, the base letter that was already typed simply remains
|
|
5. A quick tap (shorter than the Hold duration) types the base letter only, and
|
|
modifier combinations (Ctrl/Alt/AltGr/Win + letter) are left untouched
|
|
|
|
### Character Sets
|
|
|
|
The module includes multiple language-specific character sets and special character sets:
|
|
- Various language sets for different alphabets and writing systems
|
|
- Special character sets (currency symbols, mathematical notations, etc.)
|
|
- These sets are defined in the core component and can be extended
|
|
|
|
### Known Behaviors
|
|
|
|
- The module has a specific timing mechanism for activation that users have become accustomed to. Initially, this was considered a bug (where the toolbar would still appear even after quickly tapping and releasing keys), but it has been maintained as expected behavior since users rely on it.
|
|
- Multiple rapid key presses can trigger multiple background tasks.
|
|
|
|
## Future Considerations
|
|
|
|
- Potential refinements to the activation timing mechanism
|
|
- Additional language and special character sets
|
|
- Improved UI positioning in different application contexts
|
|
|
|
## Debugging
|
|
|
|
To debug the Quick Accent module via **runner** approach, follow these steps:
|
|
|
|
0. Get familiar with the overall [Debugging Process](../development/debugging.md) for PowerToys.
|
|
1. **Build** the entire PowerToys solution in Visual Studio
|
|
2. Navigate to the **PowerAccent** folder in Solution Explorer
|
|
3. Open the file you want to debug and set **breakpoints** at the relevant locations
|
|
4. Find the **runner** project in the root of the solution
|
|
5. Right-click on the **runner** project and select "*Set as Startup Project*"
|
|
6. Start debugging by pressing `F5` or clicking the "*Start*" button
|
|
7. When the PowerToys Runner launches, **enable** the Quick Accent module in the UI
|
|
8. Use the Visual Studio Debug menu or press `Ctrl+Alt+P` to open "*Reattach to Process*"
|
|
9. Find and select "**PowerToys.PowerAccent.exe**" in the process list
|
|
10. Trigger the action in Quick Accent that should hit your breakpoint
|
|
11. Verify that the debugger breaks at your breakpoint and you can inspect variables and step through code
|
|
|
|
This process allows you to debug the Quick Accent module while it's running as part of the full PowerToys application.
|
|
|
|
### Alternative Debugging Approach
|
|
|
|
To directly debug the Quick Accent UI component:
|
|
|
|
0. Get familiar with the overall [Debugging Process](../development/debugging.md) for PowerToys.
|
|
1. **Build** the entire PowerToys solution in Visual Studio
|
|
2. Navigate to the **PowerAccent** folder in Solution Explorer
|
|
3. Open the file you want to debug and set **breakpoints** at the relevant locations
|
|
4. Right-click on the **PowerAccent.UI** project and select "*Set as Startup Project*"
|
|
5. Start debugging by pressing `F5` or clicking the "*Start*" button
|
|
6. Verify that the debugger breaks at your breakpoint and you can inspect variables and step through code
|
|
|
|
**Known issue**: A first incremental build can surface transient errors (for example from CsWinRT projection / WinUI XAML codegen ordering).<br>
|
|
**Solution**: Right-click the **PowerAccent** folder in Solution Explorer and select "*Rebuild*", then start debugging again.
|