pointer

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 27, 2026 License: BSD-3-Clause Imports: 1 Imported by: 0

README

pointer

ci Go Reference

Where the macOS mouse pointer is, and putting it somewhere. Pure Go through purego, CGO_ENABLED=0.

p, _ := pointer.Position()          // in CoreGraphics global display space
_ = pointer.MoveTo(p)               // exactly there
_ = pointer.MoveToDisplay(displayID) // the middle of one display
ids, _ := pointer.Displays()        // which displays are attached

Why it exists

A measured failure. An application that shows one display on another — a viewer, a head-up surface, a desk of captured screens inside a pair of glasses — gives a person a picture of somewhere the pointer can go and no way to get it there. Dragging the mouse across a display whose content is a capture of elsewhere means dragging it blind: the picture does not show where the pointer is, because the pointer is not on the display being captured.

The way out, for the person who met this, was unplugging the glasses. One key that puts the pointer on the screen they are looking at fixes it, and this is what such a key needs.

What it will not do

Press anything. Moving the pointer is CGWarpMouseCursorPosition, which is not an event: it asks the window server to put the cursor somewhere. It needs neither Accessibility nor Input Monitoring, and it works in a plain unbundled Go binary — unlike CGEventPost, which is silently refused to one (measured in go-macos/hotkey, twice, with the evidence).

A package that can move the pointer is a convenience; one that can click is a robot, and the two want different questions asked of them.

Coordinates

Everything is in CoreGraphics global display space: pixels, origin at the top-left of the main display, y growing downwards, all displays in one arrangement. It is the space CGDisplayBounds and CGWarpMouseCursorPosition speak, and the space go-widgets/window reports its screens in.

It is not AppKit's. -[NSEvent mouseLocation] is bottom-left with y growing up, which is the other convention and half a screen out if the two are mixed. This package never touches AppKit, so there is one convention here and it is stated.

Two details the platform imposes

  • A warp leaves the mouse briefly disconnected from the cursor. The window server damps the mouse for about a quarter of a second so a physical nudge does not fight the jump, and a person who warps and immediately moves the mouse finds it stuck. MoveTo re-associates the two, which ends that.
  • CGDisplayBounds answers with the empty rectangle for a display it does not know rather than with an error — and "the origin, no size" is a place a caller can accidentally warp to. Bounds turns it into ErrNoDisplay.

Elsewhere

Every entry point reports ErrUnsupported off macOS, and that is not a gap to be filled in silence: an X11 pointer is XWarpPointer, a Wayland one cannot be moved by a client at all, and a Windows one is SetCursorPos — three different answers with three different rules about who may ask. The types and the coordinate space are portable and waiting.

Licence

BSD-3-Clause.

Documentation

Overview

Package pointer says where the mouse pointer is and puts it somewhere else.

It exists because of a measured failure. An application that shows one display on another -- a viewer, a head-up surface, a desk of captured screens inside a pair of glasses -- gives a person a picture of somewhere the pointer can go and no way to get it there. Dragging the mouse across a display whose content is a capture of elsewhere means dragging it BLIND: the picture does not show where the pointer is, because the pointer is not on the display being captured. The way out, for the person who met this, was unplugging the glasses.

One key that puts the pointer on the screen somebody is looking at fixes that, and this is what such a key needs.

No permission, and no synthetic events

Moving the pointer is CGWarpMouseCursorPosition, which is not an event: it asks the window server to put the cursor somewhere. It needs neither Accessibility nor Input Monitoring, and it works in a plain unbundled Go binary -- unlike CGEventPost, which is silently refused to one (measured in go-macos/hotkey, twice, with the evidence).

Nothing here presses a button or sends a keystroke, on purpose. A package that can move the pointer is a convenience; one that can click is a robot, and the two want different questions asked of them.

Coordinates

Everything here is in CoreGraphics GLOBAL DISPLAY SPACE: pixels, origin at the TOP-LEFT of the main display, y growing DOWNWARDS, all displays in one arrangement. It is the space CGDisplayBounds and CGWarpMouseCursorPosition speak, and the space go-widgets/window reports its screens in.

It is NOT AppKit's. -[NSEvent mouseLocation] is bottom-left with y growing up, which is the other convention and half a screen out if the two are mixed. This package never touches AppKit, so there is one convention here and it is stated.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnsupported is returned by every entry point on non-darwin platforms.
	// The pointer of a window server is that window server's to move.
	ErrUnsupported = errors.New("pointer: unsupported on this platform (darwin only)")

	// ErrNoDisplay reports a display id the window server does not know, or one
	// that has gone away since the caller looked. It is an ordinary event with an
	// external panel and routine with a virtual one, which is why it is an error
	// and not a panic.
	ErrNoDisplay = errors.New("pointer: no such display")
)

Errors reported by the package. They are stable and may be tested with errors.Is.

Functions

func Displays

func Displays() ([]uint32, error)

Displays reports ErrUnsupported.

func MoveTo

func MoveTo(Point) error

MoveTo reports ErrUnsupported.

func MoveToDisplay

func MoveToDisplay(uint32) error

MoveToDisplay reports ErrUnsupported.

Types

type Point

type Point struct {
	X, Y float64
}

A Point is a place in CoreGraphics global display space: pixels, origin at the top-left of the main display, y growing downwards.

Floating point because that is what CoreGraphics uses, and because a display with a backing factor of two has half-pixels in this space that are whole pixels on the panel.

func Position

func Position() (Point, error)

Position reports ErrUnsupported.

func (Point) In

func (p Point) In(r Rect) bool

In reports whether the point is inside the rectangle.

type Rect

type Rect struct {
	X, Y, W, H float64
}

A Rect is a rectangle in the same space: a display's bounds, chiefly.

func Bounds

func Bounds(uint32) (Rect, error)

Bounds reports ErrUnsupported.

func (Rect) Centre

func (r Rect) Centre() Point

Centre is the middle of the rectangle.

It is where a pointer put "on a display" goes. The middle rather than a corner because a corner is shared with the next display along: half a pixel of rounding there and the pointer lands on the neighbour, which is the one place it must not.

func (Rect) Empty

func (r Rect) Empty() bool

Empty reports whether the rectangle has no area. A display that has gone away reports one of these rather than an error, because CGDisplayBounds does.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL