/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
QElectroTech is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QElectroTech. If not, see .
*/
/*
A stand-in for 3DxWare's 3DconnexionClient.framework, for
tst_spacemouseconnexion: it exports the calls ConnexionBackend makes,
plus fake*() controls the test uses to script 3DxWare's side. Like the
real driver, it delivers messages on a thread of its own.
*/
#include
#include
#include
#include
#include
#define FAKE_EXPORT extern "C" Q_DECL_EXPORT
namespace {
using MessageHandler = void (*)(uint32_t, uint32_t, void *);
using DeviceHandler = void (*)(uint32_t);
MessageHandler handler = nullptr;
int16_t handlers_result = 0;
uint16_t client_result = 7;
std::string registered_name;
uint32_t registered_mode = 0;
uint32_t registered_mask = 0;
uint32_t registered_buttons = 0;
int unregisters = 0;
int cleanups = 0;
}
FAKE_EXPORT int16_t SetConnexionHandlers(MessageHandler message, DeviceHandler, DeviceHandler, bool)
{
if (handlers_result == 0) {
handler = message;
}
return handlers_result;
}
FAKE_EXPORT void CleanupConnexionHandlers()
{
handler = nullptr;
++cleanups;
}
FAKE_EXPORT uint16_t RegisterConnexionClient(uint32_t, const uint8_t *name, uint16_t mode, uint32_t mask)
{
registered_name.assign(reinterpret_cast(name) + 1, name[0]);
registered_mode = mode;
registered_mask = mask;
return client_result;
}
FAKE_EXPORT void SetConnexionClientButtonMask(uint16_t, uint32_t mask)
{
registered_buttons = mask;
}
FAKE_EXPORT void UnregisterConnexionClient(uint16_t)
{
++unregisters;
}
/// Reset, and set what SetConnexionHandlers and RegisterConnexionClient return.
FAKE_EXPORT void fakeReset(int16_t handlers, uint16_t client)
{
handler = nullptr;
handlers_result = handlers;
client_result = client;
registered_name.clear();
registered_mode = registered_mask = registered_buttons = 0;
unregisters = cleanups = 0;
}
/// What the backend registered with: name, mode, mask, button mask, and
/// how many times it unregistered and cleaned up.
FAKE_EXPORT const char *fakeRegistration(uint32_t *mode, uint32_t *mask, uint32_t *buttons,
int *unregistered, int *cleaned)
{
*mode = registered_mode;
*mask = registered_mask;
*buttons = registered_buttons;
*unregistered = unregisters;
*cleaned = cleanups;
return registered_name.c_str();
}
/// Send one ConnexionDeviceState (packed to 2 bytes, 48 bytes long) from
/// another thread, as 3DxWare does.
FAKE_EXPORT void fakeSend(uint16_t client, uint16_t command, const int16_t axis[6], uint32_t buttons)
{
unsigned char state[48] = {};
std::memcpy(state + 2, &client, 2);
std::memcpy(state + 4, &command, 2);
std::memcpy(state + 30, axis, 12);
std::memcpy(state + 44, &buttons, 4);
std::thread driver([&state]() {
if (handler) {
handler(0, 0x33645352, state); // '3dSR'
}
});
driver.join();
}