惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
爱范儿
爱范儿
V
Visual Studio Blog
Last Week in AI
Last Week in AI
阮一峰的网络日志
阮一峰的网络日志
雷峰网
雷峰网
Hugging Face - Blog
Hugging Face - Blog
博客园 - 【当耐特】
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 三生石上(FineUI控件)
博客园 - Franky
博客园 - 叶小钗
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
大猫的无限游戏
大猫的无限游戏
人人都是产品经理
人人都是产品经理
M
MIT News - Artificial intelligence
罗磊的独立博客
L
LangChain Blog
Jina AI
Jina AI
IT之家
IT之家
J
Java Code Geeks
Microsoft Azure Blog
Microsoft Azure Blog
博客园_首页

Last Blog

CMU 15-213 Attack Lab GAMES101 [1] Affine Transformation & Projection CMU 15-213 Bomblab CMU 15-213 [1] Scribe.cx 2 - 对话与持久化存储 关于 X11 与 Wayland 的剪贴板同步问题 关于 X11 与 Wayland 的剪贴板同步问题 Scribe.cx 1 - 跨浏览器的插件侧板控制 Page Assist 2025 年终总结 2025 年终总结 关于所谓“配置工程师” 记一次小端序内存的实际体现 CS110L L3 - Memory Safety in Rust CS110L L2 - Program Analysis CS110L L1 - Safety in System Programming 在 Neovim(v0.10+) 上使用 arduino-language-server PA3 - Batch Processing System 2024 年终总结 Arcaea 曲名匹配器 Arcaea 曲名匹配器 PA W9 - Linking & Loading Hyprland 二周目 Hyprland 二周目 PA2 Part 2 - Emulated Hardware Device PA W8 - IO Devices Learn C the Hard Way PA2 Part 1 - Instruction Set Implementation & KLIB Learning Makefile with PA 阅读 MQTTX 项目:Protobuf Test Case
Linuxqq 粘贴板同步问题
Last · 2025-10-15 · via Last Blog

更新

  • 该 Shell 脚本因改来改去 Bug 频出,因此近日笔者细细研究了一番这其中的古怪机制,详情见 这篇博文

前言

  • 不知从哪个版本开始,Linuxqq 在 Wayland 下的粘贴板出现了一个奇怪的问题:可以将 qq 中的文本复制到系统粘贴板(cliphist),但是无法将系统粘贴板上的内容粘贴进 qq 中。

  • 由于问题出现当时我正好将 Linuxqq 换成了 linuxqq-nt-bwarp,于是理所当然的认为这是因为 bwarp 沙盒化引起的,乍看之下也挺合理。

  • 直到今天在群里看到群主(应要求,不透露 id)发了一份用来同步 xclipcliphist 粘贴板内容的脚本,这才恍然大悟——沟槽的 tx,虽然 linuxqq 基于的 Electron 已经默认使用 Wayland 协议,但其复制仍然选择将内容输出到 xclip


查看

可以使用 xclip -sel clip -o 来查看 xlip 粘贴板中的内容。

脚本

  • 脚本代码如下:

    clipboard_sync.sh
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    #!/bin/bash


    LOCK_DIR="${XDG_RUNTIME_DIR:-/tmp}"
    LOCK_FILE="$LOCK_DIR/clipboard_sync.lock"

    exec 200>"$LOCK_FILE"
    flock -n 200 || {
    echo "Error: Another instance of the script is already running." >&2
    exit 1
    }


    TEMP_IMG="$LOCK_DIR/clip_sync_buffer"


    INTERVAL=0.5


    COLOR_RESET="\033[0m"
    COLOR_GREEN="\033[32m"
    COLOR_BLUE="\033[34m"
    COLOR_YELLOW="\033[33m"
    COLOR_CYAN="\033[36m"


    log() {
    local timestamp=$(date '+%H:%M:%S')
    echo -e "${COLOR_CYAN}[$timestamp]${COLOR_RESET} $1"
    }


    log_sync() {
    local direction=$1
    local type=$2
    local format=$3

    case "$direction" in
    "x11->wl")
    echo -e "${COLOR_CYAN}[$(date '+%H:%M:%S')]${COLOR_RESET} ${COLOR_GREEN}${COLOR_RESET} X11 → Wayland | ${COLOR_YELLOW}${type}${COLOR_RESET}${format}"
    ;;
    "wl->x11")
    echo -e "${COLOR_CYAN}[$(date '+%H:%M:%S')]${COLOR_RESET} ${COLOR_BLUE}${COLOR_RESET} Wayland → X11 | ${COLOR_YELLOW}${type}${COLOR_RESET}${format}"
    ;;
    esac
    }


    check_dependencies() {
    local missing_deps=()
    for cmd in xclip wl-paste wl-copy sha256sum; do
    if ! command -v "$cmd" &>/dev/null; then
    missing_deps+=("$cmd")
    fi
    done

    if [[ ${#missing_deps[@]} -gt 0 ]]; then
    echo "Error: Missing required dependencies: ${missing_deps[*]}" >&2
    exit 1
    fi
    }


    last_text=""
    last_x11_img_hash=""
    last_wl_img_hash=""


    clipboard_sync() {
    while true; do
    img_synced=false


    x11_targets=$(xclip -selection clipboard -t TARGETS -o 2>/dev/null || true)
    x11_img_type=""
    if echo "$x11_targets" | grep -q "image/png"; then
    x11_img_type="image/png"
    elif echo "$x11_targets" | grep -q "image/jpeg"; then
    x11_img_type="image/jpeg"
    elif echo "$x11_targets" | grep -q "image/gif"; then
    x11_img_type="image/gif"
    fi

    if [[ -n "$x11_img_type" ]]; then
    if xclip -selection clipboard -t "$x11_img_type" -o > "TEMP_IMG" 2>/dev/null; then


    if [[ -s "$TEMP_IMG" ]]; then
    x11_img_hash=$(xclip -selection clipboard -t "$x11_img_type" -o 2>/dev/null | sha256sum | awk '{print $1}')

    if [[ -n "$x11_img_hash" && "$x11_img_hash" != "$last_x11_img_hash" ]]; then


    wl-copy -t "$x11_img_type" < "$TEMP_IMG"

    last_x11_img_hash="$x11_img_hash"
    last_wl_img_hash="$x11_img_hash"
    img_synced=true
    log_sync "x11->wl" "Image" " ($x11_img_type)"
    fi
    fi

    fi
    fi



    if [[ "$img_synced" == false ]]; then
    wl_types=$(wl-paste --list-types 2>/dev/null || true)
    wl_img_type=""
    if echo "$wl_types" | grep -q "image/png"; then
    wl_img_type="image/png"
    elif echo "$wl_types" | grep -q "image/jpeg"; then
    wl_img_type="image/jpeg"
    elif echo "$wl_types" | grep -q "image/gif"; then
    wl_img_type="image/gif"
    fi

    if [[ -n "$wl_img_type" ]]; then



    if wl-paste -t "$wl_img_type" > "$TEMP_IMG" 2>/dev/null; then
    if [[ -s "$TEMP_IMG" ]]; then
    wl_img_hash=$(sha256sum "$TEMP_IMG" | awk '{print $1}')


    if [[ -n "$wl_img_hash" && "$wl_img_hash" != "$last_wl_img_hash" ]]; then
    xclip -selection clipboard -t "wl_img_type" -i < "$TEMP_IMG"

    last_wl_img_hash="$wl_img_hash"
    last_x11_img_hash="$wl_img_hash"
    img_synced=true
    log_sync "wl->x11" "Image" " ($wl_img_type)"
    fi
    fi
    fi

    fi
    fi



    if [[ "$img_synced" == false ]]; then
    text_synced=false

    x11_targets=$(xclip -selection clipboard -t TARGETS -o 2>/dev/null || true)


    if echo "x11_targets" | grep -qE "image/png|image/jpeg|image/bmp|image/tiff"; then
    x11_text=""
    else
    x11_text=$(xclip -selection clipboard -t UTF8_STRING -o 2>/dev/null || true)
    fi

    current_text=$(wl-paste --type text/plain 2>/dev/null || true)

    if [[ -n "$x11_text" && "$x11_text" != "$last_text" && "$x11_text" != "$current_text" ]]; then
    if [[ ! "$x11_text" =~ \x00 ]]; then

    printf "%s" "$x11_text" | wl-copy --type text/plain
    last_text="$x11_text"
    text_synced=true
    log_sync "x11->wl" "Text" " \"$preview\""
    fi
    fi


    if [[ "$text_synced" == false && -n "$current_text" && "$current_text" != "$last_text" && "$x11_text" != "$current_text" ]]; then

    printf "%s" "$current_text" | xclip -selection clipboard -t UTF8_STRING -i
    last_text="$current_text"
    log_sync "wl->x11" "Text" " \"$preview\""
    fi
    fi

    sleep $INTERVAL
    done
    }


    trap 'exit' INT TERM EXIT


    check_dependencies

    log "Clipboard sync service started"
    log "Monitoring clipboard sync between Wayland ↔ X11..."

    log "Service started on lock: $LOCK_FILE"


    clipboard_sync

  • 这个脚本的思路很简单:每间隔 $INTERVAL 的时间,就同步一次两个剪贴板中的内容。同时,利用哈希算法来确保图片的同步过程中不会出现无限循环。

  • 同时,笔者加入了使用 flock 的片段来确保不会出现该脚本在同一时间被运行多次的情况。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    LOCK_DIR="${XDG_RUNTIME_DIR:-/tmp}"
    LOCK_FILE="$LOCK_DIR/clipboard_sync.lock"

    exec 200>"$LOCK_FILE"
    flock -n 200 || {
    echo "Error: Another instance of the script is already running." >&2
    exit 1
    }




    trap 'exit' INT TERM EXIT

后台运行

  • 笔者使用的是 Hyprland,因此只需在配置文件中加入:

    1
    2
    # Start clipboard sync service (for linuxqq)
    exec = ~/path/to/clipboard_sync.sh
  • 即可。

  • Title: Linuxqq 粘贴板同步问题
  • Author: Last
  • Created at : 2025-10-15 17:07:43
  • Link: https://blog.imlast.top/2025/10/15/linuxqq-clipboard-issue/
  • License: This work is licensed under CC BY-NC-SA 4.0.

On this page

Linuxqq 粘贴板同步问题

  1. 前言
  2. 脚本
  3. 后台运行