我正在制作一个简单的控制台应用程序,我在其中测试从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
如果你仔细看,你会发现x
和state
字段和y
和button
字段显示相同的值。这绝对不应该是,但我不能确定这种现象的来源。
[编辑]我修改了代码和结果,因为我发现了重复的值。
69和70不是X11ButtonPress
和ButtonRelease
事件类型。分别是4和5。(在我写这篇文章时,最后一个X11事件类型是36)。您将获得与X11核心事件不同的扩展事件。
您需要对照XInputClassInfo
的event_type_base
成员来检查您的类型,例如按钮按下事件将生成XI_DeviceButtonPress+event_type_base
事件类型,事件结构是XDeviceButtonEvent
而不是XButtonEvent
。这些不是XEvent
联合的成员,所以您需要使用((XDeviceButtonEvent&)event)而不是event.xbutton
。