diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 7936e3a42..cb25cc4d4 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -110,6 +110,13 @@ target_link_libraries( if (UNIX AND NOT APPLE) find_package(X11 REQUIRED) target_link_libraries(ui PRIVATE X11::X11) + find_package(PkgConfig REQUIRED) + pkg_check_modules(LIBEVDEV IMPORTED_TARGET libevdev) + if (LIBEVDEV_FOUND) + target_compile_definitions(ui PRIVATE EVDEV_INPUT) + target_link_libraries(ui PUBLIC PkgConfig::LIBEVDEV) + target_sources(ui PRIVATE evdev_mouse.cpp) + endif() find_package(ECM NO_MODULE) if (ECM_FOUND) diff --git a/src/qt/evdev_mouse.cpp b/src/qt/evdev_mouse.cpp new file mode 100644 index 000000000..cb4cd4ffe --- /dev/null +++ b/src/qt/evdev_mouse.cpp @@ -0,0 +1,102 @@ +#include "evdev_mouse.hpp" +#include +#include +#include + +#include +#include +#include +#include + +#include + +extern "C" +{ +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/mouse.h> +} + +static std::vector> evdev_mice; +static std::atomic stopped = false; +static QThread* evdev_thread; + +static std::atomic evdev_mouse_rel_x = 0, evdev_mouse_rel_y = 0; + +void evdev_mouse_poll() +{ + if (!evdev_mice.size() || !mouse_capture) + { + evdev_mouse_rel_x = 0; + evdev_mouse_rel_y = 0; + return; + } + mouse_x = evdev_mouse_rel_x; + mouse_y = evdev_mouse_rel_y; + evdev_mouse_rel_x = evdev_mouse_rel_y = 0; +} + +void evdev_thread_func() +{ + while (!stopped) + { + for (int i = 0; i < evdev_mice.size(); i++) + { + struct input_event ev; + int rc = libevdev_next_event(evdev_mice[i].second, LIBEVDEV_READ_FLAG_NORMAL, &ev); + if (rc == 0 && ev.type == EV_REL && mouse_capture) + { + if (ev.code == REL_X) evdev_mouse_rel_x += ev.value; + if (ev.code == REL_Y) evdev_mouse_rel_y += ev.value; + } + } + } + for (int i = 0; i < evdev_mice.size(); i++) + { + libevdev_free(evdev_mice[i].second); + close(evdev_mice[i].first); + } + evdev_mice.clear(); +} + +void evdev_stop() +{ + stopped = true; + evdev_thread->wait(); +} + +void evdev_init() +{ + for (int i = 0; i < 256; i++) + { + std::string evdev_device_path = "/dev/input/event" + std::to_string(i); + int fd = open(evdev_device_path.c_str(), O_NONBLOCK | O_RDONLY); + if (fd != -1) + { + libevdev* input_struct = nullptr; + int rc = libevdev_new_from_fd(fd, &input_struct); + if (rc <= -1) + { + close(fd); + continue; + } + else + { + if (!libevdev_has_event_type(input_struct, EV_REL) || !libevdev_has_event_code(input_struct, EV_KEY, BTN_LEFT)) + { + libevdev_free(input_struct); + close(fd); + continue; + } + evdev_mice.push_back(std::make_pair(fd, input_struct)); + } + } + else if (errno == ENOENT) break; + } + if (evdev_mice.size() != 0) + { + evdev_thread = QThread::create(evdev_thread_func); + evdev_thread->start(); + atexit(evdev_stop); + } +} diff --git a/src/qt/evdev_mouse.hpp b/src/qt/evdev_mouse.hpp new file mode 100644 index 000000000..7681771c6 --- /dev/null +++ b/src/qt/evdev_mouse.hpp @@ -0,0 +1,4 @@ +#ifdef EVDEV_INPUT +void evdev_init(); +void evdev_mouse_poll(); +#endif diff --git a/src/qt/qt_hardwarerenderer.hpp b/src/qt/qt_hardwarerenderer.hpp index 3a47c6284..916e52141 100644 --- a/src/qt/qt_hardwarerenderer.hpp +++ b/src/qt/qt_hardwarerenderer.hpp @@ -30,12 +30,6 @@ public: : QOpenGLWidget(parent), QOpenGLFunctions() { setMinimumSize(16, 16); -#ifdef WAYLAND - if (QApplication::platformName().contains("wayland")) { - wayland = true; - wl_init(); - } -#endif } ~HardwareRenderer() { diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index b1c1bde5f..fed414d12 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -4,6 +4,8 @@ #include "qt_softwarerenderer.hpp" #include "qt_hardwarerenderer.hpp" +#include "evdev_mouse.hpp" + #include #ifdef __APPLE__ @@ -25,6 +27,16 @@ RendererStack::RendererStack(QWidget *parent) : imagebufs = QVector(2); imagebufs[0] = QImage{QSize(2048 + 64, 2048 + 64), QImage::Format_RGB32}; imagebufs[1] = QImage{QSize(2048 + 64, 2048 + 64), QImage::Format_RGB32}; +#ifdef WAYLAND + if (QApplication::platformName().contains("wayland")) { + wl_init(); + } +#endif +#ifdef EVDEV_INPUT + if (QApplication::platformName() == "xcb" || QApplication::platformName() == "eglfs") { + evdev_init(); + } +#endif } RendererStack::~RendererStack() @@ -67,6 +79,9 @@ void RendererStack::mousePoll() if (QApplication::platformName().contains("wayland")) wl_mouse_poll(); #endif +#ifdef EVDEV_INPUT + evdev_mouse_poll(); +#endif #endif }