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

  • 本文关键字:结果 读取 X11 鼠标 按钮 c++ x11
  • 更新时间 :
  • 英文 :


我正在制作一个简单的控制台应用程序,我在其中测试从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不是X11ButtonPressButtonRelease事件类型。分别是4和5。(在我写这篇文章时,最后一个X11事件类型是36)。您将获得与X11核心事件不同的扩展事件。

您需要对照XInputClassInfoevent_type_base成员来检查您的类型,例如按钮按下事件将生成XI_DeviceButtonPress+event_type_base事件类型,事件结构是XDeviceButtonEvent而不是XButtonEvent。这些不是XEvent联合的成员,所以您需要使用((XDeviceButtonEvent&)event)而不是event.xbutton

最新更新