ENABLE_3DCONNEXION_DEVICES -> Mouse3DController reworked to handle reports of length 7 bytes and 13 bytes

This commit is contained in:
Enrico Turri 2019-10-08 13:38:08 +02:00
parent 8fcd4e4407
commit 9447d3e1b5
2 changed files with 188 additions and 107 deletions

View file

@ -22,18 +22,30 @@ static const std::vector<int> _3DCONNEXION_VENDORS =
0x256F // 3DCONNECTION = 9583 // 3Dconnexion 0x256F // 3DCONNECTION = 9583 // 3Dconnexion
}; };
// See: https://github.com/FreeSpacenav/spacenavd/blob/a9eccf34e7cac969ee399f625aef827f4f4aaec6/src/dev.c#L202 for a wider list of devices // See: https://github.com/FreeSpacenav/spacenavd/blob/a9eccf34e7cac969ee399f625aef827f4f4aaec6/src/dev.c#L202
static const std::vector<int> _3DCONNEXION_DEVICES = static const std::vector<int> _3DCONNEXION_DEVICES =
{ {
0xC623, // TRAVELER = 50723 0xc603, /* 50691 spacemouse plus XT */
0xC626, // NAVIGATOR = 50726 *TESTED* 0xc605, /* 50693 cadman */
0xc628, // NAVIGATOR_FOR_NOTEBOOKS = 50728 0xc606, /* 50694 spacemouse classic */
0xc627, // SPACEEXPLORER = 50727 0xc621, /* 50721 spaceball 5000 */
0xC603, // SPACEMOUSE = 50691 0xc623, /* 50723 space traveller */
0xC62B, // SPACEMOUSEPRO = 50731 0xc625, /* 50725 space pilot */
0xc621, // SPACEBALL5000 = 50721 0xc626, /* 50726 space navigator *TESTED* */
0xc625, // SPACEPILOT = 50725 0xc627, /* 50727 space explorer */
0xc652, // SPACEMOUSE PRO WIRELESS = 50770 *TESTED* 0xc628, /* 50728 space navigator for notebooks*/
0xc629, /* 50729 space pilot pro*/
0xc62b, /* 50731 space mouse pro*/
0xc62e, /* 50734 spacemouse wireless (USB cable) */
0xc62f, /* 50735 spacemouse wireless receiver */
0xc631, /* 50737 spacemouse pro wireless *TESTED* */
0xc632, /* 50738 spacemouse pro wireless receiver */
0xc633, /* 50739 spacemouse enterprise */
0xc635, /* 50741 spacemouse compact */
0xc636, /* 50742 spacemouse module */
0xc640, /* 50752 nulooq */
// 0xc652, /* 50770 3Dconnexion universal receiver */
}; };
namespace Slic3r { namespace Slic3r {
@ -51,18 +63,18 @@ Mouse3DController::State::State()
bool Mouse3DController::State::process_mouse_wheel() bool Mouse3DController::State::process_mouse_wheel()
{ {
if (m_mouse_wheel_counter > 0) if (m_mouse_wheel_counter == 0)
return false;
else if (!m_rotation.empty())
{ {
--m_mouse_wheel_counter; --m_mouse_wheel_counter;
return true; return true;
} }
else if (m_rotation.empty()) else
{ {
m_mouse_wheel_counter = 0; m_mouse_wheel_counter = 0;
return true; return true;
} }
return false;
} }
bool Mouse3DController::State::apply(Camera& camera) bool Mouse3DController::State::apply(Camera& camera)
@ -225,20 +237,29 @@ bool Mouse3DController::connect_device()
unsigned short vendor_id = 0; unsigned short vendor_id = 0;
unsigned short product_id = 0; unsigned short product_id = 0;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
hid_device_info* cur = devices;
while (cur != nullptr)
{
std::cout << "Detected device '";
if (cur->manufacturer_string != nullptr)
std::wcout << cur->manufacturer_string << L" ";
else
std::wcout << "MMM ";
if (cur->product_string != nullptr)
std::wcout << cur->product_string;
else
std::wcout << "PPP";
std::cout << "' code: " << cur->product_id << " (" << std::hex << cur->product_id << std::dec << ")" << std::endl;
cur = cur->next;
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
hid_device_info* current = devices; hid_device_info* current = devices;
while (current != nullptr) while (current != nullptr)
{ {
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
if (current->manufacturer_string != nullptr)
{
std::string aaa = boost::nowide::narrow(current->manufacturer_string);
if (aaa == "3Dconnexion")
{
std::cout << "Detected 3Dconnexion device code: " << current->product_id << " (" << std::hex << current->product_id << std::dec << ")" << std::endl;
}
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
for (size_t i = 0; i < _3DCONNEXION_VENDORS.size(); ++i) for (size_t i = 0; i < _3DCONNEXION_VENDORS.size(); ++i)
{ {
if (_3DCONNEXION_VENDORS[i] == current->vendor_id) if (_3DCONNEXION_VENDORS[i] == current->vendor_id)
@ -340,30 +361,8 @@ void Mouse3DController::run()
void Mouse3DController::collect_input() void Mouse3DController::collect_input()
{ {
auto convert_input = [](unsigned char first, unsigned char second)-> double DataPacket packet = { 0 };
{ int res = hid_read_timeout(m_device, packet.data(), packet.size(), 100);
int ret = 0;
switch (second)
{
case 0: { ret = (int)first; break; }
case 1: { ret = (int)first + 255; break; }
case 254: { ret = -511 + (int)first; break; }
case 255: { ret = -255 + (int)first; break; }
default: { break; }
}
return (double)ret / 349.0;
};
// Read data from device
enum EDataType
{
Translation = 1,
Rotation,
Button
};
unsigned char retrieved_data[8] = { 0 };
int res = hid_read_timeout(m_device, retrieved_data, sizeof(retrieved_data), 100);
if (res < 0) if (res < 0)
{ {
// An error occourred (device detached from pc ?) // An error occourred (device detached from pc ?)
@ -371,73 +370,148 @@ void Mouse3DController::collect_input()
return; return;
} }
if (!wxGetApp().IsActive())
return;
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
if (res > 0) bool updated = false;
if (res == 7)
updated = handle_packet(packet);
else if (res == 13)
updated = handle_wireless_packet(packet);
else if (res > 0)
std::cout << "Got unknown data packet of length: " << res << ", code:" << (int)packet[0] << std::endl;
if (updated)
// ask for an idle event to update 3D scene
wxWakeUpIdle();
}
bool Mouse3DController::handle_packet(const DataPacket& packet)
{
switch (packet[0])
{ {
bool updated = false; case 1: // Translation
switch (retrieved_data[0])
{ {
case Translation: if (handle_packet_translation(packet))
{ return true;
Vec3d translation(-convert_input(retrieved_data[1], retrieved_data[2]),
convert_input(retrieved_data[3], retrieved_data[4]),
convert_input(retrieved_data[5], retrieved_data[6]));
if (!translation.isApprox(Vec3d::Zero()))
{
updated = true;
m_state.append_translation(translation);
}
break;
}
case Rotation:
{
Vec3f rotation(-(float)convert_input(retrieved_data[1], retrieved_data[2]),
(float)convert_input(retrieved_data[3], retrieved_data[4]),
-(float)convert_input(retrieved_data[5], retrieved_data[6]));
if (!rotation.isApprox(Vec3f::Zero()))
{
updated = true;
m_state.append_rotation(rotation);
}
break;
}
case Button:
{
// Because of lack of documentation, it is not clear how we should interpret the retrieved data for the button case.
// Experiments made with SpaceNavigator:
// retrieved_data[1] == 0 if no button pressed
// retrieved_data[1] == 1 if left button pressed
// retrieved_data[1] == 2 if right button pressed
// retrieved_data[1] == 3 if left and right button pressed
// seems to show that each button is associated to a bit of retrieved_data[1], which means that at max 8 buttons can be supported.
for (unsigned int i = 0; i < 8; ++i)
{
if (retrieved_data[1] & (0x1 << i))
{
updated = true;
m_state.append_button(i);
}
}
// // On the other hand, other libraries, as in https://github.com/koenieee/CrossplatformSpacemouseDriver/blob/master/SpaceMouseDriver/driver/SpaceMouseController.cpp
// // interpret retrieved_data[1] as the button id
// if (retrieved_data[1] > 0)
// m_state.set_button((unsigned int)retrieved_data[1]);
break;
}
default:
break; break;
} }
case 2: // Rotation
{
if (handle_packet_rotation(packet, 1))
return true;
if (updated) break;
// ask for an idle event to update 3D scene }
wxWakeUpIdle(); case 3: // Button
{
if (handle_packet_button(packet, 6))
return true;
break;
}
default:
{
std::cout << "Got unknown data packet of code: " << (int)packet[0] << std::endl;
break;
}
} }
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;
break;
}
default:
{
std::cout << "Got unknown data packet of code: " << (int)packet[0] << std::endl;
break;
}
}
return false;
}
double convert_input(unsigned char first, unsigned char second)
{
int ret = 0;
switch (second)
{
case 0: { ret = (int)first; break; }
case 1: { ret = (int)first + 255; break; }
case 254: { ret = -511 + (int)first; break; }
case 255: { ret = -255 + (int)first; break; }
default: { break; }
}
return (double)ret / 349.0;
};
bool Mouse3DController::handle_packet_translation(const DataPacket& packet)
{
Vec3d translation(-convert_input(packet[1], packet[2]),
convert_input(packet[3], packet[4]),
convert_input(packet[5], packet[6]));
if (!translation.isApprox(Vec3d::Zero()))
{
m_state.append_translation(translation);
return true;
}
return false;
}
bool Mouse3DController::handle_packet_rotation(const DataPacket& packet, unsigned int first_byte)
{
Vec3f rotation(-(float)convert_input(packet[first_byte + 0], packet[first_byte + 1]),
(float)convert_input(packet[first_byte + 2], packet[first_byte + 3]),
-(float)convert_input(packet[first_byte + 4], packet[first_byte + 5]));
if (!rotation.isApprox(Vec3f::Zero()))
{
m_state.append_rotation(rotation);
return true;
}
return false;
}
bool Mouse3DController::handle_packet_button(const DataPacket& packet, unsigned int packet_size)
{
for (unsigned int i = 0, base = 0; i < packet_size; ++i, base += 8)
{
for (unsigned int j = 0; j < 8; ++j)
{
if (packet[i + 1] & (0x1 << j))
{
m_state.append_button(base + j);
return true;
}
}
}
return false;
} }
} // namespace GUI } // namespace GUI

View file

@ -104,6 +104,13 @@ private:
// secondary thread methods // secondary thread methods
void run(); void run();
void collect_input(); void collect_input();
typedef std::array<unsigned char, 13> DataPacket;
bool handle_packet(const DataPacket& packet);
bool handle_wireless_packet(const DataPacket& packet);
bool handle_packet_translation(const DataPacket& packet);
bool handle_packet_rotation(const DataPacket& packet, unsigned int first_byte);
bool handle_packet_button(const DataPacket& packet, unsigned int packet_size);
}; };
} // namespace GUI } // namespace GUI