213 lines
5.6 KiB
C++
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;
|
|
}
|