From 7ccc77743e4093968fef15fbcc213a5239be7690 Mon Sep 17 00:00:00 2001 From: ruevs Date: Tue, 20 Feb 2024 18:54:29 +0200 Subject: [PATCH] SpaceMouse: libspnavdev works with older USB devices. Initialize `spndev_event ev = {};` so that older USB devices where the translation and rotation are in separate HID reports work properly. Before they caused "wild" movement rotation due to half the members of the structure being uninitialized. Add the axis scaling factor to the AxisData structure. Remap the axis (swap Y and Z and invert Y) so that the movement of the model matches the movement of the "hat" on the 3Dconnexion device. --- .gitmodules | 2 +- extlib/libspnavdev | 2 +- src/platform/spnavdevice.cpp | 69 ++++++++++++++++++++++++++++-------- src/platform/spnavdevice.h | 3 +- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/.gitmodules b/.gitmodules index 309c87fe6..8d3d8aef9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,4 +28,4 @@ url = https://gitlab.com/libeigen/eigen.git [submodule "extlib/libspnavdev"] path = extlib/libspnavdev - url = https://github.com/rpavlik/libspnavdev.git + url = https://github.com/ruevs/libspnavdev.git diff --git a/extlib/libspnavdev b/extlib/libspnavdev index 69f892568..143b4bd95 160000 --- a/extlib/libspnavdev +++ b/extlib/libspnavdev @@ -1 +1 @@ -Subproject commit 69f892568b7b69120d52a0a4c49faa02d4ddd830 +Subproject commit 143b4bd95cecc8d77ad9f3a2ed170ccf22867580 diff --git a/src/platform/spnavdevice.cpp b/src/platform/spnavdevice.cpp index 911d2a291..e3a8d71ca 100644 --- a/src/platform/spnavdevice.cpp +++ b/src/platform/spnavdevice.cpp @@ -35,11 +35,11 @@ static double transformIndex(union spndev_event const& ev, if(axisData.spnavdevIndex < 0) { return 0; } - return double(ev.mot.v[axisData.spnavdevIndex]); + return double(ev.mot.v[axisData.spnavdevIndex])*axisData.scale; } bool NavDeviceWrapper::process(SolveSpace::Platform::SixDofEvent& event) { using SolveSpace::Platform::SixDofEvent; - union spndev_event ev; + union spndev_event ev = {}; if(0 == spndev_process(dev, &ev)) { return false; } @@ -55,9 +55,9 @@ bool NavDeviceWrapper::process(SolveSpace::Platform::SixDofEvent& event) { event.translationX = transformIndex(ev, axes[0]); event.translationY = transformIndex(ev, axes[1]); event.translationZ = transformIndex(ev, axes[2]); - event.rotationX = transformIndex(ev, axes[3]) * 0.001; - event.rotationY = transformIndex(ev, axes[4]) * 0.001; - event.rotationZ = transformIndex(ev, axes[5]) * 0.001; + event.rotationX = transformIndex(ev, axes[3]); + event.rotationY = transformIndex(ev, axes[4]); + event.rotationZ = transformIndex(ev, axes[5]); return true; case SPNDEV_BUTTON: { if(ev.bn.num >= buttons.size()) { @@ -93,18 +93,57 @@ bool NavDeviceWrapper::process(SolveSpace::Platform::SixDofEvent& event) { } void NavDeviceWrapper::populateAxes() { + // This array remaps the axis and their directions/scaling, so that they match what the standard + // 3Dconnexion driver outputs. In this way SolveSpace will control the object "properly". The + // array may not be requiered if it turns out that all devices use the same axis orientation and + // have similar sensitivities, but it is better if we test them. The ones that are already + // tested and working are marked. + // See also: https://github.com/FreeSpacenav/spacenavd/blob/master/src/dev.c#L38 + const struct { + const std::wstring name; + const std::string axis_names[6]; + const double axis_scale[6]; + } axisRemap[] = { + {L"SpaceMouse Plus XT USB" , {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"CadMan USB", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, // Tested + {L"SpaceMouse Classic USB", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpaceBall 5000 USB", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, // Tested + {L"SpaceTraveler USB", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, // Tested + {L"SpacePilot", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, // Tested + {L"SpaceNavigator", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, // Tested + {L"SpaceExplorer", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, // Tested + {L"SpaceNavigator for Notebooks", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpacePilot Pro", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpaceMouse Pro", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"NuLOOQ", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"LIPARI", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpaceMouse Wireless (cabled)", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpaceMouse Wireless Receiver", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpaceMouse Pro Wireless (cabled)", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpaceMouse Pro Wireless Receiver", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpaceMouse Enterprise", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpaceMouse Compact", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpaceMouse Module", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + {L"SpaceMouse Universal Receiver", {"Tx", "Tz", "Ty", "Rx", "Rz", "Ry"}, {1.0, 1.0, -1.0, .001, .001, -.001}}, + }; + using std::begin; using std::end; - const std::string axis_names[] = {"Tx", "Ty", "Tz", "Rx", "Ry", "Rz"}; - const auto b = begin(axis_names); - const auto e = end(axis_names); - const auto num_axes = spndev_num_axes(dev); - for(int axis_idx = 0; axis_idx < num_axes; ++axis_idx) { - auto axis_name = spndev_axis_name(dev, axis_idx); - auto it = std::find_if(b, e, [&](std::string const& name) { return name == axis_name; }); - if(it != e) { - ptrdiff_t remapped_index = std::distance(b, it); - axes[remapped_index] = AxisData{axis_idx}; + + auto da = std::find_if(begin(axisRemap), end(axisRemap), + [&](auto const& devaxis) { return devaxis.name == (wchar_t *)spndev_name(dev); }); + + if(da != end(axisRemap)) { + const auto b = begin(da->axis_names); + const auto e = end(da->axis_names); + const auto num_axes = spndev_num_axes(dev); + for(int axis_idx = 0; axis_idx < num_axes; ++axis_idx) { + auto axis_name = spndev_axis_name(dev, axis_idx); + auto it = std::find_if(b, e, [&](std::string const& name) { return name == axis_name; }); + if(it != e) { + ptrdiff_t remapped_index = std::distance(b, it); + axes[remapped_index] = AxisData{axis_idx, da->axis_scale[axis_idx]}; + } } } } diff --git a/src/platform/spnavdevice.h b/src/platform/spnavdevice.h index b358a6555..42323710b 100644 --- a/src/platform/spnavdevice.h +++ b/src/platform/spnavdevice.h @@ -42,10 +42,11 @@ class NavDeviceWrapper { }; struct AxisData { AxisData() = default; - AxisData(int spnavdevIndex_) : spnavdevIndex(spnavdevIndex_) { + AxisData(int spnavdevIndex_, double scale_) : spnavdevIndex(spnavdevIndex_), scale(scale_) { } int spnavdevIndex = -1; + double scale = 1.; }; private: