From f90b77dd5e342ebc45259051d23d6396f37c660d Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 1 Nov 2015 09:01:57 +0100 Subject: cmake: fix spline widget linkage --- opentrack/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'opentrack') diff --git a/opentrack/CMakeLists.txt b/opentrack/CMakeLists.txt index 590eaca5e..c3676979b 100644 --- a/opentrack/CMakeLists.txt +++ b/opentrack/CMakeLists.txt @@ -4,3 +4,5 @@ if(NOT WIN32) else() target_link_libraries(opentrack-api winmm) endif() +link_with_dinput8(opentrack-api) +target_link_libraries(opentrack-api opentrack-spline-widget) -- cgit v1.2.3 From 0424a2802aec3600774ba9347c49312bb09b8cfe Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 1 Nov 2015 11:28:17 +0100 Subject: all: adjust options.hpp move to compat --- filter-accela/ftnoir_filter_accela.h | 2 +- filter-ewma2/ftnoir_filter_ewma2.h | 2 +- filter-kalman/ftnoir_filter_kalman.h | 2 +- gui/main.cpp | 2 +- gui/new_file_dialog.h | 2 +- gui/process_detector.h | 2 +- gui/ui.cpp | 4 +-- gui/ui.h | 2 +- opentrack-compat/compat-export.hpp | 15 +++++++++ opentrack-compat/compat-import.hpp | 15 +++++++++ opentrack-compat/export.hpp | 22 +++++++------ opentrack-compat/import.hpp | 15 +++++++++ opentrack-compat/shm.h | 22 ++----------- opentrack/CMakeLists.txt | 2 +- opentrack/main-settings.hpp | 2 +- opentrack/mappings.hpp | 2 +- opentrack/plugin-api.hpp | 40 +++++++++++++++++++----- opentrack/plugin-support.hpp | 2 +- opentrack/selected-libraries.hpp | 9 +++++- opentrack/shortcuts.h | 14 ++++++--- opentrack/state.hpp | 2 +- opentrack/tracker.h | 10 ++++-- opentrack/win32-shortcuts.h | 8 ++++- proto-fg/ftnoir_protocol_fg.h | 2 +- proto-fsuipc/ftnoir_protocol_fsuipc.h | 2 +- proto-ft/ftnoir_protocol_ft.h | 2 +- proto-ftn/ftnoir_protocol_ftn.h | 2 +- proto-mouse/ftnoir_protocol_mouse.h | 2 +- proto-sc/ftnoir_protocol_sc.h | 2 +- spline-widget/CMakeLists.txt | 1 + spline-widget/qfunctionconfigurator.cpp | 2 +- tracker-aruco/ftnoir_tracker_aruco.h | 2 +- tracker-freepie-udp/ftnoir_tracker_freepie-udp.h | 2 +- tracker-hatire/ftnoir_tracker_hat_settings.cpp | 2 +- tracker-ht/ftnoir_tracker_ht.h | 2 +- tracker-hydra/ftnoir_tracker_hydra.h | 2 +- tracker-joystick/ftnoir_tracker_joystick.h | 2 +- tracker-pt/ftnoir_tracker_pt_settings.h | 2 +- tracker-rift-025/ftnoir_tracker_rift_025.h | 2 +- tracker-rift-042/ftnoir_tracker_rift_042.h | 2 +- tracker-rift-080/ftnoir_tracker_rift_080.h | 2 +- tracker-udp/ftnoir_tracker_udp.h | 2 +- 42 files changed, 157 insertions(+), 78 deletions(-) create mode 100644 opentrack-compat/compat-export.hpp create mode 100644 opentrack-compat/compat-import.hpp create mode 100644 opentrack-compat/import.hpp (limited to 'opentrack') diff --git a/filter-accela/ftnoir_filter_accela.h b/filter-accela/ftnoir_filter_accela.h index b15e0ceaa..289b84f03 100644 --- a/filter-accela/ftnoir_filter_accela.h +++ b/filter-accela/ftnoir_filter_accela.h @@ -12,7 +12,7 @@ #include #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include "opentrack-compat/timer.hpp" diff --git a/filter-ewma2/ftnoir_filter_ewma2.h b/filter-ewma2/ftnoir_filter_ewma2.h index bf4e83ad9..bdb9cedc6 100644 --- a/filter-ewma2/ftnoir_filter_ewma2.h +++ b/filter-ewma2/ftnoir_filter_ewma2.h @@ -5,7 +5,7 @@ #include #include #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/filter-kalman/ftnoir_filter_kalman.h b/filter-kalman/ftnoir_filter_kalman.h index a6f40bb7e..773f61d57 100644 --- a/filter-kalman/ftnoir_filter_kalman.h +++ b/filter-kalman/ftnoir_filter_kalman.h @@ -16,7 +16,7 @@ #include #include #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/gui/main.cpp b/gui/main.cpp index a63fe54ac..3ae014041 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -3,7 +3,7 @@ #endif #include "ui.h" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include #include diff --git a/gui/new_file_dialog.h b/gui/new_file_dialog.h index 3a35cf71b..5fdabb3af 100644 --- a/gui/new_file_dialog.h +++ b/gui/new_file_dialog.h @@ -1,7 +1,7 @@ #pragma once #include "ui_new_config.h" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include #include #include diff --git a/gui/process_detector.h b/gui/process_detector.h index f6497c908..e395e1a28 100644 --- a/gui/process_detector.h +++ b/gui/process_detector.h @@ -13,7 +13,7 @@ #include #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; class FancyTable : public QTableWidget diff --git a/gui/ui.cpp b/gui/ui.cpp index 5ea5dbfa0..fc6d47540 100644 --- a/gui/ui.cpp +++ b/gui/ui.cpp @@ -8,7 +8,7 @@ #include "ui.h" #include "opentrack/tracker.h" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "new_file_dialog.h" #include #include @@ -411,7 +411,7 @@ bool mk_dialog(mem lib, mem& orig) dialog->show(); dialog->raise(); - QObject::connect(dialog.get(), &BaseDialog::closing, [&]() -> void { orig = nullptr; }); + QObject::connect(dialog.get(), &plugin_api::detail::BaseDialog::closing, [&]() -> void { orig = nullptr; }); return true; } diff --git a/gui/ui.h b/gui/ui.h index 91e4ebbfb..44bcde0c2 100644 --- a/gui/ui.h +++ b/gui/ui.h @@ -19,7 +19,7 @@ #include "ui_main.h" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "opentrack/main-settings.hpp" #include "opentrack/plugin-support.hpp" #include "opentrack/tracker.h" diff --git a/opentrack-compat/compat-export.hpp b/opentrack-compat/compat-export.hpp new file mode 100644 index 000000000..2d6f1d3d7 --- /dev/null +++ b/opentrack-compat/compat-export.hpp @@ -0,0 +1,15 @@ +#pragma once + +#ifndef OPENTRACK_COMPAT_EXPORT +# ifdef _WIN32 +# define OPENTRACK_COMPAT_LINKAGE __declspec(dllexport) +# else +# define OPENTRACK_COMPAT_LINKAGE +# endif + +# ifndef _MSC_VER +# define OPENTRACK_COMPAT_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_COMPAT_LINKAGE +# else +# define OPENTRACK_COMPAT_EXPORT OPENTRACK_COMPAT_LINKAGE +# endif +#endif diff --git a/opentrack-compat/compat-import.hpp b/opentrack-compat/compat-import.hpp new file mode 100644 index 000000000..161ccc5d1 --- /dev/null +++ b/opentrack-compat/compat-import.hpp @@ -0,0 +1,15 @@ +#pragma once + +#ifndef OPENTRACK_COMPAT_EXPORT +# ifdef _WIN32 +# define OPENTRACK_COMPAT_LINKAGE __declspec(dllimport) +# else +# define OPENTRACK_COMPAT_LINKAGE +# endif + +# ifndef _MSC_VER +# define OPENTRACK_COMPAT_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_COMPAT_LINKAGE +# else +# define OPENTRACK_COMPAT_EXPORT OPENTRACK_COMPAT_LINKAGE +# endif +#endif diff --git a/opentrack-compat/export.hpp b/opentrack-compat/export.hpp index f0983b753..100950a02 100644 --- a/opentrack-compat/export.hpp +++ b/opentrack-compat/export.hpp @@ -1,13 +1,15 @@ #pragma once -#ifdef _WIN32 -# define OPENTRACK_LINKAGE __declspec(dllexport) -#else -# define OPENTRACK_LINKAGE -#endif +#ifndef OPENTRACK_EXPORT +# ifdef _WIN32 +# define OPENTRACK_LINKAGE __declspec(dllexport) +# else +# define OPENTRACK_LINKAGE +# endif -#ifndef _MSC_VER -# define OPENTRACK_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_LINKAGE -#else -# define OPENTRACK_EXPORT OPENTRACK_LINKAGE -#endif \ No newline at end of file +# ifndef _MSC_VER +# define OPENTRACK_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_LINKAGE +# else +# define OPENTRACK_EXPORT OPENTRACK_LINKAGE +# endif +#endif diff --git a/opentrack-compat/import.hpp b/opentrack-compat/import.hpp new file mode 100644 index 000000000..3747b1412 --- /dev/null +++ b/opentrack-compat/import.hpp @@ -0,0 +1,15 @@ +#pragma once + +#ifndef OPENTRACK_EXPORT +# ifdef _WIN32 +# define OPENTRACK_LINKAGE __declspec(dllimport) +# else +# define OPENTRACK_LINKAGE +# endif + +# ifndef _MSC_VER +# define OPENTRACK_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_LINKAGE +# else +# define OPENTRACK_EXPORT OPENTRACK_LINKAGE +# endif +#endif diff --git a/opentrack-compat/shm.h b/opentrack-compat/shm.h index 28bda9868..c62976bdf 100644 --- a/opentrack-compat/shm.h +++ b/opentrack-compat/shm.h @@ -22,29 +22,13 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wattributes" -#ifdef __GNUC__ -# define COMPAT_GNUC_VISIBILITY __attribute__ ((visibility ("default"))) -#else -# define COMPAT_GNUC_VISIBILITY -#endif - #ifdef BUILD_compat -# ifdef _WIN32 -# define COMPAT_WIN32_EXPORT __declspec(dllexport) -# else -# define COMPAT_WIN32_EXPORT -# endif +# include "compat-export.hpp" #else -# ifdef _WIN32 -# define COMPAT_WIN32_EXPORT __declspec(dllimport) -# else -# define COMPAT_WIN32_EXPORT -# endif +# include "compat-import.hpp" #endif -#define COMPAT_EXPORT COMPAT_WIN32_EXPORT COMPAT_GNUC_VISIBILITY - -class COMPAT_EXPORT PortableLockedShm { +class OPENTRACK_COMPAT_EXPORT PortableLockedShm { public: PortableLockedShm(const char *shmName, const char *mutexName, int mapSize); ~PortableLockedShm(); diff --git a/opentrack/CMakeLists.txt b/opentrack/CMakeLists.txt index c3676979b..de5975e23 100644 --- a/opentrack/CMakeLists.txt +++ b/opentrack/CMakeLists.txt @@ -1,4 +1,4 @@ -opentrack_boilerplate(opentrack-api NO-LINKER-SCRIPT NO-COMPAT) +opentrack_boilerplate(opentrack-api NO-LINKER-SCRIPT NO-COMPAT LINKAGE) if(NOT WIN32) target_link_libraries(opentrack-api opentrack-qxt-mini opentrack-compat dl) else() diff --git a/opentrack/main-settings.hpp b/opentrack/main-settings.hpp index 613223ce0..b7b086ad2 100644 --- a/opentrack/main-settings.hpp +++ b/opentrack/main-settings.hpp @@ -9,7 +9,7 @@ #pragma once #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "opentrack/plugin-api.hpp" using namespace options; diff --git a/opentrack/mappings.hpp b/opentrack/mappings.hpp index bb38a3ca0..087ea7f3e 100644 --- a/opentrack/mappings.hpp +++ b/opentrack/mappings.hpp @@ -8,7 +8,7 @@ #pragma once #include -#include "options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include "spline-widget/functionconfig.h" #include "main-settings.hpp" diff --git a/opentrack/plugin-api.hpp b/opentrack/plugin-api.hpp index a57077abb..5fdc3bcbc 100644 --- a/opentrack/plugin-api.hpp +++ b/opentrack/plugin-api.hpp @@ -8,17 +8,38 @@ #pragma once -#include "../opentrack-compat/export.hpp" #include #include #include #include +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +#ifndef OPENTRACK_PLUGIN_EXPORT +# ifdef _WIN32 +# define OPENTRACK_PLUGIN_LINKAGE __declspec(dllexport) +# else +# define OPENTRACK_PLUGIN_LINKAGE +# endif +# ifndef _MSC_VER +# define OPENTRACK_PLUGIN_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_PLUGIN_LINKAGE +# else +# define OPENTRACK_PLUGIN_EXPORT OPENTRACK_PLUGIN_LINKAGE +# endif +#endif + enum Axis { TX = 0, TY, TZ, Yaw, Pitch, Roll }; -class BaseDialog : public QWidget +namespace plugin_api { +namespace detail { + +class OPENTRACK_EXPORT BaseDialog : public QWidget { Q_OBJECT public: @@ -27,16 +48,19 @@ signals: void closing(); }; +} // ns +} // ns + #define OPENTRACK_DECLARE_PLUGIN_INTERNAL(ctor_class, ctor_ret_class, metadata_class, dialog_class, dialog_ret_class) \ - extern "C" OPENTRACK_EXPORT ctor_ret_class* GetConstructor() \ + extern "C" OPENTRACK_PLUGIN_EXPORT ctor_ret_class* GetConstructor() \ { \ return new ctor_class; \ } \ - extern "C" OPENTRACK_EXPORT Metadata* GetMetadata() \ + extern "C" OPENTRACK_PLUGIN_EXPORT Metadata* GetMetadata() \ { \ return new metadata_class; \ } \ - extern "C" OPENTRACK_EXPORT dialog_ret_class* GetDialog() \ + extern "C" OPENTRACK_PLUGIN_EXPORT dialog_ret_class* GetDialog() \ { \ return new dialog_class; \ } @@ -65,7 +89,7 @@ struct IFilter virtual void center() {} }; -struct IFilterDialog : public BaseDialog +struct IFilterDialog : public plugin_api::detail::BaseDialog { // optional destructor virtual ~IFilterDialog() {} @@ -93,7 +117,7 @@ struct IProtocol virtual QString game_name() = 0; }; -struct IProtocolDialog : public BaseDialog +struct IProtocolDialog : public plugin_api::detail::BaseDialog { // optional destructor virtual ~IProtocolDialog() {} @@ -118,7 +142,7 @@ struct ITracker virtual void data(double *data) = 0; }; -struct ITrackerDialog : public BaseDialog +struct ITrackerDialog : public plugin_api::detail::BaseDialog { // optional destructor virtual ~ITrackerDialog() {} diff --git a/opentrack/plugin-support.hpp b/opentrack/plugin-support.hpp index 102d11c41..650eec10d 100644 --- a/opentrack/plugin-support.hpp +++ b/opentrack/plugin-support.hpp @@ -8,7 +8,7 @@ #pragma once #include "plugin-api.hpp" -#include "options.hpp" +#include "opentrack-compat/options.hpp" #include #include diff --git a/opentrack/selected-libraries.hpp b/opentrack/selected-libraries.hpp index 3719b109d..b396b5ec3 100644 --- a/opentrack/selected-libraries.hpp +++ b/opentrack/selected-libraries.hpp @@ -11,7 +11,14 @@ #include "opentrack/plugin-support.hpp" #include -struct SelectedLibraries { + +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +struct OPENTRACK_EXPORT SelectedLibraries { using dylibptr = mem; mem pTracker; mem pFilter; diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index 63d918295..03adc1ab1 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -17,9 +17,15 @@ #include #include +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + #include "qxt-mini/QxtGlobalShortcut" #include "opentrack/plugin-support.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "opentrack/main-settings.hpp" using namespace options; @@ -66,9 +72,7 @@ typedef unsigned char BYTE; struct Key { int foo; }; #endif -struct Shortcuts; - -struct KeybindingWorker : public QThread { +struct OPENTRACK_EXPORT KeybindingWorker : public QThread { #ifdef _WIN32 private: LPDIRECTINPUT8 din; @@ -87,7 +91,7 @@ public: #endif }; -struct Shortcuts : public QObject { +struct OPENTRACK_EXPORT Shortcuts : public QObject { Q_OBJECT public: diff --git a/opentrack/state.hpp b/opentrack/state.hpp index e4cb0f04b..dcb182930 100644 --- a/opentrack/state.hpp +++ b/opentrack/state.hpp @@ -9,7 +9,7 @@ #pragma once #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include "opentrack/plugin-support.hpp" #include "opentrack/main-settings.hpp" diff --git a/opentrack/tracker.h b/opentrack/tracker.h index 890660e1a..e26c3f7ac 100644 --- a/opentrack/tracker.h +++ b/opentrack/tracker.h @@ -18,7 +18,7 @@ #include "spline-widget/functionconfig.h" #include "main-settings.hpp" -#include "options.hpp" +#include "opentrack-compat/options.hpp" #include #include @@ -40,7 +40,13 @@ public: inline double operator()(int i) const { return axes[i]; } }; -class Tracker : private QThread { +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +class OPENTRACK_EXPORT Tracker : private QThread { Q_OBJECT private: QMutex mtx; diff --git a/opentrack/win32-shortcuts.h b/opentrack/win32-shortcuts.h index fe92ae53b..9b2c61215 100644 --- a/opentrack/win32-shortcuts.h +++ b/opentrack/win32-shortcuts.h @@ -10,7 +10,13 @@ struct win_key; extern QList windows_key_mods; extern QList windows_key_sequences; -struct win_key +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +struct OPENTRACK_EXPORT win_key { win_key(int win, Qt::Key qt) : win(win), qt(qt) {} int win; diff --git a/proto-fg/ftnoir_protocol_fg.h b/proto-fg/ftnoir_protocol_fg.h index de5282705..5b1cbc818 100644 --- a/proto-fg/ftnoir_protocol_fg.h +++ b/proto-fg/ftnoir_protocol_fg.h @@ -15,7 +15,7 @@ #include #include #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/proto-fsuipc/ftnoir_protocol_fsuipc.h b/proto-fsuipc/ftnoir_protocol_fsuipc.h index c8e91a42b..af59e988f 100644 --- a/proto-fsuipc/ftnoir_protocol_fsuipc.h +++ b/proto-fsuipc/ftnoir_protocol_fsuipc.h @@ -24,7 +24,7 @@ #include #include #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #define FSUIPC_FILENAME "C:\\Program Files\\Microsoft Games\\Flight Simulator 9\\Modules\\FSUIPC.dll" diff --git a/proto-ft/ftnoir_protocol_ft.h b/proto-ft/ftnoir_protocol_ft.h index 8e50f1cbf..9cf16f03f 100644 --- a/proto-ft/ftnoir_protocol_ft.h +++ b/proto-ft/ftnoir_protocol_ft.h @@ -19,7 +19,7 @@ #include #include #include "opentrack-compat/shm.h" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "freetrackclient/fttypes.h" using namespace options; diff --git a/proto-ftn/ftnoir_protocol_ftn.h b/proto-ftn/ftnoir_protocol_ftn.h index 7fe6c225d..d8b8aff0e 100644 --- a/proto-ftn/ftnoir_protocol_ftn.h +++ b/proto-ftn/ftnoir_protocol_ftn.h @@ -16,7 +16,7 @@ #include #include #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/proto-mouse/ftnoir_protocol_mouse.h b/proto-mouse/ftnoir_protocol_mouse.h index 595be3931..f1730777a 100644 --- a/proto-mouse/ftnoir_protocol_mouse.h +++ b/proto-mouse/ftnoir_protocol_mouse.h @@ -10,7 +10,7 @@ #include "ui_ftnoir_mousecontrols.h" #include #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/proto-sc/ftnoir_protocol_sc.h b/proto-sc/ftnoir_protocol_sc.h index 671a3500b..dcc0ca779 100644 --- a/proto-sc/ftnoir_protocol_sc.h +++ b/proto-sc/ftnoir_protocol_sc.h @@ -20,7 +20,7 @@ #include #include #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include diff --git a/spline-widget/CMakeLists.txt b/spline-widget/CMakeLists.txt index 4d951f92d..651a7874f 100644 --- a/spline-widget/CMakeLists.txt +++ b/spline-widget/CMakeLists.txt @@ -1 +1,2 @@ opentrack_boilerplate(opentrack-spline-widget NO-LINKER-SCRIPT NO-COMPAT LINKAGE) +target_link_libraries(opentrack-spline-widget opentrack-compat) diff --git a/spline-widget/qfunctionconfigurator.cpp b/spline-widget/qfunctionconfigurator.cpp index 7ab1e3608..5d910826c 100644 --- a/spline-widget/qfunctionconfigurator.cpp +++ b/spline-widget/qfunctionconfigurator.cpp @@ -5,7 +5,7 @@ * copyright notice and this permission notice appear in all copies. */ -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; #include "spline-widget/qfunctionconfigurator.h" #include diff --git a/tracker-aruco/ftnoir_tracker_aruco.h b/tracker-aruco/ftnoir_tracker_aruco.h index f827da77d..018f69eaf 100644 --- a/tracker-aruco/ftnoir_tracker_aruco.h +++ b/tracker-aruco/ftnoir_tracker_aruco.h @@ -15,7 +15,7 @@ #include #include #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "trans_calib.h" #include "opentrack/plugin-api.hpp" #include "opentrack/opencv-camera-dialog.hpp" diff --git a/tracker-freepie-udp/ftnoir_tracker_freepie-udp.h b/tracker-freepie-udp/ftnoir_tracker_freepie-udp.h index 7cff2ec94..9d18c7d18 100644 --- a/tracker-freepie-udp/ftnoir_tracker_freepie-udp.h +++ b/tracker-freepie-udp/ftnoir_tracker_freepie-udp.h @@ -10,7 +10,7 @@ #include #include "ui_freepie-udp-controls.h" #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-hatire/ftnoir_tracker_hat_settings.cpp b/tracker-hatire/ftnoir_tracker_hat_settings.cpp index e6b320476..df0480a19 100644 --- a/tracker-hatire/ftnoir_tracker_hat_settings.cpp +++ b/tracker-hatire/ftnoir_tracker_hat_settings.cpp @@ -14,7 +14,7 @@ #include "ftnoir_tracker_hat_settings.h" #ifdef OPENTRACK_API -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #endif void TrackerSettings::load_ini() diff --git a/tracker-ht/ftnoir_tracker_ht.h b/tracker-ht/ftnoir_tracker_ht.h index 1e3644565..0563fe1c0 100644 --- a/tracker-ht/ftnoir_tracker_ht.h +++ b/tracker-ht/ftnoir_tracker_ht.h @@ -12,7 +12,7 @@ #include "ht_video_widget.h" #include "opentrack-compat/shm.h" #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" #include "opentrack/plugin-api.hpp" #include "opentrack/opencv-camera-dialog.hpp" diff --git a/tracker-hydra/ftnoir_tracker_hydra.h b/tracker-hydra/ftnoir_tracker_hydra.h index 47a1eb9ab..94396b7c5 100644 --- a/tracker-hydra/ftnoir_tracker_hydra.h +++ b/tracker-hydra/ftnoir_tracker_hydra.h @@ -1,6 +1,6 @@ #include "ui_ftnoir_hydra_clientcontrols.h" #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-joystick/ftnoir_tracker_joystick.h b/tracker-joystick/ftnoir_tracker_joystick.h index 75305f073..29e65af1c 100644 --- a/tracker-joystick/ftnoir_tracker_joystick.h +++ b/tracker-joystick/ftnoir_tracker_joystick.h @@ -27,7 +27,7 @@ #include #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-pt/ftnoir_tracker_pt_settings.h b/tracker-pt/ftnoir_tracker_pt_settings.h index 85eec8f90..e4bfa371a 100644 --- a/tracker-pt/ftnoir_tracker_pt_settings.h +++ b/tracker-pt/ftnoir_tracker_pt_settings.h @@ -9,7 +9,7 @@ #ifndef FTNOIR_TRACKER_PT_SETTINGS_H #define FTNOIR_TRACKER_PT_SETTINGS_H -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings_pt : opts diff --git a/tracker-rift-025/ftnoir_tracker_rift_025.h b/tracker-rift-025/ftnoir_tracker_rift_025.h index 2bd5024be..8333e092b 100644 --- a/tracker-rift-025/ftnoir_tracker_rift_025.h +++ b/tracker-rift-025/ftnoir_tracker_rift_025.h @@ -6,7 +6,7 @@ #include "opentrack/plugin-api.hpp" #include "OVR.h" #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-rift-042/ftnoir_tracker_rift_042.h b/tracker-rift-042/ftnoir_tracker_rift_042.h index 437a2a39d..77e7ffa6a 100644 --- a/tracker-rift-042/ftnoir_tracker_rift_042.h +++ b/tracker-rift-042/ftnoir_tracker_rift_042.h @@ -6,7 +6,7 @@ #include "opentrack/plugin-api.hpp" #include "OVR.h" #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-rift-080/ftnoir_tracker_rift_080.h b/tracker-rift-080/ftnoir_tracker_rift_080.h index 08684dd29..879d31d28 100644 --- a/tracker-rift-080/ftnoir_tracker_rift_080.h +++ b/tracker-rift-080/ftnoir_tracker_rift_080.h @@ -6,7 +6,7 @@ #include "opentrack/plugin-api.hpp" #include "OVR.h" #include -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { diff --git a/tracker-udp/ftnoir_tracker_udp.h b/tracker-udp/ftnoir_tracker_udp.h index 6de5b2957..3f0e6d8cc 100644 --- a/tracker-udp/ftnoir_tracker_udp.h +++ b/tracker-udp/ftnoir_tracker_udp.h @@ -4,7 +4,7 @@ #include #include #include "opentrack/plugin-api.hpp" -#include "opentrack/options.hpp" +#include "opentrack-compat/options.hpp" using namespace options; struct settings : opts { -- cgit v1.2.3 From be36337e46218c6f843a478036497a3f494502ed Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 1 Nov 2015 11:29:24 +0100 Subject: options: don't define options singleton in every module Instead, define in opentrack-api.so only. Also, move to opentrack-compat to break a circular dependency --- opentrack-compat/options.cpp | 16 ++ opentrack-compat/options.hpp | 485 +++++++++++++++++++++++++++++++++++++++++++ opentrack/options.hpp | 481 ------------------------------------------ 3 files changed, 501 insertions(+), 481 deletions(-) create mode 100644 opentrack-compat/options.cpp create mode 100644 opentrack-compat/options.hpp delete mode 100644 opentrack/options.hpp (limited to 'opentrack') diff --git a/opentrack-compat/options.cpp b/opentrack-compat/options.cpp new file mode 100644 index 000000000..91cd3664b --- /dev/null +++ b/opentrack-compat/options.cpp @@ -0,0 +1,16 @@ +#include "options.hpp" + +namespace options +{ + +namespace detail +{ +OPENTRACK_COMPAT_EXPORT opt_singleton& singleton() +{ + static auto ret = std::make_shared(); + return *ret; +} + +} + +} diff --git a/opentrack-compat/options.hpp b/opentrack-compat/options.hpp new file mode 100644 index 000000000..be8c688ce --- /dev/null +++ b/opentrack-compat/options.hpp @@ -0,0 +1,485 @@ +/* Copyright (c) 2013-2015 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#ifdef BUILD_compat +# include "compat-export.hpp" +#else +# include "compat-import.hpp" +#endif + +template using mem = std::shared_ptr; + +#define OPENTRACK_CONFIG_FILENAME_KEY "settings-filename" +#define OPENTRACK_DEFAULT_CONFIG "default.ini" +#define OPENTRACK_ORG "opentrack-2.3" + +namespace options { + template + using map = std::map; + using std::string; + + template + // don't elide usages of the function, qvariant default implicit + // conversion results in nonsensical runtime behavior -sh + inline t qcruft_to_t (const QVariant& datum); + + template<> + inline int qcruft_to_t(const QVariant& t) + { + return t.toInt(); + } + + template<> + inline QString qcruft_to_t(const QVariant& t) + { + return t.toString(); + } + + template<> + inline bool qcruft_to_t(const QVariant& t) + { + return t.toBool(); + } + + template<> + inline double qcruft_to_t(const QVariant& t) + { + return t.toDouble(); + } + + template<> + inline QVariant qcruft_to_t(const QVariant& t) + { + return t; + } + + // snapshot of qsettings group at given time + class group { + private: + map kvs; + string name; + public: + group(const string& name) : name(name) + { + auto conf = ini_file(); + auto q_name = QString::fromStdString(name); + conf->beginGroup(q_name); + for (auto& k_ : conf->childKeys()) + { + auto tmp = k_.toUtf8(); + string k(tmp); + kvs[k] = conf->value(k_); + } + conf->endGroup(); + } + + void save() + { + auto s = ini_file(); + auto q_name = QString::fromStdString(name); + s->beginGroup(q_name); + for (auto& i : kvs) + { + auto k = QString::fromStdString(i.first); + s->setValue(k, i.second); + } + s->endGroup(); + s->sync(); + } + + template + t get(const string& k) + { + return qcruft_to_t(kvs[k]); + } + + void put(const string& s, const QVariant& d) + { + kvs[s] = d; + } + + bool contains(const string& s) + { + return kvs.count(s) != 0; + } + + static QString ini_directory() + { + const auto dirs = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation); + if (dirs.size() == 0) + return ""; + if (QDir(dirs[0]).mkpath(OPENTRACK_ORG)) + return dirs[0] + "/" OPENTRACK_ORG; + return ""; + } + + static QString ini_filename() + { + QSettings settings(OPENTRACK_ORG); + return settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString(); + } + + static QString ini_pathname() + { + const auto dir = ini_directory(); + if (dir == "") + return ""; + QSettings settings(OPENTRACK_ORG); + return dir + "/" + settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString(); + } + + static const QStringList ini_list() + { + const auto dirname = ini_directory(); + if (dirname == "") + return QStringList(); + QDir settings_dir(dirname); + return settings_dir.entryList( QStringList { "*.ini" } , QDir::Files, QDir::Name ); + } + + static const mem ini_file() + { + const auto pathname = ini_pathname(); + if (pathname != "") + return std::make_shared(ini_pathname(), QSettings::IniFormat); + return std::make_shared(); + } + }; + + class OPENTRACK_COMPAT_EXPORT impl_bundle : public QObject { + Q_OBJECT + protected: + QMutex mtx; + const string group_name; + group saved; + group transient; + bool modified; + impl_bundle(const impl_bundle&) = delete; + impl_bundle& operator=(const impl_bundle&) = delete; + signals: + void reloading(); + void saving(); + public: + impl_bundle(const string& group_name) : + mtx(QMutex::Recursive), + group_name(group_name), + saved(group_name), + transient(saved), + modified(false) + { + } + + string name() { return group_name; } + + void reload() { + { + QMutexLocker l(&mtx); + saved = group(group_name); + transient = saved; + modified = false; + } + emit reloading(); + } + + void store_kv(const string& name, const QVariant& datum) + { + QMutexLocker l(&mtx); + + auto old = transient.get(name); + if (!transient.contains(name) || datum != old) + { + modified = true; + transient.put(name, datum); + } + } + bool contains(const string& name) + { + QMutexLocker l(&mtx); + return transient.contains(name); + } + template + t get(const string& name) + { + QMutexLocker l(&mtx); + return transient.get(name); + } + void save() + { + { + QMutexLocker l(&mtx); + modified = false; + saved = transient; + transient.save(); + } + emit saving(); + } + + bool modifiedp() { + QMutexLocker l(&mtx); + return modified; + } + }; + + class opt_bundle; + + namespace detail + { + struct OPENTRACK_COMPAT_EXPORT opt_singleton + { + public: + using k = std::string; + using v = opt_bundle; + using cnt = int; + using pbundle = std::shared_ptr; + using tt = std::tuple>; + private: + QMutex implsgl_mtx; + map implsgl_data; + public: + opt_singleton() : implsgl_mtx(QMutex::Recursive) {} + + pbundle bundle(const k& key) + { + QMutexLocker l(&implsgl_mtx); + + if (implsgl_data.count(key) != 0) + { + auto shared = std::get<1>(implsgl_data[key]).lock(); + if (shared != nullptr) + return shared; + } + + qDebug() << "bundle +" << QString::fromStdString(key); + + auto shr = std::make_shared(key); + implsgl_data[key] = tt(cnt(1), shr); + return shr; + } + + void bundle_decf(const k& key) + { + QMutexLocker l(&implsgl_mtx); + + if (--std::get<0>(implsgl_data[key]) == 0) + implsgl_data.erase(key); + } + }; + + OPENTRACK_COMPAT_EXPORT opt_singleton& singleton(); + } + + using pbundle = std::shared_ptr; + + static inline pbundle bundle(const string name) { return detail::singleton().bundle(name); } + + class opt_bundle : public impl_bundle + { + public: + opt_bundle() : impl_bundle("i-have-no-name") {} + opt_bundle(const string& group_name) : impl_bundle(group_name) + { + } + + ~opt_bundle() + { + qDebug() << "bundle -" << QString::fromStdString(group_name); + detail::singleton().bundle_decf(group_name); + } + }; + + class OPENTRACK_COMPAT_EXPORT base_value : public QObject + { + Q_OBJECT +#define DEFINE_SLOT(t) void setValue(t datum) { store(datum); } +#define DEFINE_SIGNAL(t) void valueChanged(t) + public: + string name() { return self_name; } + base_value(pbundle b, const string& name) : b(b), self_name(name) {} + signals: + DEFINE_SIGNAL(double); + DEFINE_SIGNAL(int); + DEFINE_SIGNAL(bool); + DEFINE_SIGNAL(QString); + protected: + pbundle b; + string self_name; + + template + void store(const t& datum) + { + b->store_kv(self_name, datum); + emit valueChanged(static_cast(datum)); + } + public slots: + DEFINE_SLOT(double) + DEFINE_SLOT(int) + DEFINE_SLOT(QString) + DEFINE_SLOT(bool) + public slots: + virtual void reload() = 0; + }; + + static inline string string_from_qstring(const QString& datum) + { + auto tmp = datum.toUtf8(); + return string(tmp.constData()); + } + + template + class value : public base_value { + public: + t operator=(const t datum) + { + store(datum); + return datum; + } + static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; + static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::UniqueConnection; + value(pbundle b, const string& name, t def) : base_value(b, name), def(def) + { + QObject::connect(b.get(), SIGNAL(reloading()), + this, SLOT(reload()), + DIRECT_CONNTYPE); + if (!b->contains(name) || b->get(name).type() == QVariant::Invalid) + *this = def; + } + value(pbundle b, const QString& name, t def) : value(b, string_from_qstring(name), def) {} + value(pbundle b, const char* name, t def) : value(b, string(name), def) {} + + operator t() + { + return b->contains(self_name) ? b->get(self_name) : def; + } + void reload() override { + *this = static_cast(*this); + } + private: + t def; + }; + + struct opts + { + pbundle b; + + opts(const std::string& name) : b(bundle(name)) {} + + ~opts() + { + b->reload(); + } + }; + + template + inline void tie_setting(value&, q*); + + template<> + inline void tie_setting(value& v, QComboBox* cb) + { + cb->setCurrentIndex(v); + v = cb->currentIndex(); + base_value::connect(cb, SIGNAL(currentIndexChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(int)), cb, SLOT(setCurrentIndex(int)), v.SAFE_CONNTYPE); + } + + template<> + inline void tie_setting(value& v, QComboBox* cb) + { + cb->setCurrentText(v); + v = cb->currentText(); + base_value::connect(cb, SIGNAL(currentTextChanged(QString)), &v, SLOT(setValue(QString)), v.DIRECT_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(QString)), cb, SLOT(setCurrentText(QString)), v.SAFE_CONNTYPE); + } + + template<> + inline void tie_setting(value& v, QCheckBox* cb) + { + cb->setChecked(v); + base_value::connect(cb, SIGNAL(toggled(bool)), &v, SLOT(setValue(bool)), v.DIRECT_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(bool)), cb, SLOT(setChecked(bool)), v.SAFE_CONNTYPE); + } + + template<> + inline void tie_setting(value& v, QDoubleSpinBox* dsb) + { + dsb->setValue(v); + base_value::connect(dsb, SIGNAL(valueChanged(double)), &v, SLOT(setValue(double)), v.DIRECT_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(double)), dsb, SLOT(setValue(double)), v.SAFE_CONNTYPE); + } + + template<> + inline void tie_setting(value& v, QSpinBox* sb) + { + sb->setValue(v); + base_value::connect(sb, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(int)), sb, SLOT(setValue(int)), v.SAFE_CONNTYPE); + } + + template<> + inline void tie_setting(value& v, QSlider* sl) + { + sl->setValue(v); + v = sl->value(); + base_value::connect(sl, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(int)), sl, SLOT(setValue(int)), v.SAFE_CONNTYPE); + } + + template<> + inline void tie_setting(value& v, QLineEdit* le) + { + le->setText(v); + base_value::connect(le, SIGNAL(textChanged(QString)), &v, SLOT(setValue(QString)), v.DIRECT_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(QString)),le, SLOT(setText(QString)), v.SAFE_CONNTYPE); + } + + template<> + inline void tie_setting(value& v, QLabel* lb) + { + lb->setText(v); + base_value::connect(&v, SIGNAL(valueChanged(QString)), lb, SLOT(setText(QString)), v.SAFE_CONNTYPE); + } + + template<> + inline void tie_setting(value& v, QTabWidget* t) + { + t->setCurrentIndex(v); + base_value::connect(t, SIGNAL(currentChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); + base_value::connect(&v, SIGNAL(valueChanged(int)), t, SLOT(setCurrentIndex(int)), v.SAFE_CONNTYPE); + } +} diff --git a/opentrack/options.hpp b/opentrack/options.hpp deleted file mode 100644 index f84758779..000000000 --- a/opentrack/options.hpp +++ /dev/null @@ -1,481 +0,0 @@ -/* Copyright (c) 2013-2015 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 -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -template using mem = std::shared_ptr; - -#define OPENTRACK_CONFIG_FILENAME_KEY "settings-filename" -#define OPENTRACK_DEFAULT_CONFIG "default.ini" -#define OPENTRACK_ORG "opentrack-2.3" - -namespace options { - template - using map = std::map; - using std::string; - - template - // don't elide usages of the function, qvariant default implicit - // conversion results in nonsensical runtime behavior -sh - inline t qcruft_to_t (const QVariant& datum); - - template<> - inline int qcruft_to_t(const QVariant& t) - { - return t.toInt(); - } - - template<> - inline QString qcruft_to_t(const QVariant& t) - { - return t.toString(); - } - - template<> - inline bool qcruft_to_t(const QVariant& t) - { - return t.toBool(); - } - - template<> - inline double qcruft_to_t(const QVariant& t) - { - return t.toDouble(); - } - - template<> - inline QVariant qcruft_to_t(const QVariant& t) - { - return t; - } - - // snapshot of qsettings group at given time - class group { - private: - map kvs; - string name; - public: - group(const string& name) : name(name) - { - auto conf = ini_file(); - auto q_name = QString::fromStdString(name); - conf->beginGroup(q_name); - for (auto& k_ : conf->childKeys()) - { - auto tmp = k_.toUtf8(); - string k(tmp); - kvs[k] = conf->value(k_); - } - conf->endGroup(); - } - - void save() - { - auto s = ini_file(); - auto q_name = QString::fromStdString(name); - s->beginGroup(q_name); - for (auto& i : kvs) - { - auto k = QString::fromStdString(i.first); - s->setValue(k, i.second); - } - s->endGroup(); - s->sync(); - } - - template - t get(const string& k) - { - return qcruft_to_t(kvs[k]); - } - - void put(const string& s, const QVariant& d) - { - kvs[s] = d; - } - - bool contains(const string& s) - { - return kvs.count(s) != 0; - } - - static QString ini_directory() - { - const auto dirs = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation); - if (dirs.size() == 0) - return ""; - if (QDir(dirs[0]).mkpath(OPENTRACK_ORG)) - return dirs[0] + "/" OPENTRACK_ORG; - return ""; - } - - static QString ini_filename() - { - QSettings settings(OPENTRACK_ORG); - return settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString(); - } - - static QString ini_pathname() - { - const auto dir = ini_directory(); - if (dir == "") - return ""; - QSettings settings(OPENTRACK_ORG); - return dir + "/" + settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString(); - } - - static const QStringList ini_list() - { - const auto dirname = ini_directory(); - if (dirname == "") - return QStringList(); - QDir settings_dir(dirname); - return settings_dir.entryList( QStringList { "*.ini" } , QDir::Files, QDir::Name ); - } - - static const mem ini_file() - { - const auto pathname = ini_pathname(); - if (pathname != "") - return std::make_shared(ini_pathname(), QSettings::IniFormat); - return std::make_shared(); - } - }; - - class impl_bundle : public QObject { - Q_OBJECT - protected: - QMutex mtx; - const string group_name; - group saved; - group transient; - bool modified; - impl_bundle(const impl_bundle&) = delete; - impl_bundle& operator=(const impl_bundle&) = delete; - signals: - void reloading(); - void saving(); - public: - impl_bundle(const string& group_name) : - mtx(QMutex::Recursive), - group_name(group_name), - saved(group_name), - transient(saved), - modified(false) - { - } - - string name() { return group_name; } - - void reload() { - { - QMutexLocker l(&mtx); - saved = group(group_name); - transient = saved; - modified = false; - } - emit reloading(); - } - - void store_kv(const string& name, const QVariant& datum) - { - QMutexLocker l(&mtx); - - auto old = transient.get(name); - if (!transient.contains(name) || datum != old) - { - modified = true; - transient.put(name, datum); - } - } - bool contains(const string& name) - { - QMutexLocker l(&mtx); - return transient.contains(name); - } - template - t get(const string& name) - { - QMutexLocker l(&mtx); - return transient.get(name); - } - void save() - { - { - QMutexLocker l(&mtx); - modified = false; - saved = transient; - transient.save(); - } - emit saving(); - } - - bool modifiedp() { - QMutexLocker l(&mtx); - return modified; - } - }; - - class opt_bundle; - - namespace - { - template - struct opt_singleton - { - public: - using pbundle = std::shared_ptr; - using tt = std::tuple>; - private: - QMutex implsgl_mtx; - map implsgl_data; - public: - opt_singleton() : implsgl_mtx(QMutex::Recursive) {} - - static opt_singleton& datum() - { - static auto ret = std::make_shared>(); - return *ret; - } - - pbundle bundle(const k& key) - { - QMutexLocker l(&implsgl_mtx); - - if (implsgl_data.count(key) != 0) - { - auto shared = std::get<1>(implsgl_data[key]).lock(); - if (shared != nullptr) - return shared; - } - - qDebug() << "bundle +" << QString::fromStdString(key); - - auto shr = std::make_shared(key); - implsgl_data[key] = tt(cnt(1), shr); - return shr; - } - - void bundle_decf(const k& key) - { - QMutexLocker l(&implsgl_mtx); - - if (--std::get<0>(implsgl_data[key]) == 0) - implsgl_data.erase(key); - } - }; - - using pbundle = std::shared_ptr; - using t_fact = opt_singleton; - } - - static inline t_fact::pbundle bundle(const string name) { return t_fact::datum().bundle(name); } - - class opt_bundle : public impl_bundle - { - public: - opt_bundle() : impl_bundle("i-have-no-name") {} - opt_bundle(const string& group_name) : impl_bundle(group_name) - { - } - - ~opt_bundle() - { - qDebug() << "bundle -" << QString::fromStdString(group_name); - t_fact::datum().bundle_decf(group_name); - } - }; - - class base_value : public QObject - { - Q_OBJECT -#define DEFINE_SLOT(t) void setValue(t datum) { store(datum); } -#define DEFINE_SIGNAL(t) void valueChanged(t) - public: - string name() { return self_name; } - base_value(pbundle b, const string& name) : b(b), self_name(name) {} - signals: - DEFINE_SIGNAL(double); - DEFINE_SIGNAL(int); - DEFINE_SIGNAL(bool); - DEFINE_SIGNAL(QString); - protected: - pbundle b; - string self_name; - - template - void store(const t& datum) - { - b->store_kv(self_name, datum); - emit valueChanged(static_cast(datum)); - } - public slots: - DEFINE_SLOT(double) - DEFINE_SLOT(int) - DEFINE_SLOT(QString) - DEFINE_SLOT(bool) - public slots: - virtual void reload() = 0; - }; - - static inline string string_from_qstring(const QString& datum) - { - auto tmp = datum.toUtf8(); - return string(tmp.constData()); - } - - template - class value : public base_value { - public: - t operator=(const t datum) - { - store(datum); - return datum; - } - static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; - static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::UniqueConnection; - value(pbundle b, const string& name, t def) : base_value(b, name), def(def) - { - QObject::connect(b.get(), SIGNAL(reloading()), - this, SLOT(reload()), - DIRECT_CONNTYPE); - if (!b->contains(name) || b->get(name).type() == QVariant::Invalid) - *this = def; - } - value(pbundle b, const QString& name, t def) : value(b, string_from_qstring(name), def) {} - value(pbundle b, const char* name, t def) : value(b, string(name), def) {} - - operator t() - { - return b->contains(self_name) ? b->get(self_name) : def; - } - void reload() override { - *this = static_cast(*this); - } - private: - t def; - }; - - struct opts - { - pbundle b; - - opts(const std::string& name) : b(bundle(name)) {} - - ~opts() - { - b->reload(); - } - }; - - template - inline void tie_setting(value&, q*); - - template<> - inline void tie_setting(value& v, QComboBox* cb) - { - cb->setCurrentIndex(v); - v = cb->currentIndex(); - base_value::connect(cb, SIGNAL(currentIndexChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(int)), cb, SLOT(setCurrentIndex(int)), v.SAFE_CONNTYPE); - } - - template<> - inline void tie_setting(value& v, QComboBox* cb) - { - cb->setCurrentText(v); - v = cb->currentText(); - base_value::connect(cb, SIGNAL(currentTextChanged(QString)), &v, SLOT(setValue(QString)), v.DIRECT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(QString)), cb, SLOT(setCurrentText(QString)), v.SAFE_CONNTYPE); - } - - template<> - inline void tie_setting(value& v, QCheckBox* cb) - { - cb->setChecked(v); - base_value::connect(cb, SIGNAL(toggled(bool)), &v, SLOT(setValue(bool)), v.DIRECT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(bool)), cb, SLOT(setChecked(bool)), v.SAFE_CONNTYPE); - } - - template<> - inline void tie_setting(value& v, QDoubleSpinBox* dsb) - { - dsb->setValue(v); - base_value::connect(dsb, SIGNAL(valueChanged(double)), &v, SLOT(setValue(double)), v.DIRECT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(double)), dsb, SLOT(setValue(double)), v.SAFE_CONNTYPE); - } - - template<> - inline void tie_setting(value& v, QSpinBox* sb) - { - sb->setValue(v); - base_value::connect(sb, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(int)), sb, SLOT(setValue(int)), v.SAFE_CONNTYPE); - } - - template<> - inline void tie_setting(value& v, QSlider* sl) - { - sl->setValue(v); - v = sl->value(); - base_value::connect(sl, SIGNAL(valueChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(int)), sl, SLOT(setValue(int)), v.SAFE_CONNTYPE); - } - - template<> - inline void tie_setting(value& v, QLineEdit* le) - { - le->setText(v); - base_value::connect(le, SIGNAL(textChanged(QString)), &v, SLOT(setValue(QString)), v.DIRECT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(QString)),le, SLOT(setText(QString)), v.SAFE_CONNTYPE); - } - - template<> - inline void tie_setting(value& v, QLabel* lb) - { - lb->setText(v); - base_value::connect(&v, SIGNAL(valueChanged(QString)), lb, SLOT(setText(QString)), v.SAFE_CONNTYPE); - } - - template<> - inline void tie_setting(value& v, QTabWidget* t) - { - t->setCurrentIndex(v); - base_value::connect(t, SIGNAL(currentChanged(int)), &v, SLOT(setValue(int)), v.DIRECT_CONNTYPE); - base_value::connect(&v, SIGNAL(valueChanged(int)), t, SLOT(setCurrentIndex(int)), v.SAFE_CONNTYPE); - } -} -- cgit v1.2.3 From 712f2e6c09713024d0d92f129577b498d5945fb7 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 1 Nov 2015 11:29:48 +0100 Subject: shortcuts: cleanup --- opentrack/shortcuts.h | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'opentrack') diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index 03adc1ab1..81c1bb80c 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -30,18 +30,15 @@ using namespace options; -extern QList global_key_sequences; - -struct key_opts { - value keycode; - - key_opts(pbundle b, const QString& name) : - keycode(b, QString("keycode-%1").arg(name), "") - {} -}; +namespace { + extern QList global_key_sequences; +} #if defined(_WIN32) -extern QList global_windows_key_sequences; + +namespace { + extern QList global_windows_key_sequences; +} # undef DIRECTINPUT_VERSION # define DIRECTINPUT_VERSION 0x0800 # include @@ -111,6 +108,14 @@ public: #ifdef _WIN32 mem keybindingWorker; #endif + + struct key_opts { + value keycode; + + key_opts(pbundle b, const QString& name) : + keycode(b, QString("keycode-%1").arg(name), "") + {} + }; struct settings : opts { key_opts center, toggle, zero; @@ -136,5 +141,3 @@ signals: void toggle(); void zero(); }; - - -- cgit v1.2.3 From 8dca727968bf64c8aa89cce09172f101c2ade069 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 1 Nov 2015 11:44:42 +0100 Subject: shortcuts: separate keybinding worker to another file --- opentrack/keybinding-worker.cpp | 112 ++++++++++++++++++++++++++++++++++++++++ opentrack/keybinding-worker.hpp | 70 +++++++++++++++++++++++++ opentrack/shortcuts.cpp | 104 +------------------------------------ opentrack/shortcuts.h | 69 ++----------------------- 4 files changed, 186 insertions(+), 169 deletions(-) create mode 100644 opentrack/keybinding-worker.cpp create mode 100644 opentrack/keybinding-worker.hpp (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp new file mode 100644 index 000000000..29b2cf9f7 --- /dev/null +++ b/opentrack/keybinding-worker.cpp @@ -0,0 +1,112 @@ +/* Copyright (c) 2014-2015, 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 "keybinding-worker.hpp" + +#if defined(_WIN32) +# include +# include +# include + +KeybindingWorker::~KeybindingWorker() { + should_quit = true; + wait(); + if (dinkeyboard) { + dinkeyboard->Unacquire(); + dinkeyboard->Release(); + } + if (din) + din->Release(); +} + +KeybindingWorker::KeybindingWorker(std::function receiver, WId h) : + should_quit(true), receiver(receiver) +{ + HWND handle = reinterpret_cast(h); + + if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) { + qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); + return; + } + if (din->CreateDevice(GUID_SysKeyboard, &dinkeyboard, NULL) != DI_OK) { + din->Release(); + din = 0; + qDebug() << "setup CreateDevice function failed!" << GetLastError(); + return; + } + if (dinkeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK) { + qDebug() << "setup SetDataFormat function failed!" << GetLastError(); + dinkeyboard->Release(); + dinkeyboard = 0; + din->Release(); + din = 0; + return; + } + if (dinkeyboard->SetCooperativeLevel((HWND) handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) { + dinkeyboard->Release(); + din->Release(); + din = 0; + dinkeyboard = 0; + qDebug() << "setup SetCooperativeLevel function failed!" << GetLastError(); + return; + } + if (dinkeyboard->Acquire() != DI_OK) + { + dinkeyboard->Release(); + din->Release(); + din = 0; + dinkeyboard = 0; + qDebug() << "setup dinkeyboard Acquire failed!" << GetLastError(); + return; + } + should_quit = false; +} + +void KeybindingWorker::run() { + BYTE keystate[256]; + + while (!should_quit) + { + if (dinkeyboard->GetDeviceState(256, (LPVOID)keystate) != DI_OK) { + qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError(); + Sleep(25); + continue; + } + + QMutexLocker l(&mtx); + + for (int i = 0; i < 256; i++) + { + Key k; + if (keystate[i] & 0x80) + { + switch (i) + { + case DIK_LCONTROL: + case DIK_LSHIFT: + case DIK_LALT: + case DIK_RCONTROL: + case DIK_RSHIFT: + case DIK_RALT: + break; + default: + k.shift = !!(keystate[DIK_LSHIFT] & 0x80) || !!(keystate[DIK_RSHIFT] & 0x80); + k.alt = !!(keystate[DIK_LALT] & 0x80) || !!(keystate[DIK_RALT] & 0x80); + k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80) || !!(keystate[DIK_RCONTROL] & 0x80); + k.keycode = i; + receiver(k); + break; + } + } + } + + // keypresses get dropped with high values + Sleep(4); + } +} +#endif \ No newline at end of file diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp new file mode 100644 index 000000000..e720ffdcc --- /dev/null +++ b/opentrack/keybinding-worker.hpp @@ -0,0 +1,70 @@ +/* Copyright (c) 2014-2015, 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 + +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +#include "opentrack-compat/timer.hpp" +#include +#include +#include +#include + +#ifdef _WIN32 +# undef DIRECTINPUT_VERSION +# define DIRECTINPUT_VERSION 0x0800 +# include +# include +struct Key { + BYTE keycode; + bool shift; + bool ctrl; + bool alt; + Timer timer; +public: + Key() : keycode(0), shift(false), ctrl(false), alt(false) + { + } + + bool should_process() + { + if (keycode == 0) + return false; + bool ret = timer.elapsed_ms() > 100; + timer.start(); + return ret; + } +}; +#else +typedef unsigned char BYTE; +struct Key { int foo; }; +#endif + +struct OPENTRACK_EXPORT KeybindingWorker : public QThread { +#ifdef _WIN32 +private: + LPDIRECTINPUT8 din; + LPDIRECTINPUTDEVICE8 dinkeyboard; + QMutex mtx; +public: + volatile bool should_quit; + std::function receiver; + ~KeybindingWorker(); + KeybindingWorker(std::function receiver, WId h); + void run(); +#else +public: + KeybindingWorker(Key, Key, Key, WId) {} + void run() {} +#endif +}; \ No newline at end of file diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp index a33cf0883..5f5ad922b 100644 --- a/opentrack/shortcuts.cpp +++ b/opentrack/shortcuts.cpp @@ -7,110 +7,8 @@ */ #include "shortcuts.h" -#include - -#if defined(_WIN32) -#include -#include #include "win32-shortcuts.h" - -KeybindingWorker::~KeybindingWorker() { - should_quit = true; - wait(); - if (dinkeyboard) { - dinkeyboard->Unacquire(); - dinkeyboard->Release(); - } - if (din) - din->Release(); -} - -KeybindingWorker::KeybindingWorker(std::function receiver, WId h) : - should_quit(true), receiver(receiver) -{ - HWND handle = reinterpret_cast(h); - - if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) { - qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); - return; - } - if (din->CreateDevice(GUID_SysKeyboard, &dinkeyboard, NULL) != DI_OK) { - din->Release(); - din = 0; - qDebug() << "setup CreateDevice function failed!" << GetLastError(); - return; - } - if (dinkeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK) { - qDebug() << "setup SetDataFormat function failed!" << GetLastError(); - dinkeyboard->Release(); - dinkeyboard = 0; - din->Release(); - din = 0; - return; - } - if (dinkeyboard->SetCooperativeLevel((HWND) handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) { - dinkeyboard->Release(); - din->Release(); - din = 0; - dinkeyboard = 0; - qDebug() << "setup SetCooperativeLevel function failed!" << GetLastError(); - return; - } - if (dinkeyboard->Acquire() != DI_OK) - { - dinkeyboard->Release(); - din->Release(); - din = 0; - dinkeyboard = 0; - qDebug() << "setup dinkeyboard Acquire failed!" << GetLastError(); - return; - } - should_quit = false; -} - -void KeybindingWorker::run() { - BYTE keystate[256]; - - while (!should_quit) - { - if (dinkeyboard->GetDeviceState(256, (LPVOID)keystate) != DI_OK) { - qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError(); - Sleep(25); - continue; - } - - QMutexLocker l(&mtx); - - for (int i = 0; i < 256; i++) - { - Key k; - if (keystate[i] & 0x80) - { - switch (i) - { - case DIK_LCONTROL: - case DIK_LSHIFT: - case DIK_LALT: - case DIK_RCONTROL: - case DIK_RSHIFT: - case DIK_RALT: - break; - default: - k.shift = !!(keystate[DIK_LSHIFT] & 0x80) || !!(keystate[DIK_RSHIFT] & 0x80); - k.alt = !!(keystate[DIK_LALT] & 0x80) || !!(keystate[DIK_RALT] & 0x80); - k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80) || !!(keystate[DIK_RCONTROL] & 0x80); - k.keycode = i; - receiver(k); - break; - } - } - } - - // keypresses get dropped with high values - Sleep(4); - } -} -#endif +#include void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k) { diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index 81c1bb80c..84231850b 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -8,14 +8,6 @@ #pragma once #include -#include -#include "opentrack-compat/timer.hpp" -#include -#include -#include -#include -#include -#include #ifdef BUILD_api # include "opentrack-compat/export.hpp" @@ -24,69 +16,14 @@ #endif #include "qxt-mini/QxtGlobalShortcut" -#include "opentrack/plugin-support.hpp" #include "opentrack-compat/options.hpp" #include "opentrack/main-settings.hpp" -using namespace options; - -namespace { - extern QList global_key_sequences; -} - -#if defined(_WIN32) - -namespace { - extern QList global_windows_key_sequences; -} -# undef DIRECTINPUT_VERSION -# define DIRECTINPUT_VERSION 0x0800 -# include -# include - -struct Key { - BYTE keycode; - bool shift; - bool ctrl; - bool alt; - Timer timer; -public: - Key() : keycode(0), shift(false), ctrl(false), alt(false) - { - } - - bool should_process() - { - if (keycode == 0) - return false; - bool ret = timer.elapsed_ms() > 100; - timer.start(); - return ret; - } -}; -#else -typedef unsigned char BYTE; -struct Key { int foo; }; -#endif - -struct OPENTRACK_EXPORT KeybindingWorker : public QThread { #ifdef _WIN32 -private: - LPDIRECTINPUT8 din; - LPDIRECTINPUTDEVICE8 dinkeyboard; - QMutex mtx; -public: - volatile bool should_quit; - std::function receiver; - ~KeybindingWorker(); - KeybindingWorker(std::function receiver, WId h); - void run(); -#else -public: - KeybindingWorker(Key, Key, Key, WId) {} - void run() {} +# include "keybinding-worker.hpp" #endif -}; + +using namespace options; struct OPENTRACK_EXPORT Shortcuts : public QObject { Q_OBJECT -- cgit v1.2.3 From e138d155d2f2cfb7e87c353f98ffea0e2592483f Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 1 Nov 2015 17:09:52 +0100 Subject: simple-mat: nix porked ctor --- opentrack/simple-mat.hpp | 8 -------- 1 file changed, 8 deletions(-) (limited to 'opentrack') diff --git a/opentrack/simple-mat.hpp b/opentrack/simple-mat.hpp index e462812b6..59afbbf03 100644 --- a/opentrack/simple-mat.hpp +++ b/opentrack/simple-mat.hpp @@ -198,14 +198,6 @@ public: data[j][i] = *iter++; } - template - Mat(const t* xs) - { - for (int j = 0; j < h_; j++) - for (int i = 0; i < w_; i++) - data[j][i] = num(*xs++); - } - Mat() { for (int j = 0; j < h_; j++) -- cgit v1.2.3 From 2d90e4039c6dd1aab00c738f9bbc70a4949cd583 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Nov 2015 06:14:00 +0100 Subject: allow for binding joystick buttons to shortcut functions Win32 only Issue: #118 --- gui/keyboard.h | 16 +- gui/options-dialog.cpp | 44 ++++-- gui/options-dialog.hpp | 2 +- opentrack/keybinding-worker.cpp | 13 ++ opentrack/keybinding-worker.hpp | 5 +- opentrack/shortcuts.cpp | 34 +++-- opentrack/shortcuts.h | 7 +- opentrack/win32-joystick-shortcuts.hpp | 264 +++++++++++++++++++++++++++++++++ 8 files changed, 354 insertions(+), 31 deletions(-) create mode 100644 opentrack/win32-joystick-shortcuts.hpp (limited to 'opentrack') diff --git a/gui/keyboard.h b/gui/keyboard.h index 03edacc75..aa4b4a24b 100644 --- a/gui/keyboard.h +++ b/gui/keyboard.h @@ -20,10 +20,17 @@ public: #ifdef _WIN32 , w([&](Key& k) { - Qt::KeyboardModifiers m; - QKeySequence k_; - if (win_key::to_qt(k, k_, m)) - key_pressed(static_cast(k_).toInt() | m); + if(k.guid != "") + { + joystick_button_pressed(k.guid, k.keycode); + } + else + { + Qt::KeyboardModifiers m; + QKeySequence k_; + if (win_key::to_qt(k, k_, m)) + key_pressed(static_cast(k_).toInt() | m); + } }, this->winId()) #endif { @@ -47,4 +54,5 @@ public: #endif signals: void key_pressed(QKeySequence k); + void joystick_button_pressed(QString guid, int idx); }; diff --git a/gui/options-dialog.cpp b/gui/options-dialog.cpp index 2778be0f7..c8bf668d2 100644 --- a/gui/options-dialog.cpp +++ b/gui/options-dialog.cpp @@ -12,9 +12,18 @@ #include #include +static QString kopts_to_string(const Shortcuts::key_opts& kopts) +{ + if (static_cast(kopts.guid) != "") + return "Joystick button " + QString::number(kopts.button); + if (static_cast(kopts.keycode) == "") + return "None"; + return kopts.keycode; +} + OptionsDialog::OptionsDialog() { - ui.setupUi( this ); + ui.setupUi(this); connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); @@ -53,18 +62,20 @@ OptionsDialog::OptionsDialog() tie_setting(s.s_main.center_method, ui.center_method); - connect(ui.bind_center, &QPushButton::pressed, [&]() -> void { bind_key(s.center.keycode, ui.center_text); }); - connect(ui.bind_zero, &QPushButton::pressed, [&]() -> void { bind_key(s.zero.keycode, ui.zero_text); }); - connect(ui.bind_toggle, &QPushButton::pressed, [&]() -> void { bind_key(s.toggle.keycode, ui.toggle_text); }); + connect(ui.bind_center, &QPushButton::pressed, [&]() -> void { bind_key(s.center, ui.center_text); }); + connect(ui.bind_zero, &QPushButton::pressed, [&]() -> void { bind_key(s.zero, ui.zero_text); }); + connect(ui.bind_toggle, &QPushButton::pressed, [&]() -> void { bind_key(s.toggle, ui.toggle_text); }); - ui.center_text->setText(s.center.keycode == "" ? "None" : static_cast(s.center.keycode)); - ui.toggle_text->setText(s.toggle.keycode == "" ? "None" : static_cast(s.toggle.keycode)); - ui.zero_text->setText(s.zero.keycode == "" ? "None" : static_cast(s.zero.keycode)); + ui.center_text->setText(kopts_to_string(s.center)); + ui.toggle_text->setText(kopts_to_string(s.toggle)); + ui.zero_text->setText(kopts_to_string(s.zero)); } -void OptionsDialog::bind_key(value& ret, QLabel* label) +void OptionsDialog::bind_key(Shortcuts::key_opts& kopts, QLabel* label) { - ret = ""; + kopts.button = -1; + kopts.guid = ""; + kopts.keycode = ""; QDialog d; auto l = new QHBoxLayout; l->setMargin(0); @@ -73,9 +84,20 @@ void OptionsDialog::bind_key(value& ret, QLabel* label) d.setLayout(l); d.setFixedSize(QSize(500, 300)); d.setWindowFlags(Qt::Dialog); - connect(k, &KeyboardListener::key_pressed, [&] (QKeySequence s) -> void { ret = s.toString(QKeySequence::PortableText); d.close(); }); + connect(k, &KeyboardListener::key_pressed, [&] (QKeySequence s) -> void { + kopts.keycode = s.toString(QKeySequence::PortableText); + kopts.guid = ""; + kopts.button = -1; + d.close(); + }); + connect(k, &KeyboardListener::joystick_button_pressed, [&](QString guid, int idx) -> void { + kopts.guid = guid; + kopts.keycode = ""; + kopts.button = idx; + d.close(); + }); d.exec(); - label->setText(ret == "" ? "None" : static_cast(ret)); + label->setText(kopts_to_string(kopts)); delete k; delete l; } diff --git a/gui/options-dialog.hpp b/gui/options-dialog.hpp index 3ef99d06e..308b5b0f8 100644 --- a/gui/options-dialog.hpp +++ b/gui/options-dialog.hpp @@ -19,5 +19,5 @@ private: private slots: void doOK(); void doCancel(); - void bind_key(value& ret, QLabel* label); + void bind_key(Shortcuts::key_opts &kopts, QLabel* label); }; diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index 29b2cf9f7..e6c023ef1 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -72,6 +72,19 @@ void KeybindingWorker::run() { while (!should_quit) { + { + using joy_fn = std::function; + + joy_fn f = [&](const QString& guid, int idx) -> void { + Key k; + k.keycode = idx; + k.guid = guid; + receiver(k); + }; + + joy_ctx.poll(f); + } + if (dinkeyboard->GetDeviceState(256, (LPVOID)keystate) != DI_OK) { qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError(); Sleep(25); diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index e720ffdcc..8cf59d657 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -15,6 +15,7 @@ #endif #include "opentrack-compat/timer.hpp" +#include "opentrack/win32-joystick-shortcuts.hpp" #include #include #include @@ -27,6 +28,7 @@ # include struct Key { BYTE keycode; + QString guid; bool shift; bool ctrl; bool alt; @@ -38,7 +40,7 @@ public: bool should_process() { - if (keycode == 0) + if (keycode == 0 && guid == "") return false; bool ret = timer.elapsed_ms() > 100; timer.start(); @@ -56,6 +58,7 @@ private: LPDIRECTINPUT8 din; LPDIRECTINPUTDEVICE8 dinkeyboard; QMutex mtx; + win32_joy_ctx joy_ctx; public: volatile bool should_quit; std::function receiver; diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp index 5f5ad922b..0d7f79b99 100644 --- a/opentrack/shortcuts.cpp +++ b/opentrack/shortcuts.cpp @@ -34,19 +34,27 @@ void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k) key = K(); int idx = 0; QKeySequence code; - - if (k.keycode == "") - code = QKeySequence(Qt::Key_unknown); + + if (k.guid != "") + { + key.guid = k.guid; + key.keycode = k.button; + } else - code = QKeySequence::fromString(k.keycode, QKeySequence::PortableText); - - Qt::KeyboardModifiers mods = Qt::NoModifier; - if (code != Qt::Key_unknown) - win_key::from_qt(code, idx, mods); - key.shift = !!(mods & Qt::ShiftModifier); - key.alt = !!(mods & Qt::AltModifier); - key.ctrl = !!(mods & Qt::ControlModifier); - key.keycode = idx; + { + if (k.keycode == "") + code = QKeySequence(Qt::Key_unknown); + else + code = QKeySequence::fromString(k.keycode, QKeySequence::PortableText); + + Qt::KeyboardModifiers mods = Qt::NoModifier; + if (code != Qt::Key_unknown) + win_key::from_qt(code, idx, mods); + key.shift = !!(mods & Qt::ShiftModifier); + key.alt = !!(mods & Qt::AltModifier); + key.ctrl = !!(mods & Qt::ControlModifier); + key.keycode = idx; + } } #endif @@ -56,6 +64,8 @@ void Shortcuts::receiver(Key &k) std::vector ks { &keyCenter, &keyToggle, &keyZero }; for (K* k_ : ks) { + if (k.guid != k_->guid) + continue; if (k.keycode != k_->keycode) continue; if (!k_->should_process()) diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index 84231850b..1643485e7 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -47,10 +47,13 @@ public: #endif struct key_opts { - value keycode; + value keycode, guid; + value button; key_opts(pbundle b, const QString& name) : - keycode(b, QString("keycode-%1").arg(name), "") + keycode(b, QString("keycode-%1").arg(name), ""), + guid(b, QString("guid-%1").arg(name), ""), + button(b, QString("button-%1").arg(name), -1) {} }; diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp new file mode 100644 index 000000000..67465bcec --- /dev/null +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -0,0 +1,264 @@ +#pragma once + +#include +#include +#include +#include +#include +#ifndef DIRECTINPUT_VERSION +# define DIRECTINPUT_VERSION 0x800 +#endif +#include +#include +#include "opentrack-compat/timer.hpp" +#include +#include + +struct win32_joy_ctx +{ + using fn = std::function; + + void poll(fn f) + { + refresh(); + for (int i = joys.size() - 1; i >= 0; i--) + { + if (!joys[i]->poll(f)) + joys.erase(joys.begin() + i); + } + } + + struct joy + { + LPDIRECTINPUTDEVICE8 joy_handle; + QString guid; + + joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid) : joy_handle(handle), guid(guid) + { + qDebug() << "got joy" << guid; + } + + ~joy() + { + qDebug() << "nix joy" << guid; + release(); + } + + void release() + { + if (joy_handle) + { + (void) joy_handle->Unacquire(); + joy_handle->Release(); + joy_handle = nullptr; + } + } + + bool poll(fn f) + { + HRESULT hr; + bool ok = false; + + for (int i = 0; i < 5; i++) + { + if (!FAILED(joy_handle->Poll())) + { + ok = true; + break; + } + if ((hr = joy_handle->Acquire()) != DI_OK) + continue; + else + ok = true; + break; + } + + if (!ok) + { + qDebug() << "joy acquire failed" << guid << hr; + return false; + } + + DIJOYSTATE2 js; + + if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) + { + qDebug() << "joy get state failed" << guid << hr; + return false; + } + + for (int i = 0; i < 128; i++) + if (js.rgbButtons[i] & 0x80) + f(guid, i); + + return true; + } + }; + + static 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); + } + + win32_joy_ctx() : dinput_handle(nullptr) + { + (void) CoInitialize(nullptr); + + HRESULT hr; + + if (FAILED(hr = DirectInput8Create(GetModuleHandle(nullptr), + DIRECTINPUT_VERSION, + IID_IDirectInput8, + (void**) &dinput_handle, + nullptr))) + goto fail; + + return; +fail: + qDebug() << "dinput8 failed for shortcuts" << hr; + + release(); + } + + ~win32_joy_ctx() + { + release(); + } + + void release() + { + joys = std::vector>(); + if (dinput_handle) + { + dinput_handle->Release(); + dinput_handle = nullptr; + } + } + + void refresh() + { + if (!dinput_handle) + return; + + if (timer_joylist.elapsed_ms() < joylist_refresh_ms) + return; + + timer_joylist.start(); + + enum_state st(dinput_handle, joys); + } + + struct enum_state + { + std::vector>& joys; + std::vector all; + LPDIRECTINPUT8 dinput_handle; + + enum_state(LPDIRECTINPUT8 di, std::vector>& joys) : joys(joys), dinput_handle(di) + { + HRESULT hr; + + if(FAILED(hr = dinput_handle->EnumDevices(DI8DEVCLASS_GAMECTRL, + EnumJoysticksCallback, + this, + DIEDFL_ATTACHEDONLY))) + { + qDebug() << "failed enum joysticks" << hr; + return; + } + + for (int i = joys.size() - 1; i >= 0; i--) + { + const auto& guid = joys[i]->guid; + if (std::find_if(all.cbegin(), all.cend(), [&](const QString& guid2) -> bool { return guid == guid2; }) == all.cend()) + joys.erase(joys.begin() + i); + } + } + + static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext) + { + enum_state& state = *reinterpret_cast(pContext); + const QString guid = guid_to_string(pdidInstance->guidInstance); +#if 0 + const QString name = QString(pdidInstance->tszInstanceName); + // the logic here is that iff multiple joysticks of same name exist, then take guids into account at all + const int cnt_names = std::count_if(state.joys.begin(), state.joys.end(), [&](const joy& j) -> bool { return j.name == name; }); + // this is potentially bad since replugged sticks can change guids (?) +#endif + + const bool exists = std::find_if(state.joys.cbegin(), + state.joys.cend(), + [&](const std::shared_ptr& j) -> bool { return j->guid == guid; }) != state.joys.cend(); + + state.all.push_back(guid); + + if (!exists) + { + HRESULT hr; + LPDIRECTINPUTDEVICE8 h; + if (FAILED(hr = state.dinput_handle->CreateDevice(pdidInstance->guidInstance, &h, nullptr))) + { + qDebug() << "create joystick breakage" << guid << hr; + goto end; + } + if (FAILED(h->SetDataFormat(&c_dfDIJoystick2))) + { + qDebug() << "format"; + h->Release(); + goto end; + } + + if (FAILED(h->SetCooperativeLevel((HWND) GetDesktopWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) + { + qDebug() << "coop"; + h->Release(); + goto end; + } +#if 0 + if (FAILED(hr = h->EnumObjects(EnumObjectsCallback, h, DIDFT_ALL))) + { + qDebug() << "enum-objects"; + h->Release(); + goto end; + } +#endif + state.joys.push_back(std::make_shared(h, guid)); + } + +end: return DIENUM_CONTINUE; + } + +#if 0 + static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx) + { + if (pdidoi->dwType & DIDFT_AXIS) + { + DIPROPRANGE diprg; + memset(&diprg, 0, sizeof(diprg)); + diprg.diph.dwSize = sizeof( DIPROPRANGE ); + diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER ); + diprg.diph.dwHow = DIPH_BYID; + diprg.diph.dwObj = pdidoi->dwType; + diprg.lMax = 32; + diprg.lMin = -32; + + if (FAILED(reinterpret_cast(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph))) + return DIENUM_STOP; + } + + return DIENUM_CONTINUE; + } +#endif + }; + + LPDIRECTINPUT8 dinput_handle; + std::vector> joys; + Timer timer_joylist; + enum { joylist_refresh_ms = 2000 }; +}; \ No newline at end of file -- cgit v1.2.3 From 17849b12f232c89bdae16f7e179d3a92a32280ad Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Nov 2015 13:44:45 +0100 Subject: shortcuts: map joystick buttons on depress only Some buttons like the X65 mode switch are held all the time. Prevent them from hogging all the keybindings. Issue: #118 --- gui/keyboard.h | 4 ++-- gui/options-dialog.cpp | 13 ++++++++----- opentrack/keybinding-worker.cpp | 5 +++-- opentrack/keybinding-worker.hpp | 3 ++- opentrack/win32-joystick-shortcuts.hpp | 13 ++++++++++--- 5 files changed, 25 insertions(+), 13 deletions(-) (limited to 'opentrack') diff --git a/gui/keyboard.h b/gui/keyboard.h index aa4b4a24b..b840bc782 100644 --- a/gui/keyboard.h +++ b/gui/keyboard.h @@ -22,7 +22,7 @@ public: { if(k.guid != "") { - joystick_button_pressed(k.guid, k.keycode); + joystick_button_pressed(k.guid, k.keycode, k.held); } else { @@ -54,5 +54,5 @@ public: #endif signals: void key_pressed(QKeySequence k); - void joystick_button_pressed(QString guid, int idx); + void joystick_button_pressed(QString guid, int idx, bool held); }; diff --git a/gui/options-dialog.cpp b/gui/options-dialog.cpp index c8bf668d2..4cff6e774 100644 --- a/gui/options-dialog.cpp +++ b/gui/options-dialog.cpp @@ -90,11 +90,14 @@ void OptionsDialog::bind_key(Shortcuts::key_opts& kopts, QLabel* label) kopts.button = -1; d.close(); }); - connect(k, &KeyboardListener::joystick_button_pressed, [&](QString guid, int idx) -> void { - kopts.guid = guid; - kopts.keycode = ""; - kopts.button = idx; - d.close(); + connect(k, &KeyboardListener::joystick_button_pressed, [&](QString guid, int idx, bool held) -> void { + if (!held) + { + kopts.guid = guid; + kopts.keycode = ""; + kopts.button = idx; + d.close(); + } }); d.exec(); label->setText(kopts_to_string(kopts)); diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index e6c023ef1..e9255801a 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -73,12 +73,13 @@ void KeybindingWorker::run() { while (!should_quit) { { - using joy_fn = std::function; + using joy_fn = std::function; - joy_fn f = [&](const QString& guid, int idx) -> void { + joy_fn f = [&](const QString& guid, int idx, bool held) -> void { Key k; k.keycode = idx; k.guid = guid; + k.held = held; receiver(k); }; diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index 8cf59d657..cb3e5f9fd 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -32,9 +32,10 @@ struct Key { bool shift; bool ctrl; bool alt; + bool held; Timer timer; public: - Key() : keycode(0), shift(false), ctrl(false), alt(false) + Key() : keycode(0), shift(false), ctrl(false), alt(false), held(true) { } diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index 67465bcec..3c8391977 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -16,7 +16,7 @@ struct win32_joy_ctx { - using fn = std::function; + using fn = std::function; void poll(fn f) { @@ -32,10 +32,13 @@ struct win32_joy_ctx { LPDIRECTINPUTDEVICE8 joy_handle; QString guid; + bool pressed[128]; joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid) : joy_handle(handle), guid(guid) { qDebug() << "got joy" << guid; + for (int i = 0; i < 128; i++) + pressed[i] = false; } ~joy() @@ -88,8 +91,12 @@ struct win32_joy_ctx } for (int i = 0; i < 128; i++) - if (js.rgbButtons[i] & 0x80) - f(guid, i); + { + const bool state = !!(js.rgbButtons[i] & 0x80); + if (state != pressed[i]) + f(guid, i, state); + pressed[i] = state; + } return true; } -- cgit v1.2.3 From dce46278e8ccb63a1f6dd60733671fdcaad59873 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Nov 2015 13:45:10 +0100 Subject: shortcuts: register joysticks every 250 ms, not 2 seconds Issue: #118 --- opentrack/win32-joystick-shortcuts.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index 3c8391977..23228835f 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -267,5 +267,5 @@ end: return DIENUM_CONTINUE; LPDIRECTINPUT8 dinput_handle; std::vector> joys; Timer timer_joylist; - enum { joylist_refresh_ms = 2000 }; + enum { joylist_refresh_ms = 250 }; }; \ No newline at end of file -- cgit v1.2.3 From 4c2529611677e204b7ecf40508723f355cfd423b Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Nov 2015 14:13:46 +0100 Subject: joy: refresh immediately once on startup --- opentrack/win32-joystick-shortcuts.hpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index 23228835f..5a2fc6c81 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -20,7 +20,7 @@ struct win32_joy_ctx void poll(fn f) { - refresh(); + refresh(false); for (int i = joys.size() - 1; i >= 0; i--) { if (!joys[i]->poll(f)) @@ -126,6 +126,8 @@ struct win32_joy_ctx nullptr))) goto fail; + refresh(true); + return; fail: qDebug() << "dinput8 failed for shortcuts" << hr; @@ -148,15 +150,17 @@ fail: } } - void refresh() + void refresh(bool first) { if (!dinput_handle) return; - if (timer_joylist.elapsed_ms() < joylist_refresh_ms) - return; - - timer_joylist.start(); + if (!first) + { + if (timer_joylist.elapsed_ms() < joylist_refresh_ms) + return; + timer_joylist.start(); + } enum_state st(dinput_handle, joys); } -- cgit v1.2.3 From 605d267622b8d2e69bc761f4f49442566164d843 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Nov 2015 14:35:13 +0100 Subject: joy: pass shortcut only if pressed, not depressed Issue: #118 Reported-by: @Len62 --- opentrack/shortcuts.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'opentrack') diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp index 0d7f79b99..108b6b3bc 100644 --- a/opentrack/shortcuts.cpp +++ b/opentrack/shortcuts.cpp @@ -68,6 +68,8 @@ void Shortcuts::receiver(Key &k) continue; if (k.keycode != k_->keycode) continue; + if (!k.held) + continue; if (!k_->should_process()) continue; if (k_->alt && !k.alt) continue; -- cgit v1.2.3 From 9f8cbd79fc1040e855fe9325447983bd8d13f1b9 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Nov 2015 14:35:26 +0100 Subject: joy: memset won't hurt --- opentrack/win32-joystick-shortcuts.hpp | 1 + 1 file changed, 1 insertion(+) (limited to 'opentrack') diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index 5a2fc6c81..ee26215eb 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -83,6 +83,7 @@ struct win32_joy_ctx } DIJOYSTATE2 js; + memset(&js, 0, sizeof(js)); if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) { -- cgit v1.2.3 From ef897ea95734917c3679dc9e2cad89e8d55c3099 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Nov 2015 14:35:34 +0100 Subject: joy: add cheap debug info --- opentrack/win32-joystick-shortcuts.hpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'opentrack') diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index ee26215eb..bde690c57 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -95,7 +95,10 @@ struct win32_joy_ctx { const bool state = !!(js.rgbButtons[i] & 0x80); if (state != pressed[i]) + { f(guid, i, state); + qDebug() << "btn" << guid << i << state; + } pressed[i] = state; } -- cgit v1.2.3 From e79ab73d99d3cc19e0db82cce8884589e0e93396 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Nov 2015 14:35:46 +0100 Subject: joy: slurp keys on startup --- opentrack/win32-joystick-shortcuts.hpp | 1 + 1 file changed, 1 insertion(+) (limited to 'opentrack') diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index bde690c57..530545dc9 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -39,6 +39,7 @@ struct win32_joy_ctx qDebug() << "got joy" << guid; for (int i = 0; i < 128; i++) pressed[i] = false; + poll([&](const QString&, int idx, bool held) -> void { pressed[idx] = held; }); } ~joy() -- cgit v1.2.3 From c8805112acca1ba3bd0056fcf0b9332c4ba10f03 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Nov 2015 15:28:50 +0100 Subject: shortcuts: alloy kbd mods for joystick buttons --- gui/keyboard.h | 6 +++++- opentrack/keybinding-worker.cpp | 21 ++++++++++++++------- opentrack/shortcuts.cpp | 5 ++++- 3 files changed, 23 insertions(+), 9 deletions(-) (limited to 'opentrack') diff --git a/gui/keyboard.h b/gui/keyboard.h index b840bc782..75226aa3b 100644 --- a/gui/keyboard.h +++ b/gui/keyboard.h @@ -22,7 +22,11 @@ public: { if(k.guid != "") { - joystick_button_pressed(k.guid, k.keycode, k.held); + int mods = 0; + if (k.alt) mods |= Qt::AltModifier; + if (k.shift) mods |= Qt::ShiftModifier; + if (k.ctrl) mods |= Qt::ControlModifier; + joystick_button_pressed(k.guid, k.keycode | mods, k.held); } else { diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index e9255801a..fd7772111 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -68,16 +68,29 @@ KeybindingWorker::KeybindingWorker(std::function receiver, WId h) : } void KeybindingWorker::run() { - BYTE keystate[256]; + BYTE keystate[256] = {0}; while (!should_quit) { + { + const HRESULT hr = dinkeyboard->GetDeviceState(256, (LPVOID)keystate); + + if (hr != DI_OK) { + qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError(); + Sleep(25); + continue; + } + } + { using joy_fn = std::function; joy_fn f = [&](const QString& guid, int idx, bool held) -> void { Key k; k.keycode = idx; + k.shift = !!(keystate[DIK_LSHIFT] & 0x80 || keystate[DIK_RSHIFT] & 0x80); + k.alt = !!(keystate[DIK_LALT] & 0x80 || keystate[DIK_RALT] & 0x80); + k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80 || keystate[DIK_RCONTROL] & 0x80); k.guid = guid; k.held = held; receiver(k); @@ -85,12 +98,6 @@ void KeybindingWorker::run() { joy_ctx.poll(f); } - - if (dinkeyboard->GetDeviceState(256, (LPVOID)keystate) != DI_OK) { - qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError(); - Sleep(25); - continue; - } QMutexLocker l(&mtx); diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp index 108b6b3bc..6eab60712 100644 --- a/opentrack/shortcuts.cpp +++ b/opentrack/shortcuts.cpp @@ -38,7 +38,10 @@ void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k) if (k.guid != "") { key.guid = k.guid; - key.keycode = k.button; + key.keycode = k.button & ~Qt::KeyboardModifierMask; + key.ctrl = !!(k.button & Qt::ControlModifier); + key.alt = !!(k.button & Qt::AltModifier); + key.shift = !!(k.button & Qt::ShiftModifier); } else { -- cgit v1.2.3 From 390e9f1ad63a4ac90ffa4fab8094999cfe794c64 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Wed, 11 Nov 2015 15:52:50 +0100 Subject: joy: guard _WIN32. retab. --- opentrack/win32-joystick-shortcuts.hpp | 86 ++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 41 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index 530545dc9..3e384da5b 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -1,5 +1,7 @@ #pragma once +#ifdef _WIN32 + #include #include #include @@ -17,7 +19,7 @@ struct win32_joy_ctx { using fn = std::function; - + void poll(fn f) { refresh(false); @@ -27,13 +29,13 @@ struct win32_joy_ctx joys.erase(joys.begin() + i); } } - + struct joy { LPDIRECTINPUTDEVICE8 joy_handle; QString guid; bool pressed[128]; - + joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid) : joy_handle(handle), guid(guid) { qDebug() << "got joy" << guid; @@ -41,13 +43,13 @@ struct win32_joy_ctx pressed[i] = false; poll([&](const QString&, int idx, bool held) -> void { pressed[idx] = held; }); } - + ~joy() { qDebug() << "nix joy" << guid; release(); } - + void release() { if (joy_handle) @@ -57,12 +59,12 @@ struct win32_joy_ctx joy_handle = nullptr; } } - + bool poll(fn f) { HRESULT hr; bool ok = false; - + for (int i = 0; i < 5; i++) { if (!FAILED(joy_handle->Poll())) @@ -76,22 +78,22 @@ struct win32_joy_ctx ok = true; break; } - + if (!ok) { qDebug() << "joy acquire failed" << guid << hr; return false; } - + DIJOYSTATE2 js; memset(&js, 0, sizeof(js)); - + if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) { qDebug() << "joy get state failed" << guid << hr; return false; } - + for (int i = 0; i < 128; i++) { const bool state = !!(js.rgbButtons[i] & 0x80); @@ -102,49 +104,49 @@ struct win32_joy_ctx } pressed[i] = state; } - + return true; } }; - + static 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); } - + win32_joy_ctx() : dinput_handle(nullptr) { (void) CoInitialize(nullptr); - + HRESULT hr; - + if (FAILED(hr = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**) &dinput_handle, nullptr))) goto fail; - + refresh(true); - + return; fail: qDebug() << "dinput8 failed for shortcuts" << hr; - + release(); } - + ~win32_joy_ctx() { release(); } - + void release() { joys = std::vector>(); @@ -154,32 +156,32 @@ fail: dinput_handle = nullptr; } } - + void refresh(bool first) { if (!dinput_handle) return; - + if (!first) { if (timer_joylist.elapsed_ms() < joylist_refresh_ms) return; timer_joylist.start(); } - + enum_state st(dinput_handle, joys); } - + struct enum_state { std::vector>& joys; std::vector all; LPDIRECTINPUT8 dinput_handle; - + enum_state(LPDIRECTINPUT8 di, std::vector>& joys) : joys(joys), dinput_handle(di) { HRESULT hr; - + if(FAILED(hr = dinput_handle->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, this, @@ -188,7 +190,7 @@ fail: qDebug() << "failed enum joysticks" << hr; return; } - + for (int i = joys.size() - 1; i >= 0; i--) { const auto& guid = joys[i]->guid; @@ -196,7 +198,7 @@ fail: joys.erase(joys.begin() + i); } } - + static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext) { enum_state& state = *reinterpret_cast(pContext); @@ -207,13 +209,13 @@ fail: const int cnt_names = std::count_if(state.joys.begin(), state.joys.end(), [&](const joy& j) -> bool { return j.name == name; }); // this is potentially bad since replugged sticks can change guids (?) #endif - + const bool exists = std::find_if(state.joys.cbegin(), state.joys.cend(), [&](const std::shared_ptr& j) -> bool { return j->guid == guid; }) != state.joys.cend(); - + state.all.push_back(guid); - + if (!exists) { HRESULT hr; @@ -229,7 +231,7 @@ fail: h->Release(); goto end; } - + if (FAILED(h->SetCooperativeLevel((HWND) GetDesktopWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) { qDebug() << "coop"; @@ -246,10 +248,10 @@ fail: #endif state.joys.push_back(std::make_shared(h, guid)); } - + end: return DIENUM_CONTINUE; } - + #if 0 static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx) { @@ -263,18 +265,20 @@ end: return DIENUM_CONTINUE; diprg.diph.dwObj = pdidoi->dwType; diprg.lMax = 32; diprg.lMin = -32; - + if (FAILED(reinterpret_cast(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph))) return DIENUM_STOP; } - + return DIENUM_CONTINUE; } #endif }; - + LPDIRECTINPUT8 dinput_handle; std::vector> joys; Timer timer_joylist; enum { joylist_refresh_ms = 250 }; -}; \ No newline at end of file +}; + +#endif -- cgit v1.2.3 From afc6da0a17eec9e1da31a79c610a8f090507b39e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 12 Nov 2015 08:28:41 +0100 Subject: joy: for newly plugged sticks, only emit events after 3 seconds My X65 emits modeswitch events only a while after getting plugged in. This only affects newly hotplugged joysticks. Ones plugged in before listening start start processing events immediately. Issue: #118 --- opentrack/win32-joystick-shortcuts.hpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index 3e384da5b..f3bca827e 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -35,13 +35,16 @@ struct win32_joy_ctx LPDIRECTINPUTDEVICE8 joy_handle; QString guid; bool pressed[128]; + Timer first_timer; + bool first; + + enum { first_event_delay_ms = 3000 }; - joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid) : joy_handle(handle), guid(guid) + joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, bool first) : joy_handle(handle), guid(guid), first(first) { qDebug() << "got joy" << guid; for (int i = 0; i < 128; i++) pressed[i] = false; - poll([&](const QString&, int idx, bool held) -> void { pressed[idx] = held; }); } ~joy() @@ -64,6 +67,9 @@ struct win32_joy_ctx { HRESULT hr; bool ok = false; + + if (first_timer.elapsed_ms() > first_event_delay_ms) + first = true; for (int i = 0; i < 5; i++) { @@ -97,7 +103,7 @@ struct win32_joy_ctx for (int i = 0; i < 128; i++) { const bool state = !!(js.rgbButtons[i] & 0x80); - if (state != pressed[i]) + if (state != pressed[i] && first) { f(guid, i, state); qDebug() << "btn" << guid << i << state; @@ -169,7 +175,7 @@ fail: timer_joylist.start(); } - enum_state st(dinput_handle, joys); + enum_state st(dinput_handle, joys, first); } struct enum_state @@ -177,8 +183,9 @@ fail: std::vector>& joys; std::vector all; LPDIRECTINPUT8 dinput_handle; + bool first; - enum_state(LPDIRECTINPUT8 di, std::vector>& joys) : joys(joys), dinput_handle(di) + enum_state(LPDIRECTINPUT8 di, std::vector>& joys, bool first) : joys(joys), dinput_handle(di), first(first) { HRESULT hr; @@ -246,7 +253,7 @@ fail: goto end; } #endif - state.joys.push_back(std::make_shared(h, guid)); + state.joys.push_back(std::make_shared(h, guid, state.first)); } end: return DIENUM_CONTINUE; -- cgit v1.2.3 From 798f6e9076855bf7769aba8abde4d570960d0755 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 12 Nov 2015 08:48:51 +0100 Subject: joy: remove branching --- opentrack/win32-joystick-shortcuts.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index f3bca827e..e54596bdb 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -67,9 +67,6 @@ struct win32_joy_ctx { HRESULT hr; bool ok = false; - - if (first_timer.elapsed_ms() > first_event_delay_ms) - first = true; for (int i = 0; i < 5; i++) { @@ -99,6 +96,8 @@ struct win32_joy_ctx qDebug() << "joy get state failed" << guid << hr; return false; } + + first |= first_timer.elapsed_ms() > first_event_delay_ms; for (int i = 0; i < 128; i++) { -- cgit v1.2.3 From 42217bbb858ddb158ad13777e2aace942aaf9525 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 19 Nov 2015 01:41:49 +0100 Subject: shortcuts: nix single-use mutex It also slept with lock held. Good riddance. --- opentrack/keybinding-worker.cpp | 2 -- opentrack/keybinding-worker.hpp | 1 - opentrack/shortcuts.cpp | 1 - 3 files changed, 4 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index fd7772111..31eb9e80d 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -99,8 +99,6 @@ void KeybindingWorker::run() { joy_ctx.poll(f); } - QMutexLocker l(&mtx); - for (int i = 0; i < 256; i++) { Key k; diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index cb3e5f9fd..b5d63fac4 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -58,7 +58,6 @@ struct OPENTRACK_EXPORT KeybindingWorker : public QThread { private: LPDIRECTINPUT8 din; LPDIRECTINPUTDEVICE8 dinkeyboard; - QMutex mtx; win32_joy_ctx joy_ctx; public: volatile bool should_quit; diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp index 6eab60712..059febdb4 100644 --- a/opentrack/shortcuts.cpp +++ b/opentrack/shortcuts.cpp @@ -8,7 +8,6 @@ #include "shortcuts.h" #include "win32-shortcuts.h" -#include void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k) { -- cgit v1.2.3 From a9860e951757bf454b83b13ce7eff865f0b6644e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 15:06:30 +0100 Subject: api/keyboard: implement a central worker DirectInput dies when two LPDIRECTINPUT8 handles are obtained. Implement a singleton worker providing keypress events. --- opentrack/keybinding-worker.cpp | 153 ++++++++++++++++++++++++++-------------- opentrack/keybinding-worker.hpp | 48 ++++++++++--- 2 files changed, 137 insertions(+), 64 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index 31eb9e80d..d876d5a12 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -9,11 +9,14 @@ #include "keybinding-worker.hpp" #if defined(_WIN32) -# include -# include -# include + +#include +#include +#include +#include KeybindingWorker::~KeybindingWorker() { + qDebug() << "keybinding worker stop"; should_quit = true; wait(); if (dinkeyboard) { @@ -24,11 +27,8 @@ KeybindingWorker::~KeybindingWorker() { din->Release(); } -KeybindingWorker::KeybindingWorker(std::function receiver, WId h) : - should_quit(true), receiver(receiver) +KeybindingWorker::KeybindingWorker() : should_quit(true) { - HWND handle = reinterpret_cast(h); - if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) { qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); return; @@ -47,7 +47,7 @@ KeybindingWorker::KeybindingWorker(std::function receiver, WId h) : din = 0; return; } - if (dinkeyboard->SetCooperativeLevel((HWND) handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) { + if (dinkeyboard->SetCooperativeLevel(GetDesktopWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) { dinkeyboard->Release(); din->Release(); din = 0; @@ -65,6 +65,13 @@ KeybindingWorker::KeybindingWorker(std::function receiver, WId h) : return; } should_quit = false; + start(); +} + +KeybindingWorker& KeybindingWorker::make() +{ + static KeybindingWorker k; + return k; } void KeybindingWorker::run() { @@ -73,59 +80,99 @@ void KeybindingWorker::run() { while (!should_quit) { { - const HRESULT hr = dinkeyboard->GetDeviceState(256, (LPVOID)keystate); - - if (hr != DI_OK) { - qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError(); - Sleep(25); - continue; - } - } - - { - using joy_fn = std::function; - - joy_fn f = [&](const QString& guid, int idx, bool held) -> void { - Key k; - k.keycode = idx; - k.shift = !!(keystate[DIK_LSHIFT] & 0x80 || keystate[DIK_RSHIFT] & 0x80); - k.alt = !!(keystate[DIK_LALT] & 0x80 || keystate[DIK_RALT] & 0x80); - k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80 || keystate[DIK_RCONTROL] & 0x80); - k.guid = guid; - k.held = held; - receiver(k); - }; + QMutexLocker l(&mtx); - joy_ctx.poll(f); - } - - for (int i = 0; i < 256; i++) - { - Key k; - if (keystate[i] & 0x80) + if (receivers.size()) { - switch (i) { - case DIK_LCONTROL: - case DIK_LSHIFT: - case DIK_LALT: - case DIK_RCONTROL: - case DIK_RSHIFT: - case DIK_RALT: - break; - default: - k.shift = !!(keystate[DIK_LSHIFT] & 0x80) || !!(keystate[DIK_RSHIFT] & 0x80); - k.alt = !!(keystate[DIK_LALT] & 0x80) || !!(keystate[DIK_RALT] & 0x80); - k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80) || !!(keystate[DIK_RCONTROL] & 0x80); - k.keycode = i; - receiver(k); - break; + const HRESULT hr = dinkeyboard->GetDeviceState(256, (LPVOID)keystate); + + if (hr != DI_OK) { + qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError(); + Sleep(25); + continue; + } + } + + { + using joy_fn = std::function; + + joy_fn f = [&](const QString& guid, int idx, bool held) -> void { + Key k; + k.keycode = idx; + k.shift = !!(keystate[DIK_LSHIFT] & 0x80 || keystate[DIK_RSHIFT] & 0x80); + k.alt = !!(keystate[DIK_LALT] & 0x80 || keystate[DIK_RALT] & 0x80); + k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80 || keystate[DIK_RCONTROL] & 0x80); + k.guid = guid; + k.held = held; + + for (auto& r : receivers) + r(k); + }; + + joy_ctx.poll(f); + } + + for (int i = 0; i < 256; i++) + { + Key k; + if (keystate[i] & 0x80) + { + switch (i) + { + case DIK_LCONTROL: + case DIK_LSHIFT: + case DIK_LALT: + case DIK_RCONTROL: + case DIK_RSHIFT: + case DIK_RALT: + break; + default: + k.shift = !!(keystate[DIK_LSHIFT] & 0x80) || !!(keystate[DIK_RSHIFT] & 0x80); + k.alt = !!(keystate[DIK_LALT] & 0x80) || !!(keystate[DIK_RALT] & 0x80); + k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80) || !!(keystate[DIK_RCONTROL] & 0x80); + k.keycode = i; + + for (auto& r : receivers) + r(k); + break; + } + } } } } - + // keypresses get dropped with high values Sleep(4); } } + +KeybindingWorker::fun* KeybindingWorker::_add_receiver(KeybindingWorker::fun receiver) +{ + QMutexLocker l(&mtx); + receivers.push_back(receiver); + qDebug() << "add receiver" << (long) &receivers[receivers.size()-1]; + return &receivers[receivers.size()-1]; +} + +void KeybindingWorker::remove_receiver(KeybindingWorker::fun* pos) +{ + QMutexLocker l(&mtx); + bool ok = false; + + for (int i = receivers.size() - 1; i >= 0; i--) + { + if (&receivers[i] == pos) + { + ok = true; + qDebug() << "remove receiver" << (long) pos; + receivers.erase(receivers.begin() + i); + } + } + if (!ok) + { + qDebug() << "bad remove receiver" << (long) pos; + } +} + #endif \ No newline at end of file diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index b5d63fac4..5a73b1b1c 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef _WIN32 # undef DIRECTINPUT_VERSION @@ -53,21 +54,46 @@ typedef unsigned char BYTE; struct Key { int foo; }; #endif -struct OPENTRACK_EXPORT KeybindingWorker : public QThread { -#ifdef _WIN32 +struct OPENTRACK_EXPORT KeybindingWorker : private QThread +{ private: LPDIRECTINPUT8 din; LPDIRECTINPUTDEVICE8 dinkeyboard; win32_joy_ctx joy_ctx; -public: volatile bool should_quit; - std::function receiver; + using fun = std::function; + std::vector receivers; + QMutex mtx; + + void run() override; + KeybindingWorker(); + + KeybindingWorker(const KeybindingWorker&) = delete; + KeybindingWorker& operator=(KeybindingWorker&) = delete; + static KeybindingWorker& make(); + fun* _add_receiver(fun receiver); + void remove_receiver(fun* pos); ~KeybindingWorker(); - KeybindingWorker(std::function receiver, WId h); - void run(); -#else public: - KeybindingWorker(Key, Key, Key, WId) {} - void run() {} -#endif -}; \ No newline at end of file + class Token + { + friend class KeybindingWorker; + fun* pos; + //Token(const Token&) = delete; + Token& operator=(Token&) = delete; + public: + Token(fun receiver) + { + pos = make()._add_receiver(receiver); + } + ~Token() + { + make().remove_receiver(pos); + } + }; + friend class Token; + static Token add_receiver(fun receiver) + { + return Token(receiver); + } +}; -- cgit v1.2.3 From bf5931532f91107747cc45befffb5cc189777c89 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 15:07:23 +0100 Subject: work: use the centralized keypress worker --- gui/keyboard.h | 10 +++------- opentrack/shortcuts.cpp | 10 +--------- opentrack/shortcuts.h | 11 ++++++----- opentrack/work.hpp | 3 ++- 4 files changed, 12 insertions(+), 22 deletions(-) (limited to 'opentrack') diff --git a/gui/keyboard.h b/gui/keyboard.h index 75226aa3b..696df6059 100644 --- a/gui/keyboard.h +++ b/gui/keyboard.h @@ -13,13 +13,12 @@ class KeyboardListener : public QLabel Q_OBJECT Ui_keyboard_listener ui; #ifdef _WIN32 - KeybindingWorker w; + KeybindingWorker::Token token; #endif public: KeyboardListener(QWidget* parent = nullptr) : QLabel(parent) #ifdef _WIN32 - , w([&](Key& k) - { + , token([&](const Key& k) { if(k.guid != "") { int mods = 0; @@ -35,14 +34,11 @@ public: if (win_key::to_qt(k, k_, m)) key_pressed(static_cast(k_).toInt() | m); } - }, this->winId()) + }) #endif { ui.setupUi(this); setFocusPolicy(Qt::StrongFocus); -#ifdef _WIN32 - w.start(); -#endif } #ifndef _WIN32 void keyPressEvent(QKeyEvent* event) override diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp index 059febdb4..b961294f7 100644 --- a/opentrack/shortcuts.cpp +++ b/opentrack/shortcuts.cpp @@ -61,7 +61,7 @@ void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k) #endif #ifdef _WIN32 -void Shortcuts::receiver(Key &k) +void Shortcuts::receiver(const Key& k) { std::vector ks { &keyCenter, &keyToggle, &keyZero }; for (K* k_ : ks) @@ -92,12 +92,4 @@ void Shortcuts::reload() { bind_keyboard_shortcut(keyCenter, s.center); bind_keyboard_shortcut(keyToggle, s.toggle); bind_keyboard_shortcut(keyZero, s.zero); -#ifdef _WIN32 - bool is_new = keybindingWorker == nullptr; - if (is_new) - { - keybindingWorker = std::make_shared([&](Key& k) { receiver(k); }, handle); - keybindingWorker->start(); - } -#endif } diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index 1643485e7..930952e89 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -40,10 +40,8 @@ public: K keyCenter; K keyToggle; K keyZero; - - WId handle; #ifdef _WIN32 - mem keybindingWorker; + KeybindingWorker::Token key_token; #endif struct key_opts { @@ -68,13 +66,16 @@ public: {} } s; - Shortcuts(WId handle) : handle(handle) { reload(); } + Shortcuts() : key_token(KeybindingWorker::add_receiver([&](const Key& k) { receiver(k); })) + { + reload(); + } void reload(); private: void bind_keyboard_shortcut(K &key, key_opts& k); #ifdef _WIN32 - void receiver(Key& k); + void receiver(const Key& k); #endif signals: void center(); diff --git a/opentrack/work.hpp b/opentrack/work.hpp index 5d1f6b548..e338e9f48 100644 --- a/opentrack/work.hpp +++ b/opentrack/work.hpp @@ -28,7 +28,7 @@ struct Work Work(main_settings& s, Mappings& m, SelectedLibraries& libs, QObject* recv, WId handle) : s(s), libs(libs), tracker(std::make_shared(s, m, libs)), - sc(std::make_shared(handle)), + sc(std::make_shared()), handle(handle) { #ifndef _WIN32 @@ -50,6 +50,7 @@ struct Work ~Work() { + sc = nullptr; // order matters, otherwise use-after-free -sh tracker = nullptr; libs = SelectedLibraries(); -- cgit v1.2.3 From 38a7253d20f7e29760e536e7e172a43d413a9372 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 15:11:31 +0100 Subject: api/joy: implement a central joystick worker - Make the dinput handle a singleton also across module boundaries. - Provide axis values per connected stick. - Robustify in case of sudden unplug. --- opentrack/win32-joystick-shortcuts.cpp | 24 ++++ opentrack/win32-joystick-shortcuts.hpp | 216 +++++++++++++++++++++------------ 2 files changed, 162 insertions(+), 78 deletions(-) create mode 100644 opentrack/win32-joystick-shortcuts.cpp (limited to 'opentrack') diff --git a/opentrack/win32-joystick-shortcuts.cpp b/opentrack/win32-joystick-shortcuts.cpp new file mode 100644 index 000000000..44659b7e5 --- /dev/null +++ b/opentrack/win32-joystick-shortcuts.cpp @@ -0,0 +1,24 @@ +#include "win32-joystick-shortcuts.hpp" + +LPDIRECTINPUT8& win32_joy_ctx::dinput_handle() +{ + (void) CoInitialize(nullptr); + + static LPDIRECTINPUT8 dinput_handle_ = nullptr; + + if (dinput_handle_ == nullptr) + (void) DirectInput8Create(GetModuleHandle(nullptr), + DIRECTINPUT_VERSION, + IID_IDirectInput8, + (void**) &dinput_handle_, + nullptr); + + return dinput_handle_; +} + +std::unordered_map>& win32_joy_ctx::joys() +{ + static std::unordered_map> js; + + return js; +} diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index e54596bdb..081dc0ce8 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #ifndef DIRECTINPUT_VERSION # define DIRECTINPUT_VERSION 0x800 #endif @@ -15,32 +16,109 @@ #include "opentrack-compat/timer.hpp" #include #include +#include +#include -struct win32_joy_ctx +namespace std { +template<> +struct hash +{ + std::size_t operator()(const QString& value) const + { + return qHash(value); + } +}; +} + +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +struct OPENTRACK_EXPORT win32_joy_ctx { using fn = std::function; void poll(fn f) { + QMutexLocker l(&mtx); + refresh(false); - for (int i = joys.size() - 1; i >= 0; i--) + for (auto& j : joys()) { - if (!joys[i]->poll(f)) - joys.erase(joys.begin() + i); + j.second->poll(f); } } + + bool poll_axis(const QString& guid, int axes[8]) + { + QMutexLocker l(&mtx); + + auto iter = joys().find(guid); + + if (iter == joys().end() || iter->second->joy_handle == nullptr) + return false; + + refresh(false); + + auto& j = iter->second; + + auto& joy_handle = j->joy_handle; + bool ok = false; + HRESULT hr; + + (void) joy_handle->Acquire(); + + if (!FAILED(hr = joy_handle->Poll())) + ok = true; + + if (!ok) + { + qDebug() << "joy acquire failed" << guid << hr; + (void) joy_handle->Unacquire(); + return false; + } + + DIJOYSTATE2 js; + memset(&js, 0, sizeof(js)); + + if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) + { + qDebug() << "joy get state failed" << guid << hr; + return false; + } + + const int values[] = { + js.lX, + js.lY, + js.lZ, + js.lRx, + js.lRy, + js.lRz, + js.rglSlider[0], + js.rglSlider[1] + }; + + for (int i = 0; i < 8; i++) + axes[i] = values[i]; + + (void) joy_handle->Unacquire(); + + return true; + } struct joy { LPDIRECTINPUTDEVICE8 joy_handle; - QString guid; + QString guid, name; bool pressed[128]; Timer first_timer; bool first; enum { first_event_delay_ms = 3000 }; - joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, bool first) : joy_handle(handle), guid(guid), first(first) + joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name, bool first) : joy_handle(handle), guid(guid), name(name), first(first) { qDebug() << "got joy" << guid; for (int i = 0; i < 128; i++) @@ -67,24 +145,19 @@ struct win32_joy_ctx { HRESULT hr; bool ok = false; - - for (int i = 0; i < 5; i++) - { - if (!FAILED(joy_handle->Poll())) - { - ok = true; - break; - } - if ((hr = joy_handle->Acquire()) != DI_OK) - continue; - else - ok = true; - break; - } + + if (joy_handle == nullptr) + return false; + + (void) joy_handle->Acquire(); + + if (!FAILED(joy_handle->Poll())) + ok = true; if (!ok) { qDebug() << "joy acquire failed" << guid << hr; + (void) joy_handle->Unacquire(); return false; } @@ -97,6 +170,8 @@ struct win32_joy_ctx return false; } + (void) joy_handle->Unacquire(); + first |= first_timer.elapsed_ms() > first_event_delay_ms; for (int i = 0; i < 128; i++) @@ -125,26 +200,10 @@ struct win32_joy_ctx return QString(buf); } - win32_joy_ctx() : dinput_handle(nullptr) + win32_joy_ctx() { - (void) CoInitialize(nullptr); - - HRESULT hr; - - if (FAILED(hr = DirectInput8Create(GetModuleHandle(nullptr), - DIRECTINPUT_VERSION, - IID_IDirectInput8, - (void**) &dinput_handle, - nullptr))) - goto fail; - refresh(true); - return; -fail: - qDebug() << "dinput8 failed for shortcuts" << hr; - - release(); } ~win32_joy_ctx() @@ -154,19 +213,17 @@ fail: void release() { - joys = std::vector>(); - if (dinput_handle) + qDebug() << "release dinput handle"; + joys() = std::unordered_map>(); { - dinput_handle->Release(); - dinput_handle = nullptr; + auto& di = dinput_handle(); + di->Release(); + di = nullptr; } } void refresh(bool first) { - if (!dinput_handle) - return; - if (!first) { if (timer_joylist.elapsed_ms() < joylist_refresh_ms) @@ -174,34 +231,37 @@ fail: timer_joylist.start(); } - enum_state st(dinput_handle, joys, first); + enum_state st(joys(), first); } + + enum { joy_axis_size = 65535 }; struct enum_state { - std::vector>& joys; + std::unordered_map>& joys; std::vector all; - LPDIRECTINPUT8 dinput_handle; bool first; - enum_state(LPDIRECTINPUT8 di, std::vector>& joys, bool first) : joys(joys), dinput_handle(di), first(first) + enum_state(std::unordered_map>& joys, bool first) : joys(joys), first(first) { HRESULT hr; + LPDIRECTINPUT8 di = dinput_handle(); - if(FAILED(hr = dinput_handle->EnumDevices(DI8DEVCLASS_GAMECTRL, - EnumJoysticksCallback, - this, - DIEDFL_ATTACHEDONLY))) + if(FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, + EnumJoysticksCallback, + this, + DIEDFL_ATTACHEDONLY))) { qDebug() << "failed enum joysticks" << hr; return; } - - for (int i = joys.size() - 1; i >= 0; i--) + + for (auto it = joys.begin(); it != joys.end(); ) { - const auto& guid = joys[i]->guid; - if (std::find_if(all.cbegin(), all.cend(), [&](const QString& guid2) -> bool { return guid == guid2; }) == all.cend()) - joys.erase(joys.begin() + i); + if (std::find_if(all.cbegin(), all.cend(), [&](const QString& guid2) -> bool { return it->second->guid == guid2; }) == all.cend()) + it = joys.erase(it); + else + it++; } } @@ -209,16 +269,10 @@ fail: { enum_state& state = *reinterpret_cast(pContext); const QString guid = guid_to_string(pdidInstance->guidInstance); -#if 0 const QString name = QString(pdidInstance->tszInstanceName); - // the logic here is that iff multiple joysticks of same name exist, then take guids into account at all - const int cnt_names = std::count_if(state.joys.begin(), state.joys.end(), [&](const joy& j) -> bool { return j.name == name; }); - // this is potentially bad since replugged sticks can change guids (?) -#endif - - const bool exists = std::find_if(state.joys.cbegin(), - state.joys.cend(), - [&](const std::shared_ptr& j) -> bool { return j->guid == guid; }) != state.joys.cend(); + + auto it = state.joys.find(guid); + const bool exists = it != state.joys.end() && it->second->joy_handle != nullptr; state.all.push_back(guid); @@ -226,9 +280,10 @@ fail: { HRESULT hr; LPDIRECTINPUTDEVICE8 h; - if (FAILED(hr = state.dinput_handle->CreateDevice(pdidInstance->guidInstance, &h, nullptr))) + LPDIRECTINPUT8 di = dinput_handle(); + if (FAILED(hr = di->CreateDevice(pdidInstance->guidInstance, &h, nullptr))) { - qDebug() << "create joystick breakage" << guid << hr; + qDebug() << "createdevice" << guid << hr; goto end; } if (FAILED(h->SetDataFormat(&c_dfDIJoystick2))) @@ -244,21 +299,20 @@ fail: h->Release(); goto end; } -#if 0 if (FAILED(hr = h->EnumObjects(EnumObjectsCallback, h, DIDFT_ALL))) { qDebug() << "enum-objects"; h->Release(); goto end; } -#endif - state.joys.push_back(std::make_shared(h, guid, state.first)); + + qDebug() << "add joy" << guid; + state.joys[guid] = std::make_shared(h, guid, name, state.first); } end: return DIENUM_CONTINUE; } -#if 0 static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx) { if (pdidoi->dwType & DIDFT_AXIS) @@ -269,20 +323,26 @@ end: return DIENUM_CONTINUE; diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER ); diprg.diph.dwHow = DIPH_BYID; diprg.diph.dwObj = pdidoi->dwType; - diprg.lMax = 32; - diprg.lMin = -32; + diprg.lMax = joy_axis_size; + diprg.lMin = -joy_axis_size; + + HRESULT hr; - if (FAILED(reinterpret_cast(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph))) + if (FAILED(hr = reinterpret_cast(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph))) + { + qDebug() << "DIPROP_RANGE" << hr; return DIENUM_STOP; + } } return DIENUM_CONTINUE; } -#endif }; - LPDIRECTINPUT8 dinput_handle; - std::vector> joys; + static LPDIRECTINPUT8& dinput_handle(); + static std::unordered_map>& joys(); + + QMutex mtx; Timer timer_joylist; enum { joylist_refresh_ms = 250 }; }; -- cgit v1.2.3 From 86f1df90b405b56b46d698b4059ed2c6b10df8b3 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 15:49:52 +0100 Subject: api/joy: protect dinput with mutex in all cases Also practice object-oriented information hiding to avoid accesses without the mutex. Also provide basic joy information (guid, name) without exposing dinput handles and so on. --- opentrack/win32-joystick-shortcuts.cpp | 6 ++ opentrack/win32-joystick-shortcuts.hpp | 132 +++++++++++++++++++-------------- 2 files changed, 82 insertions(+), 56 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick-shortcuts.cpp b/opentrack/win32-joystick-shortcuts.cpp index 44659b7e5..61a2a74ad 100644 --- a/opentrack/win32-joystick-shortcuts.cpp +++ b/opentrack/win32-joystick-shortcuts.cpp @@ -22,3 +22,9 @@ std::unordered_map>& win32_joy_ctx: return js; } + +win32_joy_ctx& win32_joy_ctx::make() +{ + static win32_joy_ctx ret; + return ret; +} diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp index 081dc0ce8..ed0b4412b 100644 --- a/opentrack/win32-joystick-shortcuts.hpp +++ b/opentrack/win32-joystick-shortcuts.hpp @@ -55,13 +55,13 @@ struct OPENTRACK_EXPORT win32_joy_ctx { QMutexLocker l(&mtx); + refresh(false); + auto iter = joys().find(guid); if (iter == joys().end() || iter->second->joy_handle == nullptr) return false; - refresh(false); - auto& j = iter->second; auto& joy_handle = j->joy_handle; @@ -107,7 +107,79 @@ struct OPENTRACK_EXPORT win32_joy_ctx return true; } + + ~win32_joy_ctx() + { + release(); + } + + enum { joy_axis_size = 65535 }; + + struct joy_info + { + QString name, guid; + }; + + std::vector get_joy_info() + { + QMutexLocker l(&mtx); + + std::vector ret; + + for (auto& j : joys()) + ret.push_back(joy_info { j.second->name, j.first }); + + return ret; + } + + static win32_joy_ctx& make(); + + win32_joy_ctx(const win32_joy_ctx&) = delete; + win32_joy_ctx& operator=(const win32_joy_ctx&) = delete; +private: + static 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); + } + + static LPDIRECTINPUT8& dinput_handle(); + + win32_joy_ctx() + { + refresh(true); + } + void release() + { + qDebug() << "release joystick dinput handle"; + joys() = std::unordered_map>(); + { + auto& di = dinput_handle(); + di->Release(); + di = nullptr; + } + } + void refresh(bool first) + { + if (!first) + { + if (timer_joylist.elapsed_ms() < joylist_refresh_ms) + return; + timer_joylist.start(); + } + + enum_state st(joys(), first); + } + QMutex mtx; + Timer timer_joylist; + enum { joylist_refresh_ms = 250 }; + struct joy { LPDIRECTINPUTDEVICE8 joy_handle; @@ -140,7 +212,7 @@ struct OPENTRACK_EXPORT win32_joy_ctx joy_handle = nullptr; } } - + bool poll(fn f) { HRESULT hr; @@ -189,53 +261,6 @@ struct OPENTRACK_EXPORT win32_joy_ctx } }; - static 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); - } - - win32_joy_ctx() - { - refresh(true); - return; - } - - ~win32_joy_ctx() - { - release(); - } - - void release() - { - qDebug() << "release dinput handle"; - joys() = std::unordered_map>(); - { - auto& di = dinput_handle(); - di->Release(); - di = nullptr; - } - } - - void refresh(bool first) - { - if (!first) - { - if (timer_joylist.elapsed_ms() < joylist_refresh_ms) - return; - timer_joylist.start(); - } - - enum_state st(joys(), first); - } - - enum { joy_axis_size = 65535 }; - struct enum_state { std::unordered_map>& joys; @@ -338,13 +363,8 @@ end: return DIENUM_CONTINUE; return DIENUM_CONTINUE; } }; - - static LPDIRECTINPUT8& dinput_handle(); + static std::unordered_map>& joys(); - - QMutex mtx; - Timer timer_joylist; - enum { joylist_refresh_ms = 250 }; }; #endif -- cgit v1.2.3 From 119671e4e7f4dc07c1fb20eb999a0a7fcfbbdba8 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 15:50:46 +0100 Subject: api/shortcuts, tracker/joy: adapt to synchronized joy api --- opentrack/keybinding-worker.cpp | 2 +- opentrack/keybinding-worker.hpp | 2 +- tracker-joystick/ftnoir_tracker_joystick.cpp | 11 ++++++++++- tracker-joystick/ftnoir_tracker_joystick.h | 2 +- tracker-joystick/ftnoir_tracker_joystick_dialog.cpp | 9 +++++---- 5 files changed, 18 insertions(+), 8 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index d876d5a12..5f42f44eb 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -27,7 +27,7 @@ KeybindingWorker::~KeybindingWorker() { din->Release(); } -KeybindingWorker::KeybindingWorker() : should_quit(true) +KeybindingWorker::KeybindingWorker() : joy_ctx(win32_joy_ctx::make()), should_quit(true) { if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) { qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index 5a73b1b1c..551be144b 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -59,7 +59,7 @@ struct OPENTRACK_EXPORT KeybindingWorker : private QThread private: LPDIRECTINPUT8 din; LPDIRECTINPUTDEVICE8 dinkeyboard; - win32_joy_ctx joy_ctx; + win32_joy_ctx& joy_ctx; volatile bool should_quit; using fun = std::function; std::vector receivers; diff --git a/tracker-joystick/ftnoir_tracker_joystick.cpp b/tracker-joystick/ftnoir_tracker_joystick.cpp index 4c180eaa0..112f20cab 100644 --- a/tracker-joystick/ftnoir_tracker_joystick.cpp +++ b/tracker-joystick/ftnoir_tracker_joystick.cpp @@ -8,8 +8,17 @@ #include "opentrack/plugin-api.hpp" #include -FTNoIR_Tracker::FTNoIR_Tracker() +FTNoIR_Tracker::FTNoIR_Tracker() : joy_ctx(win32_joy_ctx::make()) { + if (static_cast(s.guid) == "") + { + std::vector info = joy_ctx.get_joy_info(); + if (info.size()) + { + s.guid = info[0].guid; + s.b->save(); + } + } } FTNoIR_Tracker::~FTNoIR_Tracker() diff --git a/tracker-joystick/ftnoir_tracker_joystick.h b/tracker-joystick/ftnoir_tracker_joystick.h index 18ac349e2..e94e2ee75 100644 --- a/tracker-joystick/ftnoir_tracker_joystick.h +++ b/tracker-joystick/ftnoir_tracker_joystick.h @@ -47,7 +47,7 @@ public: settings s; QString guid; static constexpr int AXIS_MAX = win32_joy_ctx::joy_axis_size - 1; - win32_joy_ctx joy_ctx; + win32_joy_ctx& joy_ctx; }; class TrackerControls: public ITrackerDialog diff --git a/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp b/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp index 288468090..1ca1441ce 100644 --- a/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp +++ b/tracker-joystick/ftnoir_tracker_joystick_dialog.cpp @@ -10,20 +10,21 @@ TrackerControls::TrackerControls() : tracker(nullptr) connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); { - win32_joy_ctx joy_ctx; + win32_joy_ctx& joy_ctx(win32_joy_ctx::make()); _joys = QList(); - for (auto& j : joy_ctx.joys()) - _joys.push_back(joys { j.second->name, j.first }); + for (auto j : joy_ctx.get_joy_info()) + _joys.push_back(joys { j.name, j.guid }); } { + const QString guid = s.guid; int idx = 0; for (int i = 0; i < _joys.size(); i++) { const joys& j = _joys[i]; - if (j.guid == s.guid && j.name == s.joyid) + if (j.guid == guid) idx = i; ui.joylist->addItem(j.name + " " + j.guid); } -- cgit v1.2.3 From b7541ef9c3fe8e52fd6d27fe6e65d48a68acff96 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 15:57:51 +0100 Subject: api/shortcuts: add missing win32 delete key definition --- opentrack/win32-shortcuts.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'opentrack') diff --git a/opentrack/win32-shortcuts.cpp b/opentrack/win32-shortcuts.cpp index a0ed51b35..fb84e709e 100644 --- a/opentrack/win32-shortcuts.cpp +++ b/opentrack/win32-shortcuts.cpp @@ -116,6 +116,7 @@ QList windows_key_sequences = win_key(DIK_Z, Qt::Key::Key_Z ), win_key(DIK_RETURN, Qt::Key::Key_Return), win_key(DIK_INSERT, Qt::Key::Key_Insert), + win_key(DIK_DELETE, Qt::Key::Key_Delete), win_key(DIK_SPACE, Qt::Key::Key_Space), win_key(DIK_SYSRQ, Qt::Key::Key_Print), win_key(DIK_SCROLL, Qt::Key::Key_ScrollLock), -- cgit v1.2.3 From aac65283a2b254f0338a6ad1609e5d916ba9dcfc Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 17:44:19 +0100 Subject: opentrack/joystick: rename header to clarify usage --- opentrack/keybinding-worker.hpp | 2 +- opentrack/win32-joystick-shortcuts.cpp | 30 --- opentrack/win32-joystick-shortcuts.hpp | 370 ----------------------------- opentrack/win32-joystick.cpp | 30 +++ opentrack/win32-joystick.hpp | 370 +++++++++++++++++++++++++++++ tracker-joystick/ftnoir_tracker_joystick.h | 2 +- 6 files changed, 402 insertions(+), 402 deletions(-) delete mode 100644 opentrack/win32-joystick-shortcuts.cpp delete mode 100644 opentrack/win32-joystick-shortcuts.hpp create mode 100644 opentrack/win32-joystick.cpp create mode 100644 opentrack/win32-joystick.hpp (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index 551be144b..8474ae1e7 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -15,7 +15,7 @@ #endif #include "opentrack-compat/timer.hpp" -#include "opentrack/win32-joystick-shortcuts.hpp" +#include "opentrack/win32-joystick.hpp" #include #include #include diff --git a/opentrack/win32-joystick-shortcuts.cpp b/opentrack/win32-joystick-shortcuts.cpp deleted file mode 100644 index 61a2a74ad..000000000 --- a/opentrack/win32-joystick-shortcuts.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "win32-joystick-shortcuts.hpp" - -LPDIRECTINPUT8& win32_joy_ctx::dinput_handle() -{ - (void) CoInitialize(nullptr); - - static LPDIRECTINPUT8 dinput_handle_ = nullptr; - - if (dinput_handle_ == nullptr) - (void) DirectInput8Create(GetModuleHandle(nullptr), - DIRECTINPUT_VERSION, - IID_IDirectInput8, - (void**) &dinput_handle_, - nullptr); - - return dinput_handle_; -} - -std::unordered_map>& win32_joy_ctx::joys() -{ - static std::unordered_map> js; - - return js; -} - -win32_joy_ctx& win32_joy_ctx::make() -{ - static win32_joy_ctx ret; - return ret; -} diff --git a/opentrack/win32-joystick-shortcuts.hpp b/opentrack/win32-joystick-shortcuts.hpp deleted file mode 100644 index ed0b4412b..000000000 --- a/opentrack/win32-joystick-shortcuts.hpp +++ /dev/null @@ -1,370 +0,0 @@ -#pragma once - -#ifdef _WIN32 - -#include -#include -#include -#include -#include -#include -#ifndef DIRECTINPUT_VERSION -# define DIRECTINPUT_VERSION 0x800 -#endif -#include -#include -#include "opentrack-compat/timer.hpp" -#include -#include -#include -#include - -namespace std { -template<> -struct hash -{ - std::size_t operator()(const QString& value) const - { - return qHash(value); - } -}; -} - -#ifdef BUILD_api -# include "opentrack-compat/export.hpp" -#else -# include "opentrack-compat/import.hpp" -#endif - -struct OPENTRACK_EXPORT win32_joy_ctx -{ - using fn = std::function; - - void poll(fn f) - { - QMutexLocker l(&mtx); - - refresh(false); - for (auto& j : joys()) - { - j.second->poll(f); - } - } - - bool poll_axis(const QString& guid, int axes[8]) - { - QMutexLocker l(&mtx); - - refresh(false); - - auto iter = joys().find(guid); - - if (iter == joys().end() || iter->second->joy_handle == nullptr) - return false; - - auto& j = iter->second; - - auto& joy_handle = j->joy_handle; - bool ok = false; - HRESULT hr; - - (void) joy_handle->Acquire(); - - if (!FAILED(hr = joy_handle->Poll())) - ok = true; - - if (!ok) - { - qDebug() << "joy acquire failed" << guid << hr; - (void) joy_handle->Unacquire(); - return false; - } - - DIJOYSTATE2 js; - memset(&js, 0, sizeof(js)); - - if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) - { - qDebug() << "joy get state failed" << guid << hr; - return false; - } - - const int values[] = { - js.lX, - js.lY, - js.lZ, - js.lRx, - js.lRy, - js.lRz, - js.rglSlider[0], - js.rglSlider[1] - }; - - for (int i = 0; i < 8; i++) - axes[i] = values[i]; - - (void) joy_handle->Unacquire(); - - return true; - } - - ~win32_joy_ctx() - { - release(); - } - - enum { joy_axis_size = 65535 }; - - struct joy_info - { - QString name, guid; - }; - - std::vector get_joy_info() - { - QMutexLocker l(&mtx); - - std::vector ret; - - for (auto& j : joys()) - ret.push_back(joy_info { j.second->name, j.first }); - - return ret; - } - - static win32_joy_ctx& make(); - - win32_joy_ctx(const win32_joy_ctx&) = delete; - win32_joy_ctx& operator=(const win32_joy_ctx&) = delete; -private: - static 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); - } - - static LPDIRECTINPUT8& dinput_handle(); - - win32_joy_ctx() - { - refresh(true); - } - void release() - { - qDebug() << "release joystick dinput handle"; - joys() = std::unordered_map>(); - { - auto& di = dinput_handle(); - di->Release(); - di = nullptr; - } - } - - void refresh(bool first) - { - if (!first) - { - if (timer_joylist.elapsed_ms() < joylist_refresh_ms) - return; - timer_joylist.start(); - } - - enum_state st(joys(), first); - } - QMutex mtx; - Timer timer_joylist; - enum { joylist_refresh_ms = 250 }; - - struct joy - { - LPDIRECTINPUTDEVICE8 joy_handle; - QString guid, name; - bool pressed[128]; - Timer first_timer; - bool first; - - enum { first_event_delay_ms = 3000 }; - - joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name, bool first) : joy_handle(handle), guid(guid), name(name), first(first) - { - qDebug() << "got joy" << guid; - for (int i = 0; i < 128; i++) - pressed[i] = false; - } - - ~joy() - { - qDebug() << "nix joy" << guid; - release(); - } - - void release() - { - if (joy_handle) - { - (void) joy_handle->Unacquire(); - joy_handle->Release(); - joy_handle = nullptr; - } - } - - bool poll(fn f) - { - HRESULT hr; - bool ok = false; - - if (joy_handle == nullptr) - return false; - - (void) joy_handle->Acquire(); - - if (!FAILED(joy_handle->Poll())) - ok = true; - - if (!ok) - { - qDebug() << "joy acquire failed" << guid << hr; - (void) joy_handle->Unacquire(); - return false; - } - - DIJOYSTATE2 js; - memset(&js, 0, sizeof(js)); - - if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) - { - qDebug() << "joy get state failed" << guid << hr; - return false; - } - - (void) joy_handle->Unacquire(); - - first |= first_timer.elapsed_ms() > first_event_delay_ms; - - for (int i = 0; i < 128; i++) - { - const bool state = !!(js.rgbButtons[i] & 0x80); - if (state != pressed[i] && first) - { - f(guid, i, state); - qDebug() << "btn" << guid << i << state; - } - pressed[i] = state; - } - - return true; - } - }; - - struct enum_state - { - std::unordered_map>& joys; - std::vector all; - bool first; - - enum_state(std::unordered_map>& joys, bool first) : joys(joys), first(first) - { - HRESULT hr; - LPDIRECTINPUT8 di = dinput_handle(); - - if(FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, - EnumJoysticksCallback, - this, - DIEDFL_ATTACHEDONLY))) - { - qDebug() << "failed enum joysticks" << hr; - return; - } - - for (auto it = joys.begin(); it != joys.end(); ) - { - if (std::find_if(all.cbegin(), all.cend(), [&](const QString& guid2) -> bool { return it->second->guid == guid2; }) == all.cend()) - it = joys.erase(it); - else - it++; - } - } - - static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext) - { - enum_state& state = *reinterpret_cast(pContext); - const QString guid = guid_to_string(pdidInstance->guidInstance); - const QString name = QString(pdidInstance->tszInstanceName); - - auto it = state.joys.find(guid); - const bool exists = it != state.joys.end() && it->second->joy_handle != nullptr; - - state.all.push_back(guid); - - if (!exists) - { - HRESULT hr; - LPDIRECTINPUTDEVICE8 h; - LPDIRECTINPUT8 di = dinput_handle(); - if (FAILED(hr = di->CreateDevice(pdidInstance->guidInstance, &h, nullptr))) - { - qDebug() << "createdevice" << guid << hr; - goto end; - } - if (FAILED(h->SetDataFormat(&c_dfDIJoystick2))) - { - qDebug() << "format"; - h->Release(); - goto end; - } - - if (FAILED(h->SetCooperativeLevel((HWND) GetDesktopWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) - { - qDebug() << "coop"; - h->Release(); - goto end; - } - if (FAILED(hr = h->EnumObjects(EnumObjectsCallback, h, DIDFT_ALL))) - { - qDebug() << "enum-objects"; - h->Release(); - goto end; - } - - qDebug() << "add joy" << guid; - state.joys[guid] = std::make_shared(h, guid, name, state.first); - } - -end: return DIENUM_CONTINUE; - } - - static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx) - { - if (pdidoi->dwType & DIDFT_AXIS) - { - DIPROPRANGE diprg; - memset(&diprg, 0, sizeof(diprg)); - diprg.diph.dwSize = sizeof( DIPROPRANGE ); - diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER ); - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = pdidoi->dwType; - diprg.lMax = joy_axis_size; - diprg.lMin = -joy_axis_size; - - HRESULT hr; - - if (FAILED(hr = reinterpret_cast(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph))) - { - qDebug() << "DIPROP_RANGE" << hr; - return DIENUM_STOP; - } - } - - return DIENUM_CONTINUE; - } - }; - - static std::unordered_map>& joys(); -}; - -#endif diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp new file mode 100644 index 000000000..b4a1f9cd4 --- /dev/null +++ b/opentrack/win32-joystick.cpp @@ -0,0 +1,30 @@ +#include "win32-joystick.hpp" + +LPDIRECTINPUT8& win32_joy_ctx::dinput_handle() +{ + (void) CoInitialize(nullptr); + + static LPDIRECTINPUT8 dinput_handle_ = nullptr; + + if (dinput_handle_ == nullptr) + (void) DirectInput8Create(GetModuleHandle(nullptr), + DIRECTINPUT_VERSION, + IID_IDirectInput8, + (void**) &dinput_handle_, + nullptr); + + return dinput_handle_; +} + +std::unordered_map>& win32_joy_ctx::joys() +{ + static std::unordered_map> js; + + return js; +} + +win32_joy_ctx& win32_joy_ctx::make() +{ + static win32_joy_ctx ret; + return ret; +} diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp new file mode 100644 index 000000000..ed0b4412b --- /dev/null +++ b/opentrack/win32-joystick.hpp @@ -0,0 +1,370 @@ +#pragma once + +#ifdef _WIN32 + +#include +#include +#include +#include +#include +#include +#ifndef DIRECTINPUT_VERSION +# define DIRECTINPUT_VERSION 0x800 +#endif +#include +#include +#include "opentrack-compat/timer.hpp" +#include +#include +#include +#include + +namespace std { +template<> +struct hash +{ + std::size_t operator()(const QString& value) const + { + return qHash(value); + } +}; +} + +#ifdef BUILD_api +# include "opentrack-compat/export.hpp" +#else +# include "opentrack-compat/import.hpp" +#endif + +struct OPENTRACK_EXPORT win32_joy_ctx +{ + using fn = std::function; + + void poll(fn f) + { + QMutexLocker l(&mtx); + + refresh(false); + for (auto& j : joys()) + { + j.second->poll(f); + } + } + + bool poll_axis(const QString& guid, int axes[8]) + { + QMutexLocker l(&mtx); + + refresh(false); + + auto iter = joys().find(guid); + + if (iter == joys().end() || iter->second->joy_handle == nullptr) + return false; + + auto& j = iter->second; + + auto& joy_handle = j->joy_handle; + bool ok = false; + HRESULT hr; + + (void) joy_handle->Acquire(); + + if (!FAILED(hr = joy_handle->Poll())) + ok = true; + + if (!ok) + { + qDebug() << "joy acquire failed" << guid << hr; + (void) joy_handle->Unacquire(); + return false; + } + + DIJOYSTATE2 js; + memset(&js, 0, sizeof(js)); + + if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) + { + qDebug() << "joy get state failed" << guid << hr; + return false; + } + + const int values[] = { + js.lX, + js.lY, + js.lZ, + js.lRx, + js.lRy, + js.lRz, + js.rglSlider[0], + js.rglSlider[1] + }; + + for (int i = 0; i < 8; i++) + axes[i] = values[i]; + + (void) joy_handle->Unacquire(); + + return true; + } + + ~win32_joy_ctx() + { + release(); + } + + enum { joy_axis_size = 65535 }; + + struct joy_info + { + QString name, guid; + }; + + std::vector get_joy_info() + { + QMutexLocker l(&mtx); + + std::vector ret; + + for (auto& j : joys()) + ret.push_back(joy_info { j.second->name, j.first }); + + return ret; + } + + static win32_joy_ctx& make(); + + win32_joy_ctx(const win32_joy_ctx&) = delete; + win32_joy_ctx& operator=(const win32_joy_ctx&) = delete; +private: + static 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); + } + + static LPDIRECTINPUT8& dinput_handle(); + + win32_joy_ctx() + { + refresh(true); + } + void release() + { + qDebug() << "release joystick dinput handle"; + joys() = std::unordered_map>(); + { + auto& di = dinput_handle(); + di->Release(); + di = nullptr; + } + } + + void refresh(bool first) + { + if (!first) + { + if (timer_joylist.elapsed_ms() < joylist_refresh_ms) + return; + timer_joylist.start(); + } + + enum_state st(joys(), first); + } + QMutex mtx; + Timer timer_joylist; + enum { joylist_refresh_ms = 250 }; + + struct joy + { + LPDIRECTINPUTDEVICE8 joy_handle; + QString guid, name; + bool pressed[128]; + Timer first_timer; + bool first; + + enum { first_event_delay_ms = 3000 }; + + joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name, bool first) : joy_handle(handle), guid(guid), name(name), first(first) + { + qDebug() << "got joy" << guid; + for (int i = 0; i < 128; i++) + pressed[i] = false; + } + + ~joy() + { + qDebug() << "nix joy" << guid; + release(); + } + + void release() + { + if (joy_handle) + { + (void) joy_handle->Unacquire(); + joy_handle->Release(); + joy_handle = nullptr; + } + } + + bool poll(fn f) + { + HRESULT hr; + bool ok = false; + + if (joy_handle == nullptr) + return false; + + (void) joy_handle->Acquire(); + + if (!FAILED(joy_handle->Poll())) + ok = true; + + if (!ok) + { + qDebug() << "joy acquire failed" << guid << hr; + (void) joy_handle->Unacquire(); + return false; + } + + DIJOYSTATE2 js; + memset(&js, 0, sizeof(js)); + + if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) + { + qDebug() << "joy get state failed" << guid << hr; + return false; + } + + (void) joy_handle->Unacquire(); + + first |= first_timer.elapsed_ms() > first_event_delay_ms; + + for (int i = 0; i < 128; i++) + { + const bool state = !!(js.rgbButtons[i] & 0x80); + if (state != pressed[i] && first) + { + f(guid, i, state); + qDebug() << "btn" << guid << i << state; + } + pressed[i] = state; + } + + return true; + } + }; + + struct enum_state + { + std::unordered_map>& joys; + std::vector all; + bool first; + + enum_state(std::unordered_map>& joys, bool first) : joys(joys), first(first) + { + HRESULT hr; + LPDIRECTINPUT8 di = dinput_handle(); + + if(FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, + EnumJoysticksCallback, + this, + DIEDFL_ATTACHEDONLY))) + { + qDebug() << "failed enum joysticks" << hr; + return; + } + + for (auto it = joys.begin(); it != joys.end(); ) + { + if (std::find_if(all.cbegin(), all.cend(), [&](const QString& guid2) -> bool { return it->second->guid == guid2; }) == all.cend()) + it = joys.erase(it); + else + it++; + } + } + + static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext) + { + enum_state& state = *reinterpret_cast(pContext); + const QString guid = guid_to_string(pdidInstance->guidInstance); + const QString name = QString(pdidInstance->tszInstanceName); + + auto it = state.joys.find(guid); + const bool exists = it != state.joys.end() && it->second->joy_handle != nullptr; + + state.all.push_back(guid); + + if (!exists) + { + HRESULT hr; + LPDIRECTINPUTDEVICE8 h; + LPDIRECTINPUT8 di = dinput_handle(); + if (FAILED(hr = di->CreateDevice(pdidInstance->guidInstance, &h, nullptr))) + { + qDebug() << "createdevice" << guid << hr; + goto end; + } + if (FAILED(h->SetDataFormat(&c_dfDIJoystick2))) + { + qDebug() << "format"; + h->Release(); + goto end; + } + + if (FAILED(h->SetCooperativeLevel((HWND) GetDesktopWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) + { + qDebug() << "coop"; + h->Release(); + goto end; + } + if (FAILED(hr = h->EnumObjects(EnumObjectsCallback, h, DIDFT_ALL))) + { + qDebug() << "enum-objects"; + h->Release(); + goto end; + } + + qDebug() << "add joy" << guid; + state.joys[guid] = std::make_shared(h, guid, name, state.first); + } + +end: return DIENUM_CONTINUE; + } + + static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx) + { + if (pdidoi->dwType & DIDFT_AXIS) + { + DIPROPRANGE diprg; + memset(&diprg, 0, sizeof(diprg)); + diprg.diph.dwSize = sizeof( DIPROPRANGE ); + diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER ); + diprg.diph.dwHow = DIPH_BYID; + diprg.diph.dwObj = pdidoi->dwType; + diprg.lMax = joy_axis_size; + diprg.lMin = -joy_axis_size; + + HRESULT hr; + + if (FAILED(hr = reinterpret_cast(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph))) + { + qDebug() << "DIPROP_RANGE" << hr; + return DIENUM_STOP; + } + } + + return DIENUM_CONTINUE; + } + }; + + static std::unordered_map>& joys(); +}; + +#endif diff --git a/tracker-joystick/ftnoir_tracker_joystick.h b/tracker-joystick/ftnoir_tracker_joystick.h index 670615850..9923dd1c6 100644 --- a/tracker-joystick/ftnoir_tracker_joystick.h +++ b/tracker-joystick/ftnoir_tracker_joystick.h @@ -17,7 +17,7 @@ #include #include "opentrack/plugin-api.hpp" -#include "opentrack/win32-joystick-shortcuts.hpp" +#include "opentrack/win32-joystick.hpp" #include "opentrack-compat/options.hpp" using namespace options; -- cgit v1.2.3 From 0c3a306b8588ae1cbe190ee18db2336bcd0eb527 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 17:46:46 +0100 Subject: api/shortcuts: hopefully guard joystick _WIN32 --- opentrack/keybinding-worker.cpp | 8 +++++++- opentrack/keybinding-worker.hpp | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index 5f42f44eb..3659a7680 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -27,7 +27,11 @@ KeybindingWorker::~KeybindingWorker() { din->Release(); } -KeybindingWorker::KeybindingWorker() : joy_ctx(win32_joy_ctx::make()), should_quit(true) +KeybindingWorker::KeybindingWorker() : +#ifdef _WIN32 + joy_ctx(win32_joy_ctx::make()), +#endif + should_quit(true) { if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) { qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); @@ -94,6 +98,7 @@ void KeybindingWorker::run() { } } +#ifdef _WIN32 { using joy_fn = std::function; @@ -112,6 +117,7 @@ void KeybindingWorker::run() { joy_ctx.poll(f); } +#endif for (int i = 0; i < 256; i++) { diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index 8474ae1e7..c4a39ec64 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -15,7 +15,9 @@ #endif #include "opentrack-compat/timer.hpp" -#include "opentrack/win32-joystick.hpp" +#ifdef _WIN32 +# include "opentrack/win32-joystick.hpp" +#endif #include #include #include @@ -59,7 +61,9 @@ struct OPENTRACK_EXPORT KeybindingWorker : private QThread private: LPDIRECTINPUT8 din; LPDIRECTINPUTDEVICE8 dinkeyboard; +#ifdef _WIN32 win32_joy_ctx& joy_ctx; +#endif volatile bool should_quit; using fun = std::function; std::vector receivers; -- cgit v1.2.3 From 5d4a9c78fbbbd59d366e91bfe4c4263d12833abe Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 18:01:06 +0100 Subject: api/joy: guard _WIN32 properly --- opentrack/keybinding-worker.hpp | 10 ++++++---- opentrack/shortcuts.h | 5 ++++- opentrack/win32-joystick.cpp | 4 ++++ 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index c4a39ec64..83ffadf10 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -59,19 +59,18 @@ struct Key { int foo; }; struct OPENTRACK_EXPORT KeybindingWorker : private QThread { private: +#ifdef _WIN32 LPDIRECTINPUT8 din; LPDIRECTINPUTDEVICE8 dinkeyboard; -#ifdef _WIN32 win32_joy_ctx& joy_ctx; -#endif volatile bool should_quit; using fun = std::function; std::vector receivers; QMutex mtx; - + void run() override; KeybindingWorker(); - + KeybindingWorker(const KeybindingWorker&) = delete; KeybindingWorker& operator=(KeybindingWorker&) = delete; static KeybindingWorker& make(); @@ -100,4 +99,7 @@ public: { return Token(receiver); } +#else + void run() override {} +#endif }; diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index 930952e89..8acc5ba54 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -66,7 +66,10 @@ public: {} } s; - Shortcuts() : key_token(KeybindingWorker::add_receiver([&](const Key& k) { receiver(k); })) + Shortcuts() +#ifdef _WIN32 + : key_token(KeybindingWorker::add_receiver([&](const Key& k) { receiver(k); })) +#endif { reload(); } diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index b4a1f9cd4..56a1b070b 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -1,5 +1,7 @@ #include "win32-joystick.hpp" +#ifdef _WIN32 + LPDIRECTINPUT8& win32_joy_ctx::dinput_handle() { (void) CoInitialize(nullptr); @@ -28,3 +30,5 @@ win32_joy_ctx& win32_joy_ctx::make() static win32_joy_ctx ret; return ret; } + +#endif -- cgit v1.2.3 From e2ea45a81d5f30fdbd42e0b03a192afa81e877dc Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 18:05:04 +0100 Subject: api/shortcuts: don't provide guard/stubs for non-win32 The worker class is win32-only. Don't guard there, consumers are expected only to include it on _WIN32. For the same reason don't provide a stub for the keybinding worker. --- opentrack/keybinding-worker.cpp | 29 ++++++++++++++--------------- opentrack/keybinding-worker.hpp | 20 +++++--------------- 2 files changed, 19 insertions(+), 30 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index 3659a7680..dcf5c1b6f 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -6,10 +6,9 @@ * notice appear in all copies. */ -#include "keybinding-worker.hpp" - -#if defined(_WIN32) +#ifdef _WIN32 +#include "keybinding-worker.hpp" #include #include #include @@ -29,7 +28,7 @@ KeybindingWorker::~KeybindingWorker() { KeybindingWorker::KeybindingWorker() : #ifdef _WIN32 - joy_ctx(win32_joy_ctx::make()), + joy_ctx(win32_joy_ctx::make()), #endif should_quit(true) { @@ -85,23 +84,23 @@ void KeybindingWorker::run() { { { QMutexLocker l(&mtx); - + if (receivers.size()) { { const HRESULT hr = dinkeyboard->GetDeviceState(256, (LPVOID)keystate); - + if (hr != DI_OK) { qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError(); Sleep(25); continue; } } - + #ifdef _WIN32 { using joy_fn = std::function; - + joy_fn f = [&](const QString& guid, int idx, bool held) -> void { Key k; k.keycode = idx; @@ -110,15 +109,15 @@ void KeybindingWorker::run() { k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80 || keystate[DIK_RCONTROL] & 0x80); k.guid = guid; k.held = held; - + for (auto& r : receivers) r(k); }; - + joy_ctx.poll(f); } #endif - + for (int i = 0; i < 256; i++) { Key k; @@ -138,7 +137,7 @@ void KeybindingWorker::run() { k.alt = !!(keystate[DIK_LALT] & 0x80) || !!(keystate[DIK_RALT] & 0x80); k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80) || !!(keystate[DIK_RCONTROL] & 0x80); k.keycode = i; - + for (auto& r : receivers) r(k); break; @@ -147,7 +146,7 @@ void KeybindingWorker::run() { } } } - + // keypresses get dropped with high values Sleep(4); } @@ -165,7 +164,7 @@ void KeybindingWorker::remove_receiver(KeybindingWorker::fun* pos) { QMutexLocker l(&mtx); bool ok = false; - + for (int i = receivers.size() - 1; i >= 0; i--) { if (&receivers[i] == pos) @@ -181,4 +180,4 @@ void KeybindingWorker::remove_receiver(KeybindingWorker::fun* pos) } } -#endif \ No newline at end of file +#endif diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index 83ffadf10..e39676829 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -15,20 +15,17 @@ #endif #include "opentrack-compat/timer.hpp" -#ifdef _WIN32 -# include "opentrack/win32-joystick.hpp" -#endif +#include "opentrack/win32-joystick.hpp" #include #include #include #include #include -#ifdef _WIN32 -# undef DIRECTINPUT_VERSION -# define DIRECTINPUT_VERSION 0x0800 -# include -# include +#undef DIRECTINPUT_VERSION +#define DIRECTINPUT_VERSION 0x0800 +#include +#include struct Key { BYTE keycode; QString guid; @@ -51,15 +48,10 @@ public: return ret; } }; -#else -typedef unsigned char BYTE; -struct Key { int foo; }; -#endif struct OPENTRACK_EXPORT KeybindingWorker : private QThread { private: -#ifdef _WIN32 LPDIRECTINPUT8 din; LPDIRECTINPUTDEVICE8 dinkeyboard; win32_joy_ctx& joy_ctx; @@ -99,7 +91,5 @@ public: { return Token(receiver); } -#else void run() override {} -#endif }; -- cgit v1.2.3 From c72948a8fcec675f5ddb059d6ad5e5d6c10f0691 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 22 Nov 2015 18:46:34 +0100 Subject: api/shortcuts: fix copy-paste error --- opentrack/keybinding-worker.hpp | 1 - 1 file changed, 1 deletion(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index e39676829..7661f88d0 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -91,5 +91,4 @@ public: { return Token(receiver); } - void run() override {} }; -- cgit v1.2.3 From f09ff290addc66f2256534641f1dc91318da47c3 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Tue, 24 Nov 2015 01:03:55 +0100 Subject: api/shortcuts: don't unacquire joy handle pointlessly --- opentrack/win32-joystick.hpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp index ed0b4412b..b08da6c8d 100644 --- a/opentrack/win32-joystick.hpp +++ b/opentrack/win32-joystick.hpp @@ -103,8 +103,6 @@ struct OPENTRACK_EXPORT win32_joy_ctx for (int i = 0; i < 8; i++) axes[i] = values[i]; - (void) joy_handle->Unacquire(); - return true; } @@ -242,8 +240,6 @@ private: return false; } - (void) joy_handle->Unacquire(); - first |= first_timer.elapsed_ms() > first_event_delay_ms; for (int i = 0; i < 128; i++) -- cgit v1.2.3 From 3566dc23946b798b396946297cbf70f2d46fd242 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 26 Nov 2015 09:04:29 +0100 Subject: api/shortcuts: move to separate definition There's no need to have definitions in header for non-template classes --- opentrack/keybinding-worker.cpp | 10 ++ opentrack/keybinding-worker.hpp | 13 +- opentrack/win32-joystick.cpp | 275 +++++++++++++++++++++++++++++++++++ opentrack/win32-joystick.hpp | 308 ++++------------------------------------ 4 files changed, 315 insertions(+), 291 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index dcf5c1b6f..59bc4afd7 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -14,6 +14,15 @@ #include #include +bool Key::should_process() +{ + if (keycode == 0 && guid == "") + return false; + bool ret = timer.elapsed_ms() > 100; + timer.start(); + return ret; +} + KeybindingWorker::~KeybindingWorker() { qDebug() << "keybinding worker stop"; should_quit = true; @@ -172,6 +181,7 @@ void KeybindingWorker::remove_receiver(KeybindingWorker::fun* pos) ok = true; qDebug() << "remove receiver" << (long) pos; receivers.erase(receivers.begin() + i); + break; } } if (!ok) diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index 7661f88d0..054182e7b 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -35,18 +35,9 @@ struct Key { bool held; Timer timer; public: - Key() : keycode(0), shift(false), ctrl(false), alt(false), held(true) - { - } + Key() : keycode(0), shift(false), ctrl(false), alt(false), held(true) {} - bool should_process() - { - if (keycode == 0 && guid == "") - return false; - bool ret = timer.elapsed_ms() > 100; - timer.start(); - return ret; - } + bool should_process(); }; struct OPENTRACK_EXPORT KeybindingWorker : private QThread diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index 56a1b070b..29a51a435 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -31,4 +31,279 @@ win32_joy_ctx& win32_joy_ctx::make() return ret; } +void win32_joy_ctx::poll(fn f) +{ + QMutexLocker l(&mtx); + + refresh(false); + for (auto& j : joys()) + { + j.second->poll(f); + } +} + +bool win32_joy_ctx::poll_axis(const QString &guid, int axes[]) +{ + QMutexLocker l(&mtx); + + refresh(false); + + auto iter = joys().find(guid); + + if (iter == joys().end() || iter->second->joy_handle == nullptr) + return false; + + auto& j = iter->second; + + auto& joy_handle = j->joy_handle; + bool ok = false; + HRESULT hr; + + (void) joy_handle->Acquire(); + + if (!FAILED(hr = joy_handle->Poll())) + ok = true; + + if (!ok) + { + qDebug() << "joy acquire failed" << guid << hr; + (void) joy_handle->Unacquire(); + return false; + } + + DIJOYSTATE2 js; + memset(&js, 0, sizeof(js)); + + if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) + { + qDebug() << "joy get state failed" << guid << hr; + return false; + } + + const int values[] = { + js.lX, + js.lY, + js.lZ, + js.lRx, + js.lRy, + js.lRz, + js.rglSlider[0], + js.rglSlider[1] + }; + + for (int i = 0; i < 8; i++) + axes[i] = values[i]; + + return true; +} + +win32_joy_ctx::~win32_joy_ctx() +{ + release(); +} + +std::vector win32_joy_ctx::get_joy_info() +{ + QMutexLocker l(&mtx); + + std::vector ret; + + for (auto& j : joys()) + ret.push_back(joy_info { j.second->name, j.first }); + + return ret; +} + +win32_joy_ctx::win32_joy_ctx() +{ + refresh(true); +} + +void win32_joy_ctx::release() +{ + qDebug() << "release joystick dinput handle"; + joys() = std::unordered_map>(); + { + auto& di = dinput_handle(); + di->Release(); + di = nullptr; + } +} + +void win32_joy_ctx::refresh(bool first) +{ + if (!first) + { + if (timer_joylist.elapsed_ms() < joylist_refresh_ms) + return; + timer_joylist.start(); + } + + enum_state st(joys(), first); +} + +QString win32_joy_ctx::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); +} + +using fn = win32_joy_ctx::fn; + +void win32_joy_ctx::joy::release() +{ + if (joy_handle) + { + (void) joy_handle->Unacquire(); + joy_handle->Release(); + joy_handle = nullptr; + } +} + +bool win32_joy_ctx::joy::poll(fn f) +{ + HRESULT hr; + bool ok = false; + + if (joy_handle == nullptr) + return false; + + (void) joy_handle->Acquire(); + + if (!FAILED(joy_handle->Poll())) + ok = true; + + if (!ok) + { + qDebug() << "joy acquire failed" << guid << hr; + (void) joy_handle->Unacquire(); + return false; + } + + DIJOYSTATE2 js; + memset(&js, 0, sizeof(js)); + + if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) + { + qDebug() << "joy get state failed" << guid << hr; + return false; + } + + first |= first_timer.elapsed_ms() > first_event_delay_ms; + + for (int i = 0; i < 128; i++) + { + const bool state = !!(js.rgbButtons[i] & 0x80); + if (state != pressed[i] && first) + { + f(guid, i, state); + qDebug() << "btn" << guid << i << state; + } + pressed[i] = state; + } + + return true; +} + +win32_joy_ctx::enum_state::enum_state(std::unordered_map > &joys, bool first) : joys(joys), first(first) +{ + HRESULT hr; + LPDIRECTINPUT8 di = dinput_handle(); + + if(FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, + EnumJoysticksCallback, + this, + DIEDFL_ATTACHEDONLY))) + { + qDebug() << "failed enum joysticks" << hr; + return; + } + + for (auto it = joys.begin(); it != joys.end(); ) + { + if (std::find_if(all.cbegin(), all.cend(), [&](const QString& guid2) -> bool { return it->second->guid == guid2; }) == all.cend()) + it = joys.erase(it); + else + it++; + } +} + +win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINSTANCE *pdidInstance, void *pContext) +{ + enum_state& state = *reinterpret_cast(pContext); + const QString guid = guid_to_string(pdidInstance->guidInstance); + const QString name = QString(pdidInstance->tszInstanceName); + + auto it = state.joys.find(guid); + const bool exists = it != state.joys.end() && it->second->joy_handle != nullptr; + + state.all.push_back(guid); + + if (!exists) + { + HRESULT hr; + LPDIRECTINPUTDEVICE8 h; + LPDIRECTINPUT8 di = dinput_handle(); + if (FAILED(hr = di->CreateDevice(pdidInstance->guidInstance, &h, nullptr))) + { + qDebug() << "createdevice" << guid << hr; + goto end; + } + if (FAILED(h->SetDataFormat(&c_dfDIJoystick2))) + { + qDebug() << "format"; + h->Release(); + goto end; + } + + if (FAILED(h->SetCooperativeLevel((HWND) GetDesktopWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) + { + qDebug() << "coop"; + h->Release(); + goto end; + } + if (FAILED(hr = h->EnumObjects(EnumObjectsCallback, h, DIDFT_ALL))) + { + qDebug() << "enum-objects"; + h->Release(); + goto end; + } + + qDebug() << "add joy" << guid; + state.joys[guid] = std::make_shared(h, guid, name, state.first); + } +end: + return DIENUM_CONTINUE; +} + +win32_joy_ctx::enum_state::EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE *pdidoi, void *ctx) +{ + if (pdidoi->dwType & DIDFT_AXIS) + { + DIPROPRANGE diprg; + memset(&diprg, 0, sizeof(diprg)); + diprg.diph.dwSize = sizeof( DIPROPRANGE ); + diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER ); + diprg.diph.dwHow = DIPH_BYID; + diprg.diph.dwObj = pdidoi->dwType; + diprg.lMax = joy_axis_size; + diprg.lMin = -joy_axis_size; + + HRESULT hr; + + if (FAILED(hr = reinterpret_cast(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph))) + { + qDebug() << "DIPROP_RANGE" << hr; + return DIENUM_STOP; + } + } + + return DIENUM_CONTINUE; +} + #endif diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp index b08da6c8d..334b617a4 100644 --- a/opentrack/win32-joystick.hpp +++ b/opentrack/win32-joystick.hpp @@ -39,77 +39,6 @@ struct hash struct OPENTRACK_EXPORT win32_joy_ctx { using fn = std::function; - - void poll(fn f) - { - QMutexLocker l(&mtx); - - refresh(false); - for (auto& j : joys()) - { - j.second->poll(f); - } - } - - bool poll_axis(const QString& guid, int axes[8]) - { - QMutexLocker l(&mtx); - - refresh(false); - - auto iter = joys().find(guid); - - if (iter == joys().end() || iter->second->joy_handle == nullptr) - return false; - - auto& j = iter->second; - - auto& joy_handle = j->joy_handle; - bool ok = false; - HRESULT hr; - - (void) joy_handle->Acquire(); - - if (!FAILED(hr = joy_handle->Poll())) - ok = true; - - if (!ok) - { - qDebug() << "joy acquire failed" << guid << hr; - (void) joy_handle->Unacquire(); - return false; - } - - DIJOYSTATE2 js; - memset(&js, 0, sizeof(js)); - - if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) - { - qDebug() << "joy get state failed" << guid << hr; - return false; - } - - const int values[] = { - js.lX, - js.lY, - js.lZ, - js.lRx, - js.lRy, - js.lRz, - js.rglSlider[0], - js.rglSlider[1] - }; - - for (int i = 0; i < 8; i++) - axes[i] = values[i]; - - return true; - } - - ~win32_joy_ctx() - { - release(); - } enum { joy_axis_size = 65535 }; @@ -117,78 +46,42 @@ struct OPENTRACK_EXPORT win32_joy_ctx { QString name, guid; }; - - std::vector get_joy_info() - { - QMutexLocker l(&mtx); - - std::vector ret; - - for (auto& j : joys()) - ret.push_back(joy_info { j.second->name, j.first }); - - return ret; - } + void poll(fn f); + bool poll_axis(const QString& guid, int axes[8]); + ~win32_joy_ctx(); + std::vector get_joy_info(); static win32_joy_ctx& make(); - win32_joy_ctx(const win32_joy_ctx&) = delete; win32_joy_ctx& operator=(const win32_joy_ctx&) = delete; -private: - static 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); - } - static LPDIRECTINPUT8& dinput_handle(); +private: + enum { joylist_refresh_ms = 250 }; - win32_joy_ctx() - { - refresh(true); - } - void release() - { - qDebug() << "release joystick dinput handle"; - joys() = std::unordered_map>(); - { - auto& di = dinput_handle(); - di->Release(); - di = nullptr; - } - } - - void refresh(bool first) - { - if (!first) - { - if (timer_joylist.elapsed_ms() < joylist_refresh_ms) - return; - timer_joylist.start(); - } - - enum_state st(joys(), first); - } QMutex mtx; Timer timer_joylist; - enum { joylist_refresh_ms = 250 }; + + static QString guid_to_string(const GUID guid); + static LPDIRECTINPUT8& dinput_handle(); + win32_joy_ctx(); + void release(); + void refresh(bool first); + + struct joy; + static std::unordered_map>& joys(); struct joy { + enum { first_event_delay_ms = 3000 }; + LPDIRECTINPUTDEVICE8 joy_handle; QString guid, name; bool pressed[128]; Timer first_timer; bool first; - - enum { first_event_delay_ms = 3000 }; - joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name, bool first) : joy_handle(handle), guid(guid), name(name), first(first) + joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name, bool first) + : joy_handle(handle), guid(guid), name(name), first(first) { qDebug() << "got joy" << guid; for (int i = 0; i < 128; i++) @@ -201,166 +94,21 @@ private: release(); } - void release() - { - if (joy_handle) - { - (void) joy_handle->Unacquire(); - joy_handle->Release(); - joy_handle = nullptr; - } - } - - bool poll(fn f) - { - HRESULT hr; - bool ok = false; - - if (joy_handle == nullptr) - return false; - - (void) joy_handle->Acquire(); - - if (!FAILED(joy_handle->Poll())) - ok = true; - - if (!ok) - { - qDebug() << "joy acquire failed" << guid << hr; - (void) joy_handle->Unacquire(); - return false; - } - - DIJOYSTATE2 js; - memset(&js, 0, sizeof(js)); - - if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js))) - { - qDebug() << "joy get state failed" << guid << hr; - return false; - } - - first |= first_timer.elapsed_ms() > first_event_delay_ms; - - for (int i = 0; i < 128; i++) - { - const bool state = !!(js.rgbButtons[i] & 0x80); - if (state != pressed[i] && first) - { - f(guid, i, state); - qDebug() << "btn" << guid << i << state; - } - pressed[i] = state; - } - - return true; - } + void release(); + bool poll(fn f); }; - struct enum_state + class enum_state { std::unordered_map>& joys; - std::vector all; bool first; - - enum_state(std::unordered_map>& joys, bool first) : joys(joys), first(first) - { - HRESULT hr; - LPDIRECTINPUT8 di = dinput_handle(); - - if(FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, - EnumJoysticksCallback, - this, - DIEDFL_ATTACHEDONLY))) - { - qDebug() << "failed enum joysticks" << hr; - return; - } - - for (auto it = joys.begin(); it != joys.end(); ) - { - if (std::find_if(all.cbegin(), all.cend(), [&](const QString& guid2) -> bool { return it->second->guid == guid2; }) == all.cend()) - it = joys.erase(it); - else - it++; - } - } - - static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext) - { - enum_state& state = *reinterpret_cast(pContext); - const QString guid = guid_to_string(pdidInstance->guidInstance); - const QString name = QString(pdidInstance->tszInstanceName); - - auto it = state.joys.find(guid); - const bool exists = it != state.joys.end() && it->second->joy_handle != nullptr; - - state.all.push_back(guid); - - if (!exists) - { - HRESULT hr; - LPDIRECTINPUTDEVICE8 h; - LPDIRECTINPUT8 di = dinput_handle(); - if (FAILED(hr = di->CreateDevice(pdidInstance->guidInstance, &h, nullptr))) - { - qDebug() << "createdevice" << guid << hr; - goto end; - } - if (FAILED(h->SetDataFormat(&c_dfDIJoystick2))) - { - qDebug() << "format"; - h->Release(); - goto end; - } - - if (FAILED(h->SetCooperativeLevel((HWND) GetDesktopWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) - { - qDebug() << "coop"; - h->Release(); - goto end; - } - if (FAILED(hr = h->EnumObjects(EnumObjectsCallback, h, DIDFT_ALL))) - { - qDebug() << "enum-objects"; - h->Release(); - goto end; - } - - qDebug() << "add joy" << guid; - state.joys[guid] = std::make_shared(h, guid, name, state.first); - } - -end: return DIENUM_CONTINUE; - } - - static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx) - { - if (pdidoi->dwType & DIDFT_AXIS) - { - DIPROPRANGE diprg; - memset(&diprg, 0, sizeof(diprg)); - diprg.diph.dwSize = sizeof( DIPROPRANGE ); - diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER ); - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = pdidoi->dwType; - diprg.lMax = joy_axis_size; - diprg.lMin = -joy_axis_size; - - HRESULT hr; - - if (FAILED(hr = reinterpret_cast(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph))) - { - qDebug() << "DIPROP_RANGE" << hr; - return DIENUM_STOP; - } - } - - return DIENUM_CONTINUE; - } + + std::vector all; + static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext); + static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx); + public: + enum_state(std::unordered_map>& joys, bool first); }; - - static std::unordered_map>& joys(); }; #endif -- cgit v1.2.3 From bb605f416f9dd5e89150e8937d17c6647fcfe346 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 26 Nov 2015 09:09:43 +0100 Subject: api/shortcuts: remove pointless "friend" declarations --- opentrack/keybinding-worker.hpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index 054182e7b..5b669331a 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -63,7 +63,6 @@ private: public: class Token { - friend class KeybindingWorker; fun* pos; //Token(const Token&) = delete; Token& operator=(Token&) = delete; @@ -77,7 +76,6 @@ public: make().remove_receiver(pos); } }; - friend class Token; static Token add_receiver(fun receiver) { return Token(receiver); -- cgit v1.2.3 From edb0e01947f67142c00c3f75a62df7af708cdf11 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 29 Nov 2015 11:58:20 +0100 Subject: api/joystick: reduce mutex contention Don't look for changes in hotplug joysticks by freezing up polling for joysticks' axis and button. Issue: #267 --- opentrack/win32-joystick.cpp | 21 ++++++++++++++++----- opentrack/win32-joystick.hpp | 4 ++-- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index 29a51a435..0bd6bfdad 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -33,9 +33,10 @@ win32_joy_ctx& win32_joy_ctx::make() void win32_joy_ctx::poll(fn f) { + refresh(false); + QMutexLocker l(&mtx); - refresh(false); for (auto& j : joys()) { j.second->poll(f); @@ -44,10 +45,10 @@ void win32_joy_ctx::poll(fn f) bool win32_joy_ctx::poll_axis(const QString &guid, int axes[]) { - QMutexLocker l(&mtx); - refresh(false); + QMutexLocker l(&mtx); + auto iter = joys().find(guid); if (iter == joys().end() || iter->second->joy_handle == nullptr) @@ -134,12 +135,14 @@ void win32_joy_ctx::refresh(bool first) { if (!first) { + QMutexLocker l(&mtx); + if (timer_joylist.elapsed_ms() < joylist_refresh_ms) return; timer_joylist.start(); } - enum_state st(joys(), first); + enum_state st(joys(), first, mtx); } QString win32_joy_ctx::guid_to_string(const GUID guid) @@ -210,11 +213,16 @@ bool win32_joy_ctx::joy::poll(fn f) return true; } -win32_joy_ctx::enum_state::enum_state(std::unordered_map > &joys, bool first) : joys(joys), first(first) +win32_joy_ctx::enum_state::enum_state(std::unordered_map > &joys, bool first, QMutex& mtx) : first(first) { HRESULT hr; LPDIRECTINPUT8 di = dinput_handle(); + { + QMutexLocker l(&mtx); + this->joys = joys; + } + if(FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, this, @@ -231,6 +239,9 @@ win32_joy_ctx::enum_state::enum_state(std::unordered_mapjoys; } win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINSTANCE *pdidInstance, void *pContext) diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp index 334b617a4..3f47d1704 100644 --- a/opentrack/win32-joystick.hpp +++ b/opentrack/win32-joystick.hpp @@ -100,14 +100,14 @@ private: class enum_state { - std::unordered_map>& joys; + std::unordered_map> joys; bool first; std::vector all; static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext); static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx); public: - enum_state(std::unordered_map>& joys, bool first); + enum_state(std::unordered_map>& joys, bool first, QMutex &mtx); }; }; -- cgit v1.2.3 From c03c6f2bdb6a4f236c22a916753d4aa9728085fa Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 29 Nov 2015 12:34:05 +0100 Subject: api/joystick: oops, access the right 'joys' variable --- opentrack/win32-joystick.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index 0bd6bfdad..a705adbc9 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -232,7 +232,7 @@ win32_joy_ctx::enum_state::enum_state(std::unordered_mapjoys.begin(); it != this->joys.end(); ) { if (std::find_if(all.cbegin(), all.cend(), [&](const QString& guid2) -> bool { return it->second->guid == guid2; }) == all.cend()) it = joys.erase(it); -- cgit v1.2.3 From a07eed2a0de09224adb1381d7744a2f98857836e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 29 Nov 2015 12:34:19 +0100 Subject: api/joystick: drop locking, add comment --- opentrack/win32-joystick.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index a705adbc9..6e64355cc 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -135,8 +135,8 @@ void win32_joy_ctx::refresh(bool first) { if (!first) { - QMutexLocker l(&mtx); - + // accessing struct Timer without a lock. worst can happen is seconds + // and nanoseconds getting out of sync. no big deal. if (timer_joylist.elapsed_ms() < joylist_refresh_ms) return; timer_joylist.start(); -- cgit v1.2.3 From dd67c2971d4f41267d4d08ebd8c5aefdb675c6e5 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 3 Dec 2015 22:27:01 +0100 Subject: api/joy: fix race erase from iterator referenced the wrong 'joys' variable --- opentrack/win32-joystick.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index 6e64355cc..0f8a08f8e 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -222,7 +222,7 @@ win32_joy_ctx::enum_state::enum_state(std::unordered_mapjoys = joys; } - + if(FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, this, @@ -232,10 +232,12 @@ win32_joy_ctx::enum_state::enum_state(std::unordered_mapjoys.begin(); it != this->joys.end(); ) + auto& js = this->joys; + + for (auto it = js.begin(); it != js.end(); ) { if (std::find_if(all.cbegin(), all.cend(), [&](const QString& guid2) -> bool { return it->second->guid == guid2; }) == all.cend()) - it = joys.erase(it); + it = js.erase(it); else it++; } -- cgit v1.2.3 From 22d4c7cc0cadf212052ef72c3bf8ddda6f73a647 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 3 Dec 2015 22:31:57 +0100 Subject: api, compat: clean up verbose fprintf logspam --- opentrack-compat/shm.cpp | 1 - opentrack/keybinding-worker.cpp | 1 - opentrack/win32-joystick.cpp | 1 - 3 files changed, 3 deletions(-) (limited to 'opentrack') diff --git a/opentrack-compat/shm.cpp b/opentrack-compat/shm.cpp index fffb3709b..a306d581d 100644 --- a/opentrack-compat/shm.cpp +++ b/opentrack-compat/shm.cpp @@ -92,7 +92,6 @@ struct secattr attrs.lpSecurityDescriptor = pSD; attrs.nLength = sizeof(SECURITY_ATTRIBUTES); - fprintf(stderr, "security descriptor ok\n"); fflush(stderr); return; diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index 59bc4afd7..3c801cf22 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -24,7 +24,6 @@ bool Key::should_process() } KeybindingWorker::~KeybindingWorker() { - qDebug() << "keybinding worker stop"; should_quit = true; wait(); if (dinkeyboard) { diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index 0f8a08f8e..cd3502b45 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -122,7 +122,6 @@ win32_joy_ctx::win32_joy_ctx() void win32_joy_ctx::release() { - qDebug() << "release joystick dinput handle"; joys() = std::unordered_map>(); { auto& di = dinput_handle(); -- cgit v1.2.3 From fc9d0a76f47e97f2bdd35edc24695c95654a2a67 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 3 Dec 2015 22:32:44 +0100 Subject: api/joy: there's no joy_handle == nullptr case, don't check for it --- opentrack/win32-joystick.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index cd3502b45..1c658c757 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -51,7 +51,7 @@ bool win32_joy_ctx::poll_axis(const QString &guid, int axes[]) auto iter = joys().find(guid); - if (iter == joys().end() || iter->second->joy_handle == nullptr) + if (iter == joys().end()) return false; auto& j = iter->second; @@ -172,9 +172,6 @@ bool win32_joy_ctx::joy::poll(fn f) HRESULT hr; bool ok = false; - if (joy_handle == nullptr) - return false; - (void) joy_handle->Acquire(); if (!FAILED(joy_handle->Poll())) @@ -252,7 +249,7 @@ win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINSTANCE *pdidIns const QString name = QString(pdidInstance->tszInstanceName); auto it = state.joys.find(guid); - const bool exists = it != state.joys.end() && it->second->joy_handle != nullptr; + const bool exists = it != state.joys.end(); state.all.push_back(guid); -- cgit v1.2.3 From 3ac3eb2b4874782bac4aeac14cc39e63c1188acd Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 3 Dec 2015 22:45:02 +0100 Subject: api/joystick: refresh more often, it's cheap enough cpu-wise --- opentrack/win32-joystick.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp index 3f47d1704..421774a9a 100644 --- a/opentrack/win32-joystick.hpp +++ b/opentrack/win32-joystick.hpp @@ -56,7 +56,7 @@ struct OPENTRACK_EXPORT win32_joy_ctx win32_joy_ctx& operator=(const win32_joy_ctx&) = delete; private: - enum { joylist_refresh_ms = 250 }; + enum { joylist_refresh_ms = 100 }; QMutex mtx; Timer timer_joylist; -- cgit v1.2.3 From 578749c5b7f245aac08c4e514d2767dba059c4db Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 5 Dec 2015 23:30:43 +0100 Subject: api/keys: fix multiple shortcut receivers We can't depend on std::vector's address of array subscript to remain constant, duh. --- opentrack/keybinding-worker.cpp | 15 ++++++++------- opentrack/keybinding-worker.hpp | 20 ++++++++------------ 2 files changed, 16 insertions(+), 19 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index 3c801cf22..9ff825a08 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -119,7 +119,7 @@ void KeybindingWorker::run() { k.held = held; for (auto& r : receivers) - r(k); + r->operator()(k); }; joy_ctx.poll(f); @@ -147,7 +147,7 @@ void KeybindingWorker::run() { k.keycode = i; for (auto& r : receivers) - r(k); + r->operator()(k); break; } } @@ -160,12 +160,13 @@ void KeybindingWorker::run() { } } -KeybindingWorker::fun* KeybindingWorker::_add_receiver(KeybindingWorker::fun receiver) +KeybindingWorker::fun* KeybindingWorker::_add_receiver(fun& receiver) { QMutexLocker l(&mtx); - receivers.push_back(receiver); - qDebug() << "add receiver" << (long) &receivers[receivers.size()-1]; - return &receivers[receivers.size()-1]; + receivers.push_back(std::unique_ptr(new fun(receiver))); + fun* f = receivers[receivers.size() - 1].get(); + qDebug() << "add receiver" << (long) f; + return f; } void KeybindingWorker::remove_receiver(KeybindingWorker::fun* pos) @@ -175,7 +176,7 @@ void KeybindingWorker::remove_receiver(KeybindingWorker::fun* pos) for (int i = receivers.size() - 1; i >= 0; i--) { - if (&receivers[i] == pos) + if (receivers[i].get() == pos) { ok = true; qDebug() << "remove receiver" << (long) pos; diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index 5b669331a..c8d8e009d 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -47,8 +47,8 @@ private: LPDIRECTINPUTDEVICE8 dinkeyboard; win32_joy_ctx& joy_ctx; volatile bool should_quit; - using fun = std::function; - std::vector receivers; + using fun = std::function; + std::vector> receivers; QMutex mtx; void run() override; @@ -57,27 +57,23 @@ private: KeybindingWorker(const KeybindingWorker&) = delete; KeybindingWorker& operator=(KeybindingWorker&) = delete; static KeybindingWorker& make(); - fun* _add_receiver(fun receiver); + fun* _add_receiver(fun &receiver); void remove_receiver(fun* pos); ~KeybindingWorker(); public: class Token { fun* pos; - //Token(const Token&) = delete; + Token(const Token&) = delete; Token& operator=(Token&) = delete; public: - Token(fun receiver) - { - pos = make()._add_receiver(receiver); - } ~Token() { make().remove_receiver(pos); } + Token(fun receiver) + { + pos = make()._add_receiver(receiver); + } }; - static Token add_receiver(fun receiver) - { - return Token(receiver); - } }; -- cgit v1.2.3 From 86708a2311c1a3efd975798ff42d934eea0078ed Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 5 Dec 2015 23:32:43 +0100 Subject: api/shortcuts: no longer keep shortcuts hardcoded --- gui/options-dialog.cpp | 3 +++ gui/ui.cpp | 23 +---------------------- gui/ui.h | 4 ---- opentrack/shortcuts.cpp | 48 +++++++++++++++++++++++++++++------------------- opentrack/shortcuts.h | 34 +++++++++++++++++----------------- opentrack/tracker.h | 6 +++--- opentrack/work.hpp | 32 ++++++++++++++++++-------------- 7 files changed, 71 insertions(+), 79 deletions(-) (limited to 'opentrack') diff --git a/gui/options-dialog.cpp b/gui/options-dialog.cpp index 9631d41ed..70d5be628 100644 --- a/gui/options-dialog.cpp +++ b/gui/options-dialog.cpp @@ -73,6 +73,9 @@ OptionsDialog::OptionsDialog() connect(ui.bind_center, &QPushButton::pressed, [&]() -> void { bind_key(s.center, ui.center_text); }); connect(ui.bind_zero, &QPushButton::pressed, [&]() -> void { bind_key(s.zero, ui.zero_text); }); connect(ui.bind_toggle, &QPushButton::pressed, [&]() -> void { bind_key(s.toggle, ui.toggle_text); }); + connect(ui.bind_start, &QPushButton::pressed, [&]() -> void { bind_key(s.start_tracking, ui.start_tracking_text); }); + connect(ui.bind_stop, &QPushButton::pressed, [&]() -> void { bind_key(s.stop_tracking, ui.stop_tracking_text); }); + connect(ui.bind_toggle_tracking, &QPushButton::pressed, [&]() -> void { bind_key(s.toggle_tracking, ui.toggle_tracking_text); }); ui.center_text->setText(kopts_to_string(s.center)); ui.toggle_text->setText(kopts_to_string(s.toggle)); diff --git a/gui/ui.cpp b/gui/ui.cpp index fc6d47540..c3e47912f 100644 --- a/gui/ui.cpp +++ b/gui/ui.cpp @@ -281,7 +281,7 @@ void MainWindow::startTracker() { return; } - work = std::make_shared(s, pose, libs, this, winId()); + work = std::make_shared(s, pose, libs, winId()); reload_options(); @@ -489,27 +489,6 @@ void MainWindow::profileSelected(QString name) } } -void MainWindow::shortcutRecentered() -{ - qDebug() << "Center"; - if (work) - work->tracker->center(); -} - -void MainWindow::shortcutToggled() -{ - qDebug() << "Toggle"; - if (work) - work->tracker->toggle_enabled(); -} - -void MainWindow::shortcutZeroed() -{ - qDebug() << "Zero"; - if (work) - work->tracker->zero(); -} - void MainWindow::ensure_tray() { if (tray) diff --git a/gui/ui.h b/gui/ui.h index 44bcde0c2..b4bab271a 100644 --- a/gui/ui.h +++ b/gui/ui.h @@ -100,10 +100,6 @@ private slots: void startTracker(); void stopTracker(); void reload_options(); -public slots: - void shortcutRecentered(); - void shortcutToggled(); - void shortcutZeroed(); public: MainWindow(); ~MainWindow(); diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp index b961294f7..560a31abf 100644 --- a/opentrack/shortcuts.cpp +++ b/opentrack/shortcuts.cpp @@ -9,7 +9,7 @@ #include "shortcuts.h" #include "win32-shortcuts.h" -void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k) +void Shortcuts::bind_keyboard_shortcut(K &key, const key_opts& k) { #if !defined(_WIN32) using sh = QxtGlobalShortcut; @@ -63,33 +63,43 @@ void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k) #ifdef _WIN32 void Shortcuts::receiver(const Key& k) { - std::vector ks { &keyCenter, &keyToggle, &keyZero }; - for (K* k_ : ks) + const int sz = keys.size(); + for (int i = 0; i < sz; i++) { - if (k.guid != k_->guid) + K& k_ = std::get<0>(keys[i]); + auto& fun = std::get<1>(keys[i]); + if (k.guid != k_.guid) continue; - if (k.keycode != k_->keycode) + if (k.keycode != k_.keycode) continue; if (!k.held) continue; - if (!k_->should_process()) + if (!k_.should_process()) continue; - if (k_->alt && !k.alt) continue; - if (k_->ctrl && !k.ctrl) continue; - if (k_->shift && !k.shift) continue; + if (k_.alt && !k.alt) continue; + if (k_.ctrl && !k.ctrl) continue; + if (k_.shift && !k.shift) continue; - if (k_ == &keyCenter) - emit center(); - else if (k_ == &keyToggle) - emit toggle(); - else if (k_ == &keyZero) - emit zero(); + fun(); } } #endif -void Shortcuts::reload() { - bind_keyboard_shortcut(keyCenter, s.center); - bind_keyboard_shortcut(keyToggle, s.toggle); - bind_keyboard_shortcut(keyZero, s.zero); +void Shortcuts::reload(const std::vector > &keys_) +{ + const int sz = keys_.size(); + keys = std::vector(); + + for (int i = 0; i < sz; i++) + { + const auto& kk = keys_[i]; + const key_opts& opts = std::get<0>(kk); + auto& fun = std::get<1>(kk); + K k; + bind_keyboard_shortcut(k, opts); + keys.push_back(std::tuple(k, fun)); +#ifndef _WIN32 + connect(k.get(), &QGlobalShortcut::activated, fun); +#endif + } } diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index 8acc5ba54..4dec7c2cb 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -8,6 +8,9 @@ #pragma once #include +#include +#include +#include #ifdef BUILD_api # include "opentrack-compat/export.hpp" @@ -36,10 +39,10 @@ public: Key #endif ; - - K keyCenter; - K keyToggle; - K keyZero; + + using fun = std::function; + using tt = std::tuple; + std::vector keys; #ifdef _WIN32 KeybindingWorker::Token key_token; #endif @@ -56,32 +59,29 @@ public: }; struct settings : opts { - key_opts center, toggle, zero; + key_opts center, toggle, zero, start_tracking, stop_tracking, toggle_tracking; main_settings s_main; settings() : opts("keyboard-shortcuts"), center(b, "center"), toggle(b, "toggle"), - zero(b, "zero") + zero(b, "zero"), + start_tracking(b, "start-tracking"), + stop_tracking(b, "stop-tracking"), + toggle_tracking(b, "toggle-tracking") {} } s; - Shortcuts() + Shortcuts() : #ifdef _WIN32 - : key_token(KeybindingWorker::add_receiver([&](const Key& k) { receiver(k); })) + key_token([&](const Key& k) { receiver(k); }) #endif - { - reload(); - } + {} - void reload(); + void reload(const std::vector > &keys); private: - void bind_keyboard_shortcut(K &key, key_opts& k); + void bind_keyboard_shortcut(K &key, const key_opts& k); #ifdef _WIN32 void receiver(const Key& k); #endif -signals: - void center(); - void toggle(); - void zero(); }; diff --git a/opentrack/tracker.h b/opentrack/tracker.h index e26c3f7ac..36b5cad46 100644 --- a/opentrack/tracker.h +++ b/opentrack/tracker.h @@ -80,7 +80,7 @@ public: void get_raw_and_mapped_poses(double* mapped, double* raw) const; void start() { QThread::start(); } - void toggle_enabled() { enabledp = !enabledp; } - void center() { centerp = !centerp; } - void zero() { zero_ = !zero_; } + void toggle_enabled() { qDebug() << "toggle enabled"; enabledp = !enabledp; } + void center() { qDebug() << "toggle center"; centerp = !centerp; } + void zero() { qDebug() << "toggle zero"; zero_ = !zero_; } }; diff --git a/opentrack/work.hpp b/opentrack/work.hpp index e338e9f48..a3c0e0141 100644 --- a/opentrack/work.hpp +++ b/opentrack/work.hpp @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include struct Work { @@ -24,28 +27,29 @@ struct Work mem tracker; mem sc; WId handle; - - Work(main_settings& s, Mappings& m, SelectedLibraries& libs, QObject* recv, WId handle) : + using fn = std::function; + using key_opts = Shortcuts::key_opts; + using tt = std::tuple; + std::vector> keys; + + Work(main_settings& s, Mappings& m, SelectedLibraries& libs, WId handle) : s(s), libs(libs), tracker(std::make_shared(s, m, libs)), sc(std::make_shared()), - handle(handle) + handle(handle), + keys { + tt(sc->s.center, [&]() -> void { tracker->center(); }), + tt(sc->s.toggle, [&]() -> void { tracker->toggle_enabled(); }), + tt(sc->s.zero, [&]() -> void { tracker->zero(); }), + } { -#ifndef _WIN32 - QObject::connect(sc->keyCenter.get(), SIGNAL(activated()), recv, SLOT(shortcutRecentered())); - QObject::connect(sc->keyToggle.get(), SIGNAL(activated()), recv, SLOT(shortcutToggled())); - QObject::connect(sc->keyZero.get(), SIGNAL(activated()), recv, SLOT(shortcutZeroed())); -#else - QObject::connect(sc.get(), SIGNAL(center()), recv, SLOT(shortcutRecentered())); - QObject::connect(sc.get(), SIGNAL(toggle()), recv, SLOT(shortcutToggled())); - QObject::connect(sc.get(), SIGNAL(zero()), recv, SLOT(shortcutZeroed())); -#endif - tracker->start(); + reload_shortcuts(); + tracker->start(); } void reload_shortcuts() { - sc->reload(); + sc->reload(keys); } ~Work() -- cgit v1.2.3 From 52b75a02aeeaf2c23f5af32fededf4e5fb24bade Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 00:43:58 +0100 Subject: api, main: implement global shortcuts for controlling tracking Issue: #252 That involves moving stuff around to get rid of circular dependencies. You need to bind keys to shortcuts again this once. --- gui/options-dialog.cpp | 100 +++++++++++++++++++++++--------------------- gui/options-dialog.hpp | 12 +++--- gui/ui.cpp | 50 +++++++++++++++++++--- gui/ui.h | 10 +++++ opentrack/main-settings.hpp | 26 ++++++++++-- opentrack/shortcuts.h | 27 +----------- opentrack/work.hpp | 7 ++-- 7 files changed, 140 insertions(+), 92 deletions(-) (limited to 'opentrack') diff --git a/gui/options-dialog.cpp b/gui/options-dialog.cpp index 70d5be628..1edf069dc 100644 --- a/gui/options-dialog.cpp +++ b/gui/options-dialog.cpp @@ -12,7 +12,7 @@ #include #include -static QString kopts_to_string(const Shortcuts::key_opts& kopts) +static QString kopts_to_string(const key_opts& kopts) { if (static_cast(kopts.guid) != "") { @@ -29,60 +29,65 @@ static QString kopts_to_string(const Shortcuts::key_opts& kopts) return kopts.keycode; } -OptionsDialog::OptionsDialog() +OptionsDialog::OptionsDialog(main_settings& main, std::function register_global_keys) + : main(main), register_global_keys(register_global_keys) { ui.setupUi(this); connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); - tie_setting(s.s_main.tray_enabled, ui.trayp); + tie_setting(main.tray_enabled, ui.trayp); - tie_setting(s.s_main.center_at_startup, ui.center_at_startup); + tie_setting(main.center_at_startup, ui.center_at_startup); - tie_setting(s.s_main.tcomp_p, ui.tcomp_enable); - tie_setting(s.s_main.tcomp_tz, ui.tcomp_rz); - - tie_setting(s.s_main.a_x.zero, ui.pos_tx); - tie_setting(s.s_main.a_y.zero, ui.pos_ty); - tie_setting(s.s_main.a_z.zero, ui.pos_tz); - tie_setting(s.s_main.a_yaw.zero, ui.pos_rx); - tie_setting(s.s_main.a_pitch.zero, ui.pos_ry); - tie_setting(s.s_main.a_roll.zero, ui.pos_rz); - - tie_setting(s.s_main.a_yaw.invert, ui.invert_yaw); - tie_setting(s.s_main.a_pitch.invert, ui.invert_pitch); - tie_setting(s.s_main.a_roll.invert, ui.invert_roll); - tie_setting(s.s_main.a_x.invert, ui.invert_x); - tie_setting(s.s_main.a_y.invert, ui.invert_y); - tie_setting(s.s_main.a_z.invert, ui.invert_z); - - tie_setting(s.s_main.a_yaw.src, ui.src_yaw); - tie_setting(s.s_main.a_pitch.src, ui.src_pitch); - tie_setting(s.s_main.a_roll.src, ui.src_roll); - tie_setting(s.s_main.a_x.src, ui.src_x); - tie_setting(s.s_main.a_y.src, ui.src_y); - tie_setting(s.s_main.a_z.src, ui.src_z); + tie_setting(main.tcomp_p, ui.tcomp_enable); + tie_setting(main.tcomp_tz, ui.tcomp_rz); + + tie_setting(main.a_x.zero, ui.pos_tx); + tie_setting(main.a_y.zero, ui.pos_ty); + tie_setting(main.a_z.zero, ui.pos_tz); + tie_setting(main.a_yaw.zero, ui.pos_rx); + tie_setting(main.a_pitch.zero, ui.pos_ry); + tie_setting(main.a_roll.zero, ui.pos_rz); + + tie_setting(main.a_yaw.invert, ui.invert_yaw); + tie_setting(main.a_pitch.invert, ui.invert_pitch); + tie_setting(main.a_roll.invert, ui.invert_roll); + tie_setting(main.a_x.invert, ui.invert_x); + tie_setting(main.a_y.invert, ui.invert_y); + tie_setting(main.a_z.invert, ui.invert_z); + + tie_setting(main.a_yaw.src, ui.src_yaw); + tie_setting(main.a_pitch.src, ui.src_pitch); + tie_setting(main.a_roll.src, ui.src_roll); + tie_setting(main.a_x.src, ui.src_x); + tie_setting(main.a_y.src, ui.src_y); + tie_setting(main.a_z.src, ui.src_z); - tie_setting(s.s_main.camera_yaw, ui.camera_yaw); - tie_setting(s.s_main.camera_pitch, ui.camera_pitch); - tie_setting(s.s_main.camera_roll, ui.camera_roll); - - tie_setting(s.s_main.center_method, ui.center_method); - - connect(ui.bind_center, &QPushButton::pressed, [&]() -> void { bind_key(s.center, ui.center_text); }); - connect(ui.bind_zero, &QPushButton::pressed, [&]() -> void { bind_key(s.zero, ui.zero_text); }); - connect(ui.bind_toggle, &QPushButton::pressed, [&]() -> void { bind_key(s.toggle, ui.toggle_text); }); - connect(ui.bind_start, &QPushButton::pressed, [&]() -> void { bind_key(s.start_tracking, ui.start_tracking_text); }); - connect(ui.bind_stop, &QPushButton::pressed, [&]() -> void { bind_key(s.stop_tracking, ui.stop_tracking_text); }); - connect(ui.bind_toggle_tracking, &QPushButton::pressed, [&]() -> void { bind_key(s.toggle_tracking, ui.toggle_tracking_text); }); - - ui.center_text->setText(kopts_to_string(s.center)); - ui.toggle_text->setText(kopts_to_string(s.toggle)); - ui.zero_text->setText(kopts_to_string(s.zero)); + tie_setting(main.camera_yaw, ui.camera_yaw); + tie_setting(main.camera_pitch, ui.camera_pitch); + tie_setting(main.camera_roll, ui.camera_roll); + + tie_setting(main.center_method, ui.center_method); + + connect(ui.bind_center, &QPushButton::pressed, [&]() -> void { bind_key(main.key_center, ui.center_text); }); + connect(ui.bind_zero, &QPushButton::pressed, [&]() -> void { bind_key(main.key_zero, ui.zero_text); }); + connect(ui.bind_toggle, &QPushButton::pressed, [&]() -> void { bind_key(main.key_toggle, ui.toggle_text); }); + connect(ui.bind_start, &QPushButton::pressed, [&]() -> void { bind_key(main.key_start_tracking, ui.start_tracking_text); }); + connect(ui.bind_stop, &QPushButton::pressed, [&]() -> void { bind_key(main.key_stop_tracking, ui.stop_tracking_text); }); + connect(ui.bind_toggle_tracking, &QPushButton::pressed, [&]() -> void { bind_key(main.key_toggle_tracking, ui.toggle_tracking_text); }); + + ui.center_text->setText(kopts_to_string(main.key_center)); + ui.toggle_text->setText(kopts_to_string(main.key_toggle)); + ui.zero_text->setText(kopts_to_string(main.key_zero)); + + ui.start_tracking_text->setText(kopts_to_string(main.key_start_tracking)); + ui.stop_tracking_text->setText(kopts_to_string(main.key_stop_tracking)); + ui.toggle_tracking_text->setText(kopts_to_string(main.key_toggle_tracking)); } -void OptionsDialog::bind_key(Shortcuts::key_opts& kopts, QLabel* label) +void OptionsDialog::bind_key(key_opts& kopts, QLabel* label) { kopts.button = -1; kopts.guid = ""; @@ -111,22 +116,21 @@ void OptionsDialog::bind_key(Shortcuts::key_opts& kopts, QLabel* label) } }); d.exec(); + register_global_keys(); label->setText(kopts_to_string(kopts)); delete k; delete l; } void OptionsDialog::doOK() { - s.b->save(); - s.s_main.b->save(); + main.b->save(); ui.game_detector->save(); this->close(); emit reload(); } void OptionsDialog::doCancel() { - s.b->reload(); - s.s_main.b->reload(); + main.b->reload(); ui.game_detector->revert(); close(); } diff --git a/gui/options-dialog.hpp b/gui/options-dialog.hpp index 308b5b0f8..72ae3c30b 100644 --- a/gui/options-dialog.hpp +++ b/gui/options-dialog.hpp @@ -1,9 +1,10 @@ #pragma once -#include -#include #include "ui_settings.h" #include "opentrack/shortcuts.h" +#include +#include +#include class OptionsDialog: public QWidget { @@ -11,13 +12,14 @@ class OptionsDialog: public QWidget signals: void reload(); public: - OptionsDialog(); + OptionsDialog(main_settings& main, std::function register_global_keys); private: + main_settings& main; + std::function register_global_keys; Ui::UI_Settings ui; - Shortcuts::settings s; void closeEvent(QCloseEvent *) override { doCancel(); } private slots: void doOK(); void doCancel(); - void bind_key(Shortcuts::key_opts &kopts, QLabel* label); + void bind_key(key_opts &kopts, QLabel* label); }; diff --git a/gui/ui.cpp b/gui/ui.cpp index c3e47912f..26fcd9eda 100644 --- a/gui/ui.cpp +++ b/gui/ui.cpp @@ -108,10 +108,40 @@ MainWindow::MainWindow() : "Configuration not saved.", "Can't create configuration directory! Expect major malfunction.", QMessageBox::Ok, QMessageBox::NoButton); - + + connect(this, &MainWindow::emit_start_tracker, + this, [&]() -> void { qDebug() << "start tracker"; startTracker(); }, + Qt::QueuedConnection); + + connect(this, &MainWindow::emit_stop_tracker, + this, [&]() -> void { qDebug() << "stop tracker"; stopTracker(); }, + Qt::QueuedConnection); + + connect(this, &MainWindow::emit_toggle_tracker, + this, [&]() -> void { qDebug() << "toggle tracker"; if (work) stopTracker(); else startTracker(); }, + Qt::QueuedConnection); + + register_shortcuts(); + ui.btnStartTracker->setFocus(); } +void MainWindow::register_shortcuts() +{ + using t_shortcut = std::tuple; + + std::vector keys { + t_shortcut(s.key_start_tracking, [&]() -> void { emit_start_tracker(); }), + t_shortcut(s.key_stop_tracking, [&]() -> void { emit_stop_tracker(); }), + t_shortcut(s.key_toggle_tracking, [&]() -> void { emit_toggle_tracker(); }), + }; + + global_shortcuts.reload(keys); + + if (work) + work->reload_shortcuts(); +} + bool MainWindow::get_new_config_name_from_dialog(QString& ret) { new_file_dialog dlg; @@ -261,6 +291,9 @@ void MainWindow::reload_options() } void MainWindow::startTracker() { + if (work) + return; + // tracker dtor needs run first work = nullptr; @@ -306,7 +339,10 @@ void MainWindow::startTracker() { ui.btnStopTracker->setFocus(); } -void MainWindow::stopTracker( ) { +void MainWindow::stopTracker() { + if (!work) + return; + //ui.game_name->setText("Not connected"); pose_update_timer.stop(); @@ -436,7 +472,7 @@ void MainWindow::showFilterSettings() { } template -bool mk_window(mem* place, Args... params) +bool mk_window(mem* place, Args&&... params) { if (*place && (*place)->isVisible()) { @@ -446,7 +482,7 @@ bool mk_window(mem* place, Args... params) } else { - *place = std::make_shared(params...); + *place = std::make_shared(std::forward(params)...); (*place)->setWindowFlags(Qt::Dialog); (*place)->show(); (*place)->raise(); @@ -455,12 +491,14 @@ bool mk_window(mem* place, Args... params) } void MainWindow::show_options_dialog() { - if (mk_window(&options_widget)) + if (mk_window(&options_widget, + s, + [&]() -> void { register_shortcuts(); })) connect(options_widget.get(), SIGNAL(reload()), this, SLOT(reload_options())); } void MainWindow::showCurveConfiguration() { - mk_window(&mapping_widget, pose, s); + mk_window(&mapping_widget, pose, s); } void MainWindow::exit() { diff --git a/gui/ui.h b/gui/ui.h index b4bab271a..12ef1f244 100644 --- a/gui/ui.h +++ b/gui/ui.h @@ -17,6 +17,9 @@ #include #include +#include +#include + #include "ui_main.h" #include "opentrack-compat/options.hpp" @@ -35,6 +38,8 @@ using namespace options; class MainWindow : public QMainWindow, private State { Q_OBJECT + + Shortcuts global_shortcuts; Ui::OpentrackUI ui; mem tray; @@ -76,6 +81,7 @@ class MainWindow : public QMainWindow, private State static bool get_new_config_name_from_dialog(QString &ret); void set_profile(const QString& profile); void maybe_save(); + void register_shortcuts(); private slots: void _save(); void save(); @@ -100,6 +106,10 @@ private slots: void startTracker(); void stopTracker(); void reload_options(); +signals: + void emit_start_tracker(); + void emit_stop_tracker(); + void emit_toggle_tracker(); public: MainWindow(); ~MainWindow(); diff --git a/opentrack/main-settings.hpp b/opentrack/main-settings.hpp index b7b086ad2..793c52f75 100644 --- a/opentrack/main-settings.hpp +++ b/opentrack/main-settings.hpp @@ -32,7 +32,18 @@ private: } }; -struct main_settings : opts { +struct key_opts { + value keycode, guid; + value button; + + key_opts(pbundle b, const QString& name) : + keycode(b, QString("keycode-%1").arg(name), ""), + guid(b, QString("guid-%1").arg(name), ""), + button(b, QString("button-%1").arg(name), -1) + {} +}; + +struct main_settings : opts { value tracker_dll, filter_dll, protocol_dll; axis_opts a_x, a_y, a_z, a_yaw, a_pitch, a_roll; value tcomp_p, tcomp_tz; @@ -40,6 +51,8 @@ struct main_settings : opts { value camera_yaw, camera_pitch, camera_roll; value center_at_startup; value center_method; + key_opts key_start_tracking, key_stop_tracking, key_toggle_tracking; + key_opts key_center, key_toggle, key_zero; main_settings() : opts("opentrack-ui"), tracker_dll(b, "tracker-dll", ""), @@ -58,6 +71,13 @@ struct main_settings : opts { camera_pitch(b, "camera-pitch", 0), camera_roll(b, "camera-roll", 0), center_at_startup(b, "center-at-startup", true), - center_method(b, "centering-method", true) - {} + center_method(b, "centering-method", true), + key_start_tracking(b, "start-tracking"), + key_stop_tracking(b, "stop-tracking"), + key_toggle_tracking(b, "toggle-tracking"), + key_center(b, "center"), + key_toggle(b, "toggle"), + key_zero(b, "zero") + { + } }; diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index 4dec7c2cb..f8343ad8a 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -46,31 +46,6 @@ public: #ifdef _WIN32 KeybindingWorker::Token key_token; #endif - - struct key_opts { - value keycode, guid; - value button; - - key_opts(pbundle b, const QString& name) : - keycode(b, QString("keycode-%1").arg(name), ""), - guid(b, QString("guid-%1").arg(name), ""), - button(b, QString("button-%1").arg(name), -1) - {} - }; - - struct settings : opts { - key_opts center, toggle, zero, start_tracking, stop_tracking, toggle_tracking; - main_settings s_main; - settings() : - opts("keyboard-shortcuts"), - center(b, "center"), - toggle(b, "toggle"), - zero(b, "zero"), - start_tracking(b, "start-tracking"), - stop_tracking(b, "stop-tracking"), - toggle_tracking(b, "toggle-tracking") - {} - } s; Shortcuts() : #ifdef _WIN32 @@ -78,7 +53,7 @@ public: #endif {} - void reload(const std::vector > &keys); + void reload(const std::vector > &keys); private: void bind_keyboard_shortcut(K &key, const key_opts& k); #ifdef _WIN32 diff --git a/opentrack/work.hpp b/opentrack/work.hpp index a3c0e0141..4188b937c 100644 --- a/opentrack/work.hpp +++ b/opentrack/work.hpp @@ -28,7 +28,6 @@ struct Work mem sc; WId handle; using fn = std::function; - using key_opts = Shortcuts::key_opts; using tt = std::tuple; std::vector> keys; @@ -38,9 +37,9 @@ struct Work sc(std::make_shared()), handle(handle), keys { - tt(sc->s.center, [&]() -> void { tracker->center(); }), - tt(sc->s.toggle, [&]() -> void { tracker->toggle_enabled(); }), - tt(sc->s.zero, [&]() -> void { tracker->zero(); }), + tt(s.key_center, [&]() -> void { tracker->center(); }), + tt(s.key_toggle, [&]() -> void { tracker->toggle_enabled(); }), + tt(s.key_zero, [&]() -> void { tracker->zero(); }), } { reload_shortcuts(); -- cgit v1.2.3 From ae1faae5d963b75a0b04bf69e77fc0ee12d2232d Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 00:53:44 +0100 Subject: api/keys: fix build --- opentrack/shortcuts.cpp | 2 +- opentrack/shortcuts.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'opentrack') diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp index 560a31abf..bab1283ac 100644 --- a/opentrack/shortcuts.cpp +++ b/opentrack/shortcuts.cpp @@ -99,7 +99,7 @@ void Shortcuts::reload(const std::vector > &keys_) bind_keyboard_shortcut(k, opts); keys.push_back(std::tuple(k, fun)); #ifndef _WIN32 - connect(k.get(), &QGlobalShortcut::activated, fun); + connect(k.get(), &QxtGlobalShortcut::activated, fun); #endif } } diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h index f8343ad8a..380379234 100644 --- a/opentrack/shortcuts.h +++ b/opentrack/shortcuts.h @@ -47,9 +47,9 @@ public: KeybindingWorker::Token key_token; #endif - Shortcuts() : + Shortcuts() #ifdef _WIN32 - key_token([&](const Key& k) { receiver(k); }) + : key_token([&](const Key& k) { receiver(k); }) #endif {} -- cgit v1.2.3 From 0be7e0a4e6ec65800a12bff1e7384995592c226f Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 02:02:55 +0100 Subject: api/keys: initialize hresult --- opentrack/win32-joystick.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index 1c658c757..e3147929b 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -174,7 +174,7 @@ bool win32_joy_ctx::joy::poll(fn f) (void) joy_handle->Acquire(); - if (!FAILED(joy_handle->Poll())) + if (!FAILED(hr = joy_handle->Poll())) ok = true; if (!ok) -- cgit v1.2.3 From dbc4722f14aa6d4b3322405c9251c5cee2e165d8 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 02:14:23 +0100 Subject: api/camera: move from header There's no need to have a copy in each module. --- opentrack/camera-names.cpp | 113 +++++++++++++++++++++++++++++++++++++++++++++ opentrack/camera-names.hpp | 113 +-------------------------------------------- 2 files changed, 115 insertions(+), 111 deletions(-) create mode 100644 opentrack/camera-names.cpp (limited to 'opentrack') diff --git a/opentrack/camera-names.cpp b/opentrack/camera-names.cpp new file mode 100644 index 000000000..74e998ca8 --- /dev/null +++ b/opentrack/camera-names.cpp @@ -0,0 +1,113 @@ +#include "camera-names.hpp" + +#if defined(OPENTRACK_API) && defined(_WIN32) +# define NO_DSHOW_STRSAFE +# include +# include +#endif + +#if defined(OPENTRACK_API) && (defined(__unix) || defined(__linux) || defined(__APPLE__)) +# include +#endif + +#ifdef __linux +#include +#include +#include +#include +#endif + +#include + +int camera_name_to_index(const QString &name) +{ + auto list = get_camera_names(); + int ret = list.indexOf(name); + if (ret < 0) + ret = 0; + return ret; +} + +QList get_camera_names() { + QList ret; +#if defined(_WIN32) + // Create the System Device Enumerator. + HRESULT hr; + hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + if (FAILED(hr)) + qDebug() << "failed CoInitializeEx" << hr; + ICreateDevEnum *pSysDevEnum = NULL; + hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); + if (FAILED(hr)) + { + qDebug() << "failed CLSID_SystemDeviceEnum" << hr; + return ret; + } + // Obtain a class enumerator for the video compressor category. + IEnumMoniker *pEnumCat = NULL; + hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); + + if (hr == S_OK) { + // Enumerate the monikers. + IMoniker *pMoniker = NULL; + ULONG cFetched; + while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); + if (SUCCEEDED(hr)) { + // To retrieve the filter's friendly name, do the following: + VARIANT varName; + VariantInit(&varName); + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if (SUCCEEDED(hr)) + { + // Display the name in your UI somehow. + QString str((QChar*)varName.bstrVal, wcslen(varName.bstrVal)); + ret.append(str); + } + VariantClear(&varName); + + ////// To create an instance of the filter, do the following: + ////IBaseFilter *pFilter; + ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, + //// (void**)&pFilter); + // Now add the filter to the graph. + //Remember to release pFilter later. + pPropBag->Release(); + } + pMoniker->Release(); + } + pEnumCat->Release(); + } + else + qDebug() << "failed CLSID_VideoInputDeviceCategory" << hr; + + pSysDevEnum->Release(); +#endif +#ifdef __linux + for (int i = 0; i < 16; i++) { + char buf[128]; + sprintf(buf, "/dev/video%d", i); + if (access(buf, F_OK) == 0) + ret.append(buf); + else + continue; + + if (access(buf, R_OK | W_OK) == 0) { + int fd = open(buf, O_RDONLY); + if (fd == -1) + continue; + struct v4l2_capability video_cap; + if(ioctl(fd, VIDIOC_QUERYCAP, &video_cap) == -1) + { + qDebug() << "VIDIOC_QUERYCAP" << errno; + close(fd); + continue; + } + ret[ret.size()-1] = reinterpret_cast(video_cap.card); + close(fd); + } + } +#endif + return ret; +} \ No newline at end of file diff --git a/opentrack/camera-names.hpp b/opentrack/camera-names.hpp index f6ab736ec..ef9144588 100644 --- a/opentrack/camera-names.hpp +++ b/opentrack/camera-names.hpp @@ -10,116 +10,7 @@ #include #include -#include -#if defined(OPENTRACK_API) && defined(_WIN32) -# define NO_DSHOW_STRSAFE -# include -# include -#endif +QList get_camera_names(); +int camera_name_to_index(const QString &name); -#if defined(OPENTRACK_API) && (defined(__unix) || defined(__linux) || defined(__APPLE__)) -# include -#endif - -#ifdef __linux -#include -#include -#include -#include -#endif - -template -QList get_camera_names() { - QList ret; -#if defined(_WIN32) - // Create the System Device Enumerator. - HRESULT hr; - hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - if (FAILED(hr)) - qDebug() << "failed CoInitializeEx" << hr; - ICreateDevEnum *pSysDevEnum = NULL; - hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); - if (FAILED(hr)) - { - qDebug() << "failed CLSID_SystemDeviceEnum" << hr; - return ret; - } - // Obtain a class enumerator for the video compressor category. - IEnumMoniker *pEnumCat = NULL; - hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); - - if (hr == S_OK) { - // Enumerate the monikers. - IMoniker *pMoniker = NULL; - ULONG cFetched; - while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { - IPropertyBag *pPropBag; - hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); - if (SUCCEEDED(hr)) { - // To retrieve the filter's friendly name, do the following: - VARIANT varName; - VariantInit(&varName); - hr = pPropBag->Read(L"FriendlyName", &varName, 0); - if (SUCCEEDED(hr)) - { - // Display the name in your UI somehow. - QString str((QChar*)varName.bstrVal, wcslen(varName.bstrVal)); - ret.append(str); - } - VariantClear(&varName); - - ////// To create an instance of the filter, do the following: - ////IBaseFilter *pFilter; - ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, - //// (void**)&pFilter); - // Now add the filter to the graph. - //Remember to release pFilter later. - pPropBag->Release(); - } - pMoniker->Release(); - } - pEnumCat->Release(); - } - else - qDebug() << "failed CLSID_VideoInputDeviceCategory" << hr; - - pSysDevEnum->Release(); -#endif -#ifdef __linux - for (int i = 0; i < 16; i++) { - char buf[128]; - sprintf(buf, "/dev/video%d", i); - if (access(buf, F_OK) == 0) - ret.append(buf); - else - continue; - - if (access(buf, R_OK | W_OK) == 0) { - int fd = open(buf, O_RDONLY); - if (fd == -1) - continue; - struct v4l2_capability video_cap; - if(ioctl(fd, VIDIOC_QUERYCAP, &video_cap) == -1) - { - qDebug() << "VIDIOC_QUERYCAP" << errno; - close(fd); - continue; - } - ret[ret.size()-1] = reinterpret_cast(video_cap.card); - close(fd); - } - } -#endif - return ret; -} - -template -int camera_name_to_index(const QString &name) -{ - auto list = get_camera_names(); - int ret = list.indexOf(name); - if (ret < 0) - ret = 0; - return ret; -} -- cgit v1.2.3 From 211a17996e3ffc0d84c985c43c612da32923b42d Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 02:24:44 +0100 Subject: api/camera-names: move to compat/ --- opentrack-compat/CMakeLists.txt | 1 + opentrack-compat/camera-names.cpp | 113 ++++++++++++++++++++++++++++++++ opentrack-compat/camera-names.hpp | 22 +++++++ opentrack/CMakeLists.txt | 1 - opentrack/camera-names.cpp | 113 -------------------------------- opentrack/camera-names.hpp | 16 ----- opentrack/opencv-camera-dialog.hpp | 2 +- tracker-aruco/ftnoir_tracker_aruco.cpp | 2 +- tracker-pt/ftnoir_tracker_pt.cpp | 2 +- tracker-pt/ftnoir_tracker_pt_dialog.cpp | 2 +- 10 files changed, 140 insertions(+), 134 deletions(-) create mode 100644 opentrack-compat/camera-names.cpp create mode 100644 opentrack-compat/camera-names.hpp delete mode 100644 opentrack/camera-names.cpp delete mode 100644 opentrack/camera-names.hpp (limited to 'opentrack') diff --git a/opentrack-compat/CMakeLists.txt b/opentrack-compat/CMakeLists.txt index 37d53e6cb..8dba67e2a 100644 --- a/opentrack-compat/CMakeLists.txt +++ b/opentrack-compat/CMakeLists.txt @@ -2,3 +2,4 @@ opentrack_boilerplate(opentrack-compat NO-COMPAT NO-LINKER-SCRIPT LINKAGE) if(NOT WIN32 AND NOT APPLE) target_link_libraries(opentrack-compat rt) endif() +link_with_dinput8(opentrack-compat) diff --git a/opentrack-compat/camera-names.cpp b/opentrack-compat/camera-names.cpp new file mode 100644 index 000000000..72bcf41ae --- /dev/null +++ b/opentrack-compat/camera-names.cpp @@ -0,0 +1,113 @@ +#include "camera-names.hpp" + +#if defined(OPENTRACK_API) && defined(_WIN32) +# define NO_DSHOW_STRSAFE +# include +# include +#endif + +#if defined(OPENTRACK_API) && (defined(__unix) || defined(__linux) || defined(__APPLE__)) +# include +#endif + +#ifdef __linux +#include +#include +#include +#include +#endif + +#include + +OPENTRACK_COMPAT_EXPORT int camera_name_to_index(const QString &name) +{ + auto list = get_camera_names(); + int ret = list.indexOf(name); + if (ret < 0) + ret = 0; + return ret; +} + +OPENTRACK_COMPAT_EXPORT QList get_camera_names() { + QList ret; +#if defined(_WIN32) + // Create the System Device Enumerator. + HRESULT hr; + hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + if (FAILED(hr)) + qDebug() << "failed CoInitializeEx" << hr; + ICreateDevEnum *pSysDevEnum = NULL; + hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); + if (FAILED(hr)) + { + qDebug() << "failed CLSID_SystemDeviceEnum" << hr; + return ret; + } + // Obtain a class enumerator for the video compressor category. + IEnumMoniker *pEnumCat = NULL; + hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); + + if (hr == S_OK) { + // Enumerate the monikers. + IMoniker *pMoniker = NULL; + ULONG cFetched; + while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); + if (SUCCEEDED(hr)) { + // To retrieve the filter's friendly name, do the following: + VARIANT varName; + VariantInit(&varName); + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if (SUCCEEDED(hr)) + { + // Display the name in your UI somehow. + QString str((QChar*)varName.bstrVal, wcslen(varName.bstrVal)); + ret.append(str); + } + VariantClear(&varName); + + ////// To create an instance of the filter, do the following: + ////IBaseFilter *pFilter; + ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, + //// (void**)&pFilter); + // Now add the filter to the graph. + //Remember to release pFilter later. + pPropBag->Release(); + } + pMoniker->Release(); + } + pEnumCat->Release(); + } + else + qDebug() << "failed CLSID_VideoInputDeviceCategory" << hr; + + pSysDevEnum->Release(); +#endif +#ifdef __linux + for (int i = 0; i < 16; i++) { + char buf[128]; + sprintf(buf, "/dev/video%d", i); + if (access(buf, F_OK) == 0) + ret.append(buf); + else + continue; + + if (access(buf, R_OK | W_OK) == 0) { + int fd = open(buf, O_RDONLY); + if (fd == -1) + continue; + struct v4l2_capability video_cap; + if(ioctl(fd, VIDIOC_QUERYCAP, &video_cap) == -1) + { + qDebug() << "VIDIOC_QUERYCAP" << errno; + close(fd); + continue; + } + ret[ret.size()-1] = reinterpret_cast(video_cap.card); + close(fd); + } + } +#endif + return ret; +} \ No newline at end of file diff --git a/opentrack-compat/camera-names.hpp b/opentrack-compat/camera-names.hpp new file mode 100644 index 000000000..c28790009 --- /dev/null +++ b/opentrack-compat/camera-names.hpp @@ -0,0 +1,22 @@ +/* Copyright (c) 2014-2015, 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 +#include + +#ifdef BUILD_compat +# include "compat-export.hpp" +#else +# include "compat-import.hpp" +#endif + +OPENTRACK_COMPAT_EXPORT QList get_camera_names(); +OPENTRACK_COMPAT_EXPORT int camera_name_to_index(const QString &name); + diff --git a/opentrack/CMakeLists.txt b/opentrack/CMakeLists.txt index de5975e23..08003a5cf 100644 --- a/opentrack/CMakeLists.txt +++ b/opentrack/CMakeLists.txt @@ -4,5 +4,4 @@ if(NOT WIN32) else() target_link_libraries(opentrack-api winmm) endif() -link_with_dinput8(opentrack-api) target_link_libraries(opentrack-api opentrack-spline-widget) diff --git a/opentrack/camera-names.cpp b/opentrack/camera-names.cpp deleted file mode 100644 index 74e998ca8..000000000 --- a/opentrack/camera-names.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "camera-names.hpp" - -#if defined(OPENTRACK_API) && defined(_WIN32) -# define NO_DSHOW_STRSAFE -# include -# include -#endif - -#if defined(OPENTRACK_API) && (defined(__unix) || defined(__linux) || defined(__APPLE__)) -# include -#endif - -#ifdef __linux -#include -#include -#include -#include -#endif - -#include - -int camera_name_to_index(const QString &name) -{ - auto list = get_camera_names(); - int ret = list.indexOf(name); - if (ret < 0) - ret = 0; - return ret; -} - -QList get_camera_names() { - QList ret; -#if defined(_WIN32) - // Create the System Device Enumerator. - HRESULT hr; - hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - if (FAILED(hr)) - qDebug() << "failed CoInitializeEx" << hr; - ICreateDevEnum *pSysDevEnum = NULL; - hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); - if (FAILED(hr)) - { - qDebug() << "failed CLSID_SystemDeviceEnum" << hr; - return ret; - } - // Obtain a class enumerator for the video compressor category. - IEnumMoniker *pEnumCat = NULL; - hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); - - if (hr == S_OK) { - // Enumerate the monikers. - IMoniker *pMoniker = NULL; - ULONG cFetched; - while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { - IPropertyBag *pPropBag; - hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); - if (SUCCEEDED(hr)) { - // To retrieve the filter's friendly name, do the following: - VARIANT varName; - VariantInit(&varName); - hr = pPropBag->Read(L"FriendlyName", &varName, 0); - if (SUCCEEDED(hr)) - { - // Display the name in your UI somehow. - QString str((QChar*)varName.bstrVal, wcslen(varName.bstrVal)); - ret.append(str); - } - VariantClear(&varName); - - ////// To create an instance of the filter, do the following: - ////IBaseFilter *pFilter; - ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, - //// (void**)&pFilter); - // Now add the filter to the graph. - //Remember to release pFilter later. - pPropBag->Release(); - } - pMoniker->Release(); - } - pEnumCat->Release(); - } - else - qDebug() << "failed CLSID_VideoInputDeviceCategory" << hr; - - pSysDevEnum->Release(); -#endif -#ifdef __linux - for (int i = 0; i < 16; i++) { - char buf[128]; - sprintf(buf, "/dev/video%d", i); - if (access(buf, F_OK) == 0) - ret.append(buf); - else - continue; - - if (access(buf, R_OK | W_OK) == 0) { - int fd = open(buf, O_RDONLY); - if (fd == -1) - continue; - struct v4l2_capability video_cap; - if(ioctl(fd, VIDIOC_QUERYCAP, &video_cap) == -1) - { - qDebug() << "VIDIOC_QUERYCAP" << errno; - close(fd); - continue; - } - ret[ret.size()-1] = reinterpret_cast(video_cap.card); - close(fd); - } - } -#endif - return ret; -} \ No newline at end of file diff --git a/opentrack/camera-names.hpp b/opentrack/camera-names.hpp deleted file mode 100644 index ef9144588..000000000 --- a/opentrack/camera-names.hpp +++ /dev/null @@ -1,16 +0,0 @@ -/* Copyright (c) 2014-2015, 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 -#include - -QList get_camera_names(); -int camera_name_to_index(const QString &name); - diff --git a/opentrack/opencv-camera-dialog.hpp b/opentrack/opencv-camera-dialog.hpp index 0d4a51af0..96c7a6437 100644 --- a/opentrack/opencv-camera-dialog.hpp +++ b/opentrack/opencv-camera-dialog.hpp @@ -12,7 +12,7 @@ #include #include #include -#include "opentrack/camera-names.hpp" +#include "opentrack-compat/camera-names.hpp" #ifdef __linux #include diff --git a/tracker-aruco/ftnoir_tracker_aruco.cpp b/tracker-aruco/ftnoir_tracker_aruco.cpp index 1da5b8df1..316c7e13d 100644 --- a/tracker-aruco/ftnoir_tracker_aruco.cpp +++ b/tracker-aruco/ftnoir_tracker_aruco.cpp @@ -16,7 +16,7 @@ #include #include #include -#include "opentrack/camera-names.hpp" +#include "opentrack-compat/camera-names.hpp" #include "opentrack-compat/sleep.hpp" typedef struct { diff --git a/tracker-pt/ftnoir_tracker_pt.cpp b/tracker-pt/ftnoir_tracker_pt.cpp index 2dbf9068f..3dd91a457 100644 --- a/tracker-pt/ftnoir_tracker_pt.cpp +++ b/tracker-pt/ftnoir_tracker_pt.cpp @@ -12,7 +12,7 @@ #include #include #include -#include "opentrack/camera-names.hpp" +#include "opentrack-compat/camera-names.hpp" #include "opentrack-compat/sleep.hpp" //#define PT_PERF_LOG //log performance diff --git a/tracker-pt/ftnoir_tracker_pt_dialog.cpp b/tracker-pt/ftnoir_tracker_pt_dialog.cpp index b1ae2238b..551910f77 100644 --- a/tracker-pt/ftnoir_tracker_pt_dialog.cpp +++ b/tracker-pt/ftnoir_tracker_pt_dialog.cpp @@ -12,7 +12,7 @@ #include #include #include -#include "opentrack/camera-names.hpp" +#include "opentrack-compat/camera-names.hpp" #include //----------------------------------------------------------------------------- -- cgit v1.2.3 From 0bd32bf56d5b31e7d7e8288b33f536158903e95e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 03:35:33 +0100 Subject: api/keys: nix tautological #ifdef --- opentrack/keybinding-worker.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index 9ff825a08..461f8416f 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -105,7 +105,6 @@ void KeybindingWorker::run() { } } -#ifdef _WIN32 { using joy_fn = std::function; @@ -124,7 +123,6 @@ void KeybindingWorker::run() { joy_ctx.poll(f); } -#endif for (int i = 0; i < 256; i++) { -- cgit v1.2.3 From 1aa7bceaed59770adeb389d6c4c8f5561d0e7402 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 05:15:07 +0100 Subject: api/keys: use a fake window for DirectInput handle --- opentrack/keybinding-worker.cpp | 6 ++---- opentrack/keybinding-worker.hpp | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index 461f8416f..2ac814af7 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -35,9 +35,6 @@ KeybindingWorker::~KeybindingWorker() { } KeybindingWorker::KeybindingWorker() : -#ifdef _WIN32 - joy_ctx(win32_joy_ctx::make()), -#endif should_quit(true) { if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) { @@ -58,7 +55,8 @@ KeybindingWorker::KeybindingWorker() : din = 0; return; } - if (dinkeyboard->SetCooperativeLevel(GetDesktopWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) { + + if (dinkeyboard->SetCooperativeLevel((HWND) fake_main_window.winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) { dinkeyboard->Release(); din->Release(); din = 0; diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp index c8d8e009d..fa50a9742 100644 --- a/opentrack/keybinding-worker.hpp +++ b/opentrack/keybinding-worker.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -45,11 +46,12 @@ struct OPENTRACK_EXPORT KeybindingWorker : private QThread private: LPDIRECTINPUT8 din; LPDIRECTINPUTDEVICE8 dinkeyboard; - win32_joy_ctx& joy_ctx; + win32_joy_ctx joy_ctx; volatile bool should_quit; using fun = std::function; std::vector> receivers; QMutex mtx; + QMainWindow fake_main_window; void run() override; KeybindingWorker(); -- cgit v1.2.3 From acef508f0b6f16a7be987eeebbb3402455f9aef8 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 05:16:39 +0100 Subject: joystick: no longer singleton, use fake window handle We can create arbitrary amount of dinput handles, given they're passed unique window handles. --- opentrack/win32-joystick.cpp | 60 ++++++++++++++++---------------------------- opentrack/win32-joystick.hpp | 23 +++++++++-------- 2 files changed, 33 insertions(+), 50 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index e3147929b..890924035 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -1,23 +1,9 @@ +#undef NDEBUG +#include #include "win32-joystick.hpp" #ifdef _WIN32 -LPDIRECTINPUT8& win32_joy_ctx::dinput_handle() -{ - (void) CoInitialize(nullptr); - - static LPDIRECTINPUT8 dinput_handle_ = nullptr; - - if (dinput_handle_ == nullptr) - (void) DirectInput8Create(GetModuleHandle(nullptr), - DIRECTINPUT_VERSION, - IID_IDirectInput8, - (void**) &dinput_handle_, - nullptr); - - return dinput_handle_; -} - std::unordered_map>& win32_joy_ctx::joys() { static std::unordered_map> js; @@ -25,12 +11,6 @@ std::unordered_map>& win32_joy_ctx: return js; } -win32_joy_ctx& win32_joy_ctx::make() -{ - static win32_joy_ctx ret; - return ret; -} - void win32_joy_ctx::poll(fn f) { refresh(false); @@ -117,17 +97,18 @@ std::vector win32_joy_ctx::get_joy_info() win32_joy_ctx::win32_joy_ctx() { + if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&di, NULL) != DI_OK) { + qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); + assert(!"direct input handle can't be created"); + } refresh(true); } void win32_joy_ctx::release() { joys() = std::unordered_map>(); - { - auto& di = dinput_handle(); - di->Release(); - di = nullptr; - } + di->Release(); + di = nullptr; } void win32_joy_ctx::refresh(bool first) @@ -141,7 +122,7 @@ void win32_joy_ctx::refresh(bool first) timer_joylist.start(); } - enum_state st(joys(), first, mtx); + enum_state st(joys(), mtx, fake_main_window, di); } QString win32_joy_ctx::guid_to_string(const GUID guid) @@ -193,12 +174,10 @@ bool win32_joy_ctx::joy::poll(fn f) return false; } - first |= first_timer.elapsed_ms() > first_event_delay_ms; - for (int i = 0; i < 128; i++) { const bool state = !!(js.rgbButtons[i] & 0x80); - if (state != pressed[i] && first) + if (state != pressed[i]) { f(guid, i, state); qDebug() << "btn" << guid << i << state; @@ -209,15 +188,19 @@ bool win32_joy_ctx::joy::poll(fn f) return true; } -win32_joy_ctx::enum_state::enum_state(std::unordered_map > &joys, bool first, QMutex& mtx) : first(first) +win32_joy_ctx::enum_state::enum_state(std::unordered_map> &joys, + QMutex& mtx, + QMainWindow &fake_main_window, + LPDIRECTINPUT8 di) : + fake_main_window(fake_main_window), + di(di) { - HRESULT hr; - LPDIRECTINPUT8 di = dinput_handle(); - { QMutexLocker l(&mtx); this->joys = joys; } + + HRESULT hr; if(FAILED(hr = di->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, @@ -257,8 +240,7 @@ win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINSTANCE *pdidIns { HRESULT hr; LPDIRECTINPUTDEVICE8 h; - LPDIRECTINPUT8 di = dinput_handle(); - if (FAILED(hr = di->CreateDevice(pdidInstance->guidInstance, &h, nullptr))) + if (FAILED(hr = state.di->CreateDevice(pdidInstance->guidInstance, &h, nullptr))) { qDebug() << "createdevice" << guid << hr; goto end; @@ -270,7 +252,7 @@ win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINSTANCE *pdidIns goto end; } - if (FAILED(h->SetCooperativeLevel((HWND) GetDesktopWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) + if (FAILED(h->SetCooperativeLevel((HWND) state.fake_main_window.winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) { qDebug() << "coop"; h->Release(); @@ -284,7 +266,7 @@ win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINSTANCE *pdidIns } qDebug() << "add joy" << guid; - state.joys[guid] = std::make_shared(h, guid, name, state.first); + state.joys[guid] = std::make_shared(h, guid, name); } end: return DIENUM_CONTINUE; diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp index 421774a9a..f7629c3d9 100644 --- a/opentrack/win32-joystick.hpp +++ b/opentrack/win32-joystick.hpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace std { template<> @@ -49,21 +50,23 @@ struct OPENTRACK_EXPORT win32_joy_ctx void poll(fn f); bool poll_axis(const QString& guid, int axes[8]); - ~win32_joy_ctx(); std::vector get_joy_info(); - static win32_joy_ctx& make(); + win32_joy_ctx(const win32_joy_ctx&) = delete; win32_joy_ctx& operator=(const win32_joy_ctx&) = delete; + win32_joy_ctx(); + ~win32_joy_ctx(); + private: enum { joylist_refresh_ms = 100 }; QMutex mtx; Timer timer_joylist; + QMainWindow fake_main_window; + LPDIRECTINPUT8 di; static QString guid_to_string(const GUID guid); - static LPDIRECTINPUT8& dinput_handle(); - win32_joy_ctx(); void release(); void refresh(bool first); @@ -72,16 +75,13 @@ private: struct joy { - enum { first_event_delay_ms = 3000 }; - LPDIRECTINPUTDEVICE8 joy_handle; QString guid, name; bool pressed[128]; Timer first_timer; - bool first; - joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name, bool first) - : joy_handle(handle), guid(guid), name(name), first(first) + joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name) + : joy_handle(handle), guid(guid), name(name) { qDebug() << "got joy" << guid; for (int i = 0; i < 128; i++) @@ -101,13 +101,14 @@ private: class enum_state { std::unordered_map> joys; - bool first; + QMainWindow& fake_main_window; + LPDIRECTINPUT8 di; std::vector all; static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext); static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx); public: - enum_state(std::unordered_map>& joys, bool first, QMutex &mtx); + enum_state(std::unordered_map>& joys, QMutex &mtx, QMainWindow& fake_main_window, LPDIRECTINPUT8 di); }; }; -- cgit v1.2.3 From 5076d0c35eacb2e7b246e7bd5e6637086ea74a15 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 05:23:04 +0100 Subject: api/joy: nix static, now that we're not a singleton --- opentrack/win32-joystick.cpp | 19 ++++++------------- opentrack/win32-joystick.hpp | 5 ++--- 2 files changed, 8 insertions(+), 16 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index 890924035..78720c793 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -4,20 +4,13 @@ #ifdef _WIN32 -std::unordered_map>& win32_joy_ctx::joys() -{ - static std::unordered_map> js; - - return js; -} - void win32_joy_ctx::poll(fn f) { refresh(false); QMutexLocker l(&mtx); - for (auto& j : joys()) + for (auto& j : joys) { j.second->poll(f); } @@ -29,9 +22,9 @@ bool win32_joy_ctx::poll_axis(const QString &guid, int axes[]) QMutexLocker l(&mtx); - auto iter = joys().find(guid); + auto iter = joys.find(guid); - if (iter == joys().end()) + if (iter == joys.end()) return false; auto& j = iter->second; @@ -89,7 +82,7 @@ std::vector win32_joy_ctx::get_joy_info() std::vector ret; - for (auto& j : joys()) + for (auto& j : joys) ret.push_back(joy_info { j.second->name, j.first }); return ret; @@ -106,7 +99,7 @@ win32_joy_ctx::win32_joy_ctx() void win32_joy_ctx::release() { - joys() = std::unordered_map>(); + joys = std::unordered_map>(); di->Release(); di = nullptr; } @@ -122,7 +115,7 @@ void win32_joy_ctx::refresh(bool first) timer_joylist.start(); } - enum_state st(joys(), mtx, fake_main_window, di); + enum_state st(joys, mtx, fake_main_window, di); } QString win32_joy_ctx::guid_to_string(const GUID guid) diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp index f7629c3d9..e68ea2c69 100644 --- a/opentrack/win32-joystick.hpp +++ b/opentrack/win32-joystick.hpp @@ -70,9 +70,6 @@ private: void release(); void refresh(bool first); - struct joy; - static std::unordered_map>& joys(); - struct joy { LPDIRECTINPUTDEVICE8 joy_handle; @@ -97,6 +94,8 @@ private: void release(); bool poll(fn f); }; + + std::unordered_map> joys; class enum_state { -- cgit v1.2.3 From b31e4997de81efc3941072cc48b5f09064e62e81 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 05:59:36 +0100 Subject: api/joy: speed up poll_axis path We don't really need to poll for joysticks in tracker/joy. --- opentrack/win32-joystick.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index 78720c793..f4bfba769 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -18,7 +18,7 @@ void win32_joy_ctx::poll(fn f) bool win32_joy_ctx::poll_axis(const QString &guid, int axes[]) { - refresh(false); + //refresh(false); QMutexLocker l(&mtx); -- cgit v1.2.3 From 75b4a6e3a32b4345941e15953d55572384eb210e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 20:13:42 +0100 Subject: api/joy: prevent idempotent keypressed passed to receiver --- opentrack/win32-joystick.cpp | 4 +++- opentrack/win32-joystick.hpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index f4bfba769..73e27f804 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -169,7 +169,7 @@ bool win32_joy_ctx::joy::poll(fn f) for (int i = 0; i < 128; i++) { - const bool state = !!(js.rgbButtons[i] & 0x80); + const bool state = !!(js.rgbButtons[i] & 0x80) && js.rgbButtons[i] != js_old.rgbButtons[i]; if (state != pressed[i]) { f(guid, i, state); @@ -178,6 +178,8 @@ bool win32_joy_ctx::joy::poll(fn f) pressed[i] = state; } + js_old = js; + return true; } diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp index e68ea2c69..df00aee7b 100644 --- a/opentrack/win32-joystick.hpp +++ b/opentrack/win32-joystick.hpp @@ -76,6 +76,7 @@ private: QString guid, name; bool pressed[128]; Timer first_timer; + DIJOYSTATE2 js_old; joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name) : joy_handle(handle), guid(guid), name(name) -- cgit v1.2.3 From 4864dfaa4b455905fece5cd93502b80890d1b2d2 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 20:13:56 +0100 Subject: api/joy: move from header --- opentrack/win32-joystick.cpp | 15 +++++++++++++++ opentrack/win32-joystick.hpp | 17 +++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) (limited to 'opentrack') diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index 73e27f804..728e2f68b 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -292,4 +292,19 @@ win32_joy_ctx::enum_state::EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE *pdi return DIENUM_CONTINUE; } +win32_joy_ctx::joy::joy(LPDIRECTINPUTDEVICE8 handle, const QString &guid, const QString &name) + : joy_handle(handle), guid(guid), name(name) +{ + qDebug() << "got joy" << guid; + for (int i = 0; i < 128; i++) + pressed[i] = false; + memset(&js_old, 0, sizeof(js_old)); +} + +win32_joy_ctx::joy::~joy() +{ + qDebug() << "nix joy" << guid; + release(); +} + #endif diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp index df00aee7b..6d5e1074f 100644 --- a/opentrack/win32-joystick.hpp +++ b/opentrack/win32-joystick.hpp @@ -24,7 +24,7 @@ namespace std { template<> struct hash { - std::size_t operator()(const QString& value) const + inline std::size_t operator()(const QString& value) const { return qHash(value); } @@ -78,19 +78,8 @@ private: Timer first_timer; DIJOYSTATE2 js_old; - joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name) - : joy_handle(handle), guid(guid), name(name) - { - qDebug() << "got joy" << guid; - for (int i = 0; i < 128; i++) - pressed[i] = false; - } - - ~joy() - { - qDebug() << "nix joy" << guid; - release(); - } + joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name); + ~joy(); void release(); bool poll(fn f); -- cgit v1.2.3 From d6eb142710e6ac307b4c5c0e0a54166852d71cbc Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sun, 6 Dec 2015 20:14:09 +0100 Subject: api/keys: prevent idempotent keys --- opentrack/keybinding-worker.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index 2ac814af7..b0cef22d8 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -85,6 +85,7 @@ KeybindingWorker& KeybindingWorker::make() void KeybindingWorker::run() { BYTE keystate[256] = {0}; + BYTE old_keystate[256] = {0}; while (!should_quit) { @@ -125,7 +126,7 @@ void KeybindingWorker::run() { for (int i = 0; i < 256; i++) { Key k; - if (keystate[i] & 0x80) + if (old_keystate[i] != keystate[i] && keystate[i] & 0x80) { switch (i) { @@ -147,6 +148,7 @@ void KeybindingWorker::run() { break; } } + old_keystate[i] = keystate[i]; } } } -- cgit v1.2.3 From 4821c0337a64ada6db44a6ccbb84f6067d898d4b Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 17 Dec 2015 10:25:55 +0100 Subject: cmake/api: link with strmiids.lib on win32 It worked by accident since cmake/compat already links to it. --- opentrack/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'opentrack') diff --git a/opentrack/CMakeLists.txt b/opentrack/CMakeLists.txt index 08003a5cf..6baa05db6 100644 --- a/opentrack/CMakeLists.txt +++ b/opentrack/CMakeLists.txt @@ -5,3 +5,4 @@ else() target_link_libraries(opentrack-api winmm) endif() target_link_libraries(opentrack-api opentrack-spline-widget) +link_with_dinput8(opentrack-api) -- cgit v1.2.3 From 3e543b11f57aa6c010045fb9614eb2638ac6ae81 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 17 Dec 2015 22:52:54 +0100 Subject: api/joy: refresh only manually on certain events Refresh joylist when new listener arrives, and when the joy singleton just gets created. Enumerating joys all the time causes high CPU usage for some of the users. Issue: #279 Backtrace-by: @exulant Reported-by: @aka2k --- opentrack/keybinding-worker.cpp | 1 + opentrack/win32-joystick.cpp | 25 +++++++------------------ opentrack/win32-joystick.hpp | 8 ++------ 3 files changed, 10 insertions(+), 24 deletions(-) (limited to 'opentrack') diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp index b0cef22d8..39693a7cb 100644 --- a/opentrack/keybinding-worker.cpp +++ b/opentrack/keybinding-worker.cpp @@ -164,6 +164,7 @@ KeybindingWorker::fun* KeybindingWorker::_add_receiver(fun& receiver) receivers.push_back(std::unique_ptr(new fun(receiver))); fun* f = receivers[receivers.size() - 1].get(); qDebug() << "add receiver" << (long) f; + joy_ctx.refresh(); return f; } diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp index 728e2f68b..5e6f20116 100644 --- a/opentrack/win32-joystick.cpp +++ b/opentrack/win32-joystick.cpp @@ -6,7 +6,7 @@ void win32_joy_ctx::poll(fn f) { - refresh(false); + //refresh(false); QMutexLocker l(&mtx); @@ -94,7 +94,7 @@ win32_joy_ctx::win32_joy_ctx() qDebug() << "setup DirectInput8 Creation failed!" << GetLastError(); assert(!"direct input handle can't be created"); } - refresh(true); + refresh(); } void win32_joy_ctx::release() @@ -104,18 +104,12 @@ void win32_joy_ctx::release() di = nullptr; } -void win32_joy_ctx::refresh(bool first) +void win32_joy_ctx::refresh() { - if (!first) - { - // accessing struct Timer without a lock. worst can happen is seconds - // and nanoseconds getting out of sync. no big deal. - if (timer_joylist.elapsed_ms() < joylist_refresh_ms) - return; - timer_joylist.start(); - } + QMutexLocker l(&mtx); - enum_state st(joys, mtx, fake_main_window, di); + qDebug() << "joy list refresh"; + enum_state st(joys, fake_main_window, di); } QString win32_joy_ctx::guid_to_string(const GUID guid) @@ -184,16 +178,12 @@ bool win32_joy_ctx::joy::poll(fn f) } win32_joy_ctx::enum_state::enum_state(std::unordered_map> &joys, - QMutex& mtx, QMainWindow &fake_main_window, LPDIRECTINPUT8 di) : fake_main_window(fake_main_window), di(di) { - { - QMutexLocker l(&mtx); - this->joys = joys; - } + this->joys = joys; HRESULT hr; @@ -216,7 +206,6 @@ win32_joy_ctx::enum_state::enum_state(std::unordered_mapjoys; } diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp index 6d5e1074f..9c888326d 100644 --- a/opentrack/win32-joystick.hpp +++ b/opentrack/win32-joystick.hpp @@ -57,18 +57,14 @@ struct OPENTRACK_EXPORT win32_joy_ctx win32_joy_ctx(); ~win32_joy_ctx(); - + void refresh(); private: - enum { joylist_refresh_ms = 100 }; - QMutex mtx; - Timer timer_joylist; QMainWindow fake_main_window; LPDIRECTINPUT8 di; static QString guid_to_string(const GUID guid); void release(); - void refresh(bool first); struct joy { @@ -97,7 +93,7 @@ private: static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext); static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* ctx); public: - enum_state(std::unordered_map>& joys, QMutex &mtx, QMainWindow& fake_main_window, LPDIRECTINPUT8 di); + enum_state(std::unordered_map>& joys, QMainWindow& fake_main_window, LPDIRECTINPUT8 di); }; }; -- cgit v1.2.3 From f53f0c3ebb3553543dcd0814d6d1fe54faef030e Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 18 Dec 2015 00:54:45 +0100 Subject: api/mat: fix typos/breakage --- opentrack/simple-mat.hpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'opentrack') diff --git a/opentrack/simple-mat.hpp b/opentrack/simple-mat.hpp index 59afbbf03..4f885f4f9 100644 --- a/opentrack/simple-mat.hpp +++ b/opentrack/simple-mat.hpp @@ -157,7 +157,7 @@ public: return ret; } - Mat operator*(const num& other) const + Mat operator*(const num other) const { Mat ret; for (int j = 0; j < h_; j++) @@ -167,20 +167,16 @@ public: } template - Mat operator*(const Mat& other) const + Mat operator*(const Mat& other) const { - Mat ret; - for (int j = 0; j < w_; j++) + Mat ret; + for (int k = 0; k < h_; k++) for (int i = 0; i < p; i++) { - num sum = num(0); - - for (int k = 0; k < h_; k++) - sum += data[j][k]*other(k, i); - - ret(j, i) = sum; + ret(k, i) = 0; + for (int j = 0; j < w_; j++) + ret(k, i) += data[k][j] * other(j, i); } - return ret; } @@ -189,7 +185,7 @@ public: template::value>::type> - Mat(ts const&... xs) + Mat(const ts... xs) { const std::initializer_list init = { static_cast(xs)... }; auto iter = init.begin(); @@ -236,7 +232,7 @@ public: for (int j = 0; j < h_; j++) for (int i = 0; i < w_; i++) - ret.data[i][j] = data[j][i]; + ret(i, j) = data[j][i]; return ret; } -- cgit v1.2.3