VTE does not support OSC52.
Work-around, make a wrapper that creates a terminal passthrough, detects osc52 and then uses Xorg clipboard.
Example: save it as osc52detect.py
#!/usr/bin/env python
import os
import pty
import select
import subprocess
import sys
import termios
import tty
import signal
import struct
import fcntl
import re
import base64
OSC52_PATTERN = re.compile(rb'\x1b]52;c;(.*?)\x07')
log_file = open('osc52_log.txt', 'w')
def callback(plaintext):
try:
# Copy to X clipboard
process = subprocess.Popen(['xclip', '-selection', 'clipboard'], stdin=subprocess.PIPE)
process.communicate(plaintext.encode('utf-8'))
# Also copy to primary selection
process = subprocess.Popen(['xclip', '-selection', 'primary'], stdin=subprocess.PIPE)
process.communicate(plaintext.encode('utf-8'))
log_file.write(f"Copied to clipboard: {plaintext}\n")
except Exception as e:
log_file.write(f"Failed to copy to clipboard: {e}\n")
log_file.flush()
def detect_osc52(data):
matches = OSC52_PATTERN.findall(data)
for match in matches:
try:
decoded = base64.b64decode(match).decode('utf-8')
callback(decoded)
except:
log_file.write(f"Failed to decode OSC52 sequence: {match}\n")
log_file.flush()
return data
def set_winsize(fd, row, col, xpix=0, ypix=0):
winsize = struct.pack("HHHH", row, col, xpix, ypix)
fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)
def get_terminal_size():
size = os.get_terminal_size()
return size.lines, size.columns
def main():
old_tty = termios.tcgetattr(sys.stdin)
try:
tty.setraw(sys.stdin.fileno())
tty.setcbreak(sys.stdin.fileno())
master, slave = pty.openpty()
rows, cols = get_terminal_size()
set_winsize(slave, rows, cols)
p = subprocess.Popen(["bash"], stdin=slave, stdout=slave, stderr=slave, preexec_fn=os.setsid)
while p.poll() is None:
rlist, _, _ = select.select([sys.stdin, master], [], [], 0.1)
if sys.stdin in rlist:
data = os.read(sys.stdin.fileno(), 1024)
os.write(master, data)
if master in rlist:
data = os.read(master, 1024)
data = detect_osc52(data)
os.write(sys.stdout.fileno(), data)
except Exception as e:
log_file.write(f"An error occurred: {e}\n")
finally:
termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, old_tty)
log_file.close()
if name == "main":
main()
then do
chmod +x osc52detect.py
./osc52detect.py
Assuming you use bash, now everytime we receive osc52 we call xclip manually, yay! this works assuming you use xorg, but if you dont just change the callback!
If you can't install xclip, you can use https://pkgs.pkgforge.dev/repo/bincache/x86_64-linux/xclip/xclip/ which is static xclip.
Or you could just use something like wezterm.