Skip to content

Commit e3af2c0

Browse files
Add Binary Paste Mode (DEC mode 2033) for image/binary clipboard paste
Introduce a new VT protocol extension that allows terminal applications to receive binary clipboard data (e.g., images) with MIME type metadata via DCS sequences. Applications opt in via DECSET 2033; feature detection uses DECRQM (CSI ? 2033 $ p) to distinguish "supported but disabled" from "not supported". Protocol: DCS 2033 ; <size> b <mime-type> ; <base64-data> ST - DECMode 2033: opt-in mode with standard DECSET/DECRST/DECRQM support - InputGenerator::generateBinaryPaste() produces DCS binary paste sequences - Terminal::sendBinaryPaste() routes binary data through the input pipeline - TerminalSession::pasteFromClipboard() inspects clipboard MIME types when mode is enabled, with priority: png > jpeg > gif > bmp > svg+xml - Size limits: 10 MB hard, 5 MB soft (user permission prompt) - Size validation: decoded payload must match declared Ps parameter - VT sequence parameters widened from uint16_t to uint32_t to support payload sizes beyond 64 KB (max ~4 GB) - 7 E2E tests covering mode control, DECRQM, DCS generation, and reset - VT extension spec at docs/vt-extensions/binary-paste.md with adoption table - Example app: examples/watch-clipboard-paste.cpp Signed-off-by: Christian Parpart <christian@parpart.family>
1 parent d9b06a9 commit e3af2c0

File tree

15 files changed

+821
-15
lines changed

15 files changed

+821
-15
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,35 @@
1+
AAAANSUh
12
ABCDEFGHIX
23
ABCXDEFGHI
34
ABCXYDEFGH
45
ABCXZEFGHI
56
BBBBB
7+
bimage
68
BLval
79
BRval
810
CCCCC
911
circleval
1012
ctrled
1113
dcx
1214
DDDDD
15+
DECRST
16+
DECSET
1317
ellips
1418
emtpy
19+
EUg
1520
FFFFF
1621
GGGGG
1722
gitbranch
1823
gitgraph
1924
HHHHH
2025
HTP
2126
isakbm
27+
KGgo
28+
mday
2229
pseudoconsole
2330
rbong
2431
ULval
2532
unscroll
2633
URval
34+
VBORw
2735
xad

docs/vt-extensions/binary-paste.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# Binary Paste Mode
2+
3+
Applications running inside a terminal currently have no way to receive binary clipboard data
4+
(such as images) from the user's clipboard. The traditional paste mechanism — including
5+
[Bracketed Paste Mode](https://en.wikipedia.org/wiki/Bracketed-paste) (DEC mode 2004) —
6+
only supports plain text.
7+
8+
Binary Paste Mode is a terminal protocol extension that allows the terminal emulator
9+
to deliver binary clipboard data to applications that opt in, complete with MIME type
10+
metadata and base64 encoding. This enables use cases such as pasting images into
11+
terminal-based editors, chat clients, or file managers.
12+
13+
## Feature Detection
14+
15+
An application can detect support by sending a **DECRQM** query for mode 2033:
16+
17+
```
18+
CSI ? 2033 $ p Query Binary Paste Mode
19+
```
20+
21+
Response: `CSI ? 2033 ; Ps $ y` where `Ps` indicates:
22+
23+
| `Ps` | Meaning |
24+
|------|---------|
25+
| `1` | Mode is set (enabled) |
26+
| `2` | Mode is reset (disabled) |
27+
| `0` | Mode not recognized (terminal does not support Binary Paste) |
28+
29+
If the terminal does not recognize mode 2033, it will respond with `Ps = 0`,
30+
allowing the application to distinguish between "supported but disabled" and
31+
"not supported at all".
32+
33+
## Mode Control
34+
35+
Applications opt in via standard DECSET/DECRST sequences using **DEC private mode 2033**:
36+
37+
```
38+
CSI ? 2033 h Enable Binary Paste Mode
39+
CSI ? 2033 l Disable Binary Paste Mode (default)
40+
```
41+
42+
Binary Paste Mode is disabled by default and resets to disabled on hard reset (RIS)
43+
and soft reset (DECSTR).
44+
45+
## Data Delivery
46+
47+
When Binary Paste Mode is enabled and the user initiates a paste action while the
48+
system clipboard contains binary data, the terminal sends the following DCS sequence
49+
to the application via the PTY:
50+
51+
```
52+
DCS 2033 ; Ps b Pt ST
53+
```
54+
55+
Where:
56+
57+
| Parameter | Description |
58+
|-----------|-------------|
59+
| `2033` | First parameter, matching the mode number |
60+
| `Ps` | Second parameter: byte count of the original (pre-encoding) binary data |
61+
| `b` | DCS final character (mnemonic: *binary*) |
62+
| `Pt` | Data string: `<mime-type>` `;` `<base64-encoded-data>` |
63+
| `ST` | String Terminator (`ESC \`) |
64+
65+
### Example
66+
67+
A 1234-byte PNG image on the clipboard produces:
68+
69+
```
70+
ESC P 2033 ; 1234 b image/png ; iVBORw0KGgoAAAANSUhEUgAA... ESC \
71+
```
72+
73+
The `Ps` (size) parameter allows the application to pre-allocate a buffer before
74+
decoding the base64 payload. If absent or zero, the size is unknown.
75+
76+
### Size Validation
77+
78+
When `Ps` is present and non-zero, the application **must** verify that the decoded
79+
payload size matches the declared `Ps` value. If the sizes do not match, the
80+
application **should** discard the entire paste and treat it as a protocol error.
81+
82+
A mismatch indicates that the data was truncated, corrupted during transfer, or
83+
that the sequence was malformed. Silently accepting mismatched data could lead to
84+
broken files or unexpected application behavior.
85+
86+
| Condition | Action |
87+
|-----------|--------|
88+
| `Ps` absent or zero | Accept (size unknown, no validation) |
89+
| Decoded size == `Ps` | Accept |
90+
| Decoded size != `Ps` | Discard and report error |
91+
92+
## MIME Type Priority
93+
94+
When the clipboard contains multiple representations, the terminal selects the
95+
highest-priority binary MIME type:
96+
97+
| Priority | MIME Type |
98+
|----------|-----------|
99+
| 1 | `image/png` |
100+
| 2 | `image/jpeg` |
101+
| 3 | `image/gif` |
102+
| 4 | `image/bmp` |
103+
| 5 | `image/svg+xml` |
104+
105+
If no supported binary MIME type is found on the clipboard, the terminal falls
106+
through to normal text paste behavior (plain or bracketed, depending on mode 2004).
107+
108+
## Interaction with Bracketed Paste Mode
109+
110+
Binary Paste Mode is independent of Bracketed Paste Mode (2004). Both can be
111+
active simultaneously. When both are active and the clipboard contains binary data,
112+
the DCS binary paste sequence takes precedence:
113+
114+
| Mode 2004 | Mode 2033 | Has Binary | Behavior |
115+
|-----------|-----------|------------|----------|
116+
| off | off | any | Normal text paste |
117+
| on | off | any | Bracketed text paste |
118+
| off | on | yes | DCS binary paste |
119+
| on | on | yes | DCS binary paste |
120+
| any | on | no | Fall through to text paste |
121+
122+
Only one representation is sent per paste action — the terminal never sends both
123+
a DCS binary paste and a bracketed text paste for the same clipboard content.
124+
125+
## Size Limits
126+
127+
Terminals implementing this extension may enforce size limits on binary paste data:
128+
129+
- **Hard limit**: Payloads exceeding the limit are silently dropped (no DCS sent).
130+
Recommended: 10 MB pre-encoding.
131+
- **Soft limit**: Payloads between the soft and hard limit may trigger a user
132+
confirmation prompt. Recommended: 5 MB pre-encoding.
133+
134+
The base64 encoding inflates the wire size by approximately 33%.
135+
136+
## Adoption State
137+
138+
| Support | Terminal/Toolkit/App | Notes |
139+
|----------|----------------------|------------------------------------|
140+
|| Contour | since `0.5.0` (initial prototype) |
141+
| not yet | Kitty | |
142+
| not yet | WezTerm | |
143+
| not yet | Ghostty | |
144+
| not yet | foot | |
145+
| not yet | tmux | |
146+
147+
If your project adds support for this feature, please
148+
[open an issue](https://github.com/contour-terminal/contour/issues) or submit a PR
149+
so we can update this table.
150+
151+
## Reference
152+
153+
- [Bracketed Paste Mode](https://en.wikipedia.org/wiki/Bracketed-paste) — DEC mode 2004, text-only predecessor
154+
- [OSC 52](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands) — clipboard read/write via escape sequences (text/base64)
155+
- [DECRQM (Request Mode)](https://vt100.net/docs/vt510-rm/DECRQM.html) — mode support query

examples/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ if(LIBTERMINAL_TESTING)
33
add_executable(watch-mouse-events watch-mouse-events.cpp)
44
target_link_libraries(watch-mouse-events vtbackend)
55

6+
add_executable(watch-clipboard-paste watch-clipboard-paste.cpp)
7+
target_link_libraries(watch-clipboard-paste vtbackend)
8+
69
add_executable(detect-dark-light-mode detect-dark-light-mode.cpp)
710
endif()
811
endif()

0 commit comments

Comments
 (0)