Skip to content

Instantly share code, notes, and snippets.

@Shihabus-Sakib-Rad
Last active April 22, 2026 14:10
Show Gist options
  • Select an option

  • Save Shihabus-Sakib-Rad/ce7db613616ec5d8e79e907e8ca73c51 to your computer and use it in GitHub Desktop.

Select an option

Save Shihabus-Sakib-Rad/ce7db613616ec5d8e79e907e8ca73c51 to your computer and use it in GitHub Desktop.
Line Break Remover on copy on Wayland

PDF Line Break Remover on KDE Plasma 6 Wayland

A Linux/Wayland equivalent of the classic AutoHotkey trick for cleaning up copied text from PDF viewers. Removes mid-sentence line breaks introduced by PDF column layout, replacing them with spaces — while preserving true paragraph breaks.

Tested on: CachyOS Linux · KDE Plasma 6.6.3 · Wayland


How It Works

On Windows, AutoHotkey can intercept Ctrl+C globally and post-process the clipboard.

#Requires AutoHotkey v2.0
#SingleInstance Force

; Create window group
GroupAdd("GroupName", "ahk_class SUMATRA_PDF_FRAME")
GroupAdd("GroupName", "ahk_class PXE:{C5309AD3-73E4-4707-B1E1-2940D8AF3B9D}")
GroupAdd("GroupName", "ahk_class classFoxitPhantom")
GroupAdd("GroupName", "ahk_class classFoxitReader")

#HotIf WinActive("ahk_group GroupName")
^c:: {
    old := ClipboardAll()
    A_Clipboard := ""
    Send("^c")
    if !ClipWait(0.8) {
        A_Clipboard := old
    } else {
        tmp := RegExReplace(A_Clipboard, "(\S.*?)\R(.*?\S)", "$1 $2")
        ; Replace double spaces with single spaces until no more remain
        while InStr(tmp, "  ")
            tmp := StrReplace(tmp, "  ", " ")
        A_Clipboard := tmp
    }
    old := ""
    tmp := ""
}
#HotIf

Wayland intentionally disallows this for security reasons. The workaround is a separate shortcut (Ctrl+Alt+C) that:

  1. Sends a real Ctrl+C to the focused window (via ydotool)
  2. Polls until the clipboard actually changes (like AHK's ClipWait)
  3. Applies a regex to join mid-sentence line breaks
  4. Writes the cleaned text back to the clipboard

Because Ctrl+Alt+C is a conscious action, no window class filtering is needed — you simply use it only when you're in a PDF viewer.


Step 1 — Install Dependencies

sudo pacman -S ydotool wl-clipboard python
  • ydotool — injects keystrokes via /dev/uinput, bypassing the compositor entirely. Works on any Wayland compositor.
  • wl-clipboard — provides wl-paste and wl-copy for Wayland clipboard access.
  • python — for the regex cleaning step.

Step 2 — Add Your User to the input Group

ydotool needs access to /dev/uinput. The package ships a udev rule that grants the input group this access.

sudo usermod -aG input $USER

Then reboot — a simple logout/login may not be sufficient because systemd can preserve the old user session without the new group.

After rebooting, verify:

groups | grep input

input should appear in the output.


Step 3 — Enable the ydotool Daemon

ydotool is a client that talks to ydotoold (the daemon). The package ships a systemd user service:

systemctl --user enable --now ydotool.service
systemctl --user status ydotool.service

The service should show Active: active (running). If it fails, check that the reboot in Step 2 was completed and the input group is active.


Step 4 — Create the Script

Save the following as ~/.local/bin/pdf-clean-copy.sh:

#!/bin/bash

sleep 0.8

# Save current clipboard to detect change
old=$(wl-paste --no-newline 2>/dev/null)

# Inject Ctrl+C into the focused window (evdev keycodes: 29=Ctrl, 46=C)
# --key-delay 50: 50ms between events prevents stuck modifier keys
ydotool key --key-delay 50 29:1 46:1 46:0 29:0


text="$new"
[ -z "$text" ] && exit 0

# Clean the text using Python regex
# Faithfully ports the original AHK regex: (\S.*?)\R(.*?\S) → $1 $2
# [^\r\n] is used intentionally — re.S/re.DOTALL must NOT be used here,
# as it would allow .* to span multiple lines and cause incorrect merges
cleaned=$(printf '%s' "$text" | python3 -c "
import sys, re
text = sys.stdin.read()
result = re.sub(r'(\S[^\r\n]*?)\r?\n([^\r\n]*?\S)', r'\1 \2', text)
result = re.sub(r' {2,}', ' ', result)
sys.stdout.write(result)
")

# Write back only if text actually changed
[ "$cleaned" != "$text" ] && printf '%s' "$cleaned" | wl-copy

Make it executable:

chmod +x ~/.local/bin/pdf-clean-copy.sh

Step 5 — Bind to Ctrl+Alt+C in KDE

  1. Open System Settings → Keyboard → Shortcuts
  2. Scroll to the bottom → Custom Shortcuts
  3. Click Edit → New → Global Shortcut → Command/URL
  4. Set:
    • Name: PDF Clean Copy
    • Trigger: Ctrl+Alt+C
    • Action: /home/yourusername/.local/bin/pdf-clean-copy.sh

KDE applies the shortcut immediately — no restart needed.


Usage

  1. Open any PDF in your viewer (Okular, PDF-XChange via Wine, Evince, etc.)
  2. Select text that has broken line endings
  3. Press Ctrl+Alt+C instead of Ctrl+C
  4. Paste anywhere — line breaks within sentences are replaced with spaces, paragraph breaks are preserved

Troubleshooting

ydotool.service fails to start

  • Confirm input group is active: groups | grep input
  • If missing, reboot (logout alone may not be enough)
  • Check udev rule: cat /usr/lib/udev/rules.d/80-uinput.rules — should grant GROUP="input" on uinput

Line breaks not being removed

  • The PDF viewer may be slow to populate the clipboard
  • increase sleep timer

Notes

  • Why not Ctrl+C directly? Wayland's security model prevents any application from intercepting or suppressing another app's keyboard shortcuts globally. A separate shortcut is the correct solution, not a workaround.
  • Why not wl-paste --watch? Passive clipboard watching applies to all copies everywhere. A deliberate shortcut is cleaner and more predictable.
  • Why not wtype? KDE Plasma does not expose the zwp_virtual_keyboard_v1 protocol by default. ydotool bypasses the compositor via the kernel uinput interface instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment