diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index f5a4a3d92d..234847bc4b 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -47,6 +47,7 @@ #include "SysInfoDialog.hpp" #include "KBShortcutsDialog.hpp" #include "UpdateDialogs.hpp" +#include "Mouse3DController.hpp" #include "RemovableDriveManager.hpp" #ifdef __WXMSW__ @@ -193,6 +194,20 @@ static void register_win32_device_notification_event() } return true; }); + + wxWindow::MSWRegisterMessageHandler(WM_INPUT, [](wxWindow *win, WXUINT /* nMsg */, WXWPARAM wParam, WXLPARAM lParam) { + auto main_frame = dynamic_cast(Slic3r::GUI::find_toplevel_parent(win)); + auto plater = (main_frame == nullptr) ? nullptr : main_frame->plater(); +// if (wParam == RIM_INPUTSINK && plater != nullptr && main_frame->IsActive()) { + if (wParam == RIM_INPUT && plater != nullptr && main_frame->IsActive()) { + RAWINPUT raw; + UINT rawSize = sizeof(RAWINPUT); + ::GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &raw, &rawSize, sizeof(RAWINPUTHEADER)); + if (raw.header.dwType == RIM_TYPEHID && plater->get_mouse3d_controller().handle_raw_input_win32(raw.data.hid.bRawData, raw.data.hid.dwSizeHid)) + return true; + } + return false; + }); } #endif // WIN32 diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 69d20fd9fb..437af6d53e 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -152,6 +152,16 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S // Failed to get desktop location assert(false); } + + { + static constexpr int device_count = 1; + RAWINPUTDEVICE devices[device_count] = { 0 }; + // multi-axis mouse (SpaceNavigator, etc.) + devices[0].usUsagePage = 0x01; + devices[0].usUsage = 0x08; + if (! RegisterRawInputDevices(devices, device_count, sizeof(RAWINPUTDEVICE))) + BOOST_LOG_TRIVIAL(error) << "RegisterRawInputDevices failed"; + } #endif // _WIN32 // propagate event diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 75ec9c3bcb..8f80f6847c 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -484,7 +484,10 @@ void Mouse3DController::init() assert(! m_thread.joinable()); if (! m_thread.joinable()) { m_stop = false; +#ifndef _WIN32 + // Don't start the background thread on Windows, as the HID messages are sent as Windows messages. m_thread = std::thread(&Mouse3DController::run, this); +#endif // _WIN32 } } @@ -600,7 +603,10 @@ bool Mouse3DController::connect_device() : path(path), usage_page(usage_page), usage(usage) {} - bool has_valid_usage() const { return (usage_page == 1) && (usage == 8); } + // https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf + // Usage page 1 - Generic Desktop Controls + // Usage page 1, usage 8 - Multi-axis Controller + bool has_valid_usage() const { return usage_page == 1 && usage == 8; } }; #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT @@ -688,7 +694,7 @@ bool Mouse3DController::connect_device() if (detected_devices.empty()) return false; - std::string path = ""; + std::string path; unsigned short vendor_id = 0; unsigned short product_id = 0; @@ -865,45 +871,60 @@ void Mouse3DController::collect_input() this->handle_input(packet, res, m_params, m_state); } -// Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by the worker thread. -bool Mouse3DController::handle_input(const DataPacketRaw& packet, const int packet_lenght, const Params ¶ms, State &state_in_out) +#ifdef _WIN32 +bool Mouse3DController::handle_raw_input_win32(const unsigned char *data, const int packet_length) { if (! wxGetApp().IsActive()) return false; - int res = packet_lenght; + if (packet_length == 7 || packet_length == 13) { + DataPacketRaw packet; + memcpy(packet.data(), data, packet_length); + handle_packet(packet, packet_length, m_params, m_state); + } + + return true; +} +#endif /* _WIN32 */ + +// Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by the worker thread. +bool Mouse3DController::handle_input(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out) +{ + if (! wxGetApp().IsActive()) + return false; + + int res = packet_length; bool updated = false; - if (res == 7) - updated = handle_packet(packet, params, state_in_out); - else if (res == 13) - updated = handle_wireless_packet(packet, params, state_in_out); - else if ((res == 3) && (packet[0] == 3)) + if (res == 7 || res == 13 || // On Mac button packets can be 3 bytes long - updated = handle_packet(packet, params, state_in_out); + ((res == 3) && (packet[0] == 3))) + updated = handle_packet(packet, res, params, state_in_out); #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT else if (res > 0) std::cout << "Got unknown data packet of length: " << res << ", code:" << (int)packet[0] << std::endl; #endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT -#if 1 if (updated) { wxGetApp().plater()->set_current_canvas_as_dirty(); // ask for an idle event to update 3D scene wxWakeUpIdle(); } -#endif return updated; } // Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by handle_input() from the worker thread. -bool Mouse3DController::handle_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out) +bool Mouse3DController::handle_packet(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out) { switch (packet[0]) { - case 1: // Translation + case 1: // Translation + Rotation { - if (handle_packet_translation(packet, params, state_in_out)) + bool updated = handle_packet_translation(packet, params, state_in_out); + if (packet_length == 13) + updated |= handle_packet_rotation(packet, 7, params, state_in_out); + + if (updated) return true; break; @@ -941,47 +962,6 @@ bool Mouse3DController::handle_packet(const DataPacketRaw& packet, const Params return false; } -// Unpack raw 3DConnexion HID packet of a wireless 3D mouse into m_state. Called by handle_input() from the worker thread. -bool Mouse3DController::handle_wireless_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out) -{ - switch (packet[0]) - { - case 1: // Translation + Rotation - { - bool updated = handle_packet_translation(packet, params, state_in_out); - updated |= handle_packet_rotation(packet, 7, params, state_in_out); - - if (updated) - return true; - - break; - } - case 3: // Button - { - if (params.buttons_enabled && handle_packet_button(packet, 12, params, state_in_out)) - return true; - - break; - } - case 23: // Battery charge - { -#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - std::cout << "3DConnexion - battery level: " << (int)packet[1] << " percent" << std::endl; -#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - break; - } - default: - { -#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - std::cout << "3DConnexion - Got unknown data packet of code: " << (int)packet[0] << std::endl; -#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - break; - } - } - - return false; -} - // Convert a signed 16bit word from a 3DConnexion mouse HID packet into a double coordinate, apply a dead zone. static double convert_input(int coord_byte_low, int coord_byte_high, double deadzone) { diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp index eb1425b88c..2c1d0bb6f0 100644 --- a/src/slic3r/GUI/Mouse3DController.hpp +++ b/src/slic3r/GUI/Mouse3DController.hpp @@ -190,6 +190,8 @@ public: #endif // __APPLE__ #ifdef WIN32 + bool handle_raw_input_win32(const unsigned char *data, const int packet_lenght); + // Called by Win32 HID enumeration callback. void device_attached(const std::string &device); @@ -218,10 +220,9 @@ private: typedef std::array DataPacketRaw; // Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by the worker thread. - static bool handle_input(const DataPacketRaw& packet, const int packet_lenght, const Params ¶ms, State &state_in_out); + static bool handle_input(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out); // The following is called by handle_input() from the worker thread. - static bool handle_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out); - static bool handle_wireless_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out); + static bool handle_packet(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out); static bool handle_packet_translation(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out); static bool handle_packet_rotation(const DataPacketRaw& packet, unsigned int first_byte, const Params ¶ms, State &state_in_out); static bool handle_packet_button(const DataPacketRaw& packet, unsigned int packet_size, const Params ¶ms, State &state_in_out);