2019-09-27 12:52:19 +00:00
# include "libslic3r/libslic3r.h"
# include "Mouse3DController.hpp"
2019-10-03 09:38:31 +00:00
# include "Camera.hpp"
2019-09-27 12:52:19 +00:00
# include "GUI_App.hpp"
# include "PresetBundle.hpp"
2019-10-03 08:26:28 +00:00
# include "AppConfig.hpp"
2019-09-27 12:52:19 +00:00
# include <wx/glcanvas.h>
2019-10-02 13:55:26 +00:00
# include <boost/nowide/convert.hpp>
2019-10-04 08:59:27 +00:00
# include <boost/log/trivial.hpp>
2019-10-02 13:55:26 +00:00
# include "I18N.hpp"
2019-10-09 12:01:13 +00:00
# include <bitset>
2019-09-30 12:58:51 +00:00
// WARN: If updating these lists, please also update resources/udev/90-3dconnexion.rules
2019-09-27 12:52:19 +00:00
static const std : : vector < int > _3DCONNEXION_VENDORS =
{
0x046d , // LOGITECH = 1133 // Logitech (3Dconnexion is made by Logitech)
0x256F // 3DCONNECTION = 9583 // 3Dconnexion
} ;
2019-10-08 11:38:08 +00:00
// See: https://github.com/FreeSpacenav/spacenavd/blob/a9eccf34e7cac969ee399f625aef827f4f4aaec6/src/dev.c#L202
2019-09-27 12:52:19 +00:00
static const std : : vector < int > _3DCONNEXION_DEVICES =
{
2019-10-08 11:38:08 +00:00
0xc603 , /* 50691 spacemouse plus XT */
0xc605 , /* 50693 cadman */
0xc606 , /* 50694 spacemouse classic */
0xc621 , /* 50721 spaceball 5000 */
0xc623 , /* 50723 space traveller */
0xc625 , /* 50725 space pilot */
0xc626 , /* 50726 space navigator *TESTED* */
0xc627 , /* 50727 space explorer */
0xc628 , /* 50728 space navigator for notebooks*/
0xc629 , /* 50729 space pilot pro*/
0xc62b , /* 50731 space mouse pro*/
2019-10-09 12:01:13 +00:00
0xc62e , /* 50734 spacemouse wireless (USB cable) *TESTED* */
0xc62f , /* 50735 spacemouse wireless receiver */
2019-10-08 11:38:08 +00:00
0xc631 , /* 50737 spacemouse pro wireless *TESTED* */
0xc632 , /* 50738 spacemouse pro wireless receiver */
0xc633 , /* 50739 spacemouse enterprise */
2019-10-09 12:01:13 +00:00
0xc635 , /* 50741 spacemouse compact *TESTED* */
2019-10-08 11:38:08 +00:00
0xc636 , /* 50742 spacemouse module */
0xc640 , /* 50752 nulooq */
2019-10-11 13:29:57 +00:00
0xc652 , /* 50770 3Dconnexion universal receiver *TESTED* */
2019-09-27 12:52:19 +00:00
} ;
namespace Slic3r {
namespace GUI {
const double Mouse3DController : : State : : DefaultTranslationScale = 2.5 ;
2019-10-10 07:04:44 +00:00
const double Mouse3DController : : State : : MaxTranslationDeadzone = 0.2 ;
2019-10-08 12:32:05 +00:00
const double Mouse3DController : : State : : DefaultTranslationDeadzone = 0.5 * Mouse3DController : : State : : MaxTranslationDeadzone ;
2019-10-08 07:52:56 +00:00
const float Mouse3DController : : State : : DefaultRotationScale = 1.0f ;
2019-10-10 07:04:44 +00:00
const float Mouse3DController : : State : : MaxRotationDeadzone = ( float ) Mouse3DController : : State : : MaxTranslationDeadzone ;
2019-10-08 12:32:05 +00:00
const float Mouse3DController : : State : : DefaultRotationDeadzone = 0.5f * Mouse3DController : : State : : MaxRotationDeadzone ;
2019-09-27 12:52:19 +00:00
Mouse3DController : : State : : State ( )
2019-10-08 12:32:05 +00:00
: m_translation_params ( DefaultTranslationScale , DefaultTranslationDeadzone )
, m_rotation_params ( DefaultRotationScale , DefaultRotationDeadzone )
2019-10-08 06:44:50 +00:00
, m_mouse_wheel_counter ( 0 )
2019-10-09 13:23:30 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
, m_translation_queue_max_size ( 0 )
, m_rotation_queue_max_size ( 0 )
, m_buttons_queue_max_size ( 0 )
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-08 06:44:50 +00:00
{
}
2019-10-10 09:55:17 +00:00
void Mouse3DController : : State : : append_translation ( const Vec3d & translation )
{
while ( m_translation . queue . size ( ) > = m_translation . max_size )
{
m_translation . queue . pop ( ) ;
}
m_translation . queue . push ( translation ) ;
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
m_translation_queue_max_size = std : : max ( m_translation_queue_max_size , m_translation . queue . size ( ) ) ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
}
void Mouse3DController : : State : : append_rotation ( const Vec3f & rotation )
{
while ( m_rotation . queue . size ( ) > = m_rotation . max_size )
{
m_rotation . queue . pop ( ) ;
}
m_rotation . queue . push ( rotation ) ;
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
m_rotation_queue_max_size = std : : max ( m_rotation_queue_max_size , m_rotation . queue . size ( ) ) ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
if ( rotation ( 0 ) ! = 0.0f )
+ + m_mouse_wheel_counter ;
}
void Mouse3DController : : State : : append_button ( unsigned int id )
{
m_buttons . push ( id ) ;
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
m_buttons_queue_max_size = std : : max ( m_buttons_queue_max_size , m_buttons . size ( ) ) ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
}
2019-10-08 06:44:50 +00:00
bool Mouse3DController : : State : : process_mouse_wheel ( )
2019-09-27 12:52:19 +00:00
{
2019-10-08 11:38:08 +00:00
if ( m_mouse_wheel_counter = = 0 )
return false ;
2019-10-10 07:04:44 +00:00
else if ( ! m_rotation . queue . empty ( ) )
2019-10-08 06:44:50 +00:00
{
- - m_mouse_wheel_counter ;
return true ;
}
2019-10-11 07:16:20 +00:00
m_mouse_wheel_counter = 0 ;
return true ;
2019-09-27 12:52:19 +00:00
}
2019-10-10 09:55:17 +00:00
void Mouse3DController : : State : : set_queues_max_size ( size_t size )
{
if ( size > 0 )
{
m_translation . max_size = size ;
m_rotation . max_size = size ;
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
m_translation_queue_max_size = 0 ;
m_rotation_queue_max_size = 0 ;
m_buttons_queue_max_size = 0 ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
}
}
2019-10-03 09:38:31 +00:00
bool Mouse3DController : : State : : apply ( Camera & camera )
2019-09-27 12:52:19 +00:00
{
if ( ! wxGetApp ( ) . IsActive ( ) )
return false ;
bool ret = false ;
if ( has_translation ( ) )
{
2019-10-10 07:04:44 +00:00
const Vec3d & translation = m_translation . queue . front ( ) ;
camera . set_target ( camera . get_target ( ) + m_translation_params . scale * ( translation ( 0 ) * camera . get_dir_right ( ) + translation ( 1 ) * camera . get_dir_forward ( ) + translation ( 2 ) * camera . get_dir_up ( ) ) ) ;
m_translation . queue . pop ( ) ;
2019-09-27 12:52:19 +00:00
ret = true ;
}
if ( has_rotation ( ) )
{
2019-10-10 07:04:44 +00:00
const Vec3f & rotation = m_rotation . queue . front ( ) ;
float theta = m_rotation_params . scale * rotation ( 0 ) ;
float phi = m_rotation_params . scale * rotation ( 2 ) ;
float sign = camera . inverted_phi ? - 1.0f : 1.0f ;
camera . phi + = sign * phi ;
camera . set_theta ( camera . get_theta ( ) + theta , wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) ! = ptSLA ) ;
m_rotation . queue . pop ( ) ;
2019-09-27 12:52:19 +00:00
ret = true ;
}
2019-10-09 12:18:43 +00:00
if ( has_button ( ) )
2019-09-27 12:52:19 +00:00
{
2019-10-08 06:44:50 +00:00
unsigned int button = m_buttons . front ( ) ;
switch ( button )
2019-09-30 13:58:45 +00:00
{
2019-10-08 06:44:50 +00:00
case 0 : { camera . update_zoom ( 1.0 ) ; break ; }
case 1 : { camera . update_zoom ( - 1.0 ) ; break ; }
default : { break ; }
2019-09-30 13:58:45 +00:00
}
2019-10-08 06:44:50 +00:00
m_buttons . pop ( ) ;
2019-09-27 12:52:19 +00:00
ret = true ;
}
return ret ;
}
Mouse3DController : : Mouse3DController ( )
: m_initialized ( false )
, m_device ( nullptr )
2019-10-03 08:26:28 +00:00
, m_device_str ( " " )
2019-09-27 12:52:19 +00:00
, m_running ( false )
2019-10-02 13:55:26 +00:00
, m_settings_dialog ( false )
2019-09-27 12:52:19 +00:00
{
}
void Mouse3DController : : init ( )
{
if ( m_initialized )
return ;
// Initialize the hidapi library
int res = hid_init ( ) ;
if ( res ! = 0 )
2019-10-04 08:59:27 +00:00
{
BOOST_LOG_TRIVIAL ( error ) < < " Unable to initialize hidapi library " ;
2019-09-27 12:52:19 +00:00
return ;
2019-10-04 08:59:27 +00:00
}
2019-09-27 12:52:19 +00:00
m_initialized = true ;
}
void Mouse3DController : : shutdown ( )
{
if ( ! m_initialized )
return ;
stop ( ) ;
disconnect_device ( ) ;
// Finalize the hidapi library
hid_exit ( ) ;
m_initialized = false ;
}
2019-10-03 10:16:59 +00:00
bool Mouse3DController : : apply ( Camera & camera )
{
2019-10-04 08:59:27 +00:00
if ( ! m_initialized )
return false ;
2019-10-03 10:16:59 +00:00
std : : lock_guard < std : : mutex > lock ( m_mutex ) ;
2019-10-04 08:59:27 +00:00
// check if the user unplugged the device
if ( ! m_running & & is_device_connected ( ) )
{
disconnect_device ( ) ;
// hides the settings dialog if the user re-plug the device
m_settings_dialog = false ;
}
// check if the user plugged the device
if ( connect_device ( ) )
start ( ) ;
return is_device_connected ( ) ? m_state . apply ( camera ) : false ;
2019-10-03 10:16:59 +00:00
}
2019-10-03 09:38:31 +00:00
void Mouse3DController : : render_settings_dialog ( unsigned int canvas_width , unsigned int canvas_height ) const
2019-10-02 13:55:26 +00:00
{
2019-10-03 09:38:31 +00:00
if ( ! m_running | | ! m_settings_dialog )
2019-10-02 13:55:26 +00:00
return ;
ImGuiWrapper & imgui = * wxGetApp ( ) . imgui ( ) ;
2019-10-03 09:38:31 +00:00
imgui . set_next_window_pos ( 0.5f * ( float ) canvas_width , 0.5f * ( float ) canvas_height , ImGuiCond_Always , 0.5f , 0.5f ) ;
2019-10-02 13:55:26 +00:00
imgui . set_next_window_bg_alpha ( 0.5f ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0.0f ) ;
imgui . begin ( _ ( L ( " 3Dconnexion settings " ) ) , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse ) ;
const ImVec4 & color = ImGui : : GetStyleColorVec4 ( ImGuiCol_Separator ) ;
ImGui : : PushStyleColor ( ImGuiCol_Text , color ) ;
imgui . text ( _ ( L ( " Device: " ) ) ) ;
ImGui : : PopStyleColor ( ) ;
ImGui : : SameLine ( ) ;
2019-10-03 08:26:28 +00:00
imgui . text ( m_device_str ) ;
2019-10-02 13:55:26 +00:00
2019-10-08 07:52:56 +00:00
ImGui : : Separator ( ) ;
2019-10-02 13:55:26 +00:00
ImGui : : PushStyleColor ( ImGuiCol_Text , color ) ;
imgui . text ( _ ( L ( " Speed: " ) ) ) ;
ImGui : : PopStyleColor ( ) ;
2019-10-08 12:32:05 +00:00
float translation_scale = ( float ) m_state . get_translation_scale ( ) / State : : DefaultTranslationScale ;
if ( ImGui : : SliderFloat ( _ ( L ( " Translation##1 " ) ) , & translation_scale , 0.5f , 2.0f , " %.1f " ) )
m_state . set_translation_scale ( State : : DefaultTranslationScale * ( double ) translation_scale ) ;
2019-10-02 13:55:26 +00:00
2019-10-08 12:32:05 +00:00
float rotation_scale = m_state . get_rotation_scale ( ) / State : : DefaultRotationScale ;
if ( ImGui : : SliderFloat ( _ ( L ( " Rotation##1 " ) ) , & rotation_scale , 0.5f , 2.0f , " %.1f " ) )
m_state . set_rotation_scale ( State : : DefaultRotationScale * rotation_scale ) ;
ImGui : : Separator ( ) ;
ImGui : : PushStyleColor ( ImGuiCol_Text , color ) ;
imgui . text ( _ ( L ( " Deadzone: " ) ) ) ;
ImGui : : PopStyleColor ( ) ;
float translation_deadzone = ( float ) m_state . get_translation_deadzone ( ) ;
if ( ImGui : : SliderFloat ( _ ( L ( " Translation##2 " ) ) , & translation_deadzone , 0.0f , ( float ) State : : MaxTranslationDeadzone , " %.2f " ) )
m_state . set_translation_deadzone ( ( double ) translation_deadzone ) ;
float rotation_deadzone = m_state . get_rotation_deadzone ( ) ;
if ( ImGui : : SliderFloat ( _ ( L ( " Rotation##2 " ) ) , & rotation_deadzone , 0.0f , State : : MaxRotationDeadzone , " %.2f " ) )
m_state . set_rotation_deadzone ( rotation_deadzone ) ;
2019-10-02 13:55:26 +00:00
2019-10-09 12:18:43 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-09 13:23:30 +00:00
ImGui : : Separator ( ) ;
2019-10-09 12:18:43 +00:00
ImGui : : Separator ( ) ;
ImGui : : PushStyleColor ( ImGuiCol_Text , color ) ;
2019-10-09 13:23:30 +00:00
imgui . text ( " DEBUG: " ) ;
imgui . text ( " Vectors: " ) ;
2019-10-09 12:18:43 +00:00
ImGui : : PopStyleColor ( ) ;
Vec3f translation = m_state . get_translation ( ) . cast < float > ( ) ;
Vec3f rotation = m_state . get_rotation ( ) ;
ImGui : : InputFloat3 ( " Translation##3 " , translation . data ( ) , " %.3f " , ImGuiInputTextFlags_ReadOnly ) ;
ImGui : : InputFloat3 ( " Rotation##3 " , rotation . data ( ) , " %.3f " , ImGuiInputTextFlags_ReadOnly ) ;
2019-10-09 13:23:30 +00:00
ImGui : : PushStyleColor ( ImGuiCol_Text , color ) ;
imgui . text ( " Queue size: " ) ;
ImGui : : PopStyleColor ( ) ;
int translation_size [ 2 ] = { ( int ) m_state . get_translation_queue_size ( ) , ( int ) m_state . get_translation_queue_max_size ( ) } ;
int rotation_size [ 2 ] = { ( int ) m_state . get_rotation_queue_size ( ) , ( int ) m_state . get_rotation_queue_max_size ( ) } ;
int buttons_size [ 2 ] = { ( int ) m_state . get_buttons_queue_size ( ) , ( int ) m_state . get_buttons_queue_max_size ( ) } ;
ImGui : : InputInt2 ( " Translation##4 " , translation_size , ImGuiInputTextFlags_ReadOnly ) ;
ImGui : : InputInt2 ( " Rotation##4 " , rotation_size , ImGuiInputTextFlags_ReadOnly ) ;
ImGui : : InputInt2 ( " Buttons " , buttons_size , ImGuiInputTextFlags_ReadOnly ) ;
2019-10-10 07:04:44 +00:00
int queue_size = ( int ) m_state . get_queues_max_size ( ) ;
if ( ImGui : : InputInt ( " Max size " , & queue_size , 1 , 1 , ImGuiInputTextFlags_ReadOnly ) )
{
if ( queue_size > 0 )
m_state . set_queues_max_size ( queue_size ) ;
}
2019-10-09 12:18:43 +00:00
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-02 13:55:26 +00:00
imgui . end ( ) ;
ImGui : : PopStyleVar ( ) ;
}
2019-10-04 08:59:27 +00:00
bool Mouse3DController : : connect_device ( )
2019-09-27 12:52:19 +00:00
{
2019-10-04 08:59:27 +00:00
if ( is_device_connected ( ) )
return false ;
2019-09-27 12:52:19 +00:00
// Enumerates devices
hid_device_info * devices = hid_enumerate ( 0 , 0 ) ;
if ( devices = = nullptr )
2019-10-04 08:59:27 +00:00
{
BOOST_LOG_TRIVIAL ( error ) < < " Unable to enumerate HID devices " ;
return false ;
}
2019-09-27 12:52:19 +00:00
// Searches for 1st connected 3Dconnexion device
2019-10-21 12:21:51 +00:00
struct DeviceData
{
2019-10-21 13:20:36 +00:00
std : : string path ;
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// int interface_number;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 13:20:36 +00:00
unsigned short usage_page ;
unsigned short usage ;
DeviceData ( )
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
: path ( " " ) , usage_page ( 0 ) , usage ( 0 )
// : path(""), interface_number(0), usage_page(0), usage(0)
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 13:20:36 +00:00
{ }
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DeviceData ( const std : : string & path , unsigned short usage_page , unsigned short usage )
: path ( path ) , usage_page ( usage_page ) , usage ( usage )
// DeviceData(const std::string& path, int interface_number, unsigned short usage_page, unsigned short usage)
// : path(path), interface_number(interface_number), usage_page(usage_page), usage(usage)
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 13:20:36 +00:00
{ }
2019-10-21 12:21:51 +00:00
} ;
2019-09-27 12:52:19 +00:00
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
// hid_device_info* cur = devices;
// while (cur != nullptr)
// {
// std::cout << "Detected device '";
// std::wcout << ((cur->manufacturer_string != nullptr) ? cur->manufacturer_string : L"Unknown");
// std::cout << "::";
// std::wcout << ((cur->product_string != nullptr) ? cur->product_string : L"Unknown");
// std::cout << "' code: " << cur->vendor_id << "/" << cur->product_id << " (" << std::hex << cur->vendor_id << "/" << cur->product_id << std::dec << ")";
// std::cout << " serial number: '";
// std::wcout << ((cur->serial_number != nullptr) ? cur->serial_number : L"Unknown");
// std::cout << "' usage page: " << cur->usage_page << " usage: " << cur->usage << " interface number: " << cur->interface_number << std::endl;
//
// cur = cur->next;
// }
//#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-09 12:18:43 +00:00
2019-10-21 12:21:51 +00:00
// When using 3Dconnexion universal receiver, multiple devices are detected sharing the same vendor_id and product_id.
// To choose from them the right one we use:
// On Windows and Mac: usage_page == 1 and usage == 8
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// On Linux: as usage_page and usage are not defined (see hidapi.h) we try all detected devices until one is succesfully open
// // On Linux: interface_number == 1, as usage_page and usage are not defined, see hidapi.h
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 12:21:51 +00:00
// When only a single device is detected, as for wired connections, vendor_id and product_id are enough
// First we count all the valid devices from the enumerated list,
2019-10-08 11:38:08 +00:00
hid_device_info * current = devices ;
2019-10-21 12:21:51 +00:00
typedef std : : pair < unsigned short , unsigned short > DeviceIds ;
typedef std : : vector < DeviceData > DeviceDataList ;
typedef std : : map < DeviceIds , DeviceDataList > DetectedDevices ;
DetectedDevices detected_devices ;
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-11-08 13:43:15 +00:00
std : : cout < < std : : endl < < " ====================================================================================================================================== " < < std : : endl ;
2019-11-08 10:51:56 +00:00
std : : cout < < std : : endl < < " Detected devices: " < < std : : endl ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-08 11:38:08 +00:00
while ( current ! = nullptr )
{
2019-10-21 12:21:51 +00:00
unsigned short vendor_id = 0 ;
unsigned short product_id = 0 ;
2019-09-27 12:52:19 +00:00
for ( size_t i = 0 ; i < _3DCONNEXION_VENDORS . size ( ) ; + + i )
{
if ( _3DCONNEXION_VENDORS [ i ] = = current - > vendor_id )
{
vendor_id = current - > vendor_id ;
break ;
}
}
if ( vendor_id ! = 0 )
{
for ( size_t i = 0 ; i < _3DCONNEXION_DEVICES . size ( ) ; + + i )
{
2019-10-21 12:21:51 +00:00
if ( _3DCONNEXION_DEVICES [ i ] = = current - > product_id )
2019-09-27 12:52:19 +00:00
{
product_id = current - > product_id ;
2019-10-21 12:21:51 +00:00
DeviceIds detected_device ( vendor_id , product_id ) ;
DetectedDevices : : iterator it = detected_devices . find ( detected_device ) ;
if ( it = = detected_devices . end ( ) )
it = detected_devices . insert ( DetectedDevices : : value_type ( detected_device , DeviceDataList ( ) ) ) . first ;
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
it - > second . emplace_back ( current - > path , current - > usage_page , current - > usage ) ;
// it->second.emplace_back(current->path, current->interface_number, current->usage_page, current->usage);
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std : : wcout < < " \" " < < ( ( current - > manufacturer_string ! = nullptr ) ? current - > manufacturer_string : L " Unknown " ) ;
std : : cout < < " / " ;
std : : wcout < < ( ( current - > product_string ! = nullptr ) ? current - > product_string : L " Unknown " ) ;
std : : cout < < " \" code: " < < current - > vendor_id < < " / " < < current - > product_id < < " ( " < < std : : hex < < current - > vendor_id < < " / " < < current - > product_id < < std : : dec < < " ) " ;
std : : cout < < " serial number: ' " ;
std : : wcout < < ( ( current - > serial_number ! = nullptr ) ? current - > serial_number : L " Unknown " ) ;
std : : cout < < " ' usage page: " < < current - > usage_page < < " usage: " < < current - > usage < < std : : endl ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-09-27 12:52:19 +00:00
}
}
}
current = current - > next ;
}
// Free enumerated devices
hid_free_enumeration ( devices ) ;
2019-10-21 12:21:51 +00:00
if ( detected_devices . empty ( ) )
return false ;
std : : string path = " " ;
unsigned short vendor_id = 0 ;
unsigned short product_id = 0 ;
// Then we'll decide the choosing logic to apply in dependence of the device count and operating system
for ( const DetectedDevices : : value_type & device : detected_devices )
{
if ( device . second . size ( ) = = 1 )
{
2019-11-08 12:31:34 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// path = device.second.front().path;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 12:21:51 +00:00
vendor_id = device . first . first ;
product_id = device . first . second ;
break ;
}
else
{
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
bool found = false ;
2019-11-08 13:43:15 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std : : cout < < std : : endl ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 12:21:51 +00:00
for ( const DeviceData & data : device . second )
{
2019-11-08 13:43:15 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std : : cout < < " Test device: " < < std : : hex < < device . first . first < < std : : dec < < " / " < < std : : hex < < device . first . second < < std : : dec < < " \" " < < data . path < < " \" " ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
# ifdef __linux__
//#if defined(__linux)
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
hid_device * test_device = hid_open_path ( data . path . c_str ( ) ) ;
if ( test_device ! = nullptr )
{
path = data . path ;
vendor_id = device . first . first ;
product_id = device . first . second ;
found = true ;
2019-11-08 12:31:34 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-11-08 13:43:15 +00:00
std : : cout < < " -> PASSED " < < std : : endl ;
2019-11-08 12:31:34 +00:00
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-11-08 13:43:15 +00:00
hid_close ( test_device ) ;
2019-11-08 10:51:56 +00:00
break ;
}
// if (data.interface_number == 1)
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 12:21:51 +00:00
# else
if ( ( data . usage_page = = 1 ) & & ( data . usage = = 8 ) )
2019-11-08 13:43:15 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# endif // __linux__
//#endif // __linux
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 12:21:51 +00:00
{
path = data . path ;
vendor_id = device . first . first ;
product_id = device . first . second ;
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
found = true ;
2019-11-08 13:43:15 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std : : cout < < " -> PASSED " < < std : : endl ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 12:21:51 +00:00
break ;
}
2019-11-08 13:43:15 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
else
std : : cout < < " -> NOT PASSED " < < std : : endl ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-21 12:21:51 +00:00
}
2019-11-08 10:51:56 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
if ( found )
break ;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 12:21:51 +00:00
}
}
2019-11-08 12:31:34 +00:00
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-21 12:21:51 +00:00
if ( path . empty ( ) )
2019-11-08 12:31:34 +00:00
{
if ( ( vendor_id ! = 0 ) & & ( product_id ! = 0 ) )
2019-11-08 13:43:15 +00:00
{
2019-11-08 12:31:34 +00:00
// Open the 3Dconnexion device using vendor_id and product_id
2019-11-08 13:43:15 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std : : cout < < std : : endl < < " Opening device: " < < std : : hex < < vendor_id < < std : : dec < < " / " < < std : : hex < < product_id < < std : : dec < < " using hid_open() " < < std : : endl ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-11-08 12:31:34 +00:00
m_device = hid_open ( vendor_id , product_id , nullptr ) ;
2019-11-08 13:43:15 +00:00
}
2019-11-08 12:31:34 +00:00
else
return false ;
}
else
2019-11-08 13:43:15 +00:00
{
2019-11-08 12:31:34 +00:00
// Open the 3Dconnexion device using the device path
2019-11-08 13:43:15 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std : : cout < < std : : endl < < " Opening device: " < < std : : hex < < vendor_id < < std : : dec < < " / " < < std : : hex < < product_id < < std : : dec < < " \" " < < path < < " \" using hid_open_path() " < < std : : endl ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-11-08 12:31:34 +00:00
m_device = hid_open_path ( path . c_str ( ) ) ;
2019-11-08 13:43:15 +00:00
}
2019-09-27 12:52:19 +00:00
2019-11-08 12:31:34 +00:00
// if (path.empty())
// return false;
//
// // Open the 3Dconnexion device using the device path
// m_device = hid_open_path(path.c_str());
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2019-10-03 08:26:28 +00:00
if ( m_device ! = nullptr )
{
2019-10-10 07:04:44 +00:00
std : : vector < wchar_t > manufacturer ( 1024 , 0 ) ;
hid_get_manufacturer_string ( m_device , manufacturer . data ( ) , 1024 ) ;
m_device_str = boost : : nowide : : narrow ( manufacturer . data ( ) ) ;
2019-10-03 08:26:28 +00:00
std : : vector < wchar_t > product ( 1024 , 0 ) ;
hid_get_product_string ( m_device , product . data ( ) , 1024 ) ;
2019-10-10 07:04:44 +00:00
m_device_str + = " / " + boost : : nowide : : narrow ( product . data ( ) ) ;
2019-10-03 08:26:28 +00:00
2019-10-04 08:59:27 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Connected device: " < < m_device_str ;
2019-10-10 08:49:47 +00:00
2019-10-10 07:04:44 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std : : cout < < std : : endl < < " Connected device: " < < std : : endl ;
2019-10-11 13:29:57 +00:00
std : : cout < < " Manufacturer/product: " < < m_device_str < < std : : endl ;
std : : cout < < " Manufacturer id.....: " < < vendor_id < < " ( " < < std : : hex < < vendor_id < < std : : dec < < " ) " < < std : : endl ;
std : : cout < < " Product id..........: " < < product_id < < " ( " < < std : : hex < < product_id < < std : : dec < < " ) " < < std : : endl ;
2019-10-21 09:06:18 +00:00
std : : cout < < " Path................: ' " < < path < < " ' " < < std : : endl ;
2019-10-10 07:04:44 +00:00
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-04 08:59:27 +00:00
// get device parameters from the config, if present
2019-10-08 12:32:05 +00:00
double translation_speed = 1.0 ;
float rotation_speed = 1.0 ;
double translation_deadzone = State : : DefaultTranslationDeadzone ;
float rotation_deadzone = State : : DefaultRotationDeadzone ;
wxGetApp ( ) . app_config - > get_mouse_device_translation_speed ( m_device_str , translation_speed ) ;
wxGetApp ( ) . app_config - > get_mouse_device_translation_deadzone ( m_device_str , translation_deadzone ) ;
wxGetApp ( ) . app_config - > get_mouse_device_rotation_speed ( m_device_str , rotation_speed ) ;
wxGetApp ( ) . app_config - > get_mouse_device_rotation_deadzone ( m_device_str , rotation_deadzone ) ;
2019-10-03 08:26:28 +00:00
// clamp to valid values
2019-10-11 07:16:20 +00:00
m_state . set_translation_scale ( State : : DefaultTranslationScale * std : : max ( 0.5 , std : : min ( 2.0 , translation_speed ) ) ) ;
2019-10-08 12:32:05 +00:00
m_state . set_translation_deadzone ( std : : max ( 0.0 , std : : min ( State : : MaxTranslationDeadzone , translation_deadzone ) ) ) ;
2019-10-11 07:16:20 +00:00
m_state . set_rotation_scale ( State : : DefaultRotationScale * std : : max ( 0.5f , std : : min ( 2.0f , rotation_speed ) ) ) ;
2019-10-08 12:32:05 +00:00
m_state . set_rotation_deadzone ( std : : max ( 0.0f , std : : min ( State : : MaxRotationDeadzone , rotation_deadzone ) ) ) ;
2019-10-03 08:26:28 +00:00
}
2019-10-21 09:06:18 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
else
{
std : : cout < < std : : endl < < " Unable to connect to device: " < < std : : endl ;
std : : cout < < " Manufacturer/product: " < < m_device_str < < std : : endl ;
std : : cout < < " Manufacturer id.....: " < < vendor_id < < " ( " < < std : : hex < < vendor_id < < std : : dec < < " ) " < < std : : endl ;
std : : cout < < " Product id..........: " < < product_id < < " ( " < < std : : hex < < product_id < < std : : dec < < " ) " < < std : : endl ;
std : : cout < < " Path................: ' " < < path < < " ' " < < std : : endl ;
}
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-04 08:59:27 +00:00
return ( m_device ! = nullptr ) ;
2019-09-27 12:52:19 +00:00
}
void Mouse3DController : : disconnect_device ( )
{
2019-10-04 08:59:27 +00:00
if ( ! is_device_connected ( ) )
2019-09-27 12:52:19 +00:00
return ;
2019-10-04 08:59:27 +00:00
// Stop the secondary thread, if running
if ( m_thread . joinable ( ) )
m_thread . join ( ) ;
// Store current device parameters into the config
2019-10-08 12:32:05 +00:00
wxGetApp ( ) . app_config - > set_mouse_device ( m_device_str , m_state . get_translation_scale ( ) / State : : DefaultTranslationScale , m_state . get_translation_deadzone ( ) ,
m_state . get_rotation_scale ( ) / State : : DefaultRotationScale , m_state . get_rotation_deadzone ( ) ) ;
2019-10-03 08:26:28 +00:00
wxGetApp ( ) . app_config - > save ( ) ;
2019-09-27 12:52:19 +00:00
// Close the 3Dconnexion device
hid_close ( m_device ) ;
m_device = nullptr ;
2019-10-04 08:59:27 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Disconnected device: " < < m_device_str ;
2019-10-03 08:26:28 +00:00
m_device_str = " " ;
2019-09-27 12:52:19 +00:00
}
void Mouse3DController : : start ( )
{
2019-10-04 08:59:27 +00:00
if ( ! is_device_connected ( ) | | m_running )
2019-09-27 12:52:19 +00:00
return ;
m_thread = std : : thread ( & Mouse3DController : : run , this ) ;
}
void Mouse3DController : : run ( )
{
m_running = true ;
while ( m_running )
{
collect_input ( ) ;
}
}
2019-10-04 05:58:01 +00:00
void Mouse3DController : : collect_input ( )
2019-09-27 12:52:19 +00:00
{
2019-10-08 11:38:08 +00:00
DataPacket packet = { 0 } ;
int res = hid_read_timeout ( m_device , packet . data ( ) , packet . size ( ) , 100 ) ;
2019-09-27 12:52:19 +00:00
if ( res < 0 )
{
// An error occourred (device detached from pc ?)
stop ( ) ;
return ;
}
2019-10-08 11:38:08 +00:00
if ( ! wxGetApp ( ) . IsActive ( ) )
return ;
2019-10-03 10:16:59 +00:00
std : : lock_guard < std : : mutex > lock ( m_mutex ) ;
2019-10-08 11:38:08 +00:00
bool updated = false ;
if ( res = = 7 )
updated = handle_packet ( packet ) ;
else if ( res = = 13 )
updated = handle_wireless_packet ( packet ) ;
2019-11-08 07:47:57 +00:00
else if ( ( res = = 3 ) & & ( packet [ 0 ] = = 3 ) )
// On Mac button packets can be 3 bytes long
updated = handle_packet ( packet ) ;
2019-10-11 07:16:20 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-08 11:38:08 +00:00
else if ( res > 0 )
std : : cout < < " Got unknown data packet of length: " < < res < < " , code: " < < ( int ) packet [ 0 ] < < std : : endl ;
2019-10-11 07:16:20 +00:00
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-08 11:38:08 +00:00
if ( updated )
// ask for an idle event to update 3D scene
wxWakeUpIdle ( ) ;
}
bool Mouse3DController : : handle_packet ( const DataPacket & packet )
{
switch ( packet [ 0 ] )
2019-09-27 12:52:19 +00:00
{
2019-10-08 11:38:08 +00:00
case 1 : // Translation
{
if ( handle_packet_translation ( packet ) )
return true ;
2019-10-07 07:31:23 +00:00
2019-10-08 11:38:08 +00:00
break ;
}
case 2 : // Rotation
2019-09-27 12:52:19 +00:00
{
2019-10-08 11:38:08 +00:00
if ( handle_packet_rotation ( packet , 1 ) )
return true ;
2019-09-27 12:52:19 +00:00
2019-10-08 11:38:08 +00:00
break ;
}
case 3 : // Button
{
2019-11-08 07:47:57 +00:00
if ( handle_packet_button ( packet , packet . size ( ) - 1 ) )
2019-10-08 11:38:08 +00:00
return true ;
2019-09-27 12:52:19 +00:00
2019-10-11 13:29:57 +00:00
break ;
}
case 23 : // Battery charge
{
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std : : cout < < m_device_str < < " - battery level: " < < ( int ) packet [ 1 ] < < " percent " < < std : : endl ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-08 11:38:08 +00:00
break ;
}
default :
{
2019-10-11 07:16:20 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-08 11:38:08 +00:00
std : : cout < < " Got unknown data packet of code: " < < ( int ) packet [ 0 ] < < std : : endl ;
2019-10-11 07:16:20 +00:00
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-08 11:38:08 +00:00
break ;
}
}
2019-09-27 12:52:19 +00:00
2019-10-08 11:38:08 +00:00
return false ;
}
bool Mouse3DController : : handle_wireless_packet ( const DataPacket & packet )
{
switch ( packet [ 0 ] )
{
case 1 : // Translation + Rotation
{
bool updated = handle_packet_translation ( packet ) ;
updated | = handle_packet_rotation ( packet , 7 ) ;
if ( updated )
return true ;
break ;
}
case 3 : // Button
{
if ( handle_packet_button ( packet , 12 ) )
return true ;
2019-10-03 08:26:28 +00:00
2019-10-11 13:29:57 +00:00
break ;
}
case 23 : // Battery charge
{
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
std : : cout < < m_device_str < < " - battery level: " < < ( int ) packet [ 1 ] < < " percent " < < std : : endl ;
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-09-27 12:52:19 +00:00
break ;
}
2019-10-08 11:38:08 +00:00
default :
{
2019-10-11 07:16:20 +00:00
# if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-08 11:38:08 +00:00
std : : cout < < " Got unknown data packet of code: " < < ( int ) packet [ 0 ] < < std : : endl ;
2019-10-11 07:16:20 +00:00
# endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
2019-10-08 11:38:08 +00:00
break ;
}
}
return false ;
}
2019-10-09 12:39:28 +00:00
double convert_input ( unsigned char first , unsigned char second , double deadzone )
2019-10-08 11:38:08 +00:00
{
2019-10-09 12:01:13 +00:00
short value = first | second < < 8 ;
2019-10-09 12:39:28 +00:00
double ret = ( double ) value / 350.0 ;
return ( std : : abs ( ret ) > deadzone ) ? ret : 0.0 ;
2019-10-09 12:01:13 +00:00
}
2019-10-08 11:38:08 +00:00
bool Mouse3DController : : handle_packet_translation ( const DataPacket & packet )
{
2019-10-08 12:32:05 +00:00
double deadzone = m_state . get_translation_deadzone ( ) ;
2019-10-09 12:39:28 +00:00
Vec3d translation ( - convert_input ( packet [ 1 ] , packet [ 2 ] , deadzone ) ,
convert_input ( packet [ 3 ] , packet [ 4 ] , deadzone ) ,
convert_input ( packet [ 5 ] , packet [ 6 ] , deadzone ) ) ;
if ( ! translation . isApprox ( Vec3d : : Zero ( ) ) )
2019-10-08 11:38:08 +00:00
{
m_state . append_translation ( translation ) ;
return true ;
}
return false ;
}
bool Mouse3DController : : handle_packet_rotation ( const DataPacket & packet , unsigned int first_byte )
{
2019-10-09 12:39:28 +00:00
double deadzone = ( double ) m_state . get_rotation_deadzone ( ) ;
Vec3f rotation ( - ( float ) convert_input ( packet [ first_byte + 0 ] , packet [ first_byte + 1 ] , deadzone ) ,
( float ) convert_input ( packet [ first_byte + 2 ] , packet [ first_byte + 3 ] , deadzone ) ,
- ( float ) convert_input ( packet [ first_byte + 4 ] , packet [ first_byte + 5 ] , deadzone ) ) ;
2019-10-08 12:32:05 +00:00
2019-10-09 12:39:28 +00:00
if ( ! rotation . isApprox ( Vec3f : : Zero ( ) ) )
2019-10-08 11:38:08 +00:00
{
m_state . append_rotation ( rotation ) ;
return true ;
}
2019-10-07 07:31:23 +00:00
2019-10-08 11:38:08 +00:00
return false ;
}
bool Mouse3DController : : handle_packet_button ( const DataPacket & packet , unsigned int packet_size )
{
2019-11-08 08:18:59 +00:00
unsigned int data = 0 ;
for ( unsigned int i = 1 ; i < packet_size ; + + i )
{
data | = packet [ i ] < < 8 * ( i - 1 ) ;
}
2019-10-09 12:01:13 +00:00
const std : : bitset < 32 > data_bits { data } ;
for ( size_t i = 0 ; i < data_bits . size ( ) ; + + i )
2019-10-08 11:38:08 +00:00
{
2019-10-09 12:01:13 +00:00
if ( data_bits . test ( i ) )
2019-10-08 11:38:08 +00:00
{
2019-10-09 12:01:13 +00:00
m_state . append_button ( ( unsigned int ) i ) ;
return true ;
2019-10-08 11:38:08 +00:00
}
2019-09-27 12:52:19 +00:00
}
2019-10-08 11:38:08 +00:00
return false ;
2019-09-27 12:52:19 +00:00
}
} // namespace GUI
} // namespace Slic3r