Spaces:
Running
Running
| 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') | |