ITADN

Tooltip is not dismissed by a keypress that starts a keybinding chord

#15399Openmidleman 创建于 12 天前
area: ui
M
midlemancommented
## System details: #### Positron and OS details: Positron dev build from `main` (fdf410ebd4), macOS 15 (Darwin 25.5.0). Reproduced against a disposable dev profile. #### Session details: n/a -- no interpreter needed. ## Describe the issue: A tooltip stays on screen through a keypress that should dismiss it, if that keypress starts a keybinding chord. Action bar hovers are shown with `persistence.hideOnKeyDown: true`, so any key should hide them. `HoverService._keyDown` (`src/vs/editor/browser/services/hoverService/hoverService.ts:517-529`) asks `keybindingService.softDispatch` about the key first and returns early unless the result is `NoMatchingKb`. While a chord is pending, `softDispatch` returns `MoreChordsNeeded`, so the hide is skipped and the hover is left showing. Chord mode self-expires after 5s of no interaction (`abstractKeybindingService.ts:169`), so the window is bounded, but the stale tooltip can outlive the UI it described. ## Steps to reproduce the issue: 1. Hover a top action bar button (e.g. **New**) and wait for its tooltip to appear. 2. Without moving the pointer, press <kbd>Cmd</kbd>+<kbd>K</kbd> (the first key of a chord -- the status bar shows "(Ctrl+K) was pressed. Waiting for second key of chord..."). 3. Observe the tooltip is still visible. For contrast, repeat with a plain key such as <kbd>a</kbd> in step 2: the tooltip hides immediately. Observed via CDP, tooltip text read from `.hover-contents` 400ms after the keypress: | Step | Chord key (`Cmd+K`) | Plain key (`a`) | |---|---|---| | tooltip before keypress | `New File/Folder` | `New File/Folder` | | tooltip after keypress | `New File/Folder` (still up) | `null` (hidden) | ## Expected or desired behavior: A keypress that starts a chord should dismiss a hover shown with `hideOnKeyDown`, the same as any other key. Waiting for the second key of a chord is not a reason to keep a tooltip on screen. ## Were there any error messages in the UI, Output panel, or Developer Tools console? No. The hover is simply never asked to hide. --- Found while triaging a Windows-only e2e flake in `Positron Notebooks: Find and Replace > Verify search widget buttons show tooltips on hover`. The test-side mitigation is in #15374, which clears a wedged chord in the shared `hotKeys` fixture; this issue is the underlying product behavior, which that PR does not change. ### E2E Triage Diagnosis <details> <summary>🟢 <b>High confidence</b> -- While a keybinding chord is pending, HoverService._keyDown skips hiding the current hover, so a tooltip survives a keypress that would normally dismiss it. Reproduced deterministically. The same chord state does NOT block later hovers, so it explains the stuck-tooltip failure mode only.</summary> - **Test:** [Positron Notebooks: Find and Replace > Verify search widget buttons show tooltips on hover](https://connect.posit.it/e2e-test-insights/?tab=test_health&repo=positron&test=Positron%20Notebooks%3A%20Find%20and%20Replace%20%3E%20Verify%20search%20widget%20buttons%20show%20tooltips%20on%20hover%7C%7C%7Ctest%2Fe2e%2Ftests%2Fnotebooks-positron%2Fnotebook-find-and-replace.test.ts) - **Targeted failure:** expect(locator(.hover-contents)).not.toBeVisible() fails with a stale tooltip still up (pattern B). Pattern A (toContainText, no widget ever created) is NOT explained by this and remains open. - **Signal:** Pattern A (`toContainText`, no widget created) 10 occurrences over 21 days of 669 main runs, mostly win/electron but at least one ubuntu/electron, so it is not Windows-only. Pattern B (`not.toBeVisible`, tooltip stuck) 1 occurrence. An earlier 14-day query reported 2 and 1 because it caps occurrences per pattern. - **Hypothesis:** Confirmed by local repro over CDP: with a chord pending, a showing hover survives the keypress, while a plain key hides it immediately (hoverService.ts:517-529 returns early unless softDispatch reports NoMatchingKb, and a pending chord reports MoreChordsNeeded). Chord mode self-expires after 5s (abstractKeybindingService.ts:169). hotKeys.closeAllEditors presses Cmd+K Cmd+W in an afterEach, so a dropped second keypress leaks chord mode into the next test. Falsified by the same repro: a pending chord does not stop a new hover being created, so hoverService.ts:273-282 rejects nothing here and pattern A is unexplained. Also falsified: the disabled-flip hypothesis (Chromium probe shows no mouseleave when a hovered button is disabled, mouseenter is delivered to disabled buttons, and :hover stays true). - **Supersedes:** an earlier disabled-flip hypothesis for this test, and an intermediate chord-wedges-all-hovers hypothesis; both falsified by direct probes </details>
1 条评论