mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-11 00:37:51 -06:00
WIP: Windows specific 3Dconnexion using WM_INPUT.
This implementation works with the 3DConnexion driver (sic!) if PrusaSlicer.xml is stored into c:\Program Files\3Dconnexion\3DxWare\3DxWinCore64\Cfg\ The implementation is inspired with Blender, see code inside WITH_INPUT_NDOF blocks.
This commit is contained in:
parent
70baa0d246
commit
25d58faaad
4 changed files with 66 additions and 60 deletions
|
@ -47,6 +47,7 @@
|
||||||
#include "SysInfoDialog.hpp"
|
#include "SysInfoDialog.hpp"
|
||||||
#include "KBShortcutsDialog.hpp"
|
#include "KBShortcutsDialog.hpp"
|
||||||
#include "UpdateDialogs.hpp"
|
#include "UpdateDialogs.hpp"
|
||||||
|
#include "Mouse3DController.hpp"
|
||||||
#include "RemovableDriveManager.hpp"
|
#include "RemovableDriveManager.hpp"
|
||||||
|
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
|
@ -193,6 +194,20 @@ static void register_win32_device_notification_event()
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
wxWindow::MSWRegisterMessageHandler(WM_INPUT, [](wxWindow *win, WXUINT /* nMsg */, WXWPARAM wParam, WXLPARAM lParam) {
|
||||||
|
auto main_frame = dynamic_cast<MainFrame*>(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
|
#endif // WIN32
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,16 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
||||||
// Failed to get desktop location
|
// Failed to get desktop location
|
||||||
assert(false);
|
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
|
#endif // _WIN32
|
||||||
|
|
||||||
// propagate event
|
// propagate event
|
||||||
|
|
|
@ -484,7 +484,10 @@ void Mouse3DController::init()
|
||||||
assert(! m_thread.joinable());
|
assert(! m_thread.joinable());
|
||||||
if (! m_thread.joinable()) {
|
if (! m_thread.joinable()) {
|
||||||
m_stop = false;
|
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);
|
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)
|
: 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
|
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||||
|
@ -688,7 +694,7 @@ bool Mouse3DController::connect_device()
|
||||||
if (detected_devices.empty())
|
if (detected_devices.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::string path = "";
|
std::string path;
|
||||||
unsigned short vendor_id = 0;
|
unsigned short vendor_id = 0;
|
||||||
unsigned short product_id = 0;
|
unsigned short product_id = 0;
|
||||||
|
|
||||||
|
@ -865,45 +871,60 @@ void Mouse3DController::collect_input()
|
||||||
this->handle_input(packet, res, m_params, m_state);
|
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.
|
#ifdef _WIN32
|
||||||
bool Mouse3DController::handle_input(const DataPacketRaw& packet, const int packet_lenght, const Params ¶ms, State &state_in_out)
|
bool Mouse3DController::handle_raw_input_win32(const unsigned char *data, const int packet_length)
|
||||||
{
|
{
|
||||||
if (! wxGetApp().IsActive())
|
if (! wxGetApp().IsActive())
|
||||||
return false;
|
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;
|
bool updated = false;
|
||||||
|
|
||||||
if (res == 7)
|
if (res == 7 || res == 13 ||
|
||||||
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))
|
|
||||||
// On Mac button packets can be 3 bytes long
|
// 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
|
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||||
else if (res > 0)
|
else if (res > 0)
|
||||||
std::cout << "Got unknown data packet of length: " << res << ", code:" << (int)packet[0] << std::endl;
|
std::cout << "Got unknown data packet of length: " << res << ", code:" << (int)packet[0] << std::endl;
|
||||||
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||||
|
|
||||||
#if 1
|
|
||||||
if (updated) {
|
if (updated) {
|
||||||
wxGetApp().plater()->set_current_canvas_as_dirty();
|
wxGetApp().plater()->set_current_canvas_as_dirty();
|
||||||
// ask for an idle event to update 3D scene
|
// ask for an idle event to update 3D scene
|
||||||
wxWakeUpIdle();
|
wxWakeUpIdle();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by handle_input() from the worker thread.
|
// 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])
|
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;
|
return true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -941,47 +962,6 @@ bool Mouse3DController::handle_packet(const DataPacketRaw& packet, const Params
|
||||||
return false;
|
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.
|
// 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)
|
static double convert_input(int coord_byte_low, int coord_byte_high, double deadzone)
|
||||||
{
|
{
|
||||||
|
|
|
@ -190,6 +190,8 @@ public:
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
bool handle_raw_input_win32(const unsigned char *data, const int packet_lenght);
|
||||||
|
|
||||||
// Called by Win32 HID enumeration callback.
|
// Called by Win32 HID enumeration callback.
|
||||||
void device_attached(const std::string &device);
|
void device_attached(const std::string &device);
|
||||||
|
|
||||||
|
@ -218,10 +220,9 @@ private:
|
||||||
typedef std::array<unsigned char, 13> DataPacketRaw;
|
typedef std::array<unsigned char, 13> DataPacketRaw;
|
||||||
|
|
||||||
// Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by the worker thread.
|
// 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.
|
// 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_packet(const DataPacketRaw& packet, const int packet_length, 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_translation(const DataPacketRaw& packet, 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_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);
|
static bool handle_packet_button(const DataPacketRaw& packet, unsigned int packet_size, const Params ¶ms, State &state_in_out);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue