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

XInput2使用RawMotion触发BadValue错误:XISelectEvents事件值过高问题

问题描述

我正在编写纯Xlib应用,希望借助XInput2扩展获取RawMotion事件。调用XISelectEvents时,若掩码中设置任何高于XI_PropertyEvent的XI2事件(例如使用XISetMask(mask, XI_RawMotion))就会报错,设置XI_Motion时则正常运行。该错误与传入的deviceid及掩码中设置的其他事件类型无关,请问这是什么原因?

代码示例

#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>

int main() {
    Display* display = XOpenDisplay(nullptr);

    int screen_num = DefaultScreen(display);

    Window window = XCreateSimpleWindow(
            display,
            RootWindow(display, screen_num),
            0, 0,
            640, 480,
            4,
            16711680,
            WhitePixel(display, screen_num)
    );
    XSelectInput(display, window, KeyPressMask);

    int major_opcode, first_event, first_error;
    XQueryExtension(display, "XInputExtension", &major_opcode, &first_event, &first_error);

    unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {0, };
    XISetMask(mask, XI_RawMotion);

    XIEventMask event_mask;
    event_mask.deviceid = XIAllDevices;
    event_mask.mask_len = sizeof(mask);
    event_mask.mask = mask;

    XISelectEvents(display, window, &event_mask, 1);

    XMapWindow(display, window);
    XFlush(display);

    while (true) {
        XEvent ev;
        XNextEvent(display, &ev);
        if (ev.type == KeyPress && ev.xkey.keycode == 9) {
            break;
        }
    }
    XUnmapWindow(display, window);
    XFlush(display);
    XDestroyWindow(display, window);
    XCloseDisplay(display);
    return 0;
}

报错信息

X Error of failed request: BadValue (integer parameter out of range for operation)
Major opcode of failed request: 131 (XInputExtension)
Minor opcode of failed request: 46 ()
Value in failed request: 0xd
Serial number of failed request: 16
Current serial number in output stream: 17

原因分析与解决方法

核心原因

只调用XQueryExtension确认XInput扩展存在,但未检查XInput2的版本支持。RawMotion这类事件是XInput 2.1及以上版本才新增的特性,若X Server或Xlib只支持更低版本的XInput2,尝试选择高版本事件就会触发BadValue错误。

另外,XIMaskLen(XI_LASTEVENT)计算的是所有XI事件的掩码长度,但低版本XInput中XI_LASTEVENT的值更小,导致传入的掩码长度超出服务器预期范围,这是触发错误的直接原因。

解决步骤

  1. 检查并获取XInput2版本
    调用XIQueryVersion替代XQueryExtension,明确获取服务器支持的XInput2版本,同时确保客户端请求的版本不低于2.1:

    int major = 2, minor = 1;
    if (XIQueryVersion(display, &major, &minor) != Success) {
        fprintf(stderr, "XInput 2.1 or higher is required\n");
        XCloseDisplay(display);
        return 1;
    }
    

    这一步会确保服务器支持RawMotion等事件。

  2. 修正掩码长度计算
    使用服务器实际支持的最高事件类型计算掩码长度,而非直接用XI_LASTEVENT:

    int max_event;
    int major = 2, minor = 1;
    XIQueryVersion(display, &major, &minor);
    if (major >= 2 && minor >= 1) {
        max_event = XI_LASTEVENT;
    } else {
        max_event = XI_PropertyEvent; // 低版本最大事件
    }
    unsigned char mask[XIMaskLen(max_event)] = {0, };
    
  3. 选择正确的设备范围
    RawMotion事件属于主设备(如鼠标)的原始输入事件,建议使用XIAllMasterDevices替代XIAllDevices,避免选择不支持Raw事件的从设备:

    event_mask.deviceid = XIAllMasterDevices;
    

修正后的完整代码示例

#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#include <stdio.h>

int main() {
    Display* display = XOpenDisplay(nullptr);
    if (!display) {
        fprintf(stderr, "Failed to open display\n");
        return 1;
    }

    int screen_num = DefaultScreen(display);

    Window window = XCreateSimpleWindow(
            display,
            RootWindow(display, screen_num),
            0, 0,
            640, 480,
            4,
            16711680,
            WhitePixel(display, screen_num)
    );
    XSelectInput(display, window, KeyPressMask);

    // 检查XInput2版本,要求至少2.1
    int major = 2, minor = 1;
    if (XIQueryVersion(display, &major, &minor) != Success) {
        fprintf(stderr, "XInput 2.1 or higher is required (server supports %d.%d)\n", major, minor);
        XCloseDisplay(display);
        return 1;
    }

    // 初始化掩码,选择RawMotion事件
    unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {0, };
    XISetMask(mask, XI_RawMotion);

    XIEventMask event_mask;
    event_mask.deviceid = XIAllMasterDevices;
    event_mask.mask_len = sizeof(mask);
    event_mask.mask = mask;

    XISelectEvents(display, window, &event_mask, 1);

    XMapWindow(display, window);
    XFlush(display);

    while (true) {
        XEvent ev;
        XNextEvent(display, &ev);
        if (ev.type == KeyPress && ev.xkey.keycode == 9) {
            break;
        }
        // 处理RawMotion事件
        if (ev.type == GenericEvent && ev.xgeneric.extension == major) {
            XIDeviceEvent* xi_ev = (XIDeviceEvent*)&ev;
            if (xi_ev->evtype == XI_RawMotion) {
                printf("RawMotion detected: dx=%d, dy=%d\n", xi_ev->rawmotion.dx, xi_ev->rawmotion.dy);
            }
        }
    }

    XUnmapWindow(display, window);
    XFlush(display);
    XDestroyWindow(display, window);
    XCloseDisplay(display);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:40:59