diff options
Diffstat (limited to 'tracker-joystick')
-rw-r--r-- | tracker-joystick/CMakeLists.txt | 4 | ||||
-rw-r--r-- | tracker-joystick/ftnoir_tracker_joystick.cpp | 253 | ||||
-rw-r--r-- | tracker-joystick/ftnoir_tracker_joystick.h | 106 | ||||
-rw-r--r-- | tracker-joystick/ftnoir_tracker_joystick_controls.ui | 492 | ||||
-rw-r--r-- | tracker-joystick/ftnoir_tracker_joystick_dialog.cpp | 69 |
5 files changed, 924 insertions, 0 deletions
diff --git a/tracker-joystick/CMakeLists.txt b/tracker-joystick/CMakeLists.txt new file mode 100644 index 00000000..c8d2d218 --- /dev/null +++ b/tracker-joystick/CMakeLists.txt @@ -0,0 +1,4 @@ +if(WIN32) + opentrack_boilerplate(opentrack-tracker-joystick) + link_with_dinput8(opentrack-tracker-joystick) +endif() diff --git a/tracker-joystick/ftnoir_tracker_joystick.cpp b/tracker-joystick/ftnoir_tracker_joystick.cpp new file mode 100644 index 00000000..77fd7241 --- /dev/null +++ b/tracker-joystick/ftnoir_tracker_joystick.cpp @@ -0,0 +1,253 @@ +/* Copyright (c) 2013 Stanislaw Halik <sthalik@misaki.pl> + * + * 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 "ftnoir_tracker_joystick.h" +#include "opentrack/plugin-api.hpp" +#include <QMutexLocker> + +FTNoIR_Tracker::FTNoIR_Tracker() : + g_pDI(nullptr), + g_pJoystick(nullptr), + mtx(QMutex::Recursive), + iter(-1) +{ +} + +void FTNoIR_Tracker::reload() +{ + s.b->reload(); + QMutexLocker foo(&mtx); + if (g_pJoystick) + { + g_pJoystick->Unacquire(); + g_pJoystick->Release(); + } + if (g_pDI) + g_pDI->Release(); + + g_pJoystick = nullptr; + g_pDI = nullptr; + + start_tracker(frame); +} + +FTNoIR_Tracker::~FTNoIR_Tracker() +{ + if (g_pJoystick) + { + g_pJoystick->Unacquire(); + g_pJoystick->Release(); + } + if (g_pDI) + { + g_pDI->Release(); + } +} + +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + +static BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, + VOID* pContext ) +{ + auto self = (FTNoIR_Tracker*) pContext; + + if( pdidoi->dwType & DIDFT_AXIS ) + { + DIPROPRANGE diprg = {0}; + diprg.diph.dwSize = sizeof( DIPROPRANGE ); + diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER ); + diprg.diph.dwHow = DIPH_BYID; + diprg.diph.dwObj = pdidoi->dwType; + diprg.lMax = FTNoIR_Tracker::AXIS_MAX; + diprg.lMin = -FTNoIR_Tracker::AXIS_MAX; + + if( FAILED( self->g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) + return DIENUM_STOP; + + self->iter++; + } + + return self->iter == 8 ? DIENUM_STOP : DIENUM_CONTINUE; +} + +static BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext ) +{ + auto self = reinterpret_cast<FTNoIR_Tracker*>(pContext); + bool stop = QString(pdidInstance->tszInstanceName) == self->s.joyid; + + if (stop) + { + if (self->guid_to_check.size()) + { + QString guid = guid_to_string(pdidInstance->guidInstance); + if (guid != self->guid_to_check) + { + return DIENUM_CONTINUE; + } + else + qDebug() << "guid ok" << self->guid_to_check; + } + + (void) self->g_pDI->CreateDevice( pdidInstance->guidInstance, &self->g_pJoystick, NULL); + qDebug() << "device" << static_cast<QString>(self->s.joyid); + } + + return stop ? DIENUM_STOP : DIENUM_CONTINUE; +} + +void FTNoIR_Tracker::start_tracker(QFrame* frame) +{ + QMutexLocker foo(&mtx); + this->frame = frame; + iter = 0; + auto hr = CoInitialize( nullptr ); + + if( FAILED( hr = DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION, + IID_IDirectInput8, ( VOID** )&g_pDI, NULL ) ) ) + { + qDebug() << "create"; + goto fail; + } + + guid_to_check = s.guid; + + if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, + EnumJoysticksCallback, + this, + DIEDFL_ATTACHEDONLY))) + { + qDebug() << "enum1"; + goto fail; + } + + if (!g_pJoystick && guid_to_check.size()) + { + guid_to_check = ""; + + if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, + EnumJoysticksCallback, + this, + DIEDFL_ATTACHEDONLY))) + { + qDebug() << "enum2"; + goto fail; + } + } + + if (!g_pJoystick) + { + qDebug() << "ENODEV"; + goto fail; + } + + if (FAILED(g_pJoystick->SetDataFormat(&c_dfDIJoystick))) + { + qDebug() << "format"; + goto fail; + } + + if (FAILED(g_pJoystick->SetCooperativeLevel((HWND) frame->window()->winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) + { + qDebug() << "coop"; + goto fail; + } + + iter = 0; + + if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback, + ( VOID* )this, DIDFT_ALL ))) + { + qDebug() << "enum axes"; + goto fail; + } + + return; + +fail: + if (g_pJoystick) + g_pJoystick->Release(); + if (g_pDI) + g_pDI->Release(); + g_pJoystick = nullptr; + g_pDI = nullptr; + + qDebug() << "joy init failure"; +} + +void FTNoIR_Tracker::data(double *data) +{ + QMutexLocker foo(&mtx); + DIJOYSTATE js = {0}; + + if( !g_pDI || !g_pJoystick) + return; + + bool ok = false; + + for (int i = 0; i < 100; i++) + { + if (!FAILED(g_pJoystick->Poll())) + { + ok = true; + break; + } + if (g_pJoystick->Acquire() != DI_OK) + continue; + else + ok = true; + break; + } + + if (!ok) + return; + + HRESULT hr = 0; + + if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof( js ), &js ) ) ) + return; + + const LONG values[] = { + js.lX, + js.lY, + js.lZ, + js.lRx, + js.lRy, + js.lRz, + js.rglSlider[0], + js.rglSlider[1] + }; + + int map[6] = { + s.joy_1 - 1, + s.joy_2 - 1, + s.joy_3 - 1, + s.joy_4 - 1, + s.joy_5 - 1, + s.joy_6 - 1, + }; + + const double limits[] = { + 100, + 100, + 100, + 180, + 180, + 180 + }; + + for (int i = 0; i < 6; i++) + { + int k = map[i] - 1; + if (k < 0 || k >= 8) + data[i] = 0; + else + data[i] = values[k] * limits[i] / AXIS_MAX; + } +} + +OPENTRACK_DECLARE_TRACKER(FTNoIR_Tracker, TrackerControls, FTNoIR_TrackerDll) diff --git a/tracker-joystick/ftnoir_tracker_joystick.h b/tracker-joystick/ftnoir_tracker_joystick.h new file mode 100644 index 00000000..75305f07 --- /dev/null +++ b/tracker-joystick/ftnoir_tracker_joystick.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2013 Stanislaw Halik <sthalik@misaki.pl> + * + * 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. + */ +#pragma once +#include "ui_ftnoir_tracker_joystick_controls.h" +#include <QComboBox> +#include <QCheckBox> +#include <QSpinBox> +#include <QMessageBox> +#include <QSettings> +#include <QList> +#include <QMutex> +#include <QFrame> +#include <QStringList> +#include <cmath> +#include "opentrack/plugin-api.hpp" +#ifndef DIRECTINPUT_VERSION +# define DIRECTINPUT_VERSION 0x800 +#endif +#include <windows.h> +#include <commctrl.h> +#include <basetsd.h> +#include <dinput.h> +#include <oleauto.h> +#include <shellapi.h> + +#include "opentrack/options.hpp" +using namespace options; + +struct settings : opts { + value<QString> joyid, guid; + value<int> joy_1, joy_2, joy_3, joy_4, joy_5, joy_6; + settings() : + opts("tracker-joystick"), + joyid(b, "joy-id", ""), + guid(b, "joy-guid", ""), + joy_1(b, "axis-map-1", 1), + joy_2(b, "axis-map-2", 2), + joy_3(b, "axis-map-3", 3), + joy_4(b, "axis-map-4", 4), + joy_5(b, "axis-map-5", 5), + joy_6(b, "axis-map-6", 6) + {} +}; + +template<typename = void> +QString guid_to_string(const GUID guid) +{ + char buf[40] = {0}; + wchar_t szGuidW[40] = {0}; + + StringFromGUID2(guid, szGuidW, 40); + WideCharToMultiByte(0, 0, szGuidW, -1, buf, 40, NULL, NULL); + + return QString(buf); +} + +class FTNoIR_Tracker : public ITracker +{ +public: + FTNoIR_Tracker(); + ~FTNoIR_Tracker(); + void start_tracker(QFrame *frame); + void data(double *data); + void reload(); + LPDIRECTINPUT8 g_pDI; + LPDIRECTINPUTDEVICE8 g_pJoystick; + QMutex mtx; + QFrame* frame; + DIDEVICEINSTANCE def; + int iter; // XXX bad style + settings s; + QString guid_to_check; + static constexpr int AXIS_MAX = 65535; +}; + +class TrackerControls: public ITrackerDialog +{ + Q_OBJECT +public: + TrackerControls(); + void register_tracker(ITracker *) {} + void unregister_tracker() {} + Ui::UIJoystickControls ui; + FTNoIR_Tracker* tracker; + settings s; + struct joys { + QString name; + QString guid; + }; + QList<joys> _joys; +private slots: + void doOK(); + void doCancel(); +}; + +class FTNoIR_TrackerDll : public Metadata +{ +public: + QString name() { return QString("Joystick input"); } + QIcon icon() { return QIcon(":/images/facetracknoir.png"); } +}; + diff --git a/tracker-joystick/ftnoir_tracker_joystick_controls.ui b/tracker-joystick/ftnoir_tracker_joystick_controls.ui new file mode 100644 index 00000000..88737023 --- /dev/null +++ b/tracker-joystick/ftnoir_tracker_joystick_controls.ui @@ -0,0 +1,492 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>UIJoystickControls</class> + <widget class="QWidget" name="UIJoystickControls"> + <property name="windowModality"> + <enum>Qt::NonModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>498</width> + <height>303</height> + </rect> + </property> + <property name="windowTitle"> + <string>Tracker settings</string> + </property> + <property name="windowIcon"> + <iconset> + <normaloff>../facetracknoir/images/facetracknoir.png</normaloff>../facetracknoir/images/facetracknoir.png</iconset> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>12</number> + </property> + <property name="topMargin"> + <number>6</number> + </property> + <property name="rightMargin"> + <number>12</number> + </property> + <property name="bottomMargin"> + <number>6</number> + </property> + <item> + <widget class="QFrame" name="frame"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Device</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="joylist"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Mapping</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="1"> + <widget class="QComboBox" name="joy_1"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>1</number> + </property> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #1</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #2</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #3</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #4</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #5</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #6</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #7</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #8</string> + </property> + </item> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="joy_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>2</number> + </property> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #1</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #2</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #3</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #4</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #5</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #6</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #7</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #8</string> + </property> + </item> + </widget> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="joy_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>3</number> + </property> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #1</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #2</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #3</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #4</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #5</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #6</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #7</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #8</string> + </property> + </item> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="joy_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>4</number> + </property> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #1</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #2</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #3</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #4</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #5</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #6</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #7</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #8</string> + </property> + </item> + </widget> + </item> + <item row="4" column="1"> + <widget class="QComboBox" name="joy_5"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>5</number> + </property> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #1</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #2</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #3</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #4</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #5</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #6</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #7</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #8</string> + </property> + </item> + </widget> + </item> + <item row="5" column="1"> + <widget class="QComboBox" name="joy_6"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>6</number> + </property> + <item> + <property name="text"> + <string>Disabled</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #1</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #2</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #3</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #4</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #5</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #6</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #7</string> + </property> + </item> + <item> + <property name="text"> + <string>Joystick axis #8</string> + </property> + </item> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>X</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Y</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Z</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Yaw</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Pitch</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Roll</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections/> + <slots> + <slot>startEngineClicked()</slot> + <slot>stopEngineClicked()</slot> + <slot>cameraSettingsClicked()</slot> + </slots> +</ui> diff --git a/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp b/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp new file mode 100644 index 00000000..0463933f --- /dev/null +++ b/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp @@ -0,0 +1,69 @@ +#include "ftnoir_tracker_joystick.h" +#include "opentrack/plugin-api.hpp" + +static BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext ) +{ + auto self = ( TrackerControls* )pContext; + auto name = QString(pdidInstance->tszInstanceName); + auto guid = guid_to_string(pdidInstance->guidInstance); + TrackerControls::joys cur { name, guid }; + self->_joys.append(cur); + + self->ui.joylist->addItem(name + " " + guid); + + return DIENUM_CONTINUE; +} + +TrackerControls::TrackerControls() : tracker(nullptr) +{ + ui.setupUi( this ); + + // Connect Qt signals to member-functions + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); + connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); + + { + auto hr = CoInitialize( nullptr ); + LPDIRECTINPUT8 g_pDI = nullptr; + + if( FAILED( hr = DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION, + IID_IDirectInput8, ( VOID** )&g_pDI, NULL ) ) ) + goto fin; + + if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, + EnumJoysticksCallback, + this, + DIEDFL_ATTACHEDONLY ))) + goto fin; + +fin: + if (g_pDI) + g_pDI->Release(); + } + + tie_setting(s.joy_1, ui.joy_1); + tie_setting(s.joy_2, ui.joy_2); + tie_setting(s.joy_3, ui.joy_3); + tie_setting(s.joy_4, ui.joy_4); + tie_setting(s.joy_5, ui.joy_5); + tie_setting(s.joy_6, ui.joy_6); +} + +void TrackerControls::doOK() { + int idx = ui.joylist->currentIndex(); + joys def { "", "" }; + auto val = _joys.value(idx, def); + s.guid = val.guid; + s.joyid = val.name; + s.b->save(); + if (tracker) + tracker->reload(); + this->close(); +} + +void TrackerControls::doCancel() { + s.b->reload(); + this->close(); +} + + |