Skip to content

Commit b85744d

Browse files
authored
feat(linux): draw the hint search input badge on every overlay backend (#1476)
1 parent eb6d00a commit b85744d

16 files changed

Lines changed: 942 additions & 115 deletions

docs/CROSS_PLATFORM.md

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ that is what [Known Gaps](#known-gaps) tracks, per
162162
| **Secure input detection** || ➖ always false | ➖ always false | ➖ always false | ➖ always false |
163163
| **System cursor hide** |`CGDisplayHideCursor` |||||
164164
| **`monitor_select` mode** | ✅ native panels | ✅ Cairo panels | ✅ Cairo panels | ✅ Cairo panels | 🟡 `CodeNotSupported` |
165-
| **Native hint-search field** | ✅ NSTextField overlay | 🟡 key-stream fallback | 🟡 key-stream fallback | 🟡 key-stream fallback | 🟡 key-stream fallback |
165+
| **Native hint-search field** | ✅ NSTextField overlay | 🟡 key-stream input ⁵ | 🟡 key-stream input ⁵ | 🟡 key-stream input ⁵ | 🟡 key-stream input ⁵ |
166166
| **Vision / OCR detection** | ✅ Vision framework |||||
167167
| **Key feed (`neru key`)** |`CGEventPost` | ✅ uinput | ✅ uinput / virtual-keyboard | ✅ uinput | 🟡 `CodeNotSupported` |
168168
| **Service management (`neru services`)** | ✅ launchd user agent | ⚠️ systemd user unit only ³ | ⚠️ systemd user unit only ³ | ⚠️ systemd user unit only ³ | 🟡 `CodeNotSupported` |
@@ -238,6 +238,18 @@ nothing else. From two notches up (`scroll_step_half`, `scroll_step_full`, or a
238238
`scroll_step` above 60) the same eased curve applies as everywhere else, and
239239
those are the scrolls the animation is worth having for.
240240

241+
⁵ This row is about the native *field* — a platform text control that owns
242+
keyboard focus and brings the system's input method with it. Only macOS has
243+
one. Everywhere else the query is read from the event tap's key stream, which
244+
is why dead keys and IME composition do not work there and a hint search takes
245+
plain characters.
246+
247+
**What the box on screen is, is a different question, and every platform draws
248+
one.** Linux paints the search badge onto the shared overlay surface with the
249+
same Cairo primitives as its other badges, so `hints.search_input_ui.*` means
250+
what it says on all three; the badge is a display of the query the mode handler
251+
already holds, and it never captures a key.
252+
241253
Neru sends the same distance on every backend; only the granularity of a step
242254
differs — though on Wayland the animated path spends that distance as a
243255
continuous delta where the unanimated one spends it as notches, and an
@@ -576,7 +588,7 @@ discovery rather than the mode itself.
576588
| **Hints** | Element discovery | ✅ full AX tree | ⚠️ AT-SPI, toolkit-dependent | ⚠️ UIA, shallow tree |
577589
| **Hints** | `vision` strategy + per-app overrides || ❌ macOS-only | ❌ macOS-only |
578590
| **Hints** | Menubar / dock elements || 🟡 | 🟡 |
579-
| **Hints** | Search input badge || 🟡 `CodeNotSupported` ||
591+
| **Hints** | Search input badge || ✅ Cairo badge ||
580592
| **Hints** | Label arrow / tail | ✅ NSBezierPath | ✅ Cairo triangle | ✅ sampled triangle, see below |
581593
| **Hints** | Label placement | ✅ top / center / bottom | ✅ top / center / bottom | ✅ top / center / bottom |
582594
| **Grid** | Transition animation ||||
@@ -703,19 +715,6 @@ green in every cell while an option means nothing, which is exactly how
703715
| `app_configs.ignore_clickable_check` | option |||| the clickable and visibility checks are AX-specific; the AT-SPI and UIA walks decide what is clickable their own way and never consult these |
704716
| `app_configs.visible_check_enabled` | option |||| the clickable and visibility checks are AX-specific; the AT-SPI and UIA walks decide what is clickable their own way and never consult these |
705717
| `grid.prewarm_enabled` | option |||| only the darwin grid overlay prewarms its layers; the other backends draw on demand |
706-
| `hints.search_input_ui.font_size` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
707-
| `hints.search_input_ui.font_family` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
708-
| `hints.search_input_ui.border_radius` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
709-
| `hints.search_input_ui.padding_x` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
710-
| `hints.search_input_ui.padding_y` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
711-
| `hints.search_input_ui.border_width` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
712-
| `hints.search_input_ui.position` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
713-
| `hints.search_input_ui.x_offset` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
714-
| `hints.search_input_ui.y_offset` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
715-
| `hints.search_input_ui.width` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
716-
| `hints.search_input_ui.background_color` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
717-
| `hints.search_input_ui.text_color` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
718-
| `hints.search_input_ui.border_color` | option |||| no Linux overlay backend draws the hints search input badge; the query still reaches hints through the event tap |
719718
| `hints.vision.detect_text` | option |||| no element-detection engine outside macOS answers the vision strategy, so it finds nothing there and none of its settings are read; use axtree |
720719
| `hints.vision.request_timeout_ms` | option |||| no element-detection engine outside macOS answers the vision strategy, so it finds nothing there and none of its settings are read; use axtree |
721720
| `hints.vision.minimum_confidence` | option |||| no element-detection engine outside macOS answers the vision strategy, so it finds nothing there and none of its settings are read; use axtree |
@@ -835,39 +834,36 @@ command — that means less here than it does on macOS, whether or not the
835834

836835
1. `neru docs` — returns `CodeNotSupported` although the tray already opens
837836
URLs through `xdg-open` in the same repo
838-
2. Hints search input badge — not drawn; the overlay manager reports
839-
`CodeNotSupported` and the query goes on reaching hints through the event
840-
tap's key stream
841-
3. Screen capture — no code path anywhere in the tree. Prerequisite for the OCR
837+
2. Screen capture — no code path anywhere in the tree. Prerequisite for the OCR
842838
strategy below and the missing half of `ports.Vision`. Take it per backend:
843839
`wlr-screencopy` on wlroots, `XGetImage` on X11, the portal only for KDE
844-
4. `vision` hint strategy — no engine. Met by linking one through
840+
3. `vision` hint strategy — no engine. Met by linking one through
845841
`#cgo pkg-config`, as every other native dependency here is, with the engine
846842
added to the required Linux library list and its language data checked at
847843
use so a missing `tessdata` reports `CodeNotSupported` naming what is
848844
absent. Note the strategy is wider than OCR: macOS also runs rectangle
849845
detection and saliency, which no OCR engine answers, so
850846
`hints.vision.detect_rectangles` and the four `rectangle_*` options are
851-
declared macOS-only and Linux `vision` is text-only. Needs 3
852-
5. X11 unmodified scroll — a scroll with no `--modifier` presses nothing, so the
847+
declared macOS-only and Linux `vision` is text-only. Needs 2
848+
4. X11 unmodified scroll — a scroll with no `--modifier` presses nothing, so the
853849
`XTestFakeButtonEvent` still carries whatever the X server records the user as
854850
physically holding. Binding `Ctrl+J` to a plain `scroll_down` therefore sends
855851
ctrl+scroll for as long as ctrl is down. macOS forces the empty set onto the
856852
event instead; a real-key backend has no per-event field to zero, so closing
857853
this means reading the live key state through `XQueryKeymap` in the C bridge
858-
6. KDE RemoteDesktop portal grant — does not survive a daemon restart, so the
854+
5. KDE RemoteDesktop portal grant — does not survive a daemon restart, so the
859855
consent prompt returns on every start
860-
7. Grid virtual-pointer indicator — a no-op on Linux, while recursive grid
856+
6. Grid virtual-pointer indicator — a no-op on Linux, while recursive grid
861857
draws it on all three platforms
862-
8. `FocusedWindowBounds` — returns not-found on KWin, so callers silently fall
858+
7. `FocusedWindowBounds` — returns not-found on KWin, so callers silently fall
863859
back to the active screen
864-
9. Wayland global hotkeys — a setup requirement rather than missing code: they
860+
8. Wayland global hotkeys — a setup requirement rather than missing code: they
865861
need `input`-group membership and a CGO build. Failing loudly with the
866862
remedy, and documenting it as a first-class setup step, is the work
867-
10. Tail — the tray tooltip is a no-op (dbusmenu carries no such property), the
868-
tray has one icon for both running and paused states where macOS has two,
869-
and the `CGO_ENABLED=0` build should announce its boundary once at startup
870-
rather than failing feature by feature
863+
9. Tail — the tray tooltip is a no-op (dbusmenu carries no such property), the
864+
tray has one icon for both running and paused states where macOS has two,
865+
and the `CGO_ENABLED=0` build should announce its boundary once at startup
866+
rather than failing feature by feature
871867

872868
The gaps above are the work; what a person writes and finds inert *today* is
873869
[Platform Support Per Word](#platform-support-per-word), which is generated

0 commit comments

Comments
 (0)