如何通过XCursor和XInput2修改全系统所有窗口的鼠标光标?
全系统鼠标光标修改方案
你的代码仅能修改浏览器窗口光标,核心问题在于只在鼠标移动时触发光标设置,且未处理窗口切换、新窗口创建等场景,以下是修正方案:
问题根源
- 仅监听
XI_RawMotion事件,窗口切换、新窗口打开时不会触发光标更新 - 部分应用会自行设置窗口光标,覆盖你的修改
XTranslateCoordinates的使用逻辑冗余,XQueryPointer已经能直接获取光标下方的子窗口
修正后的代码
#include <X11/Xlib.h> #include <X11/extensions/XInput2.h> #include <X11/Xcursor/Xcursor.h> // 补充光标创建函数的实现 void CreateCursor(const char* path, Cursor& cursor, Display* display) { cursor = XcursorLibraryLoadCursor(display, path); if (!cursor) { // 加载失败时用系统默认光标兜底 cursor = XCreateFontCursor(display, XC_left_ptr); } } int main(int argc, char **argv) { Display *display = XOpenDisplay(0); if (!display) return 1; int screen = DefaultScreen(display); Window root_window = RootWindow(display, screen); Cursor cursorDefault; CreateCursor("1.png", cursorDefault, display); // 1. 监听XInput2关键事件:鼠标移动、鼠标进入窗口 unsigned char xi_mask[(XI_LASTEVENT + 7)/8] = {0}; XISetMask(xi_mask, XI_RawMotion); XISetMask(xi_mask, XI_Enter); XIEventMask evmasks[1] = { {XIAllMasterDevices, sizeof(xi_mask), xi_mask} }; XISelectEvents(display, root_window, evmasks, 1); // 2. 监听X核心事件:新窗口创建、鼠标进入窗口 XSelectInput(display, root_window, SubstructureNotifyMask | EnterWindowMask); XEvent xevent; while (1) { XNextEvent(display, &xevent); // 处理XInput2通用事件 if (xevent.type == GenericEvent && xevent.xcookie.extension == XInputDisplay(display)) { XGetEventData(display, &xevent.xcookie); XFreeEventData(display, &xevent.xcookie); } // 获取当前光标下方的窗口 Window root_return, child_return; int root_x, root_y, win_x, win_y; unsigned int mask; XQueryPointer(display, root_window, &root_return, &child_return, &root_x, &root_y, &win_x, &win_y, &mask); // 给当前窗口和根窗口设置光标 if (child_return) { XDefineCursor(display, child_return, cursorDefault); } XDefineCursor(display, root_window, cursorDefault); // 新窗口创建时自动设置光标 if (xevent.type == CreateNotify) { XDefineCursor(display, xevent.xcreatewindow.window, cursorDefault); } } XCloseDisplay(display); return 0; }
关键改进点
- 扩展事件监听:新增
XI_Enter(鼠标进入窗口)、CreateNotify(新窗口创建)事件,确保窗口切换和新窗口打开时都能触发光标更新 - 根窗口兜底设置:直接给根窗口设置自定义光标,当没有子窗口覆盖时生效
- 简化窗口获取逻辑:直接使用
XQueryPointer返回的child_return作为目标窗口,无需额外调用XTranslateCoordinates - 强制覆盖应用光标:通过事件触发时重复设置光标,覆盖部分应用自行设置的光标样式
内容的提问来源于stack exchange,提问作者XoDefender
相关产品推荐
相关产品推荐

