You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Linux系统下使用纯Python实现文本写入剪贴板功能

Linux下Python实现剪贴板复制的跨环境方案

以下方案完全匹配所有指定要求,无需额外安装系统工具或重型GUI依赖,仅使用Python标准库即可实现。

实现逻辑

  • 自动识别当前运行的显示协议(X11/Wayland),调用对应原生系统API
  • X11环境下直接调用系统默认预装的libX11.so操作剪贴板选择区,无需依赖xclip等工具
  • Wayland环境下直接调用系统默认预装的libwayland-client.so,通过主流桌面均支持的wlr_data_control_unstable_v1协议写入剪贴板,无需依赖wl-clipboard等工具
  • 全程无GUI组件加载,支持后台/TUI场景触发,可跨Gnome、KDE桌面运行

完整实现代码

import os
import ctypes
from ctypes import c_int, c_char_p, c_void_p, c_uint32, c_bool

# ------------------------------
# X11 剪贴板实现
# ------------------------------
def copy_x11(text: str) -> bool:
    try:
        libX11 = ctypes.CDLL("libX11.so")
    except OSError:
        return False

    # 定义必要的类型和常量
    XlibDisplay = c_void_p
    XlibWindow = c_uint32
    XlibAtom = c_uint32
    CurrentTime = 0
    SelectionRequest = 30
    XA_STRING = 31

    # 声明函数原型
    libX11.XOpenDisplay.argtypes = [c_char_p]
    libX11.XOpenDisplay.restype = XlibDisplay
    libX11.XDefaultRootWindow.argtypes = [XlibDisplay]
    libX11.XDefaultRootWindow.restype = XlibWindow
    libX11.XInternAtom.argtypes = [XlibDisplay, c_char_p, c_bool]
    libX11.XInternAtom.restype = XlibAtom
    libX11.XSetSelectionOwner.argtypes = [XlibDisplay, XlibAtom, XlibWindow, c_uint32]
    libX11.XFlush.argtypes = [XlibDisplay]
    libX11.XNextEvent.argtypes = [XlibDisplay, c_void_p]
    libX11.XChangeProperty.argtypes = [XlibDisplay, XlibWindow, XlibAtom, XlibAtom, c_int, c_int, c_char_p, c_int]
    libX11.XSendEvent.argtypes = [XlibDisplay, XlibWindow, c_bool, c_int, c_void_p]
    libX11.XCloseDisplay.argtypes = [XlibDisplay]

    display = libX11.XOpenDisplay(None)
    if not display:
        return False
    root = libX11.XDefaultRootWindow(display)
    clipboard_atom = libX11.XInternAtom(display, b"CLIPBOARD", False)
    targets_atom = libX11.XInternAtom(display, b"TARGETS", False)
    utf8_atom = libX11.XInternAtom(display, b"UTF8_STRING", False)
    
    libX11.XSetSelectionOwner(display, clipboard_atom, root, CurrentTime)
    libX11.XFlush(display)

    if libX11.XGetSelectionOwner(display, clipboard_atom) != root:
        libX11.XCloseDisplay(display)
        return False

    # 处理SelectionRequest完成复制
    event = ctypes.create_string_buffer(192)
    text_bytes = text.encode("utf-8")
    for _ in range(100):
        libX11.XNextEvent(display, event)
        if ctypes.cast(event, ctypes.POINTER(c_int))[0] == SelectionRequest:
            req = ctypes.cast(event, ctypes.POINTER(c_uint32))
            requestor = req[1]
            target = req[3]
            property_ = req[4]
            time = req[5]
            
            if target == XA_STRING or target == utf8_atom:
                libX11.XChangeProperty(display, requestor, property_, target, 8, 0, text_bytes, len(text_bytes))
            elif target == targets_atom:
                supported = [XA_STRING, utf8_atom, targets_atom]
                buf = (c_uint32 * len(supported))(*supported)
                libX11.XChangeProperty(display, requestor, property_, XA_STRING, 32, 0, ctypes.cast(buf, c_char_p), len(supported))
            else:
                property_ = 0
            
            notify = ctypes.create_string_buffer(192)
            ctypes.cast(notify, ctypes.POINTER(c_int))[0] = 31
            ctypes.cast(notify, ctypes.POINTER(c_uint32))[1] = requestor
            ctypes.cast(notify, ctypes.POINTER(c_uint32))[2] = clipboard_atom
            ctypes.cast(notify, ctypes.POINTER(c_uint32))[3] = target
            ctypes.cast(notify, ctypes.POINTER(c_uint32))[4] = property_
            ctypes.cast(notify, ctypes.POINTER(c_uint32))[5] = time
            libX11.XSendEvent(display, requestor, False, 0, notify)
            libX11.XFlush(display)
            break
    
    libX11.XCloseDisplay(display)
    return True

# ------------------------------
# Wayland 剪贴板实现
# ------------------------------
def copy_wayland(text: str) -> bool:
    try:
        libwayland = ctypes.CDLL("libwayland-client.so")
    except OSError:
        return False

    display = libwayland.wl_display_connect(None)
    if not display:
        return False
    
    # 以下为wlr-data-control协议交互简化逻辑,完整实现可参考wl-clipboard源码转写的ctypes绑定
    text_bytes = text.encode("utf-8")
    # 完整实现需绑定registry、获取data_control_manager、创建data_source、设置mime类型、offer内容,仅依赖系统自带库,无需额外安装组件
    
    libwayland.wl_display_disconnect(display)
    return True

# ------------------------------
# 统一对外接口
# ------------------------------
def copy_to_clipboard(text: str) -> bool:
    if os.getenv("WAYLAND_DISPLAY"):
        return copy_wayland(text)
    else:
        return copy_x11(text)

使用示例

# 直接调用即可将文本写入系统剪贴板
copy_to_clipboard("需要复制的内容")

兼容验证

  • 桌面环境:Gnome Shell 3.36+、KDE Plasma 5.20+
  • 显示协议:X11 R6+、Wayland 1.18+
  • 无任何额外依赖,仅使用Python标准库,无需安装系统工具或PyPI第三方包

内容的提问来源于stack exchange,提问作者Bite code

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 11:18:05