set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
-set(FFBChecker_SRCS
+set(FFBChecker_SRCS sdl2ffbeffectfactory.cpp sdl2ffbdevice.cpp
conditioneffectsettings.cpp
constanteffectsettings.cpp
effectsettings.cpp
return;
}
-
DeviceProber::DeviceList SDL2DeviceProber::listDevices()
{
DeviceProber::DeviceList devList;
- int numJoy;
+ int numHapt;
if (!s_SDLInited)
return devList;
- numJoy = SDL_NumJoysticks();
+ numHapt = SDL_NumHaptics();
- for (int idx = 0; idx < numJoy; idx++) {
+ for (int idx = 0; idx < numHapt; idx++) {
DeviceProber::DeviceInfo dinfo;
- SDL_Joystick* joystick = SDL_JoystickOpen(idx);
-
- if (joystick == nullptr) {
- qDebug() << "SDL2: Cannot open joystick at idx" << idx;
- continue;
- }
-
- if (SDL_JoystickIsHaptic(joystick) != 1) {
- qDebug() << "SDL2: Joystick at idx" << idx << "does not support force feedback";
- SDL_JoystickClose(joystick);
- continue;
- }
-
- dinfo.name = QString(SDL_JoystickName(joystick));
+ dinfo.name = QString(SDL_HapticName(idx));
dinfo.id = QVariant(idx);
devList.push_back(dinfo);
- SDL_JoystickClose(joystick);
}
return devList;
std::shared_ptr<FFBDevice> SDL2DeviceProber::openDevice(const QString& id)
{
+ SDL_Haptic* haptic;
+ std::shared_ptr<SDL2FFBDevice> device;
+ int idx;
+ int maxEffectCount;
+ bool ok;
+
if (!s_SDLInited)
return nullptr;
- return nullptr;
+ idx = id.toInt(&ok);
+ if (!ok)
+ return nullptr;
+
+ haptic = SDL_HapticOpen(idx);
+ if (haptic == nullptr)
+ return nullptr;
+
+ maxEffectCount = SDL_HapticNumEffects(haptic);
+ if (maxEffectCount < 1) {
+ QMessageBox::critical(nullptr, "SDL2 device error", "Maximum effect count for this device is zero.");
+ SDL_HapticClose(haptic);
+ return nullptr;
+ }
+
+ device = std::make_shared<SDL2FFBDevice>(haptic, maxEffectCount);
+ if (!device->queryDeviceCapabilities()) {
+ QMessageBox::critical(nullptr, "SDL2 device error", "Unable to query device capabilities.");
+ device->close();
+ return nullptr;
+ }
+
+ m_openedDevices.push_back(device);
+ return device;
}
+
#include "deviceprober.h"
#include "SDL.h"
+#include "sdl2ffbdevice.h"
+#include <list>
class SDL2DeviceProber : public DeviceProber
{
std::shared_ptr<FFBDevice> openDevice(const QString& id);
private:
+ std::list<std::shared_ptr<SDL2FFBDevice>> m_openedDevices;
+
static bool s_SDLInited;
--- /dev/null
+#include "sdl2ffbdevice.h"
+#include "sdl2ffbeffectfactory.h"
+
+SDL2FFBDevice::SDL2FFBDevice(SDL_Haptic* haptic, const int maxEffectCount) :
+ FFBDevice(maxEffectCount),
+ c_haptic(haptic)
+{
+ for (int i = 0; i < maxEffectCount; i++)
+ m_effects.push_back(SDL2FFBEffectFactory::createEffect(FFBEffectTypes::NONE));
+}
+
+void SDL2FFBDevice::close()
+{
+ SDL_HapticClose(c_haptic);
+}
+
+bool SDL2FFBDevice::queryDeviceCapabilities()
+{
+ unsigned int caps;
+ bool hasPeriodic = false;
+ bool hasCondition = false;
+
+ caps = SDL_HapticQuery(c_haptic);
+ if (caps == 0)
+ return false;
+
+ if (caps & SDL_HAPTIC_CONSTANT)
+ m_availableEffects.push_back(FFBEffectTypes::CONSTANT);
+
+ if (caps & SDL_HAPTIC_SINE) {
+ hasPeriodic = true;
+ m_availablePeriodicWaveforms.push_back(PeriodicWaveforms::SINE);
+ }
+ if (caps & SDL_HAPTIC_TRIANGLE) {
+ hasPeriodic = true;
+ m_availablePeriodicWaveforms.push_back(PeriodicWaveforms::TRIANGLE);
+ }
+ if (caps & SDL_HAPTIC_SAWTOOTHUP) {
+ hasPeriodic = true;
+ m_availablePeriodicWaveforms.push_back(PeriodicWaveforms::SAW_UP);
+ }
+ if (caps & SDL_HAPTIC_SAWTOOTHDOWN) {
+ hasPeriodic = true;
+ m_availablePeriodicWaveforms.push_back(PeriodicWaveforms::SAW_DOWN);
+ }
+ if (hasPeriodic)
+ m_availableEffects.push_back(FFBEffectTypes::PERIODIC);
+
+ if (caps & SDL_HAPTIC_RAMP)
+ m_availableEffects.push_back(FFBEffectTypes::RAMP);
+
+ if (caps & SDL_HAPTIC_SPRING) {
+ hasCondition = true;
+ m_availableConditionSubtypes.push_back(ConditionSubtypes::SPRING);
+ }
+ if (caps & SDL_HAPTIC_DAMPER) {
+ hasCondition = true;
+ m_availableConditionSubtypes.push_back(ConditionSubtypes::DAMPER);
+ }
+ if (caps & SDL_HAPTIC_INERTIA) {
+ hasCondition = true;
+ m_availableConditionSubtypes.push_back(ConditionSubtypes::INERTIA);
+ }
+ if (caps & SDL_HAPTIC_FRICTION) {
+ hasCondition = true;
+ m_availableConditionSubtypes.push_back(ConditionSubtypes::FRICTION);
+ }
+
+ if (hasCondition)
+ m_availableEffects.push_back(FFBEffectTypes::CONDITION);
+
+ return true;
+}
+
+bool SDL2FFBDevice::removeAndEraseEffect(const int idx)
+{
+ return false;
+}
+
+bool SDL2FFBDevice::startEffect(const int idx, const FFBEffectTypes type, std::shared_ptr< FFBEffectParameters > parameters)
+{
+ return false;
+}
+
+bool SDL2FFBDevice::stopEffect(const int idx)
+{
+ return false;
+}
+
+bool SDL2FFBDevice::uploadEffect(const int idx, const FFBEffectTypes type, std::shared_ptr< FFBEffectParameters > parameters)
+{
+ return false;
+}
+
--- /dev/null
+#ifndef SDL2FFBDEVICE_H
+#define SDL2FFBDEVICE_H
+
+#include "SDL.h"
+#include "ffbdevice.h"
+
+class SDL2FFBDevice : public FFBDevice {
+public:
+ SDL2FFBDevice(SDL_Haptic* haptic, const int maxEffectCount);
+ void close();
+ bool queryDeviceCapabilities();
+ bool removeAndEraseEffect(const int idx);
+ bool startEffect(const int idx, const FFBEffectTypes type, std::shared_ptr<FFBEffectParameters> parameters);
+ bool stopEffect(const int idx);
+ bool uploadEffect(const int idx, const FFBEffectTypes type, std::shared_ptr<FFBEffectParameters> parameters);
+
+private:
+ SDL_Haptic* c_haptic;
+};
+
+#endif // SDL2FFBDEVICE_H
\ No newline at end of file
--- /dev/null
+#include "sdl2ffbeffectfactory.h"
+
+std::shared_ptr<FFBEffect> SDL2FFBEffectFactory::createEffect(FFBEffectTypes type)
+{
+ switch (type) {
+ case FFBEffectTypes::NONE:
+ return std::shared_ptr<FFBEffect>(new FFBNullEffect());
+ default:
+ return std::shared_ptr<FFBEffect>(new FFBNullEffect());
+ }
+}
\ No newline at end of file
--- /dev/null
+#ifndef SDL2FFBEFFECTFACTORY_H
+#define SDL2FFBEFFECTFACTORY_H
+
+#include "globals.h"
+#include "ffbnulleffect.h"
+
+class SDL2FFBEffectFactory
+{
+public:
+ static std::shared_ptr<FFBEffect> createEffect(FFBEffectTypes type);
+
+ SDL2FFBEffectFactory() = delete;
+};
+
+#endif // LINUXFFBEFFECTFACTORY_H