Repository navigation
Move the frame dump and GPU capture hotkey to Ctrl+Shift+F7 - #1075
Merged
Merged
Conversation
Ctrl+Shift+F12 is taken by the macOS Metal Performance HUD. The HUD library adds a "Metal HUD" menu to the app's menu bar with Shift+F8 logging, Shift+F9 to enable the HUD, Shift+F11 to reset its metrics, Shift+F12 for its configuration panel, and Ctrl+Shift+F9 to Ctrl+Shift+F12 to generate a performance report over 5 seconds to 5 minutes. The menu consumes the key before Wine sees it, so the chord never reached the layer, and the 5-minute report then crashed the game inside the HUD's own code. Plain F12 stays out because it is Steam's screenshot key. The hotkey is now F7 going down while Control and Shift are held and Alt (which winemac maps from Command) is up. The edge semantics are unchanged: a held chord fires once, modifiers pressed after the key never fire, and the modifiers are read only on the sample where the key goes down. The capture key's virtual-key code and the modifiers' codes move into mtld3d-core's capture_chord, so the unit tests read real key codes from each sample. They check that Ctrl+Shift+F7 fires and that F7, Shift+F7, Ctrl+F7, Ctrl+Alt+Shift+F7, F12, Ctrl+Shift+F12, the HUD's Shift+F8 to F12 and Ctrl+Shift+F9 to F12, and the near miss Ctrl+Shift+F8 do not. The d3d9 poll's latch is renamed for the capture key, and every doc and comment that named Ctrl+Shift+F12 now names Ctrl+Shift+F7. The README and the architecture notes give the real collision list and add that a MacBook keyboard needs Fn for F7 unless the standard function key setting is on.
athei
added a commit
that referenced
this pull request
Oct 6, 2026
## Symptoms Ctrl+Shift+F7 (#1075) does not arm the frame dump and GPU capture, because the key never reaches Wine. A game run with Wine's `+key` trace shows Fn+F7 alone arriving as `press 98` (kVK_F7), but with Control and Shift held Wine receives only the Shift (56) and Control (59) presses and no F7. Ctrl+Shift+F6 delivers nothing either. macOS takes Ctrl+F1 to Ctrl+F8 for its keyboard-navigation shortcuts and still takes them with Shift held. The Metal HUD's menu takes Shift+F8 to Shift+F12 and Ctrl+Shift+F9 to Ctrl+Shift+F12, and Steam takes a bare F12. So no Ctrl+Shift function-key chord reaches the game. ## Changes The hotkey is now a fixed Ctrl+Shift+P: P going down while Control and Shift are held and Alt is up (winemac reports either Command key as Alt). The edge semantics are unchanged: a held chord fires once, Control and Shift pressed after P is already down never fire, and the modifiers are read only on the present where P goes down. `CAPTURE_KEY` in `windows/core/src/capture_chord.rs` becomes `VK_P` (0x50); `windows/d3d9/src/capture.rs` already reads it from there, so only its comments change. P sits at the same place on QWERTY, QWERTZ and AZERTY, so its virtual-key code does not move with the keyboard layout, and as a letter it needs no Fn on a MacBook keyboard. macOS, the Metal HUD and Steam do not use it, and games that bind P rarely bind Ctrl+Shift+P. The unit tests in `capture_chord/tests.rs` check that Ctrl+Shift+P fires once per press and not while held, and that P, Shift+P, Ctrl+P and Ctrl+Alt+Shift+P do not. They also check that the chords that never reach Wine do not fire: F12, Ctrl+Shift+F12, the old Ctrl+Shift+F7, the HUD's Shift+F8 to F12 and Ctrl+Shift+F9 to F12, and Ctrl+F1 to F8 with or without Shift. The tests for modifiers pressed after the key and for reading modifiers only on the press are kept. Every doc and comment that named Ctrl+Shift+F7 now names Ctrl+Shift+P: the README, `docs/ARCHITECTURE.md` (section heading and its anchor), the link to it in `docs/GAMES.md`, `CONTRIBUTING.md`, the `bench-shape` text in the Makefile, `mtld3d.conf`, the bench runner's messages and the code comments on both sides. The README and the architecture section give the new reason (Steam's F12, the HUD's Shift+F8 to F12 and Ctrl+Shift+F9 to F12, and macOS's Ctrl+F1 to F8, which it takes even with Shift held), say that P sits at the same place on the common layouts, keep the Control-not-Command note, and drop the MacBook Fn note. ## Alternatives considered Another function key: Ctrl+F1 to F8 belong to macOS with or without Shift, Ctrl+Shift+F9 to F12 to the HUD, and F12 to Steam, so every Ctrl+Shift function-key chord is taken before Wine sees it. A different letter: a letter that moves between QWERTY, QWERTZ and AZERTY (such as Y, Z, A, Q or M) would put the chord on a different key position, or a different virtual-key code, depending on the layout, while P does not move. A configurable key was not added: the chord stays fixed, with no config key and no environment variable. ## Verification `make fmt`, `make check` (rustfmt, clippy with nursery and pedantic on both workspaces and the PE targets, `make audit`, `make doc`) and `make test-unit` ran green: 1972 windows-workspace tests, including the 14 `capture_chord` tests, and 755 unix-workspace tests passed. No end-to-end test uses the hotkey, so `make test` was not run. The reason for the change comes from the `+key` trace above: Fn+F7 alone reaches Wine as `press 98`, Ctrl+Shift+F7 and Ctrl+Shift+F6 deliver only the modifier presses. Ctrl+Shift+P was pressed in World of Warcraft 1.12 with Wine's `+key` trace on, and Wine received `press 59` (Control), `press 56` (Shift) and `press 35` (kVK_ANSI_P) with modifiers 0x00060103, so P arrives with Control and Shift held. The build installed for that run predates this change, so the dump itself has not fired from the new chord yet; a reviewer can check it by pressing Ctrl+Shift+P in a game started with `MTL_CAPTURE_ENABLED=1` and looking for the `[dump]` lines and a `<exe>-<pid>-<n>.gputrace` beside the log. ## Rules check The change adds no static, config key, environment variable, wire field, dependency, derive or lint suppression, and duplicates nothing: it changes the value of the existing `CAPTURE_KEY` in `mtld3d-core` and the existing per-poll latch keeps its doc-block argument. The tests stay in `capture_chord/tests.rs` (Unit tests live in `<stem>/tests.rs`), and doc blocks keep the title, blank, body shape. `make check` enforces these through clippy, `make audit` and `make doc`, and it ran green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptoms
Pressing Ctrl+Shift+F12 in a game did not arm the frame dump and GPU capture. On macOS the Metal Performance HUD library (
/usr/lib/libMTLHud.dylib) adds a "Metal HUD" menu to the app's menu bar, and that menu binds Ctrl+Shift+F9, F10, F11 and F12 to "Generate Performance Report" for 5 s, 30 s, 1 min and 5 min. The menu consumes the key before Wine sees it, so the layer never got the press, and in a game test the 5-minute report then crashed the game inside Apple's code.The same menu also takes Shift+F8 (logging), Shift+F9 (enable HUD), Shift+F11 (reset metrics) and Shift+F12 (configuration panel); its key-down watcher handles Shift+F7 (move HUD) and Shift+F10 (layout), and with
MTL_HUD_DISABLE_MENU_BAR=1Shift+F5, F6, F8, F9 and F12. Plain F12 is Steam's screenshot key, macOS uses Ctrl+F1 to Ctrl+F8 without Shift for focus moves, and F11 for Show Desktop.Changes
The hotkey is now a fixed Ctrl+Shift+F7: F7 going down while Control and Shift are held and Alt is up (winemac reports either Command key as Alt). The edge semantics are the same as before: a held chord fires once, Control and Shift pressed after F7 is already down never fire, and the modifiers are read only on the present where F7 goes down.
windows/core/src/capture_chord.rsnow owns the key codes:CAPTURE_KEY(VK_F7) andModifier::virtual_keyforVK_CONTROL,VK_SHIFTandVK_MENU.windows/d3d9/src/capture.rsdrops its localVK_*constants and reads those, and its latch static is renamed fromF12_DOWN_LASTtoCAPTURE_KEY_DOWN_LASTwith its doc-block argument kept.The unit tests in
capture_chord/tests.rsnow model each sample as the set of virtual keys held and read the capture key and modifiers by the module's codes, with the codes restated from the Win32 headers so a moved code fails a test. They check that Ctrl+Shift+F7 fires once per press and not while held, and that F7, Shift+F7, Ctrl+F7, Ctrl+Alt+Shift+F7, F12, Ctrl+Shift+F12, the HUD's Shift+F8 to F12 and Ctrl+Shift+F9 to F12, and the near miss Ctrl+Shift+F8 do not.Every doc and comment that named Ctrl+Shift+F12 now names Ctrl+Shift+F7: the README,
docs/ARCHITECTURE.md(section heading and its anchor), the link to it indocs/GAMES.md,CONTRIBUTING.md, thebench-shapetext in the Makefile,mtld3d.conf, the bench runner's messages and the code comments on both sides. The README and the architecture section replace the old reason with the actual collisions (Steam's F12 and the HUD's Shift+F8 to F12 and Ctrl+Shift+F9 to F12), keep the Control-not-Command note, and add that a MacBook keyboard needs Fn for F7 unless "Use F1, F2, etc. keys as standard function keys" is on. The mentions of dumps that were taken with plain F12 before the chord existed (thebench_wow112.rssource line and its COVERAGE row, thebench_frame_shape.rsmodule doc) stay as they are, since they describe how those dumps were made.Alternatives considered
Keeping F12 with a different modifier set: every Shift and Ctrl+Shift combination on F12 is the HUD's, and plain F12 is Steam's. Ctrl+Shift+F9 to F11 are HUD report keys too. Ctrl+F1 to Ctrl+F8 without Shift are macOS focus moves, and F11 is Show Desktop. Shift+F7 belongs to the HUD's key-down watcher, but the watcher requires Control to be up for it, and the HUD's menu has no F7 entry, so Ctrl+Shift+F7 is not a HUD key; it is not among the macOS shortcuts listed above either, which is why F7 with both modifiers was picked.
A configurable key was not added: the chord stays fixed, with no config key and no environment variable, as before.
Verification
make fmt,make check(rustfmt, clippy with nursery and pedantic on both workspaces and the PE targets,make audit,make doc) andmake test-unitran green: 1970 windows-workspace tests and 755 unix-workspace tests passed, including the 12capture_chordtests. No end-to-end test uses the hotkey, somake testwas not run. The new key has not been pressed in a game yet; a reviewer can check it by pressing Ctrl+Shift+F7 in any game withMTL_CAPTURE_ENABLED=1and looking for the[dump]lines and a<exe>-<pid>-<n>.gputracebeside the log.Rules check
The change adds no new static: the existing per-poll latch is renamed, and its doc block keeps the "resource is process-wide" argument from
docs/CONVENTIONS.md(State lives on an object, not in a static). It adds no config key, no environment variable, no wire field, no dependency, no derive and no lint suppression. The virtual-key codes move fromwindows/d3d9intomtld3d-corerather than being duplicated, which follows "Factor pure functionality intomtld3d-core;d3d9is wiring"; the tests restate them on purpose as the independent check. The tests stay incapture_chord/tests.rs(Unit tests live in<stem>/tests.rs). Doc blocks keep the title, blank, body shape.make checkenforces these through clippy,make auditandmake doc, and it ran green.