/
OS-World9f0898f
import os
import ctypes
import ctypes.util
import numpy as np
# A helper function to convert data from Xlib to byte array.
import struct, array
# Define ctypes version of XFixesCursorImage structure.
PIXEL_DATA_PTR = ctypes.POINTER(ctypes.c_ulong)
Atom = ctypes.c_ulong
class XFixesCursorImage(ctypes.Structure):
"""
See /usr/include/X11/extensions/Xfixes.h
typedef struct {
short x, y;
unsigned short width, height;
unsigned short xhot, yhot;
unsigned long cursor_serial;
unsigned long *pixels;
if XFIXES_MAJOR >= 2
Atom atom; /* Version >= 2 only */
const char *name; /* Version >= 2 only */
endif
} XFixesCursorImage;
"""
_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.")
# XFixeslib = ctypes.CDLL('libXfixes.so')
XFixes = ctypes.util.find_library("Xfixes")
if not XFixes:
raise Exception("No XFixes library found.")
self.XFixeslib = ctypes.cdll.LoadLibrary(XFixes)
# xlib = ctypes.CDLL('libX11.so.6')
x11 = ctypes.util.find_library("X11")
if not x11:
raise Exception("No X11 library found.")
self.xlib = ctypes.cdll.LoadLibrary(x11)
# Define ctypes' version of XFixesGetCursorImage function
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 argbdata_to_pixdata(self, data, len):
if data == None or len < 1: return None
# Create byte array
b = array.array('b', b'\x00' * 4 * len)
offset, i = 0, 0
while i < len:
argb = data[i] & 0xffffffff
rgba = (argb << 8) | (argb >> 24)
b1 = (rgba >> 24) & 0xff
b2 = (rgba >> 16) & 0xff
b3 = (rgba >> 8) & 0xff
b4 = rgba & 0xff
struct.pack_into("=BBBB", b, offset, b1, b2, b3, b4)
offset = offset + 4
i = i + 1
return b
def getCursorImageData(self):
# Call the function. Read data of cursor/mouse-pointer.
cursor_data = self.XFixesGetCursorImage(self.display)
if not (cursor_data and cursor_data[0]):
raise Exception("Cannot read XFixesGetCursorImage()")
# Note: cursor_data is a pointer, take cursor_data[0]
return cursor_data[0]
def getCursorImageArray(self):
data = self.getCursorImageData()
# x, y = data.x, data.y
height, width = data.height, data.width
bytearr = self.argbdata_to_pixdata(data.pixels, height * width)
imgarray = np.array(bytearr, dtype=np.uint8)
imgarray = imgarray.reshape(height, width, 4)
del bytearr
return imgarray
def getCursorImageArrayFast(self):
data = self.getCursorImageData()
# x, y = data.x, data.y
height, width = data.height, data.width
bytearr = ctypes.cast(data.pixels, ctypes.POINTER(ctypes.c_ulong * height * width))[0]
imgarray = np.array(bytearray(bytearr))
imgarray = imgarray.reshape(height, width, 8)[:, :, (0, 1, 2, 3)]
del bytearr
return imgarray
def saveImage(self, imgarray, text):
from PIL import Image
img = Image.fromarray(imgarray)
img.save(text)
if __name__ == "__main__":
cursor = Xcursor()
imgarray = cursor.getCursorImageArrayFast()
cursor.saveImage(imgarray, 'cursor_image.png')