WingTool/class/eventmonitor.cpp

213 lines
5.6 KiB
C++

#include "eventmonitor.h"
#include <QApplication>
EventMonitor::EventMonitor(QObject *parent) : QThread(parent) {
isPress = false;
}
EventMonitor::~EventMonitor() {
Display *display = XOpenDisplay(nullptr);
XRecordDisableContext(display, context);
XSync(display, 0);
wait();
XRecordFreeContext(display, context);
XCloseDisplay(display_datalink);
}
void EventMonitor::run() {
// Init x11 display.
Display *display = XOpenDisplay(nullptr);
if (display == nullptr) {
fprintf(stderr, "unable to open display\n");
return;
}
// Receive from ALL clients, including future clients.
XRecordClientSpec clients = XRecordAllClients;
XRecordRange *range = XRecordAllocRange();
if (range == nullptr) {
fprintf(stderr, "unable to allocate XRecordRange\n");
return;
}
// Receive ButtonPress, ButtonRelease and MotionNotify
// events.
memset(range, 0, sizeof(XRecordRange));
range->device_events.first = KeyPress;
range->device_events.last = MotionNotify;
// And create the XRECORD context.
context = XRecordCreateContext(display, 0, &clients, 1, &range, 1);
if (context == 0) {
fprintf(stderr, "XRecordCreateContext failed\n");
return;
}
XFree(range);
// Sync x11 display message.
XSync(display, True);
display_datalink = XOpenDisplay(nullptr);
if (display_datalink == nullptr) {
fprintf(stderr, "unable to open second display\n");
return;
}
// Enter in xrecord event loop.
if (!XRecordEnableContext(display_datalink, context, callback,
reinterpret_cast<XPointer>(this))) {
fprintf(stderr, "XRecordEnableContext() failed\n");
return;
}
// init timer
clickbefore = std::chrono::system_clock::now();
isClicked = false;
}
Qt::KeyboardModifier EventMonitor::getKeyModifier() const {
return keyModifier;
}
void EventMonitor::callback(XPointer ptr, XRecordInterceptData *data) {
(reinterpret_cast<EventMonitor *>(ptr))->handleRecordEvent(data);
}
void EventMonitor::handleRecordEvent(XRecordInterceptData *data) {
if (data->category == XRecordFromServer) {
auto event = reinterpret_cast<xEvent *>(data->data);
switch (event->u.u.type) {
case ButtonPress:
if (handleWheelEvent(event->u.u.detail)) {
isPress = true;
Qt::MouseButton btn = Qt::MouseButton::NoButton;
switch (event->u.u.detail) {
case Button1: {
btn = Qt::MouseButton::LeftButton;
auto clicknow = std::chrono::system_clock::now();
double diff_ms =
std::chrono::duration<double, std::milli>(clicknow - clickbefore)
.count();
clickbefore = clicknow;
if (isClicked && diff_ms <= QApplication::doubleClickInterval()) {
emit doubleClicked(event->u.keyButtonPointer.rootX,
event->u.keyButtonPointer.rootY);
isClicked = false;
} else {
emit clicked(event->u.keyButtonPointer.rootX,
event->u.keyButtonPointer.rootY);
isClicked = true;
}
} break;
case Button2:
btn = Qt::MouseButton::MiddleButton;
break;
case Button3:
btn = Qt::MouseButton::RightButton;
break;
case XButton_1:
btn = Qt::MouseButton::XButton1;
break;
case XButton_2:
btn = Qt::MouseButton::XButton2;
break;
}
emit buttonPress(btn, event->u.keyButtonPointer.rootX,
event->u.keyButtonPointer.rootY);
}
break;
case MotionNotify:
if (isPress) {
emit mouseDrag(event->u.keyButtonPointer.rootX,
event->u.keyButtonPointer.rootY);
} else {
emit mouseMove(event->u.keyButtonPointer.rootX,
event->u.keyButtonPointer.rootY);
}
break;
case ButtonRelease:
if (handleWheelEvent(event->u.u.detail)) {
isPress = false;
Qt::MouseButton btn = Qt::MouseButton::NoButton;
switch (event->u.u.detail) {
case Button1:
btn = Qt::MouseButton::LeftButton;
break;
case Button2:
btn = Qt::MouseButton::MiddleButton;
break;
case Button3:
btn = Qt::MouseButton::RightButton;
break;
case XButton_1:
btn = Qt::MouseButton::XButton1;
break;
case XButton_2:
btn = Qt::MouseButton::XButton2;
break;
}
emit buttonRelease(btn, event->u.keyButtonPointer.rootX,
event->u.keyButtonPointer.rootY);
}
break;
case KeyPress: {
auto code = data->data[1];
switch (code) {
case 50:
case 62:
keyModifier = Qt::ShiftModifier;
break;
case 37:
case 105:
keyModifier = Qt::ControlModifier;
break;
case 64:
case 108:
keyModifier = Qt::AltModifier;
break;
case 133:
keyModifier = Qt::MetaModifier;
break;
default:
break;
}
} break;
case KeyRelease:
keyModifier = Qt::NoModifier;
break;
default:
break;
}
}
fflush(stdout);
XRecordFreeData(data);
}
bool EventMonitor::handleWheelEvent(int detail) {
MouseWheel wheel = MouseWheel::None;
switch (detail) {
case WheelUp:
wheel = MouseWheel::Up;
break;
case WheelDown:
wheel = MouseWheel::Down;
break;
case WheelLeft:
wheel = MouseWheel::Left;
break;
case WheelRight:
wheel = MouseWheel::Right;
break;
default:
return true;
}
emit mouseWheel(wheel);
return false;
}