如何在 Linux 下跟踪 python 中的光标图像

How to track cursor images in python under Linux

我想做的是跟踪屏幕上显示的光标图像,特别是当它因我移入和移出活动区域而发生变化时。跟踪光标位置的模块很多,但是光标图像的信息比较少

我发现一个 post 提到 windows 使用 win32gui:

但是是否还有一种方法可以使用 Xlib 在 linux 下获取它?我进一步发现 XFixes 显然有一个名为 XFixesGetCursorImage 的方法并且它没有直接暴露给 python,但它也是几年老的。有谁知道这是否已经改变或我如何使用 python 中的 C 库来使用该功能(到目前为止没有关于如何做到这一点的经验)?

我能为您提供的最好的是下面的代码,来自我的一个项目 XwintrackXlib 下的 Fixes 模块仅提供 show_cursorhide_cursor,这让我们只能更改现有属性。

这也意味着,由于您无法识别现有光标或它来自的主题,如果您更改光标,则必须求助于标准 X 光标或创建您的光标自己的,例如使用 PIL 的图像。另外,当然,没有回头路。您将无法恢复到之前的光标,您必须提供来自 X 库的猜测。

如果你开始深入挖掘,研究游标和主题,实施时,你会发现这是一个多么曲折的雷区。它似乎是一个由不同部分组成的系统,只是松散地结合在一起,有蜘蛛网和唾沫。

以下依赖:

from Xlib import X, display, Xcursorfont
LEFT_PTR = Xcursorfont.left_ptr
SELECT = Xcursorfont.dotbox

def xcursorselect():
    ''' Change the cursor to a green dotbox to indicate a selection is required
        Beware - there is no way back to the original themed cursor - see xcursornormal()
    '''
    disp = display.Display()
    root = disp.screen().root
    font = disp.open_font('cursor')
    cursor = font.create_glyph_cursor(font, SELECT, SELECT+1, (0, 65535, 0), (0, 0, 0)) #green with black edges
    root.change_attributes(cursor=cursor)
    disp.flush()

def xcursornormal():
    ''' Change the cursor back to White left_ptr to indicate selection finished
        Sadly under python there appears to be no way to identify the existing
        cursor image, so we're left with returning to a standard X cursor, rather
        than the Themed one
    '''
    disp = display.Display()
    root = disp.screen().root
    font = disp.open_font('cursor')
    cursor = font.create_glyph_cursor(font, LEFT_PTR, LEFT_PTR+1, (65535, 65535, 65355), (0, 0, 0)) #white with black edges
    root.change_attributes(cursor=cursor)
    disp.flush()

如果您确实想出了解决方案,请务必在此处 post。

已经有一段时间了,但是对于那些感兴趣的人,我最近遇到了类似问题中提到的这个存储库:

https://github.com/zorvios/PyXCursor/blob/master/pyxcursor/pyxcursor.py

它更侧重于复制光标的图片,但是跟踪光标状态的相关部分是:

import os
import ctypes
import ctypes.util

PIXEL_DATA_PTR = ctypes.POINTER(ctypes.c_ulong)
Atom = ctypes.c_ulong

class XFixesCursorImage(ctypes.Structure):
    _fields_ = [('x', ctypes.c_short),
                ('y', ctypes.c_short),
                ('width', ctypes.c_ushort),
                ('height', ctypes.c_ushort),
                ('xhot', ctypes.c_ushort),
                ('yhot', ctypes.c_ushort),
                ('cursor_serial', ctypes.c_ulong),
                ('pixels', PIXEL_DATA_PTR),
                ('atom', Atom),
                ('name', ctypes.c_char_p)]

class Display(ctypes.Structure):
    pass

class Xcursor:
    display = None

    def __init__(self, display=None):
        if not display:
            try:
                display = os.environ["DISPLAY"].encode("utf-8")
            except KeyError:
                raise Exception("$DISPLAY not set.")

        XFixes = ctypes.util.find_library("Xfixes")
        if not XFixes:
            raise Exception("No XFixes library found.")
        self.XFixeslib = ctypes.cdll.LoadLibrary(XFixes)

        x11 = ctypes.util.find_library("X11")
        if not x11:
            raise Exception("No X11 library found.")
        self.xlib = ctypes.cdll.LoadLibrary(x11)

        XFixesGetCursorImage = self.XFixeslib.XFixesGetCursorImage
        XFixesGetCursorImage.restype = ctypes.POINTER(XFixesCursorImage)
        XFixesGetCursorImage.argtypes = [ctypes.POINTER(Display)]
        self.XFixesGetCursorImage = XFixesGetCursorImage

        XOpenDisplay = self.xlib.XOpenDisplay
        XOpenDisplay.restype = ctypes.POINTER(Display)
        XOpenDisplay.argtypes = [ctypes.c_char_p]

        if not self.display:
            self.display = self.xlib.XOpenDisplay(display)  # (display) or (None)

    def getCursorImageData(self):
        cursor_data = self.XFixesGetCursorImage(self.display)
        return cursor_data[0]

返回的cursor_data[0]包含XFixesGetCursorImage函数返回的信息。状态更改方面的相关信息是 cursor_serial,它提供了一些图像特定 ID 或 name 属性 这是描述光标的字符串。