From bd7ce1df885dba290111cc9317adf951a90519c1 Mon Sep 17 00:00:00 2001 From: Russell Sim Date: Fri, 19 Jun 2020 21:04:22 +0200 Subject: Add Linux Joystick Support Add support for Linux joystick devices, this allows things like the EDTracker to work, and possibly other devices. --- tracker-linux-joystick/CMakeLists.txt | 4 + .../ftnoir_tracker_linux_joystick.cpp | 87 ++++ .../ftnoir_tracker_linux_joystick.h | 90 ++++ .../ftnoir_tracker_linux_joystick_controls.ui | 492 +++++++++++++++++++++ .../ftnoir_tracker_linux_joystick_dialog.cpp | 40 ++ tracker-linux-joystick/lang/nl_NL.ts | 86 ++++ tracker-linux-joystick/lang/ru_RU.ts | 86 ++++ tracker-linux-joystick/lang/stub.ts | 86 ++++ tracker-linux-joystick/lang/zh_CN.ts | 86 ++++ tracker-linux-joystick/linux_joystick.cpp | 65 +++ 10 files changed, 1122 insertions(+) create mode 100644 tracker-linux-joystick/CMakeLists.txt create mode 100644 tracker-linux-joystick/ftnoir_tracker_linux_joystick.cpp create mode 100644 tracker-linux-joystick/ftnoir_tracker_linux_joystick.h create mode 100644 tracker-linux-joystick/ftnoir_tracker_linux_joystick_controls.ui create mode 100644 tracker-linux-joystick/ftnoir_tracker_linux_joystick_dialog.cpp create mode 100644 tracker-linux-joystick/lang/nl_NL.ts create mode 100644 tracker-linux-joystick/lang/ru_RU.ts create mode 100644 tracker-linux-joystick/lang/stub.ts create mode 100644 tracker-linux-joystick/lang/zh_CN.ts create mode 100644 tracker-linux-joystick/linux_joystick.cpp (limited to 'tracker-linux-joystick') diff --git a/tracker-linux-joystick/CMakeLists.txt b/tracker-linux-joystick/CMakeLists.txt new file mode 100644 index 00000000..4e821b01 --- /dev/null +++ b/tracker-linux-joystick/CMakeLists.txt @@ -0,0 +1,4 @@ +if(LINUX) + otr_module(tracker-linux-joystick) + target_link_libraries(opentrack-tracker-linux-joystick) +endif() diff --git a/tracker-linux-joystick/ftnoir_tracker_linux_joystick.cpp b/tracker-linux-joystick/ftnoir_tracker_linux_joystick.cpp new file mode 100644 index 00000000..8fa600e7 --- /dev/null +++ b/tracker-linux-joystick/ftnoir_tracker_linux_joystick.cpp @@ -0,0 +1,87 @@ +/* Copyright (c) 2013 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 "ftnoir_tracker_linux_joystick.h" +#include "api/plugin-api.hpp" +#include "compat/math.hpp" +#include + +joystick::joystick() +{ + QString device = getJoystickDevice(s.guid); + joy_fd = open(device.toUtf8().data(), O_RDONLY | O_NONBLOCK); +} + + +joystick::~joystick() { + if (joy_fd > 0) close(joy_fd); +} + +module_status joystick::start_tracker(QFrame *) +{ + if (joy_fd == -1) return error("Couldn't open joystick"); + return status_ok(); +} + + +void joystick::data(double *data) +{ + 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 + }; + + const QString guid = s.guid; + int axes[8]; + struct js_event event; + bool ret = true; + if (read(joy_fd, &event, sizeof(event)) > 0) + { + switch (event.type) + { + case JS_EVENT_AXIS: + if (event.number >= 8) break; + axes_state[event.number] = event.value; + + break; + default: + /* Ignore init/button events. */ + break; + } + } + + for (int i = 0; i < 6; i++) + { + axes[i] = axes_state[i]; + } + if (ret) + { + for (int i = 0; i < 6; i++) + { + int k = map[i]; + if (k < 0 || k >= 8) + data[i] = 0; + else + data[i] = clamp(axes[k] * limits[i] / AXIS_MAX, + -limits[i], limits[i]); + } + } +} + +OPENTRACK_DECLARE_TRACKER(joystick, dialog_joystick, joystickDll) diff --git a/tracker-linux-joystick/ftnoir_tracker_linux_joystick.h b/tracker-linux-joystick/ftnoir_tracker_linux_joystick.h new file mode 100644 index 00000000..6ddc4909 --- /dev/null +++ b/tracker-linux-joystick/ftnoir_tracker_linux_joystick.h @@ -0,0 +1,90 @@ +/* Copyright (c) 2013 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. + */ +#pragma once +#include "ui_ftnoir_tracker_linux_joystick_controls.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "api/plugin-api.hpp" + +#include +#include +#include + +#include "options/options.hpp" +using namespace options; + +struct settings : opts { + value guid; + value joy_1, joy_2, joy_3, joy_4, joy_5, joy_6; + settings() : + opts("tracker-linux-joystick"), + 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) + {} +}; + +struct linux_joystick { + QString name; + QString device_id; + QString dev; +}; +QList getJoysticks(); +QString getJoystickDevice(QString guid); + +class joystick : public ITracker +{ +public: + joystick(); + ~joystick(); + module_status start_tracker(QFrame *); + void data(double *data); + settings s; + QString guid; + static constexpr int AXIS_MAX = USHRT_MAX; + int axes_state[6] = {0}; + int joy_fd; +}; + +class dialog_joystick: public ITrackerDialog +{ + Q_OBJECT +public: + dialog_joystick(); + void register_tracker(ITracker *) {} + void unregister_tracker() {} + Ui::UILinuxJoystickControls ui; + joystick* tracker; + settings s; + struct joys { + QString name; + QString guid; + }; + QList joys_; +private slots: + void doOK(); + void doCancel(); +}; + +class joystickDll : public Metadata +{ + Q_OBJECT + + QString name() { return tr("Linux Joystick input"); } + QIcon icon() { return QIcon(":/images/opentrack.png"); } +}; diff --git a/tracker-linux-joystick/ftnoir_tracker_linux_joystick_controls.ui b/tracker-linux-joystick/ftnoir_tracker_linux_joystick_controls.ui new file mode 100644 index 00000000..2a54c74a --- /dev/null +++ b/tracker-linux-joystick/ftnoir_tracker_linux_joystick_controls.ui @@ -0,0 +1,492 @@ + + + UILinuxJoystickControls + + + Qt::NonModal + + + + 0 + 0 + 498 + 334 + + + + Tracker settings + + + + ../gui/images/opentrack.png../gui/images/opentrack.png + + + + 12 + + + 6 + + + 12 + + + 6 + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + + + + + 0 + 0 + + + + Device + + + + + + + + 0 + 0 + + + + + + + + + + + Mapping + + + + + + + 0 + 0 + + + + 1 + + + + Disabled + + + + + Joystick axis #1 + + + + + Joystick axis #2 + + + + + Joystick axis #3 + + + + + Joystick axis #4 + + + + + Joystick axis #5 + + + + + Joystick axis #6 + + + + + Joystick axis #7 + + + + + Joystick axis #8 + + + + + + + + + 0 + 0 + + + + 2 + + + + Disabled + + + + + Joystick axis #1 + + + + + Joystick axis #2 + + + + + Joystick axis #3 + + + + + Joystick axis #4 + + + + + Joystick axis #5 + + + + + Joystick axis #6 + + + + + Joystick axis #7 + + + + + Joystick axis #8 + + + + + + + + + 0 + 0 + + + + 3 + + + + Disabled + + + + + Joystick axis #1 + + + + + Joystick axis #2 + + + + + Joystick axis #3 + + + + + Joystick axis #4 + + + + + Joystick axis #5 + + + + + Joystick axis #6 + + + + + Joystick axis #7 + + + + + Joystick axis #8 + + + + + + + + + 0 + 0 + + + + 4 + + + + Disabled + + + + + Joystick axis #1 + + + + + Joystick axis #2 + + + + + Joystick axis #3 + + + + + Joystick axis #4 + + + + + Joystick axis #5 + + + + + Joystick axis #6 + + + + + Joystick axis #7 + + + + + Joystick axis #8 + + + + + + + + + 0 + 0 + + + + 5 + + + + Disabled + + + + + Joystick axis #1 + + + + + Joystick axis #2 + + + + + Joystick axis #3 + + + + + Joystick axis #4 + + + + + Joystick axis #5 + + + + + Joystick axis #6 + + + + + Joystick axis #7 + + + + + Joystick axis #8 + + + + + + + + + 0 + 0 + + + + 6 + + + + Disabled + + + + + Joystick axis #1 + + + + + Joystick axis #2 + + + + + Joystick axis #3 + + + + + Joystick axis #4 + + + + + Joystick axis #5 + + + + + Joystick axis #6 + + + + + Joystick axis #7 + + + + + Joystick axis #8 + + + + + + + + X + + + + + + + Y + + + + + + + Z + + + + + + + Yaw + + + + + + + Pitch + + + + + + + Roll + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + buttonBox + + + + + startEngineClicked() + stopEngineClicked() + cameraSettingsClicked() + + diff --git a/tracker-linux-joystick/ftnoir_tracker_linux_joystick_dialog.cpp b/tracker-linux-joystick/ftnoir_tracker_linux_joystick_dialog.cpp new file mode 100644 index 00000000..1cf75bc1 --- /dev/null +++ b/tracker-linux-joystick/ftnoir_tracker_linux_joystick_dialog.cpp @@ -0,0 +1,40 @@ +#include "ftnoir_tracker_linux_joystick.h" +#include "api/plugin-api.hpp" + +dialog_joystick::dialog_joystick() : 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())); + + QList<::linux_joystick> joysticks = getJoysticks(); + + for (int i = 0; i < joysticks.size(); i++) { + ::linux_joystick joy = joysticks[i]; + joys_.push_back(joys { joy.name, joy.device_id}); + ui.joylist->addItem(QString("%1 | %2").arg(joy.dev).arg(joy.name)); + if (joysticks[i].device_id == s.guid) ui.joylist->setCurrentIndex(i); + } + + 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 dialog_joystick::doOK() { + int idx = ui.joylist->currentIndex(); + static const joys def { {}, {} }; + auto val = joys_.value(idx, def); + s.guid = val.guid; + s.b->save(); + close(); +} + +void dialog_joystick::doCancel() { + close(); +} diff --git a/tracker-linux-joystick/lang/nl_NL.ts b/tracker-linux-joystick/lang/nl_NL.ts new file mode 100644 index 00000000..1c9b89d0 --- /dev/null +++ b/tracker-linux-joystick/lang/nl_NL.ts @@ -0,0 +1,86 @@ + + + + + UILinuxJoystickControls + + Tracker settings + Tracker-instellingen + + + Device + Apparaat + + + Mapping + Verwijzing + + + Disabled + Uitgeschakeld + + + Joystick axis #1 + Joystick-as #1 + + + Joystick axis #2 + Joystick-as #2 + + + Joystick axis #3 + Joystick-as #3 + + + Joystick axis #4 + Joystick-as #4 + + + Joystick axis #5 + Joystick-as #5 + + + Joystick axis #6 + Joystick-as #6 + + + Joystick axis #7 + Joystick-as #7 + + + Joystick axis #8 + Joystick-as #8 + + + X + X + + + Y + Y + + + Z + Z + + + Yaw + Yaw + + + Pitch + Pitch + + + Roll + Rol + + + + joystickDll + + Linux Joystick input + + + + diff --git a/tracker-linux-joystick/lang/ru_RU.ts b/tracker-linux-joystick/lang/ru_RU.ts new file mode 100644 index 00000000..34ed1089 --- /dev/null +++ b/tracker-linux-joystick/lang/ru_RU.ts @@ -0,0 +1,86 @@ + + + + + UILinuxJoystickControls + + Tracker settings + + + + Device + + + + Mapping + + + + Disabled + + + + Joystick axis #1 + + + + Joystick axis #2 + + + + Joystick axis #3 + + + + Joystick axis #4 + + + + Joystick axis #5 + + + + Joystick axis #6 + + + + Joystick axis #7 + + + + Joystick axis #8 + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + + joystickDll + + Linux Joystick input + + + + diff --git a/tracker-linux-joystick/lang/stub.ts b/tracker-linux-joystick/lang/stub.ts new file mode 100644 index 00000000..12dc1400 --- /dev/null +++ b/tracker-linux-joystick/lang/stub.ts @@ -0,0 +1,86 @@ + + + + + UILinuxJoystickControls + + Tracker settings + + + + Device + + + + Mapping + + + + Disabled + + + + Joystick axis #1 + + + + Joystick axis #2 + + + + Joystick axis #3 + + + + Joystick axis #4 + + + + Joystick axis #5 + + + + Joystick axis #6 + + + + Joystick axis #7 + + + + Joystick axis #8 + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + + joystickDll + + Linux Joystick input + + + + diff --git a/tracker-linux-joystick/lang/zh_CN.ts b/tracker-linux-joystick/lang/zh_CN.ts new file mode 100644 index 00000000..12dc1400 --- /dev/null +++ b/tracker-linux-joystick/lang/zh_CN.ts @@ -0,0 +1,86 @@ + + + + + UILinuxJoystickControls + + Tracker settings + + + + Device + + + + Mapping + + + + Disabled + + + + Joystick axis #1 + + + + Joystick axis #2 + + + + Joystick axis #3 + + + + Joystick axis #4 + + + + Joystick axis #5 + + + + Joystick axis #6 + + + + Joystick axis #7 + + + + Joystick axis #8 + + + + X + + + + Y + + + + Z + + + + Yaw + + + + Pitch + + + + Roll + + + + + joystickDll + + Linux Joystick input + + + + diff --git a/tracker-linux-joystick/linux_joystick.cpp b/tracker-linux-joystick/linux_joystick.cpp new file mode 100644 index 00000000..3369a29e --- /dev/null +++ b/tracker-linux-joystick/linux_joystick.cpp @@ -0,0 +1,65 @@ +#include "ftnoir_tracker_linux_joystick.h" + +#include +#include +#include + +// Discovery is done by searching for devices in the sys file system. +// +// Given a path like this +// /sys/devices/pci0000:00/0000:00:14.0/usb1/1-10/1-10:1.2/0003:2341:8036.0170/input/input380/js0 +// we want to get this part of the string 2341:8036, it will allow us to +// identify the device in the future. +// alternative way of doing this https://stackoverflow.com/questions/21173988/linux-attempting-to-get-joystick-vendor-and-product-ids-via-ioctl-get-einval-i +std::tuple sysfsDeviceToJsDev(QFileInfo device) { + using ret = std::tuple; + QString symlink = device.symLinkTarget(); + QString js_dev = QString("/dev/input/%1").arg(device.fileName()); + + QRegExp sep(QString("[:.%1]").arg(QDir::separator())); + QString device_id = symlink.section(sep, -6, -5); + return ret(js_dev, device_id); +} + +QList getJoysticks() +{ + char name[128]; + QList joysticks; + + QDir dir("/sys/class/input/"); + dir.setNameFilters({ "js*" }); + QFileInfoList list = dir.entryInfoList(); + for (int i = 0; i < list.size(); ++i) + { + QFileInfo device = list.at(i); + auto [js_dev, device_id] = sysfsDeviceToJsDev(device); + int iFile = open(js_dev.toUtf8().data(), O_RDONLY | O_NONBLOCK); + if (iFile == -1) continue; + if (ioctl(iFile, JSIOCGNAME(sizeof(name)), &name) > 0) + { + linux_joystick j; + j.name = name; + j.dev = js_dev; + j.device_id = device_id; + joysticks.append(j); + } + close(iFile); + + } + + return joysticks; +} + +QString getJoystickDevice(QString guid) { + QDir dir("/sys/class/input/"); + dir.setNameFilters({ "js*" }); + QFileInfoList list = dir.entryInfoList(); + for (int i = 0; i < list.size(); ++i) + { + QFileInfo device = list.at(i); + auto [js_dev, device_id] = sysfsDeviceToJsDev(device); + if (device_id == guid) return js_dev; + } + + return NULL; +} -- cgit v1.2.3