繁体   English   中英

在 X11 中读取鼠标按钮时出现奇怪的结果(重复值)

[英]Strange results while reading mouse button press in X11 (repeated values)

我正在制作一个简单的控制台应用程序,在其中测试从 Linux 上的 X11 读取各种事件。 我在阅读鼠标按钮时被打断了。 可以阅读它们,但结果很奇怪。

这是代码:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <ctime>

//X11
#include <X11/Xlib.h>
#include <X11/extensions/XI.h>
#include <X11/extensions/XInput.h>


std::vector<XID> findCandidates(Display* display) {
    std::vector<XID> result;
    
    int dev_count;
    XDeviceInfo* dev_list = XListInputDevices(display, &dev_count);
    if( dev_count == 0 ) { //no devices
        XFreeDeviceList(dev_list);
        return result;
    }
    
    for(int i=0; i<dev_count; ++i) {
        XID id = dev_list[i].id;
        if( dev_list[i].type == 0 ) continue; //Omit wrong devices
        
        //classes
        auto ici = dev_list[i].inputclassinfo;
        bool hasButtons = false;
        bool hasValuators = false;
        for(int cl=dev_list[i].num_classes; cl>0; --cl) {
            if( ici->c_class == ButtonClass ) hasButtons = true;
            if( ici->c_class == ValuatorClass ) hasValuators = true;
            
            ici = reinterpret_cast<decltype(ici)>(reinterpret_cast<char*>(ici) + ici->length);
        }
        
        if( hasButtons && hasValuators ) {
            //we have found a candidate
            result.push_back(id);
        }
    }
    
    //cleanup
    XFreeDeviceList(dev_list);
    
    return result;
}

void traceInputs(std::ofstream &outputFile, Display* display, XDevice* device);

int main (int argc, char **argv)
{
    Display* display = XOpenDisplay(nullptr);   
    if(display == nullptr) {
        std::cerr << "Can't connect to the display" << std::endl;
        return 1;
    }
    
    std::vector<XID> candidates = findCandidates(display);
    std::cout << "Candidates: ";
    if( candidates.empty() ) {
        std::cout << "none" << std::endl;
    } else {
        bool needComma = false;
        for(auto candidate : candidates) {
            if( needComma ) std::cout << ", ";
            std::cout << candidate;
            needComma = true;
        }
        std::cout << std::endl;
        
        for(auto deviceID : candidates) {
            std::cout << "Opening device #" << deviceID << "...";
            XDevice* device = XOpenDevice(display, deviceID);
            if( device == nullptr ) {
                std::cout << "error" << std::endl;
                continue;
            }
            std::cout << "OK" << std::endl;
            
            std::ofstream outputFile{std::string("Dev_")+std::to_string(deviceID), std::ios_base::out | std::ios_base::trunc};
            traceInputs(outputFile, display, device);
            outputFile.close();
            
            
            XCloseDevice(display, device);
        }
    }
    
    //cleanup
    XCloseDisplay(display);
    return 0;
}

void traceInputs(std::ofstream &outputFile, Display* display, XDevice* device) {
    int type;
    XEventClass event_class;
    
    constexpr int EVENT_COUNT = 2;
    constexpr int BTN_PRESS_EVENT = 0;
    constexpr int BTN_RELEASE_EVENT = 1;
    
    XEventClass registered_event_classes[EVENT_COUNT];
    int registered_event_types[EVENT_COUNT];
    //button events
    DeviceButtonPress(device, type, event_class);
        registered_event_classes[BTN_PRESS_EVENT] = event_class;
        registered_event_types[BTN_PRESS_EVENT] = type;
    DeviceButtonRelease(device, type, event_class);
        registered_event_classes[BTN_RELEASE_EVENT] = event_class;
        registered_event_types[BTN_RELEASE_EVENT] = type;
    
    //register events
    Window w = XDefaultRootWindow(display);
    XSelectExtensionEvent(display, w, registered_event_classes, EVENT_COUNT);
    
    std::time_t start, stop;
    start = std::time(nullptr);
    do{
        XEvent event;
        for(int i = 0; i < EVENT_COUNT; ++i) {
            int event_type = registered_event_types[i];
            if( XCheckTypedEvent(display, event_type, &event) ) {
                outputFile << "Type: " << event.type << ' ';
                switch(i) {
                    case BTN_PRESS_EVENT:
                        outputFile << "ButtonPress";
                        outputFile << "\tx=" << event.xbutton.x_root << " y=" << event.xbutton.y_root;
                        outputFile << " state=" << event.xbutton.state << " button=" << event.xbutton.button;
                        break;
                    case BTN_RELEASE_EVENT:
                        outputFile << "ButtonRelease";
                        outputFile << "\tx=" << event.xbutton.x_root << " y=" << event.xbutton.y_root;
                        outputFile << " state=" << event.xbutton.state << " button=" << event.xbutton.button;
                        break;
                }
                outputFile << std::endl;
            }
        }
        
        stop = std::time(nullptr);
    }while(stop - start < 3); //less than 3 seconds
}

这就是它写入与我的鼠标设备对应的文件的内容:

Type: 69 ButtonPress    x=1221 y=732 state=1221 button=732
Type: 70 ButtonRelease  x=1221 y=732 state=1221 button=732
Type: 69 ButtonPress    x=1221 y=732 state=1221 button=732
Type: 70 ButtonRelease  x=1221 y=732 state=1221 button=732
Type: 69 ButtonPress    x=1221 y=732 state=1221 button=732

如果仔细观察,您会发现xstate字段以及ybutton字段显示相同的值。 这绝对不应该,但我无法确定这种现象的根源。

[编辑]我修改了代码和结果,因为我发现了重复的值。

69 和 70 不是 X11 ButtonPressButtonRelease事件类型。 分别是 4 和 5。 (在我写这篇文章时,最后一个 X11 事件类型是 36)。 您将获得与 X11 核心事件不同的扩展事件。

您需要针对event_type_baseXInputClassInfo成员检查您的类型,例如按钮按下事件将生成XI_DeviceButtonPress+event_type_base事件类型,并且事件结构是XDeviceButtonEvent而不是XButtonEvent 这些不是XEvent联合的成员,因此您需要使用 ((XDeviceButtonEvent&)event) 而不是event.xbutton

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM