diff --git a/cMake/FreeCAD_Helpers/InitializeFreeCADBuildOptions.cmake b/cMake/FreeCAD_Helpers/InitializeFreeCADBuildOptions.cmake
index 5f67283a7e..297492fc6c 100644
--- a/cMake/FreeCAD_Helpers/InitializeFreeCADBuildOptions.cmake
+++ b/cMake/FreeCAD_Helpers/InitializeFreeCADBuildOptions.cmake
@@ -138,6 +138,11 @@ macro(InitializeFreeCADBuildOptions)
option(BUILD_CLOUD "Build the FreeCAD cloud module" OFF)
option(ENABLE_DEVELOPER_TESTS "Build the FreeCAD unit tests suit" ON)
+ if(MSVC)
+ set(FREECAD_3CONNEXION_SUPPORT "NavLib" CACHE STRING "Select version of the 3Dconnexion device integration")
+ set_property(CACHE FREECAD_3CONNEXION_SUPPORT PROPERTY STRINGS "NavLib" "SpNav")
+ endif(MSVC)
+
if(MSVC)
option(BUILD_FEM_NETGEN "Build the FreeCAD FEM module with the NETGEN mesher" ON)
option(FREECAD_USE_PCL "Build the features that use PCL libs" OFF) # 3/5/2021 current LibPack uses non-C++17 FLANN
@@ -157,6 +162,11 @@ macro(InitializeFreeCADBuildOptions)
option(FREECAD_USE_PCL "Build the features that use PCL libs" OFF)
endif(NOT MSVC)
+ if(FREECAD_3CONNEXION_SUPPORT STREQUAL "NavLib" AND FREECAD_USE_3DCONNEXION)
+ set(FREECAD_USE_3DCONNEXION_NAVLIB ON)
+ set(FREECAD_USE_3DCONNEXION OFF)
+ endif()
+
# if this is set override some options
if (FREECAD_BUILD_DEBIAN)
set(FREECAD_USE_EXTERNAL_ZIPIOS ON )
diff --git a/cMake/FreeCAD_Helpers/PrintFinalReport.cmake b/cMake/FreeCAD_Helpers/PrintFinalReport.cmake
index 52c1d1e22c..70cb84edef 100644
--- a/cMake/FreeCAD_Helpers/PrintFinalReport.cmake
+++ b/cMake/FreeCAD_Helpers/PrintFinalReport.cmake
@@ -166,7 +166,13 @@ macro(PrintFinalReport)
simple(Coin3D "${COIN3D_VERSION} [${COIN3D_LIBRARIES}] [${COIN3D_INCLUDE_DIRS}]")
simple(pivy ${PIVY_VERSION})
if (WIN32)
- #simple(SPNAV "not available yet for your OS") # FREECAD_USE_3DCONNEXION instead...
+ if (FREECAD_USE_3DCONNEXION)
+ simple(3Dconnexion "Building 3Dconnexion support with original code")
+ elseif(FREECAD_USE_3DCONNEXION_NAVLIB)
+ simple(3Dconnexion "Building 3Dconnexion support with NavLib")
+ else()
+ simple(3Dconnexion "Not building 3Dconnexion device support")
+ endif()
else()
conditional(SPNAV SPNAV_FOUND "not found" "[${SPNAV_LIBRARY}] [${SPNAV_INCLUDE_DIR}]")
endif()
diff --git a/src/3rdParty/3Dconnexion/README.txt b/src/3rdParty/3Dconnexion/README.txt
new file mode 100644
index 0000000000..894bd0bcd0
--- /dev/null
+++ b/src/3rdParty/3Dconnexion/README.txt
@@ -0,0 +1,3 @@
+This directory contains part of the the 3Dconnexion 3DxWare_SDK v4
+The full sdk can be obtained from https://3dconnexion.com/software-developer-program/
+
diff --git a/src/3rdParty/3Dconnexion/inc/SpaceMouse/CActionInput.hpp b/src/3rdParty/3Dconnexion/inc/SpaceMouse/CActionInput.hpp
new file mode 100644
index 0000000000..99a8142fa2
--- /dev/null
+++ b/src/3rdParty/3Dconnexion/inc/SpaceMouse/CActionInput.hpp
@@ -0,0 +1,336 @@
+#ifndef CInputAction_HPP_INCLUDED
+#define CInputAction_HPP_INCLUDED
+//
+// ------------------------------------------------------------------------------------------------
+// This file is part of the FreeCAD CAx development system.
+//
+// Copyright (c) 2014-2023 3Dconnexion.
+//
+// This source code is released under the GNU Library General Public License, (see "LICENSE").
+// ------------------------------------------------------------------------------------------------
+//
+//
+// ************************************************************************************************
+// File History
+//
+// $Id: CNavigation3D.hpp 16056 2019-04-10 13:42:31Z mbonk $
+//
+//
+
+// SpaceMouse
+#include
+#include
+#include
+#include
+#include
+#include
+
+// stdlib
+#include
+#include
+#include
+
+// navlib
+#include
+#include
+
+namespace TDx {
+namespace SpaceMouse {
+///
+/// Contains types that support 3Dconnexion SpaceMouse input action interface.
+///
+namespace ActionInput {
+///
+/// The base class for 3D navigation implements defaults for the interface.
+///
+/// This class can be used as the base class for the application specific implementation of
+/// the accessors.
+class CActionInput : public Navigation3D::INavlibProperty, protected IActionAccessors {
+public:
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Allow multithreading.
+ /// Set multithreaded to true for a windows console application. If the application
+ /// requires that the callbacks are executed on the main thread, either leave as false, or marshall
+ /// the callbacks back to the main thread.
+ CActionInput(bool multiThreaded = false)
+ : m_enabled(false), m_pImpl(CActionInputImpl::CreateInstance(this, multiThreaded)) {
+ }
+
+#if defined(_MSC_EXTENSIONS)
+ ///
+ /// Gets or sets a value indicating whether the connection to the input device is enabled.
+ ///
+ __declspec(property(get = IsEnabled, put = PutEnable)) bool Enable;
+
+ ///
+ /// Gets or sets the text to pass to the 3Dconnexion driver to use in Properties Utility.
+ ///
+ /// If the connection to the navlib is already open, the connection is closed and
+ /// reopened.
+ __declspec(property(get = GetProfileHint, put = PutProfileHint)) std::string Profile;
+
+ ///
+ /// Gets or sets a value representing the active command set.
+ ///
+ ///
+ __declspec(property(get = GetActiveCommands, put = PutActiveCommands)) std::string ActiveCommands;
+
+#endif
+
+ ///
+ /// Gets a value indicating whether action interface is enabled.
+ ///
+ /// true if enabled, otherwise false.
+ bool IsEnabled() const {
+ return m_enabled;
+ }
+
+ ///
+ /// Sets a value indicating whether the action interface is enabled.
+ ///
+ /// true to enable, false to disable.
+ /// The text for the '3Dconnexion Properties' is
+ /// empty.
+ /// Cannot create a connection to the library.
+ void PutEnable(bool value) {
+ if (m_enabled == value) {
+ return;
+ }
+ if (value) {
+ m_pImpl->Open(m_profileHint);
+ m_enabled = true;
+ } else {
+ m_pImpl->Close();
+ m_enabled = false;
+ }
+ }
+
+ ///
+ /// Sets a value indicating whether the action interface is enabled.
+ ///
+ /// true to enable, false to disable.
+ /// The contains the error if something goes
+ /// wrong.
+ /// The text for the '3Dconnexion Properties' is
+ /// empty.
+ /// Cannot create a connection to the library.
+ void PutEnable(bool value, std::error_code &ec) NOEXCEPT {
+ try {
+ PutEnable(value);
+ }
+#if defined(_DEBUG) && defined(TRACE_NAVLIB)
+ catch (const std::system_error &e) {
+ ec = e.code();
+ std::cerr << "system_error exception thrown in EnableNavigation(" << value << ") 0x"
+ << std::hex << ec.value() << std::dec << ", " << ec.message() << ", " << e.what()
+ << "\n";
+ } catch (const std::invalid_argument &e) {
+ ec = std::make_error_code(std::errc::invalid_argument);
+ std::cerr << "invalid_argument exception thrown in EnableNavigation(" << value << ") 0x"
+ << std::hex << ec.value() << std::dec << ", " << ec.message() << ", " << e.what()
+ << "\n";
+ } catch (const std::exception &e) {
+ ec = std::make_error_code(std::errc::io_error);
+ std::cerr << "exception thrown in EnableNavigation(" << value << ") 0x" << std::hex
+ << ec.value() << std::dec << ", " << ec.message() << ", " << e.what() << "\n";
+ }
+#else
+ catch (const std::system_error &e) {
+ ec = e.code();
+ } catch (const std::invalid_argument &) {
+ ec = std::make_error_code(std::errc::invalid_argument);
+ } catch (const std::exception &) {
+ ec = std::make_error_code(std::errc::io_error);
+ }
+#endif
+ }
+
+ ///
+ /// Gets or sets the text to pass to the 3Dconnexion driver to use in Properties Utility.
+ ///
+ /// If the connection to the navlib is already open, the connection is closed and
+ /// reopened.
+ std::string GetProfileHint() const {
+ return m_profileHint;
+ }
+ void PutProfileHint(std::string const &value) {
+ if (m_profileHint != value) {
+ m_profileHint = value;
+ if (IsEnabled()) {
+ PutEnable(false);
+ PutEnable(true);
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets a value representing the active command set.
+ ///
+ ///
+ std::string GetActiveCommands() const {
+ std::string result;
+ long error = m_pImpl->Read(navlib::commands_activeSet_k, result);
+ if (error != 0) {
+ throw std::system_error(make_error_code(error));
+ }
+ return result;
+ }
+ void PutActiveCommands(const std::string &id) {
+ long error = m_pImpl->Write(navlib::commands_activeSet_k, id);
+ if (error != 0) {
+ throw std::system_error(make_error_code(error));
+ }
+ }
+
+ ///
+ /// Add commands to the sets of commands.
+ ///
+ /// The to add.
+ ///
+ void AddCommands(const CCommandTree &commands) {
+ const SiActionNodeEx_t *pnode = &commands.GetSiActionNode();
+ long error = m_pImpl->Write(navlib::commands_tree_k, pnode);
+ if (error != 0) {
+ throw std::system_error(make_error_code(error));
+ }
+ }
+
+ ///
+ /// Add a set of commands to the sets of commands.
+ ///
+ /// The to add.
+ ///
+ void AddCommandSet(const CCommandSet &commands) {
+ AddCommands(commands);
+ }
+
+ ///
+ /// Add to the images available to the 3Dconnexion properties utility.
+ ///
+ /// The container containing the images to
+ /// add.
+ ///
+ template
+ void AddImages(const std::vector &images,
+ typename std::enable_if::value &&
+ sizeof(T) == sizeof(SiImage_t)>::type * = nullptr) {
+ long error;
+ navlib::imagearray_t imagearray = {images.data(), images.size()};
+ error = m_pImpl->Write(navlib::images_k, imagearray);
+ if (error != 0) {
+ throw std::system_error(make_error_code(error));
+ }
+ }
+
+ ///
+ /// Add to the images available to the 3Dconnexion properties utility.
+ ///
+ /// The container containing the images to
+ /// add.
+ ///
+ template
+ void
+ AddImages(const std::vector &images,
+ typename std::enable_if::value>::type * = nullptr) {
+ std::vector siImages;
+ for (auto const &image : images) {
+ siImages.push_back(static_cast(image));
+ }
+
+ const navlib::imagearray_t imagearray = {siImages.data(), siImages.size()};
+ long error = m_pImpl->Write(navlib::images_k, imagearray);
+ if (error != 0) {
+ throw std::system_error(make_error_code(error));
+ }
+ }
+
+ ///
+ /// Writes the value of a property to the navlib.
+ ///
+ /// The name of the navlib property to
+ /// write.
+ /// The to write.
+ /// 0 =no error, otherwise a value from .
+ /// No connection to the navlib / 3D Mouse.
+ long Write(const std::string &propertyName, const navlib::value &value) override {
+ return m_pImpl->Write(propertyName, value);
+ }
+
+ ///
+ /// Reads the value of a navlib property.
+ ///
+ /// The name of the navlib property to
+ /// read.
+ /// The to read.
+ /// 0 =no error, otherwise a value from .
+ /// No connection to the navlib / 3D Mouse.
+ long Read(const std::string &propertyName, navlib::value &value) const override {
+ return m_pImpl->Read(propertyName, value);
+ }
+
+ ///
+ /// Reads the value of a navlib string property.
+ ///
+ /// The name of the navlib property to
+ /// read.
+ /// The value of the property.
+ /// 0 =no error, otherwise a value from .
+ /// No connection to the navlib.
+ long Read(const std::string &propertyName, std::string &string) const override {
+ return m_pImpl->Read(propertyName, string);
+ }
+
+protected:
+ // IEvents overrides
+ ///
+ /// Default for SetSettingsChanged.
+ ///
+ /// The change count.
+ /// navlib::navlib_errc::function_not_supported error.
+ long SetSettingsChanged(long count) override {
+ (void)count;
+ return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
+ }
+
+ ///
+ /// Default for SetKeyPress.
+ ///
+ /// The virtual key code of the key pressed.
+ /// navlib::navlib_errc::function_not_supported error.
+ long SetKeyPress(long vkey) override {
+ (void)vkey;
+ return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
+ }
+
+ ///
+ /// Default for SetKeyRelease.
+ ///
+ /// The virtual key code of the key pressed.
+ /// navlib::navlib_errc::function_not_supported error.
+ long SetKeyRelease(long vkey) override {
+ (void)vkey;
+ return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
+ }
+
+
+protected:
+ std::error_code make_error_code(long result_code) const {
+ int errc = result_code & 0xffff;
+ int facility = result_code >> 16 & 0x7fff;
+ if (facility == FACILITY_NAVLIB) {
+ return std::error_code(errc, navlib_category);
+ }
+ return std::error_code(errc, std::generic_category());
+ }
+
+protected:
+ bool m_enabled;
+ std::string m_profileHint;
+ std::shared_ptr m_pImpl;
+};
+} // namespace ActionInput
+} // namespace SpaceMouse
+} // namespace TDx
+#endif // CInputAction_HPP_INCLUDED
diff --git a/src/3rdParty/3Dconnexion/inc/SpaceMouse/CActionInputImpl.hpp b/src/3rdParty/3Dconnexion/inc/SpaceMouse/CActionInputImpl.hpp
new file mode 100644
index 0000000000..8e99abc9bc
--- /dev/null
+++ b/src/3rdParty/3Dconnexion/inc/SpaceMouse/CActionInputImpl.hpp
@@ -0,0 +1,187 @@
+#ifndef CActionInputImpl_HPP_INCLUDED
+#define CActionInputImpl_HPP_INCLUDED
+//
+// ------------------------------------------------------------------------------------------------
+// This file is part of the FreeCAD CAx development system.
+//
+// Copyright (c) 2014-2023 3Dconnexion.
+//
+// This source code is released under the GNU Library General Public License, (see "LICENSE").
+// ------------------------------------------------------------------------------------------------
+//
+//
+// ************************************************************************************************
+// File History
+//
+// $Id$
+//
+//
+#include
+#include
+#include
+
+// stdlib
+#include