diff --git a/src/Gui/3Dconnexion/GuiNativeEventLinux.cpp b/src/Gui/3Dconnexion/GuiNativeEventLinux.cpp index c8e1eef835..e88db5f8e6 100644 --- a/src/Gui/3Dconnexion/GuiNativeEventLinux.cpp +++ b/src/Gui/3Dconnexion/GuiNativeEventLinux.cpp @@ -21,17 +21,70 @@ ***************************************************************************/ #include +#include +#include +#include +#include #include "GuiNativeEventLinux.h" #include "GuiApplicationNativeEventAware.h" #include +#include #include #include #include +// Cached per-axis deadzone values, auto-updated via Observer when user.cfg changes. +class Gui::DeadzoneCache: public ParameterGrp::ObserverType +{ +public: + static constexpr std::array keys = { + "PanLRDeadzone", + "PanUDDeadzone", + "ZoomDeadzone", + "TiltDeadzone", + "RollDeadzone", + "SpinDeadzone", + }; + + std::array values {}; + + explicit DeadzoneCache(ParameterGrp::handle hGrp) + : hGrp(std::move(hGrp)) + { + loadAll(); + this->hGrp->Attach(this); + } + + ~DeadzoneCache() override + { + hGrp->Detach(this); + } + + void OnChange(ParameterGrp::SubjectType& /*rCaller*/, ParameterGrp::MessageType reason) override + { + for (size_t i = 0; i < keys.size(); i++) { + if (std::strcmp(reason, keys[i]) == 0) { + values[i] = static_cast(hGrp->GetInt(keys[i], 0)); + return; + } + } + } + +private: + void loadAll() + { + for (size_t i = 0; i < keys.size(); i++) { + values[i] = static_cast(hGrp->GetInt(keys[i], 0)); + } + } + + ParameterGrp::handle hGrp; +}; + Gui::GuiNativeEvent::GuiNativeEvent(Gui::GUIApplicationNativeEventAware* app) : GuiAbstractNativeEvent(app) {} @@ -60,6 +113,9 @@ void Gui::GuiNativeEvent::initSpaceball(QMainWindow* window) QSocketNotifier* SpacenavNotifier = new QSocketNotifier(spnav_fd(), QSocketNotifier::Read, this); connect(SpacenavNotifier, SIGNAL(activated(int)), this, SLOT(pollSpacenav())); + dzCache = std::make_unique( + App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Spaceball/Motion") + ); mainApp->setSpaceballPresent(true); } } @@ -67,6 +123,7 @@ void Gui::GuiNativeEvent::initSpaceball(QMainWindow* window) void Gui::GuiNativeEvent::pollSpacenav() { spnav_event ev; + bool hasMotion = false; while (spnav_poll_event(&ev)) { switch (ev.type) { case SPNAV_EVENT_MOTION: { @@ -76,7 +133,7 @@ void Gui::GuiNativeEvent::pollSpacenav() motionDataArray[3] = -ev.motion.rx; motionDataArray[4] = -ev.motion.rz; motionDataArray[5] = -ev.motion.ry; - mainApp->postMotionEvent(motionDataArray); + hasMotion = true; break; } case SPNAV_EVENT_BUTTON: { @@ -85,6 +142,19 @@ void Gui::GuiNativeEvent::pollSpacenav() } } } + if (hasMotion) { + // Per-axis deadzone: zero out axes below their individual threshold. + // Values cached and auto-updated via Observer when user.cfg changes. + if (dzCache) { + for (size_t i = 0; i < dzCache->values.size(); i++) { + int dz = dzCache->values[i]; + if (dz > 0 && std::abs(motionDataArray[i]) < dz) { + motionDataArray[i] = 0; + } + } + } + mainApp->postMotionEvent(motionDataArray); + } } #include "3Dconnexion/moc_GuiNativeEventLinux.cpp" diff --git a/src/Gui/3Dconnexion/GuiNativeEventLinux.h b/src/Gui/3Dconnexion/GuiNativeEventLinux.h index adcb4a4929..27ced02165 100644 --- a/src/Gui/3Dconnexion/GuiNativeEventLinux.h +++ b/src/Gui/3Dconnexion/GuiNativeEventLinux.h @@ -23,12 +23,14 @@ #pragma once #include "GuiAbstractNativeEvent.h" +#include class QMainWindow; namespace Gui { class GUIApplicationNativeEventAware; +class DeadzoneCache; class GuiNativeEvent: public GuiAbstractNativeEvent { @@ -42,6 +44,9 @@ private: GuiNativeEvent(); GuiNativeEvent(const GuiNativeEvent&); GuiNativeEvent& operator=(const GuiNativeEvent&); + + std::unique_ptr dzCache; + private Q_SLOTS: void pollSpacenav(); }; diff --git a/src/Gui/Navigation/NavigationStyle.cpp b/src/Gui/Navigation/NavigationStyle.cpp index 22bdec6be8..a3a6e10156 100644 --- a/src/Gui/Navigation/NavigationStyle.cpp +++ b/src/Gui/Navigation/NavigationStyle.cpp @@ -1934,9 +1934,14 @@ SbBool NavigationStyle::processMotionEvent(const SoMotion3Event* const ev) newRotation.multVec(SbVec3f(0.0, 0.0, -1.0), newDirection); newPosition = center - (newDirection * camera->focalDistance.getValue()); + newRotation.multVec(dir, dir); + SbVec3f finalPosition = newPosition + (dir * translationFactor); + + camera->enableNotify(false); camera->orientation.setValue(newRotation); - camera->orientation.getValue().multVec(dir, dir); - camera->position = newPosition + (dir * translationFactor); + camera->position = finalPosition; + camera->enableNotify(true); + camera->touch(); return true; }