From 8dca727968bf64c8aa89cce09172f101c2ade069 Mon Sep 17 00:00:00 2001
From: Stanislaw Halik <sthalik@misaki.pl>
Date: Sun, 1 Nov 2015 11:44:42 +0100
Subject: shortcuts: separate keybinding worker to another file

---
 opentrack/shortcuts.cpp | 104 +-----------------------------------------------
 1 file changed, 1 insertion(+), 103 deletions(-)

(limited to 'opentrack/shortcuts.cpp')

diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp
index a33cf088..5f5ad922 100644
--- a/opentrack/shortcuts.cpp
+++ b/opentrack/shortcuts.cpp
@@ -7,110 +7,8 @@
  */
 
 #include "shortcuts.h"
-#include <QMutexLocker>
-
-#if defined(_WIN32)
-#include <functional>
-#include <windows.h>
 #include "win32-shortcuts.h"
-
-KeybindingWorker::~KeybindingWorker() {
-    should_quit = true;
-    wait();
-    if (dinkeyboard) {
-        dinkeyboard->Unacquire();
-        dinkeyboard->Release();
-    }
-    if (din)
-        din->Release();
-}
-
-KeybindingWorker::KeybindingWorker(std::function<void(Key&)> receiver, WId h) :
-    should_quit(true), receiver(receiver)
-{
-    HWND handle = reinterpret_cast<HWND>(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 <QMutexLocker>
 
 void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k)
 {
-- 
cgit v1.2.3


From 2d90e4039c6dd1aab00c738f9bbc70a4949cd583 Mon Sep 17 00:00:00 2001
From: Stanislaw Halik <sthalik@misaki.pl>
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/shortcuts.cpp')

diff --git a/gui/keyboard.h b/gui/keyboard.h
index 03edacc7..aa4b4a24 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<QVariant>(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<QVariant>(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 2778be0f..c8bf668d 100644
--- a/gui/options-dialog.cpp
+++ b/gui/options-dialog.cpp
@@ -12,9 +12,18 @@
 #include <QLayout>
 #include <QDialog>
 
+static QString kopts_to_string(const Shortcuts::key_opts& kopts)
+{
+    if (static_cast<QString>(kopts.guid) != "")
+        return "Joystick button " + QString::number(kopts.button);
+    if (static_cast<QString>(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<QString>(s.center.keycode));
-    ui.toggle_text->setText(s.toggle.keycode == "" ? "None" : static_cast<QString>(s.toggle.keycode));
-    ui.zero_text->setText(s.zero.keycode == "" ? "None" : static_cast<QString>(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<QString>& 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<QString>& 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<QString>(ret));
+    label->setText(kopts_to_string(kopts));
     delete k;
     delete l;
 }
diff --git a/gui/options-dialog.hpp b/gui/options-dialog.hpp
index 3ef99d06..308b5b0f 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<QString>& 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 29b2cf9f..e6c023ef 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<void(const QString& guid, int idx)>;
+            
+            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 e720ffdc..8cf59d65 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 <QThread>
 #include <QMutex>
 #include <QWidget>
@@ -27,6 +28,7 @@
 #   include <dinput.h>
 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<void(Key&)> receiver;
diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp
index 5f5ad922..0d7f79b9 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<K*> 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 84231850..1643485e 100644
--- a/opentrack/shortcuts.h
+++ b/opentrack/shortcuts.h
@@ -47,10 +47,13 @@ public:
 #endif
     
     struct key_opts {
-        value<QString> keycode;
+        value<QString> keycode, guid;
+        value<int> 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 00000000..67465bce
--- /dev/null
+++ b/opentrack/win32-joystick-shortcuts.hpp
@@ -0,0 +1,264 @@
+#pragma once
+
+#include <cstring>
+#include <memory>
+#include <vector>
+#include <functional>
+#include <algorithm>
+#ifndef DIRECTINPUT_VERSION
+#   define DIRECTINPUT_VERSION 0x800
+#endif
+#include <dinput.h>
+#include <windows.h>
+#include "opentrack-compat/timer.hpp"
+#include <QString>
+#include <QDebug>
+
+struct win32_joy_ctx
+{
+    using fn = std::function<void(const QString& guid, int btn)>;
+    
+    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<std::shared_ptr<joy>>();
+        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<std::shared_ptr<joy>>& joys;
+        std::vector<QString> all;
+        LPDIRECTINPUT8 dinput_handle;
+        
+        enum_state(LPDIRECTINPUT8 di, std::vector<std::shared_ptr<joy>>& 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<enum_state*>(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<joy>& 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<joy>(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<LPDIRECTINPUTDEVICE8>(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph)))
+                    return DIENUM_STOP;
+            }
+            
+            return DIENUM_CONTINUE;
+        }
+#endif
+    };
+    
+    LPDIRECTINPUT8 dinput_handle;
+    std::vector<std::shared_ptr<joy>> joys;
+    Timer timer_joylist;
+    enum { joylist_refresh_ms = 2000 };
+};
\ No newline at end of file
-- 
cgit v1.2.3


From 605d267622b8d2e69bc761f4f49442566164d843 Mon Sep 17 00:00:00 2001
From: Stanislaw Halik <sthalik@misaki.pl>
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/shortcuts.cpp')

diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp
index 0d7f79b9..108b6b3b 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 c8805112acca1ba3bd0056fcf0b9332c4ba10f03 Mon Sep 17 00:00:00 2001
From: Stanislaw Halik <sthalik@misaki.pl>
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/shortcuts.cpp')

diff --git a/gui/keyboard.h b/gui/keyboard.h
index b840bc78..75226aa3 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 e9255801..fd777211 100644
--- a/opentrack/keybinding-worker.cpp
+++ b/opentrack/keybinding-worker.cpp
@@ -68,16 +68,29 @@ KeybindingWorker::KeybindingWorker(std::function<void(Key&)> 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<void(const QString& guid, int idx, bool held)>;
             
             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 108b6b3b..6eab6071 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 42217bbb858ddb158ad13777e2aace942aaf9525 Mon Sep 17 00:00:00 2001
From: Stanislaw Halik <sthalik@misaki.pl>
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/shortcuts.cpp')

diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp
index fd777211..31eb9e80 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 cb3e5f9f..b5d63fac 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 6eab6071..059febdb 100644
--- a/opentrack/shortcuts.cpp
+++ b/opentrack/shortcuts.cpp
@@ -8,7 +8,6 @@
 
 #include "shortcuts.h"
 #include "win32-shortcuts.h"
-#include <QMutexLocker>
 
 void Shortcuts::bind_keyboard_shortcut(K &key, key_opts& k)
 {
-- 
cgit v1.2.3


From bf5931532f91107747cc45befffb5cc189777c89 Mon Sep 17 00:00:00 2001
From: Stanislaw Halik <sthalik@misaki.pl>
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/shortcuts.cpp')

diff --git a/gui/keyboard.h b/gui/keyboard.h
index 75226aa3..696df605 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<QVariant>(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 059febdb..b961294f 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<K*> 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<KeybindingWorker>([&](Key& k) { receiver(k); }, handle);
-        keybindingWorker->start();
-    }
-#endif
 }
diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h
index 1643485e..930952e8 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;
+    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 5d1f6b54..e338e9f4 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<Tracker>(s, m, libs)),
-        sc(std::make_shared<Shortcuts>(handle)),
+        sc(std::make_shared<Shortcuts>()),
         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 86708a2311c1a3efd975798ff42d934eea0078ed Mon Sep 17 00:00:00 2001
From: Stanislaw Halik <sthalik@misaki.pl>
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/shortcuts.cpp')

diff --git a/gui/options-dialog.cpp b/gui/options-dialog.cpp
index 9631d41e..70d5be62 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 fc6d4754..c3e47912 100644
--- a/gui/ui.cpp
+++ b/gui/ui.cpp
@@ -281,7 +281,7 @@ void MainWindow::startTracker() {
         return;
     }
     
-    work = std::make_shared<Work>(s, pose, libs, this, winId());
+    work = std::make_shared<Work>(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 44bcde0c..b4bab271 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 b961294f..560a31ab 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<K*> 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<std::tuple<key_opts&, fun> > &keys_)
+{
+    const int sz = keys_.size();
+    keys = std::vector<tt>();
+    
+    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, Shortcuts::fun>(k, fun));
+#ifndef _WIN32
+        connect(k.get(), &QGlobalShortcut::activated, fun);
+#endif
+    }
 }
diff --git a/opentrack/shortcuts.h b/opentrack/shortcuts.h
index 8acc5ba5..4dec7c2c 100644
--- a/opentrack/shortcuts.h
+++ b/opentrack/shortcuts.h
@@ -8,6 +8,9 @@
 
 #pragma once
 #include <QObject>
+#include <tuple>
+#include <vector>
+#include <functional>
 
 #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<void(void)>;
+    using tt = std::tuple<K, fun>;
+    std::vector<tt> 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<std::tuple<Shortcuts::key_opts &, Shortcuts::fun> > &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 e26c3f7a..36b5cad4 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 e338e9f4..a3c0e014 100644
--- a/opentrack/work.hpp
+++ b/opentrack/work.hpp
@@ -16,6 +16,9 @@
 #include <QObject>
 #include <QFrame>
 #include <memory>
+#include <vector>
+#include <functional>
+#include <tuple>
 
 struct Work
 {
@@ -24,28 +27,29 @@ struct Work
     mem<Tracker> tracker;
     mem<Shortcuts> sc;
     WId handle;
-
-    Work(main_settings& s, Mappings& m, SelectedLibraries& libs, QObject* recv, WId handle) :
+    using fn = std::function<void(void)>;
+    using key_opts = Shortcuts::key_opts;
+    using tt = std::tuple<key_opts&, fn>;
+    std::vector<std::tuple<key_opts&, fn>> keys;
+    
+    Work(main_settings& s, Mappings& m, SelectedLibraries& libs, WId handle) :
         s(s), libs(libs),
         tracker(std::make_shared<Tracker>(s, m, libs)),
         sc(std::make_shared<Shortcuts>()),
-        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 ae1faae5d963b75a0b04bf69e77fc0ee12d2232d Mon Sep 17 00:00:00 2001
From: Stanislaw Halik <sthalik@misaki.pl>
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/shortcuts.cpp')

diff --git a/opentrack/shortcuts.cpp b/opentrack/shortcuts.cpp
index 560a31ab..bab1283a 100644
--- a/opentrack/shortcuts.cpp
+++ b/opentrack/shortcuts.cpp
@@ -99,7 +99,7 @@ void Shortcuts::reload(const std::vector<std::tuple<key_opts&, fun> > &keys_)
         bind_keyboard_shortcut(k, opts);
         keys.push_back(std::tuple<K, Shortcuts::fun>(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 f8343ad8..38037923 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