2#include <QGuiApplication>
10#elif defined(__linux__)
12#include <X11/extensions/XInput2.h>
13#include <sys/select.h>
18 : mouseCallback(
std::move(callback)) {}
23 if (x11Thread.joinable()) {
31 if (eventType !=
"windows_generic_MSG")
34 MSG* msg =
static_cast<MSG*
>(message);
36 if (!initialized && msg->hwnd) {
37 registerRawInput(msg->hwnd);
41 if (msg->message == WM_INPUT) {
43 GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT,
nullptr, &dataSize,
sizeof(RAWINPUTHEADER));
44 std::vector<BYTE> buffer(dataSize);
45 if (GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, buffer.data(), &dataSize,
sizeof(RAWINPUTHEADER)) != dataSize)
48 RAWINPUT* raw =
reinterpret_cast<RAWINPUT*
>(buffer.data());
49 if (raw->header.dwType == RIM_TYPEMOUSE) {
50 if ((raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) == 0) {
51 int dx = raw->data.mouse.lLastX;
52 int dy = raw->data.mouse.lLastY;
53 if (mouseCallback) mouseCallback(dx, dy);
58#elif defined(__linux__)
67#elif defined(__APPLE__)
79void RawInputFilter::registerRawInput(HWND hwnd) {
81 rid.usUsagePage = 0x01;
83 rid.dwFlags = RIDEV_INPUTSINK;
84 rid.hwndTarget = hwnd;
86 if (!RegisterRawInputDevices(&rid, 1,
sizeof(rid))) {
87 std::cerr <<
"RawInputFilter: Failed to register raw input device\n";
89 std::cout <<
"RawInputFilter: Registered raw mouse input on window handle" << std::endl;
92#elif defined(__linux__)
93void RawInputFilter::registerRawInput() {
94 x11Thread = std::thread([
this]() {
95 Display* dpy = XOpenDisplay(
nullptr);
99 if (!XQueryExtension(dpy,
"XInputExtension", &xi_opcode, &event, &error)) {
100 std::cerr <<
"RawInputFilter: XInput extension not available.\n";
105 Window root = DefaultRootWindow(dpy);
107 unsigned char mask[(XI_LASTEVENT + 7)/8] = { 0 };
109 evmask.deviceid = XIAllMasterDevices;
110 evmask.mask_len =
sizeof(mask);
112 XISetMask(mask, XI_RawMotion);
114 XISelectEvents(dpy, root, &evmask, 1);
117 int fd = ConnectionNumber(dpy);
121 while (runX11Thread) {
127 if (select(fd + 1, &in_fds,
nullptr,
nullptr, &tv) > 0) {
128 while (XPending(dpy)) {
130 XNextEvent(dpy, &ev);
132 if (ev.xcookie.type == GenericEvent && ev.xcookie.extension == xi_opcode) {
133 if (XGetEventData(dpy, &ev.xcookie)) {
134 if (ev.xcookie.evtype == XI_RawMotion) {
135 XIRawEvent* raw = (XIRawEvent*)ev.xcookie.data;
136 double dx = 0.0, dy = 0.0;
137 double* values = raw->raw_values;
139 if (XIMaskIsSet(raw->valuators.mask, 0)) {
143 if (XIMaskIsSet(raw->valuators.mask, 1)) {
147 if (mouseCallback && (dx != 0.0 || dy != 0.0)) {
148 int idx =
static_cast<int>(dx);
149 int idy =
static_cast<int>(dy);
150 QMetaObject::invokeMethod(qApp, [
this, idx, idy]() {
151 mouseCallback(idx, idy);
152 }, Qt::QueuedConnection);
155 XFreeEventData(dpy, &ev.xcookie);
163 std::cout <<
"RawInputFilter: Registered XInput2 raw mouse on background thread.\n";
Hash specialization for Vertex to enable use in unordered containers.