Commit 18edd52
Fix Peek Ctrl+W shortcut not working after clicking preview (#48293)
## Summary
Fixes #48274
When previewing a file with Peek, clicking inside the preview content
(PDF, text/code, markdown, HTML) makes **Ctrl+W unable to close the
window**. This happens because the preview controls (WebView2 for most
file types, native shell handlers for others) capture keyboard focus in
their own message loop, bypassing the XAML keyboard accelerator system
entirely.
## Problem
Peek defines keyboard shortcuts (Ctrl+W to close, Escape to close, arrow
keys to navigate) as `KeyboardAccelerator` elements on the main XAML
Grid. These only fire when keyboard input flows through the XAML input
system. However:
- **WebView2** (used for PDF, text/code via Monaco, markdown, HTML):
Runs Chromium in a separate process that consumes all keyboard input
when focused. Ctrl+W is particularly problematic because Chromium treats
it as "close tab."
- **Shell Preview Handlers** (native HWND): Run in a child Win32 window
that handles keyboard messages independently.
Once either of these controls gets focus via a mouse click, keyboard
shortcuts stop working.
## Solution
Added a **low-level keyboard hook** (`WH_KEYBOARD_LL`) that intercepts
key events at the OS level, regardless of which control has focus:
- **Ctrl+W** and **Escape** → close the Peek window
- **Arrow keys** (Left/Right/Up/Down without Ctrl) → navigate between
files
The hook is installed only while the Peek window is visible and only
acts when Peek is the foreground window, so it has no impact on other
applications.
As additional defense-in-depth, `AreBrowserAcceleratorKeysEnabled` is
set to `false` on the WebView2 control, preventing Chromium from
consuming browser-specific shortcuts like Ctrl+W.
## Changes
| File | Change |
|------|--------|
| `Peek.UI/PeekXAML/MainWindow.xaml.cs` | Install/uninstall keyboard
hook in Initialize/Uninitialize; hook callback handles Ctrl+W, Escape,
and arrow keys |
| `Peek.UI/Native/NativeMethods.cs` | P/Invoke declarations for
`SetWindowsHookEx`, `UnhookWindowsHookEx`, `CallNextHookEx`,
`GetAsyncKeyState` |
| `Peek.FilePreviewer/Controls/BrowserControl.xaml.cs` | Disable browser
accelerator keys on WebView2 |
## Validation
- [x] Ctrl+W closes Peek after clicking inside PDF preview
- [x] Ctrl+W closes Peek after clicking inside text/code preview
(Monaco)
- [x] Escape closes Peek after clicking inside preview
- [x] Arrow keys navigate between files after clicking inside preview
- [x] Normal typing/interaction inside previews still works (Ctrl+C,
scrolling, etc.)
- [x] Shortcuts still work without clicking (existing behavior
preserved)
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>1 parent 3fd6a03 commit 18edd52
3 files changed
Lines changed: 204 additions & 0 deletions
File tree
- src/modules/peek
- Peek.FilePreviewer/Controls
- Peek.UI
- Native
- PeekXAML
Lines changed: 6 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
199 | 199 | | |
200 | 200 | | |
201 | 201 | | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
202 | 208 | | |
203 | 209 | | |
204 | 210 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
131 | 131 | | |
132 | 132 | | |
133 | 133 | | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
134 | 165 | | |
135 | 166 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| 24 | + | |
23 | 25 | | |
24 | 26 | | |
25 | 27 | | |
| |||
43 | 45 | | |
44 | 46 | | |
45 | 47 | | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
46 | 52 | | |
47 | 53 | | |
48 | 54 | | |
| |||
221 | 227 | | |
222 | 228 | | |
223 | 229 | | |
| 230 | + | |
224 | 231 | | |
225 | 232 | | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
226 | 236 | | |
227 | 237 | | |
228 | 238 | | |
| |||
234 | 244 | | |
235 | 245 | | |
236 | 246 | | |
| 247 | + | |
237 | 248 | | |
238 | 249 | | |
239 | 250 | | |
| |||
352 | 363 | | |
353 | 364 | | |
354 | 365 | | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
355 | 521 | | |
356 | 522 | | |
| 523 | + | |
357 | 524 | | |
358 | 525 | | |
359 | 526 | | |
| |||
0 commit comments