mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-10 16:27:54 -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 "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<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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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<unsigned char, 13> 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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue