feat: report where the user is typing, so a client can keep it on screen - #5513
Open
harrison001 wants to merge 1 commit into
Open
feat: report where the user is typing, so a client can keep it on screen#5513harrison001 wants to merge 1 commit into
harrison001 wants to merge 1 commit into
Conversation
A phone's on-screen keyboard covers half the picture, and the client cannot tell which half matters — the field being typed into is usually the hidden one. The host can tell, so GET /caret reports it. The answer is fractions of the streamed display, so the client needs to know nothing about resolutions, and "source" says which of two things it is: - "caret", the focused application's insertion point, read through Accessibility. macOS only, because no other platform exposes one. - "pointer", where the cursor is. The fallback for the applications that report no caret, which is most of them, and a good stand-in: you click into a field to type in it. It is also the only thing that helps in trackpad mode, where the client sends relative motion and never learns where the pointer ended up. An empty object means neither was available and the client should leave the picture where it is. Served over HTTPS only, so it reaches paired and enabled clients alone. Where someone is typing, and the pointer position it falls back to, describe what the user is doing closely enough to belong behind the same verification as the rest of the session. platf::pointer_location() is declared in platform/common.h and implemented on each platform. get_mouse_loc() was the obvious thing to reuse and is not usable here: it is documented as existing only for tests, and it takes the input backend of a running stream, which an HTTP handler does not have. Windows reads GetCursorPos and normalises against the primary monitor. Linux queries X11 and normalises against the X screen, which is what x11grab captures; Wayland offers no way to ask, so it reports nothing. Three details on the macOS side, each found by probing a machine rather than from documentation: - Ask the application, not the system. AXUIElementCreateSystemWide() with kAXFocusedUIElementAttribute returns nothing for applications that answer when asked directly, iTerm2 among them. - Filter by display. Accessibility works in whole-desktop coordinates, so a display above the main one gives negative values, and a caret on a display that is not being streamed means nothing to the client. - An empty rect at the origin means no caret. Elements without an insertion point return that rather than an error, and taking it at face value puts the caret in the top-left corner. Verified on macOS 26.6.1: iTerm2 and Xcode report a caret; Brave, VS Code, Sublime Text and Telegram do not and fall back to the pointer.
harrison001
force-pushed
the
macos-caret
branch
from
August 17, 2026 06:27
55a849d to
0a7fef4
Compare
|
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.



Description
On a phone the on-screen keyboard covers half the picture, and the field you're typing into is usually in the covered half. The client has no way to know which half matters. The host does.
GET /caretanswers in fractions of the streamed display, so the client doesn't need the host's resolution:sourcesays which it is.caretis the focused element's insertion point via Accessibility, macOS only.pointeris the cursor position, used when the focused application reports no caret, which most don't; that half works on Windows, Linux/X11 and macOS.{}means neither was available and the client should leave the picture where it is.HTTPS only, so it sits behind the same client-certificate check as
applistandlaunch.platf::pointer_location()is new inplatform/common.h. I didn't reuseget_mouse_loc(): it's documented as existing only for tests, and it takes the input backend of a running stream, which an HTTP handler doesn't have.Three things on the macOS side that aren't obvious from the docs:
AXUIElementCreateSystemWide()withkAXFocusedUIElementAttributereturns nothing for applications that answer when asked directly, iTerm2 among them. It has to ask the application.Nothing upstream calls this yet. The consumer is TracePort, an open-source Moonlight fork of mine that this was built for. The endpoint is additive and does nothing if no client asks.
Tested on macOS 26.6.1, M1 Max, streaming to that client:
{}. On the centre of the streamed display it returns exactly{"x":0.500,"y":0.500}.The Windows and Linux implementations of
pointer_location()are compile-tested only. CI builds both, but I have neither platform to run them on.Screenshot
Issues Fixed or Closed
Roadmap Issues
Type of Change
Checklist
AI Usage
See our AI usage policy.