Skip to main content
ansicode

DEC locator suite — DECELR / DECEFR / DECSLE / DECRQLP (mouse / locator events)

The original DEC pointing-device protocol (predates xterm SGR mouse modes by a decade). Four sequences enable, filter, select, and query locator events; modern interactive UIs use SGR mouse modes (?1000 + ?1006) instead.

Byte forms

Every common string-literal form so you can paste-and-search either direction.

\\x1b[\x1b[<Pn>;<Pu>'z \x1b[<Pm>'{ \x1b[<Pt>;<Pl>;<Pb>;<Pr>'w \x1b[<Ps>'|
\\033[\033[1;2'z
\\e[\e[1;2'z
ESC [ESC [ ... ' z / ' { / ' w / ' |
hex1b 5b ... 27 7a / 7b / 77 / 7c

Description

The DEC locator protocol predates the xterm extended mouse modes by a decade and is how VT300+ hardware terminals (and software emulators when bumped to a high DECSCL conformance — see decscl-compat-level) report pointing-device events. Four sequences make up the family — all share the single-quote (0x27) intermediate byte:

- DECELR — *Enable Locator Reports* — \x1b[<Pn>;<Pu>'z - Pn: 0 = disable locator reports, 1 = enable, 2 = enable for one report only (then auto-disable). - Pu: 0 or 2 = report coordinates in character cells, 1 = report in device units (pixels). - Once enabled, the terminal sends a DECLRP report on every button transition that passes the DECSLE filter, plus one when an outside-the-rectangle move happens (if DECEFR has set a rectangle).

- DECSLE — *Select Locator Events* — \x1b[<Pm>'{ - Pm: 0 = only explicit DECRQLP requests trigger a report; 1 = button-down events trigger reports; 2 = disable button-down reporting; 3 = button-up events trigger reports; 4 = disable button-up reporting. - May be repeated with different Pm values to enable button-down AND button-up: \x1b[1'{\x1b[3'{.

- DECEFR — *Enable Filter Rectangle* — \x1b[<Pt>;<Pl>;<Pb>;<Pr>'w - Defines an inclusive rectangle: top row, left col, bottom row, right col. Locator movement *outside* the rectangle triggers one DECLRP report, then the filter is auto-disabled. - Used for cursor-tracking apps that only care about 'mouse exited my widget' transitions.

- DECRQLP — *Request Locator Position* — \x1b[<Ps>'| - Ps: number of transactions (currently always 1). - Forces an immediate DECLRP report regardless of filter / event settings.

DECLRP — the reply\x1b[<Pe>;<Pb>;<Pr>;<Pc>;<Pp>&w (note the & intermediate, distinct from request finals): - Pe = event type: 0 = locator unavailable (no pointer), 1 = response to DECRQLP, 2 = left button down, 3 = left button up, 4 = middle down, 5 = middle up, 6 = right down, 7 = right up, 8 = M4 (button 4) down, 9 = M4 up, 10 = locator outside filter rectangle. - Pb = button-state bitmask: 1 = left, 2 = middle, 4 = right, 8 = button 4. OR them together. - Pr, Pc = row, column (1-indexed) in whatever units DECELR's Pu selected. - Pp = page number (always 1 on modern emulators — multi-page is a hardware-terminal concept).

Why you almost certainly don't need this: certain legacy CAD, terminal-based GIS, and radar / SCADA apps written in the 1980s expect this protocol. Some xterm extensions (the xterm*set-locator-events X resource) still enable it. Modern interactive UIs — tmux, htop, mc, lazygit, fzf, neovim's :terminal — all use SGR mouse modes (?1000 enable + ?1006 SGR encoding; see dec-mouse-tracking and sgr-mouse-encoding) because they're easier to parse, support multi-byte coordinates trivially, and have near-universal cross-emulator coverage.

Coverage matrix: xterm = full implementation (only widely-deployed emulator that does). gnome-terminal / konsole = partial (DECRQLP returns a synthetic 'no pointer' DECLRP). iTerm2 / kitty / wezterm / alacritty / ghostty / Windows Terminal / cmd / Linux console / macOS Terminal = none — the sequences are silently consumed and produce no reply.

When you might still reach for it: targeting xterm specifically on a legacy XFCE / CDE system; porting old SCADA terminal apps; testing terminfo entries for locator_* capabilities. Otherwise use SGR mouse modes.

Spec citation: DEC VT510 RM (DECELR / DECEFR / DECSLE / DECRQLP / DECLRP) / xterm-ctlseqs

Examples

bash
# Enable locator reports (cell coords, one-shot), then query position.\nprintf \"\\033[2;0'z\"   # DECELR Pn=2 one-shot, Pu=0 cells\nprintf \"\\033[1'|\"     # DECRQLP — force immediate DECLRP reply\n# read reply matching: \\x1b[1;Pb;Pr;Pc;1&w
python
import sys\n# Set filter rectangle around rows 5-20, cols 10-60 then enable button-down events.\nsys.stdout.write(\"\\x1b[1;0'z\")        # DECELR enable, cells\nsys.stdout.write(\"\\x1b[5;10;20;60'w\") # DECEFR filter rect\nsys.stdout.write(\"\\x1b[1'{\")          # DECSLE enable button-down reports\nsys.stdout.flush()
go
// Disable locator reports (clean exit).\nfmt.Print(\"\\x1b[0;0'z\")
javascript
// Parse a DECLRP reply: \\x1b[Pe;Pb;Pr;Pc;Pp&w\nfunction parseDECLRP(buf) {\n  const m = /\\x1b\\[(\\d+);(\\d+);(\\d+);(\\d+);(\\d+)&w/.exec(buf);\n  if (!m) return null;\n  return { event: +m[1], buttons: +m[2], row: +m[3], col: +m[4], page: +m[5] };\n}
c
/* Force a single locator-position report (synchronous-ish probe). */\nprintf(\"\\x1b[1;0'z\");   /* DECELR enable, cells */\nprintf(\"\\x1b[1'|\");     /* DECRQLP */\nfflush(stdout);\n/* read reply: matches sscanf(\"\\x1b[%d;%d;%d;%d;%d&w\", &pe,&pb,&pr,&pc,&pp) */

Terminal support

xterm
yes
Linux console (fbcon)
no
macOS Terminal.app
no
iTerm2
no
Windows Terminal
no
cmd.exe / ConPTY
no
kitty
no
alacritty
no
WezTerm
no
Ghostty
no
GNOME Terminal
partial
Konsole
partial
tmux
no
GNU screen
no

Related sequences