From 032ab045327e7c442732938818e5ca4bce217406 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 24 Oct 2013 20:11:22 +0200 Subject: initial UNTESTED implementation of joystick tracker --- .../ftnoir_tracker_joystick.cpp | 195 ++++++++-- ftnoir_tracker_joystick/ftnoir_tracker_joystick.h | 63 ++- .../ftnoir_tracker_joystick_controls.ui | 429 +++++++++++++++++++++ .../ftnoir_tracker_joystick_dialog.cpp | 92 ++++- .../ftnoir_tracker_joystick_dll.cpp | 24 -- 5 files changed, 713 insertions(+), 90 deletions(-) create mode 100644 ftnoir_tracker_joystick/ftnoir_tracker_joystick_controls.ui (limited to 'ftnoir_tracker_joystick') diff --git a/ftnoir_tracker_joystick/ftnoir_tracker_joystick.cpp b/ftnoir_tracker_joystick/ftnoir_tracker_joystick.cpp index 62462288..68ae1e91 100644 --- a/ftnoir_tracker_joystick/ftnoir_tracker_joystick.cpp +++ b/ftnoir_tracker_joystick/ftnoir_tracker_joystick.cpp @@ -1,58 +1,197 @@ #include "ftnoir_tracker_joystick.h" #include "facetracknoir/global-settings.h" +#undef NDEBUG +#include +#include -FTNoIR_Tracker::FTNoIR_Tracker() +FTNoIR_Tracker::FTNoIR_Tracker() : + g_pDI(nullptr), + g_pJoystick(nullptr), + joyid(-1) { - bEnableRoll = true; - bEnablePitch = true; - bEnableYaw = true; - bEnableX = true; - bEnableY = true; - bEnableZ = true; + for (int i = 0; i < 6; i++) + axes[i] = -1; + GUID foo = {0}; + preferred = foo; +} + +void FTNoIR_Tracker::reload() +{ + QMutexLocker foo(&mtx); + if (g_pJoystick) + { + g_pJoystick->Unacquire(); + g_pJoystick->Release(); + } + if (g_pDI) + g_pDI->Release(); + + StartTracker(frame); } FTNoIR_Tracker::~FTNoIR_Tracker() { + if (g_pJoystick) + { + g_pJoystick->Unacquire(); + g_pJoystick->Release(); + } + if (g_pDI) + g_pDI->Release(); } -void FTNoIR_Tracker::StartTracker(QFrame*) +static BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, + VOID* pContext ) { + auto self = (FTNoIR_Tracker*) pContext; + + // For axes that are returned, set the DIPROP_RANGE property for the + // enumerated axis in order to scale min/max values. + 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.lMin = -AXIS_MAX; + diprg.lMax = AXIS_MAX; + + // Set the range for the axis + if( FAILED( self->g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) + return DIENUM_STOP; + } + + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext ) +{ + DI_ENUM_CONTEXT* pEnumContext = ( DI_ENUM_CONTEXT* )pContext; + + if (!IsEqualGUID(pEnumContext->preferred_instance, pdidInstance->guidInstance)) + return DIENUM_CONTINUE; + + if (SUCCEEDED(pEnumContext->g_pDI->CreateDevice( pdidInstance->guidInstance, + pEnumContext->g_pJoystick, NULL ))) + pEnumContext->bPreferredJoyCfgValid = true; + + return DIENUM_STOP; +} + +void FTNoIR_Tracker::StartTracker(QFrame* win) +{ + QMutexLocker foo(&mtx); + frame = win; loadSettings(); + auto hr = CoInitialize( nullptr ); + IDirectInputJoyConfig8* pJoyConfig = nullptr; + DIJOYCONFIG PreferredJoyCfg = {0}; + DI_ENUM_CONTEXT enumContext = {0}; + enumContext.pPreferredJoyCfg = &PreferredJoyCfg; + enumContext.bPreferredJoyCfgValid = false; + enumContext.g_pJoystick = &g_pJoystick; + + if( FAILED( hr = DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION, + IID_IDirectInput8, ( VOID** )&g_pDI, NULL ) ) ) + goto fail; + + if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, + EnumJoysticksCallback, + &enumContext, DIEDFL_ATTACHEDONLY ) ) ) + goto fail; + + PreferredJoyCfg.dwSize = sizeof( PreferredJoyCfg ); + if( SUCCEEDED( pJoyConfig->GetConfig( 0, &PreferredJoyCfg, DIJC_GUIDINSTANCE ) ) ) + enumContext.bPreferredJoyCfgValid = true; + if (pJoyConfig) + { + pJoyConfig->Release(); + pJoyConfig = nullptr; + } + + assert((!!enumContext.bPreferredJoyCfgValid) == !!(g_pJoystick != nullptr)); + + if (FAILED(g_pJoystick->SetDataFormat(&c_dfDIJoystick2))) + goto fail; + + if (FAILED(g_pJoystick->SetCooperativeLevel((HWND) win->winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) + goto fail; + + if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback, + ( VOID* )this, DIDFT_ALL ) ) ) + goto fail; + + return; + +fail: + if (g_pJoystick) + g_pJoystick->Release(); + if (g_pDI) + g_pDI->Release(); + g_pJoystick = nullptr; + g_pDI = nullptr; } bool FTNoIR_Tracker::GiveHeadPoseData(double *data) { + QMutexLocker foo(&mtx); + DIJOYSTATE2 js; + + if( !g_pJoystick) + return false; + +start: + auto hr = g_pJoystick->Poll(); + if( FAILED( hr ) ) + { + hr = g_pJoystick->Acquire(); + while( hr == DIERR_INPUTLOST ) + hr = g_pJoystick->Acquire(); + goto start; + } + + if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof( DIJOYSTATE2 ), &js ) ) ) + return false; + + const LONG values[] = { + js.lX, + js.lY, + js.lZ, + js.lRx, + js.lRy, + js.lRz, + js.rglSlider[0], + js.rglSlider[1] + }; + + for (int i = 0; i < 6; i++) + { + auto idx = axes[i] - 1; + if (idx < 0 || idx > 7) + { + data[i] = 0; + } + else { + data[i] = values[i] / (double) AXIS_MAX; + } + } + return true; } -// -// Load the current Settings from the currently 'active' INI-file. -// void FTNoIR_Tracker::loadSettings() { QSettings settings("opentrack"); // Registry settings (in HK_USER) QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file) iniFile.beginGroup ( "tracker-joy" ); - bEnableRoll = iniFile.value ( "EnableRoll", 1 ).toBool(); - bEnablePitch = iniFile.value ( "EnablePitch", 1 ).toBool(); - bEnableYaw = iniFile.value ( "EnableYaw", 1 ).toBool(); - bEnableX = iniFile.value ( "EnableX", 1 ).toBool(); - bEnableY = iniFile.value ( "EnableY", 1 ).toBool(); - bEnableZ = iniFile.value ( "EnableZ", 1 ).toBool(); - iniFile.endGroup (); + joyid = iniFile.value("joyid", -1).toInt(); + for (int i = 0; i < 6; i++) + axes[i] = iniFile.value(QString("axis-%1").arg(i), 0).toInt() - 1; + iniFile.endGroup (); } - -//////////////////////////////////////////////////////////////////////////////// -// Factory function that creates instances if the Tracker object. - -// Export both decorated and undecorated names. -// GetTracker - Undecorated name, which can be easily used with GetProcAddress -// Win32 API function. -// _GetTracker@0 - Common name decoration for __stdcall functions in C language. -//#pragma comment(linker, "/export:GetTracker=_GetTracker@0") - extern "C" FTNOIR_TRACKER_BASE_EXPORT ITracker* CALLING_CONVENTION GetConstructor() { return new FTNoIR_Tracker; diff --git a/ftnoir_tracker_joystick/ftnoir_tracker_joystick.h b/ftnoir_tracker_joystick/ftnoir_tracker_joystick.h index 0769a51c..c1157cba 100644 --- a/ftnoir_tracker_joystick/ftnoir_tracker_joystick.h +++ b/ftnoir_tracker_joystick/ftnoir_tracker_joystick.h @@ -1,13 +1,37 @@ +#pragma once #include "ftnoir_tracker_base/ftnoir_tracker_base.h" -#include "ui_ftnoir_ftnclientcontrols.h" -#include -#include +#include "ui_ftnoir_tracker_joystick_controls.h" +#include +#include +#include #include #include +#include #include -#include +#include #include #include "facetracknoir/global-settings.h" +#ifndef DIRECTINPUT_VERSION +# define DIRECTINPUT_VERSION 0x800 +#endif +#include +#include +#include +#include +#include +#include +#include + +#define AXIS_MAX 8192 + +struct DI_ENUM_CONTEXT +{ + DIJOYCONFIG* pPreferredJoyCfg; + bool bPreferredJoyCfgValid; + GUID preferred_instance; + LPDIRECTINPUTDEVICE8* g_pJoystick; + LPDIRECTINPUT8 g_pDI; +}; class FTNoIR_Tracker : public ITracker { @@ -15,16 +39,17 @@ public: FTNoIR_Tracker(); ~FTNoIR_Tracker(); - void StartTracker(QFrame *); + void StartTracker(QFrame *win); bool GiveHeadPoseData(double *data); void loadSettings(); -private: - bool bEnableRoll; - bool bEnablePitch; - bool bEnableYaw; - bool bEnableX; - bool bEnableY; - bool bEnableZ; + LPDIRECTINPUT8 g_pDI; + LPDIRECTINPUTDEVICE8 g_pJoystick; + int axes[6]; + GUID preferred; + int joyid; + QMutex mtx; + QFrame* frame; + void reload(); }; // Widget that has controls for FTNoIR protocol client-settings. @@ -32,20 +57,24 @@ class TrackerControls: public QWidget, public ITrackerDialog { Q_OBJECT public: - explicit TrackerControls(); ~TrackerControls(); void showEvent (QShowEvent *); void Initialize(QWidget *parent); - void registerTracker(ITracker *) {} - void unRegisterTracker() {} - + void registerTracker(ITracker *foo) { + tracker = dynamic_cast(foo); + } + void unRegisterTracker() { + tracker = NULL; + } + QList guids; private: - Ui::UICFTNClientControls ui; + Ui::UIJoystickControls ui; void loadSettings(); void save(); bool settingsDirty; + FTNoIR_Tracker* tracker; private slots: void doOK(); diff --git a/ftnoir_tracker_joystick/ftnoir_tracker_joystick_controls.ui b/ftnoir_tracker_joystick/ftnoir_tracker_joystick_controls.ui new file mode 100644 index 00000000..038e5925 --- /dev/null +++ b/ftnoir_tracker_joystick/ftnoir_tracker_joystick_controls.ui @@ -0,0 +1,429 @@ + + + UIJoystickControls + + + Qt::ApplicationModal + + + + 0 + 0 + 188 + 259 + + + + + 0 + 0 + + + + FTNoIR tracker settings FaceTrackNoIR + + + + images/FaceTrackNoIR.pngimages/FaceTrackNoIR.png + + + Qt::LeftToRight + + + false + + + + + + + 0 + 0 + + + + + 0 + 85 + + + + Axis enablement + + + Qt::AlignCenter + + + + + + Yaw + + + + + + + Pitch + + + + + + + Z + + + + + + + + + + + + + #1 + + + + + #2 + + + + + #3 + + + + + #4 + + + + + #5 + + + + + #6 + + + + + #7 + + + + + #8 + + + + + + + + + + + + + + #1 + + + + + #2 + + + + + #3 + + + + + #4 + + + + + #5 + + + + + #6 + + + + + #7 + + + + + #8 + + + + + + + + + + + + + + #1 + + + + + #2 + + + + + #3 + + + + + #4 + + + + + #5 + + + + + #6 + + + + + #7 + + + + + #8 + + + + + + + + + + + + + + #1 + + + + + #2 + + + + + #3 + + + + + #4 + + + + + #5 + + + + + #6 + + + + + #7 + + + + + #8 + + + + + + + + + + + + + + #1 + + + + + #2 + + + + + #3 + + + + + #4 + + + + + #5 + + + + + #6 + + + + + #7 + + + + + #8 + + + + + + + + X + + + + + + + + + + + + + #1 + + + + + #2 + + + + + #3 + + + + + #4 + + + + + #5 + + + + + #6 + + + + + #7 + + + + + #8 + + + + + + + + Roll + + + + + + + Y + + + + + + + Joy Id + + + + + + + Joy + + + 32 + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + startEngineClicked() + stopEngineClicked() + cameraSettingsClicked() + + diff --git a/ftnoir_tracker_joystick/ftnoir_tracker_joystick_dialog.cpp b/ftnoir_tracker_joystick/ftnoir_tracker_joystick_dialog.cpp index 87d89a1f..5be36879 100644 --- a/ftnoir_tracker_joystick/ftnoir_tracker_joystick_dialog.cpp +++ b/ftnoir_tracker_joystick/ftnoir_tracker_joystick_dialog.cpp @@ -1,21 +1,51 @@ #include "ftnoir_tracker_joystick.h" #include "facetracknoir/global-settings.h" +static BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext ) +{ + auto self = ( TrackerControls* )pContext; + + self->guids.push_back(pdidInstance->guidInstance); + + return DIENUM_CONTINUE; +} + TrackerControls::TrackerControls() : QWidget() { ui.setupUi( this ); // Connect Qt signals to member-functions - connect(ui.btnOK, SIGNAL(clicked()), this, SLOT(doOK())); - connect(ui.btnCancel, SIGNAL(clicked()), this, SLOT(doCancel())); - - connect(ui.chkEnableRoll, SIGNAL(stateChanged(int)), this, SLOT(settingChanged(int))); - connect(ui.chkEnablePitch, SIGNAL(stateChanged(int)), this, SLOT(settingChanged(int))); - connect(ui.chkEnableYaw, SIGNAL(stateChanged(int)), this, SLOT(settingChanged(int))); - connect(ui.chkEnableX, SIGNAL(stateChanged(int)), this, SLOT(settingChanged(int))); - connect(ui.chkEnableY, SIGNAL(stateChanged(int)), this, SLOT(settingChanged(int))); - connect(ui.chkEnableZ, SIGNAL(stateChanged(int)), this, SLOT(settingChanged(int))); + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); + connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); + + connect(ui.spinBox, SIGNAL(valueChanged(int)), this, SLOT(settingChanged(int))); + connect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(settingChanged(int))); + connect(ui.comboBox_2, SIGNAL(currentIndexChanged(int)), this, SLOT(settingChanged(int))); + connect(ui.comboBox_3, SIGNAL(currentIndexChanged(int)), this, SLOT(settingChanged(int))); + connect(ui.comboBox_4, SIGNAL(currentIndexChanged(int)), this, SLOT(settingChanged(int))); + connect(ui.comboBox_5, SIGNAL(currentIndexChanged(int)), this, SLOT(settingChanged(int))); + connect(ui.comboBox_6, SIGNAL(currentIndexChanged(int)), this, SLOT(settingChanged(int))); + + { + 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(); + } + loadSettings(); } @@ -74,13 +104,21 @@ void TrackerControls::loadSettings() { QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file) + QComboBox* boxen[] = { + ui.comboBox, + ui.comboBox_2, + ui.comboBox_3, + ui.comboBox_4, + ui.comboBox_5, + ui.comboBox_6, + }; + iniFile.beginGroup ( "tracker-joy" ); - ui.chkEnableRoll->setChecked(iniFile.value ( "EnableRoll", 1 ).toBool()); - ui.chkEnablePitch->setChecked(iniFile.value ( "EnablePitch", 1 ).toBool()); - ui.chkEnableYaw->setChecked(iniFile.value ( "EnableYaw", 1 ).toBool()); - ui.chkEnableX->setChecked(iniFile.value ( "EnableX", 1 ).toBool()); - ui.chkEnableY->setChecked(iniFile.value ( "EnableY", 1 ).toBool()); - ui.chkEnableZ->setChecked(iniFile.value ( "EnableZ", 1 ).toBool()); + for (int i = 0; i < 6; i++) + { + boxen[i]->setCurrentIndex(iniFile.value(QString("axis-%1").arg(i), 0).toInt()); + } + ui.spinBox->setValue(iniFile.value("joyid", -1).toInt()); iniFile.endGroup (); settingsDirty = false; @@ -92,15 +130,27 @@ void TrackerControls::save() { QString currentFile = settings.value ( "SettingsFile", QCoreApplication::applicationDirPath() + "/settings/default.ini" ).toString(); QSettings iniFile( currentFile, QSettings::IniFormat ); // Application settings (in INI-file) + QComboBox* boxen[] = { + ui.comboBox, + ui.comboBox_2, + ui.comboBox_3, + ui.comboBox_4, + ui.comboBox_5, + ui.comboBox_6, + }; + iniFile.beginGroup ( "tracker-joy" ); - iniFile.setValue ( "EnableRoll", ui.chkEnableRoll->isChecked() ); - iniFile.setValue ( "EnablePitch", ui.chkEnablePitch->isChecked() ); - iniFile.setValue ( "EnableYaw", ui.chkEnableYaw->isChecked() ); - iniFile.setValue ( "EnableX", ui.chkEnableX->isChecked() ); - iniFile.setValue ( "EnableY", ui.chkEnableY->isChecked() ); - iniFile.setValue ( "EnableZ", ui.chkEnableZ->isChecked() ); + for (int i = 0; i < 6; i++) + { + iniFile.setValue(QString("axis-%1").arg(i), boxen[i]->currentIndex()); + } iniFile.endGroup (); + if(tracker) + { + tracker->reload(); + } + settingsDirty = false; } //////////////////////////////////////////////////////////////////////////////// diff --git a/ftnoir_tracker_joystick/ftnoir_tracker_joystick_dll.cpp b/ftnoir_tracker_joystick/ftnoir_tracker_joystick_dll.cpp index cc099403..c5ee4e5f 100644 --- a/ftnoir_tracker_joystick/ftnoir_tracker_joystick_dll.cpp +++ b/ftnoir_tracker_joystick/ftnoir_tracker_joystick_dll.cpp @@ -1,27 +1,3 @@ -/******************************************************************************** -* FaceTrackNoIR This program is a private project of some enthusiastic * -* gamers from Holland, who don't like to pay much for * -* head-tracking. * -* * -* Copyright (C) 2012 Wim Vriend (Developing) * -* Ron Hendriks (Researching and Testing) * -* * -* Homepage * -* * -* This program 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 3 of the License, or (at your * -* option) any later version. * -* * -* This program 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 this program; if not, see . * -* * -********************************************************************************/ #include "ftnoir_tracker_joystick.h" #include #include "facetracknoir/global-settings.h" -- cgit v1.2.3