diff options
author | Stephen Hurd <deuce@synchro.net> | 2022-01-29 07:45:27 +0300 |
---|---|---|
committer | supermerill <merill@free.fr> | 2022-02-13 22:29:00 +0300 |
commit | 2b908bc196b4a71cd4c49f16a8283a34924babc7 (patch) | |
tree | 28ef5d774838c60745df916e4be329f0cb4c3fe9 | |
parent | 8f03c8de4e113c2250af48e22897339d564b8fdb (diff) |
Add support for libspnav
When using a 3DXonnexion mouse on Linux or FreeBSD systems, USB
HID mode is being used. This means only one program can be running
at a time with Space Mouse support, and potentially means permissions
issues for USB devices.
This patch uses libspnav if available to avoid these issues. This
also has the advantage of not relying on the device driver to be
updated in Slic3r/Prusa Slicer/Super Slicer whenever a new device
is supported.
-rw-r--r-- | CMakeLists.txt | 15 | ||||
-rw-r--r-- | src/slic3r/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/slic3r/GUI/Mouse3DController.cpp | 74 |
3 files changed, 92 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 00c7e171f..23ec0717c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -475,6 +475,21 @@ if(OpenVDB_FOUND) slic3r_remap_configs(Blosc::blosc RelWithDebInfo Release) endif() +find_path(SPNAV_INCLUDE_DIR spnav.h) +if (SPNAV_INCLUDE_DIR) + find_library(HAVE_SPNAV spnav) + if (HAVE_SPNAV) + add_definitions(-DHAVE_SPNAV) + add_library(libspnav SHARED IMPORTED) + target_link_libraries(libspnav INTERFACE spnav) + message(STATUS "SPNAV library found") + else() + message(STATUS "SPNAV library NOT found, Spacenavd not supported") + endif() +else() + message(STATUS "SPNAV library NOT found, Spacenavd not supported") +endif() + set(TOP_LEVEL_PROJECT_DIR ${PROJECT_SOURCE_DIR}) function(prusaslicer_copy_dlls target) if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 3beacae68..4824f8541 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -283,6 +283,10 @@ if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE) endif () +if (HAVE_SPNAV) + target_link_libraries(libslic3r_gui spnav) +endif() + # We need to implement some hacks for wxWidgets and touch the underlying GTK # layer and sub-libraries. This forces us to use the include locations and # link these libraries. diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index fb14d9676..8afe49253 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -17,7 +17,9 @@ #include <bitset> //unofficial linux lib -//#include <spnav.h> +#ifdef HAVE_SPNAV +#include <spnav.h> +#endif // WARN: If updating these lists, please also update resources/udev/90-3dconnexion.rules @@ -709,6 +711,31 @@ void Mouse3DController::shutdown() // Main routine of the worker thread. void Mouse3DController::run() { +#ifdef HAVE_SPNAV + if (spnav_open() == -1) { + // Give up. + BOOST_LOG_TRIVIAL(error) << "Unable to open connection to spacenavd"; + return; + } + m_connected = true; + + for (;;) { + { + std::scoped_lock lock(m_params_ui_mutex); + if (m_stop) + break; + if (m_params_ui_changed) { + m_params = m_params_ui; + m_params_ui_changed = false; + } + } + this->collect_input(); + } + + m_connected = false; + // Finalize the spnav library + spnav_close(); +#else // Initialize the hidapi library int res = hid_init(); if (res != 0) { @@ -753,6 +780,7 @@ void Mouse3DController::run() // Finalize the hidapi library hid_exit(); +#endif } bool Mouse3DController::connect_device() @@ -1042,8 +1070,51 @@ void Mouse3DController::disconnect_device() } } +// Convert a signed 16bit word from a 3DConnexion mouse HID packet into a double coordinate, apply a dead zone. +static double convert_spnav_input(int value) +{ + return (double)value/100; +} + void Mouse3DController::collect_input() { +#ifdef HAVE_SPNAV + // Read packet, block maximum 100 ms. That means when closing the application, closing the application will be delayed by 100 ms. + int fd = spnav_fd(); + + if (fd != -1) { + fd_set fds; + struct timeval tv = {.tv_sec = 0, .tv_usec = 100000}; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + if (select(fd + 1, &fds, NULL, NULL, &tv) == 1) { + spnav_event ev = {}; + switch (spnav_poll_event(&ev)) { + case SPNAV_EVENT_MOTION: { + Vec3d translation(-convert_spnav_input(ev.motion.x), convert_spnav_input(ev.motion.y), -convert_spnav_input(ev.motion.z)); + if (!translation.isApprox(Vec3d::Zero())) { +std::cout << "Motion: X: " << ev.motion.x << ", Y: " << ev.motion.y << ", Z: " << ev.motion.z << std::endl; + m_state.append_translation(translation, m_params.input_queue_max_size); + } + Vec3f rotation(convert_spnav_input(ev.motion.rx), convert_spnav_input(ev.motion.ry), -convert_spnav_input(ev.motion.rz)); + if (!rotation.isApprox(Vec3f::Zero())) { +std::cout << "Motion: rX: " << ev.motion.rx << ", rY: " << ev.motion.ry << ", rZ: " << ev.motion.rz << std::endl; + m_state.append_rotation(rotation, m_params.input_queue_max_size); + } + break; + } + case SPNAV_EVENT_BUTTON: + if (ev.button.press) + m_state.append_button((unsigned int)ev.button.bnum, m_params.input_queue_max_size); + break; + } + wxGetApp().plater()->set_current_canvas_as_dirty(); + // ask for an idle event to update 3D scene + wxWakeUpIdle(); + } + } +#else DataPacketRaw packet = { 0 }; // Read packet, block maximum 100 ms. That means when closing the application, closing the application will be delayed by 100 ms. int res = hid_read_timeout(m_device, packet.data(), packet.size(), 100); @@ -1052,6 +1123,7 @@ void Mouse3DController::collect_input() this->disconnect_device(); } else this->handle_input(packet, res, m_params, m_state); +#endif } #ifdef _WIN32 |