/* Copyright (c) 2016, Stanislaw Halik * Permission to use, copy, modify, and/or distribute this * software for any purpose with or without fee is hereby granted, * provided that the above copyright notice and this permission * notice appear in all copies. */ #include "vjoystick.h" #include "api/plugin-api.hpp" #include "compat/math.hpp" #include #include #include #include #include #include // required for api headers #include #undef PPJOY_MODE #include #include #define OPENTRACK_VJOYSTICK_ID 1 const unsigned char vjoystick::axis_ids[6] = { HID_USAGE_X, HID_USAGE_Y, HID_USAGE_Z, HID_USAGE_RX, HID_USAGE_RY, HID_USAGE_RZ, // HID_USAGE_SL0, // HID_USAGE_SL1, // HID_USAGE_WHL, }; static constexpr double val_minmax[6] = { 50, 50, 50, 180, 180, 180 }; bool vjoystick::init() { if (!AcquireVJD(OPENTRACK_VJOYSTICK_ID)) return false; unsigned cnt = 0; for (unsigned i = 0; i < axis_count; i++) { bool status = true; status &= !!GetVJDAxisExist(OPENTRACK_VJOYSTICK_ID, axis_ids[i]); status &= !!GetVJDAxisMin(OPENTRACK_VJOYSTICK_ID, axis_ids[i], &axis_min[i]); status &= !!GetVJDAxisMax(OPENTRACK_VJOYSTICK_ID, axis_ids[i], &axis_max[i]); if (!status) { axis_min[i] = 0; axis_max[i] = 0; } else cnt++; } if (!cnt) { RelinquishVJD(OPENTRACK_VJOYSTICK_ID); return false; } else return true; } int vjoystick::to_axis_value(unsigned axis_id, double val) const { const double minmax = val_minmax[axis_id]; const double min = axis_min[axis_id]; const double max = axis_max[axis_id]; return (int)(clamp((val+minmax) * max / (2*minmax) - min, min, max)); } vjoystick::vjoystick() = default; vjoystick::~vjoystick() { if (status) RelinquishVJD(OPENTRACK_VJOYSTICK_ID); } module_status vjoystick::initialize() { QString msg; if (!vJoyEnabled()) msg = tr("vjoystick won't work without the driver installed."); else if (WORD VerDll, VerDrv; !DriverMatch(&VerDll, &VerDrv)) msg = tr("driver/SDK version mismatch"); else { int code; switch (code = GetVJDStatus(OPENTRACK_VJOYSTICK_ID)) { case VJD_STAT_OWN: msg = tr("BUG: handle leak."); break; case VJD_STAT_FREE: break; case VJD_STAT_BUSY: msg = tr("Virtual joystick already in use."); break; case VJD_STAT_MISS: msg = tr("Device missing. Add joystick #1."); break; case VJD_STAT_UNKN: msg = tr("Unknown error."); break; default: msg = tr("Unknown error #%1.").arg(code); break; } } status = msg.isNull(); if (!status) { QMessageBox msgbox; msgbox.setIcon(QMessageBox::Critical); msgbox.setText(tr("vjoystick driver problem")); msgbox.setInformativeText(msg); QPushButton* driver_button = msgbox.addButton(tr("Download the driver"), QMessageBox::ActionRole); QPushButton* project_site_button = msgbox.addButton(tr("Visit project site"), QMessageBox::ActionRole); msgbox.addButton(QMessageBox::Close); (void) msgbox.exec(); if (msgbox.clickedButton() == driver_button) { static const char* download_driver_url = "https://sourceforge.net/projects/vjoystick/files/latest/download"; QDesktopServices::openUrl(QUrl(download_driver_url, QUrl::StrictMode)); } else if (msgbox.clickedButton() == project_site_button) { static const char* project_site_url = "http://vjoystick.sourceforge.net/site/"; QDesktopServices::openUrl(QUrl(project_site_url, QUrl::StrictMode)); } } if (!status) return error(tr("Driver problem.")); else return {}; } void vjoystick::pose(const double *pose) { if (first_run) { status = init(); //status &= !!ResetVJD(OPENTRACK_VJOYSTICK_ID); first_run = false; } if (!status) return; for (unsigned i = 0; i < vjoystick::axis_count; i++) { if (axis_min[i] == axis_max[i]) continue; int val = to_axis_value(i, pose[i]); SetAxis(val, OPENTRACK_VJOYSTICK_ID, vjoystick::axis_ids[i]); } } OPENTRACK_DECLARE_PROTOCOL(vjoystick, vjoystick_dialog, vjoystick_metadata)