# Pointer Shape (OSC 22)

> Change the shape of the mouse pointer while it is over the terminal.

- **Sequence:** `OSC 22 ; Pt ST`
- **ECMA-48:** [§8.3.89 OSC – Operating System Command, p. 51](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n64/mode/1up)
- **Specification:** [Mouse pointer shapes, kitty documentation](https://sw.kovidgoyal.net/kitty/pointer-shapes/)
- **xterm:** [Operating System Commands](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)

`OSC 22 ; Pt ST` sets the shape of the mouse pointer over the terminal to
`Pt`, so that a program can show a hand over a link or a watch while it is
busy. It is xterm's, and xterm takes `Pt` as a name from the X cursor font:
`left_ptr` for an arrow, `hand2`, `watch`, `xterm` for the I-beam, and so on.
A name it does not know, or none at all, gives the I-beam, its default
([`xtermSetupPointer`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L991-L1029),
[`LookupCursorShape`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L891-L988)).

kitty extended it in its
[Mouse pointer shapes](https://sw.kovidgoyal.net/kitty/pointer-shapes/)
document, which uses the CSS cursor names (`default`, `pointer`, `wait`,
`text`, …) rather than X's, adds a stack, `OSC 22 ; > name ST` to push and
`OSC 22 ; < ST` to pop, and lets a program ask, with `OSC 22 ; ? names ST`,
which shapes the terminal has and which is current.

libghostty-vt keeps a shape its host can read and draw. It accepts the CSS
names, and the X names that have a CSS equivalent: `watch` is `wait`,
`left_ptr` is `default`, `xterm` is `text`. An empty `Pt` puts back `text`.
It ignores a name it does not know, rather than falling back as xterm does,
and it does not have kitty's stack or queries. The cases follow a default
xterm, and give each shape by its CSS name, which is what a case's
`pointer` line checks; the X cursors xterm sets are given by their CSS
equivalents. Those where a name is one only libghostty-vt knows, or neither
does, are known differences.

## Validation

### OSC22-1: The I-beam to begin with

Input, one step per line:

```text
A
```

Expected screen:

```text
|A_____|
pointer text
```

### OSC22-2: An X cursor name

Input, one step per line:

```text
\e]22;watch\e\\
```

Expected screen:

```text
|______|
pointer wait
```

### OSC22-3: Another

Input, one step per line:

```text
\e]22;left_ptr\e\\
```

Expected screen:

```text
|______|
pointer default
```

### OSC22-4: Empty puts back the I-beam

Input, one step per line:

```text
\e]22;watch\e\\
\e]22;\e\\
```

Expected screen:

```text
|______|
pointer text
```

### OSC22-5: A CSS name, which xterm does not know

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e]22;watch\e\\
\e]22;pointer\e\\  # not an X cursor: the I-beam
```

Expected screen:

```text
|______|
pointer text
```

### OSC22-6: A name neither knows

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e]22;watch\e\\
\e]22;nosuch\e\\
```

Expected screen:

```text
|______|
pointer text
```

### OSC22-7: kitty's query is not answered

Input, one step per line:

```text
\e]22;?__current__\e\\
```

Expected screen:

```text
|______|
reply none
```

---

This is the Markdown version of <https://control-codes.page/osc/pointer/>. On that page every validation case runs live in libghostty-vt, the terminal emulation core of Ghostty, compiled to WebAssembly.

The validation cases are written in the notation described in <https://control-codes.page/notation/index.html.md>.
