Skip to content

Commit ba68b88

Browse files
CopilotMuyuanMSCopilot
authored
Fix ZoomIt Record hotkey ignoring Alt modifier when Alt is the only modifier key (#47388)
## Summary of the Pull Request ZoomIt derives three recording hotkeys from one base key via XOR: fullscreen (base), crop (base XOR Shift), window (base XOR Alt). When Alt is the sole modifier, `base XOR Alt = 0`, registering a modifier-less hotkey that captures every bare keypress (e.g., pressing `5` triggers window recording). **`Zoomit.cpp`** — 4 hotkey registration sites: - Guard `RECORD_CROP_HOTKEY` registration behind `(g_RecordToggleMod ^ MOD_SHIFT) != 0` - Guard `RECORD_WINDOW_HOTKEY` registration behind `(g_RecordToggleMod ^ MOD_ALT) != 0` ```cpp // Before (all 4 sites): registerHotkey( RECORD_CROP_HOTKEY, ( g_RecordToggleMod ^ MOD_SHIFT ) | MOD_NOREPEAT, ... ); registerHotkey( RECORD_WINDOW_HOTKEY, ( g_RecordToggleMod ^ MOD_ALT ) | MOD_NOREPEAT, ... ); // After: if ( g_RecordToggleMod ^ MOD_SHIFT ) { registerHotkey( RECORD_CROP_HOTKEY, ( g_RecordToggleMod ^ MOD_SHIFT ) | MOD_NOREPEAT, ... ); } if ( g_RecordToggleMod ^ MOD_ALT ) { registerHotkey( RECORD_WINDOW_HOTKEY, ( g_RecordToggleMod ^ MOD_ALT ) | MOD_NOREPEAT, ... ); } ``` **`ZoomItViewModel.cs`** — `RecordToggleKeyCrop` / `RecordToggleKeyWindow` computed properties: - Return `null` when the derived hotkey would have no modifier keys, so the Settings UI omits the inapplicable shortcut description rather than displaying a bare-key shortcut. ## PR Checklist - [ ] Closes: #xxx - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx ## Detailed Description of the Pull Request / Additional comments ZoomIt registers crop and window recording variants by XOR-ing the base modifier with `MOD_SHIFT` and `MOD_ALT` respectively. This design breaks when the base modifier equals the XOR target — the result is `0`, and `RegisterHotKey` with no modifiers intercepts every bare keypress of that key system-wide. The fix is symmetric across all 4 registration sites (standalone `registerHotkey()` in `RegisterAllHotkeys`, the legacy dialog OK path, and two `WM_CREATE`-adjacent paths): skip the derived hotkey registration when the computed modifier is zero. The Settings UI ViewModel mirrors this logic by returning `null` for the affected computed properties, causing the converter to emit an empty string instead of a modifier-less shortcut label. ## Validation Steps Performed - Code review confirmed fix is applied consistently across all 4 `RegisterHotKey` call sites in `Zoomit.cpp` - Verified `HotkeySettingsToLocalizedStringConverter` returns `string.Empty` for `null` input — no display regression in Settings UI - Confirmed the default `Ctrl+5` hotkey is unaffected (`MOD_CONTROL ^ MOD_ALT = MOD_CONTROL | MOD_ALT ≠ 0`) --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MuyuanMS <116717757+MuyuanMS@users.noreply.github.com> Co-authored-by: Muyuan Li (from Dev Box) <muyuanli@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3e60249 commit ba68b88

2 files changed

Lines changed: 47 additions & 22 deletions

File tree

src/modules/ZoomIt/ZoomIt/Zoomit.cpp

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3353,8 +3353,14 @@ void RegisterAllHotkeys(HWND hWnd)
33533353
}
33543354
if (g_RecordToggleKey) {
33553355
registerHotkey( RECORD_HOTKEY, g_RecordToggleMod | MOD_NOREPEAT, g_RecordToggleKey & 0xFF );
3356-
registerHotkey( RECORD_CROP_HOTKEY, ( g_RecordToggleMod ^ MOD_SHIFT ) | MOD_NOREPEAT, g_RecordToggleKey & 0xFF );
3357-
registerHotkey( RECORD_WINDOW_HOTKEY, ( g_RecordToggleMod ^ MOD_ALT ) | MOD_NOREPEAT, g_RecordToggleKey & 0xFF );
3356+
UINT cropMod = g_RecordToggleMod ^ MOD_SHIFT;
3357+
UINT windowMod = g_RecordToggleMod ^ MOD_ALT;
3358+
if ( cropMod != 0 ) {
3359+
registerHotkey( RECORD_CROP_HOTKEY, cropMod | MOD_NOREPEAT, g_RecordToggleKey & 0xFF );
3360+
}
3361+
if ( windowMod != 0 ) {
3362+
registerHotkey( RECORD_WINDOW_HOTKEY, windowMod | MOD_NOREPEAT, g_RecordToggleKey & 0xFF );
3363+
}
33583364
}
33593365

33603366
// Note: COPY_IMAGE_HOTKEY, COPY_CROP_HOTKEY (Ctrl+C, Ctrl+Shift+C) and
@@ -5459,16 +5465,18 @@ INT_PTR CALLBACK OptionsProc( HWND hDlg, UINT message,
54595465
break;
54605466

54615467
}
5462-
else if( newRecordToggleKey &&
5463-
(!RegisterHotKey(GetParent(hDlg), RECORD_HOTKEY, newRecordToggleMod | MOD_NOREPEAT, newRecordToggleKey & 0xFF) ||
5464-
!RegisterHotKey(GetParent(hDlg), RECORD_CROP_HOTKEY, (newRecordToggleMod ^ MOD_SHIFT) | MOD_NOREPEAT, newRecordToggleKey & 0xFF) ||
5465-
!RegisterHotKey(GetParent(hDlg), RECORD_WINDOW_HOTKEY, (newRecordToggleMod ^ MOD_ALT) | MOD_NOREPEAT, newRecordToggleKey & 0xFF))) {
5466-
5467-
MessageBox(hDlg, L"The specified record hotkey is already in use.\nSelect a different record hotkey.",
5468-
APPNAME, MB_ICONERROR);
5469-
UnregisterAllHotkeys(GetParent(hDlg));
5470-
break;
5468+
else if( newRecordToggleKey ) {
5469+
UINT cropMod = newRecordToggleMod ^ MOD_SHIFT;
5470+
UINT windowMod = newRecordToggleMod ^ MOD_ALT;
5471+
if (!RegisterHotKey(GetParent(hDlg), RECORD_HOTKEY, newRecordToggleMod | MOD_NOREPEAT, newRecordToggleKey & 0xFF) ||
5472+
(cropMod != 0 && !RegisterHotKey(GetParent(hDlg), RECORD_CROP_HOTKEY, cropMod | MOD_NOREPEAT, newRecordToggleKey & 0xFF)) ||
5473+
(windowMod != 0 && !RegisterHotKey(GetParent(hDlg), RECORD_WINDOW_HOTKEY, windowMod | MOD_NOREPEAT, newRecordToggleKey & 0xFF))) {
54715474

5475+
MessageBox(hDlg, L"The specified record hotkey is already in use.\nSelect a different record hotkey.",
5476+
APPNAME, MB_ICONERROR);
5477+
UnregisterAllHotkeys(GetParent(hDlg));
5478+
break;
5479+
}
54725480
} else {
54735481

54745482
g_BreakTimeout = newTimeout;
@@ -7502,14 +7510,17 @@ LRESULT APIENTRY MainWndProc(
75027510
showOptions = TRUE;
75037511

75047512
}
7505-
else if (g_RecordToggleKey &&
7506-
(!RegisterHotKey(hWnd, RECORD_HOTKEY, g_RecordToggleMod | MOD_NOREPEAT, g_RecordToggleKey & 0xFF) ||
7507-
!RegisterHotKey(hWnd, RECORD_CROP_HOTKEY, (g_RecordToggleMod ^ MOD_SHIFT) | MOD_NOREPEAT, g_RecordToggleKey & 0xFF) ||
7508-
!RegisterHotKey(hWnd, RECORD_WINDOW_HOTKEY, (g_RecordToggleMod ^ MOD_ALT) | MOD_NOREPEAT, g_RecordToggleKey & 0xFF))) {
7513+
else if (g_RecordToggleKey) {
7514+
UINT cropMod = g_RecordToggleMod ^ MOD_SHIFT;
7515+
UINT windowMod = g_RecordToggleMod ^ MOD_ALT;
7516+
if (!RegisterHotKey(hWnd, RECORD_HOTKEY, g_RecordToggleMod | MOD_NOREPEAT, g_RecordToggleKey & 0xFF) ||
7517+
(cropMod != 0 && !RegisterHotKey(hWnd, RECORD_CROP_HOTKEY, cropMod | MOD_NOREPEAT, g_RecordToggleKey & 0xFF)) ||
7518+
(windowMod != 0 && !RegisterHotKey(hWnd, RECORD_WINDOW_HOTKEY, windowMod | MOD_NOREPEAT, g_RecordToggleKey & 0xFF))) {
75097519

7510-
MessageBox(hWnd, L"The specified record hotkey is already in use.\nSelect a different record hotkey.",
7511-
APPNAME, MB_ICONERROR);
7512-
showOptions = TRUE;
7520+
MessageBox(hWnd, L"The specified record hotkey is already in use.\nSelect a different record hotkey.",
7521+
APPNAME, MB_ICONERROR);
7522+
showOptions = TRUE;
7523+
}
75137524
}
75147525
if( showOptions ) {
75157526

@@ -10175,9 +10186,11 @@ LRESULT APIENTRY MainWndProc(
1017510186
}
1017610187
if (g_RecordToggleKey)
1017710188
{
10189+
UINT cropMod = g_RecordToggleMod ^ MOD_SHIFT;
10190+
UINT windowMod = g_RecordToggleMod ^ MOD_ALT;
1017810191
if (!RegisterHotKey(hWnd, RECORD_HOTKEY, g_RecordToggleMod | MOD_NOREPEAT, g_RecordToggleKey & 0xFF) ||
10179-
!RegisterHotKey(hWnd, RECORD_CROP_HOTKEY, (g_RecordToggleMod ^ MOD_SHIFT) | MOD_NOREPEAT, g_RecordToggleKey & 0xFF) ||
10180-
!RegisterHotKey(hWnd, RECORD_WINDOW_HOTKEY, (g_RecordToggleMod ^ MOD_ALT) | MOD_NOREPEAT, g_RecordToggleKey & 0xFF))
10192+
(cropMod != 0 && !RegisterHotKey(hWnd, RECORD_CROP_HOTKEY, cropMod | MOD_NOREPEAT, g_RecordToggleKey & 0xFF)) ||
10193+
(windowMod != 0 && !RegisterHotKey(hWnd, RECORD_WINDOW_HOTKEY, windowMod | MOD_NOREPEAT, g_RecordToggleKey & 0xFF)))
1018110194
{
1018210195
if(!g_StartedByPowerToys)
1018310196
{

src/settings-ui/Settings.UI/ViewModels/ZoomItViewModel.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,13 @@ public HotkeySettings RecordToggleKeyCrop
362362
return null;
363363
}
364364

365-
// XOR with Shift: if Shift is present, remove it; if absent, add it
365+
// XOR with Shift: if Shift is present, remove it; if absent, add it.
366+
// If the result would have no modifier keys, return null to avoid displaying a bare-key shortcut label.
367+
if (baseKey.Shift && !baseKey.Win && !baseKey.Ctrl && !baseKey.Alt)
368+
{
369+
return null;
370+
}
371+
366372
return new HotkeySettings(
367373
baseKey.Win,
368374
baseKey.Ctrl,
@@ -382,7 +388,13 @@ public HotkeySettings RecordToggleKeyWindow
382388
return null;
383389
}
384390

385-
// XOR with Alt: if Alt is present, remove it; if absent, add it
391+
// XOR with Alt: if Alt is present, remove it; if absent, add it.
392+
// If the result would have no modifier keys, return null to avoid displaying a bare-key shortcut label.
393+
if (baseKey.Alt && !baseKey.Win && !baseKey.Ctrl && !baseKey.Shift)
394+
{
395+
return null;
396+
}
397+
386398
return new HotkeySettings(
387399
baseKey.Win,
388400
baseKey.Ctrl,

0 commit comments

Comments
 (0)