From acef508f0b6f16a7be987eeebbb3402455f9aef8 Mon Sep 17 00:00:00 2001
From: Stanislaw Halik <sthalik@misaki.pl>
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(-)

diff --git a/opentrack/win32-joystick.cpp b/opentrack/win32-joystick.cpp
index e3147929..89092403 100644
--- a/opentrack/win32-joystick.cpp
+++ b/opentrack/win32-joystick.cpp
@@ -1,23 +1,9 @@
+#undef NDEBUG
+#include <cassert>
 #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<QString, std::shared_ptr<win32_joy_ctx::joy>>& win32_joy_ctx::joys()
 {
     static std::unordered_map<QString, std::shared_ptr<joy>> js;
@@ -25,12 +11,6 @@ std::unordered_map<QString, std::shared_ptr<win32_joy_ctx::joy>>& 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::joy_info> 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<QString, std::shared_ptr<joy>>();
-    {
-        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<QString, std::shared_ptr<joy> > &joys, bool first, QMutex& mtx) : first(first)
+win32_joy_ctx::enum_state::enum_state(std::unordered_map<QString, std::shared_ptr<joy>> &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<joy>(h, guid, name, state.first);
+        state.joys[guid] = std::make_shared<joy>(h, guid, name);
     }
 end:
     return DIENUM_CONTINUE;
diff --git a/opentrack/win32-joystick.hpp b/opentrack/win32-joystick.hpp
index 421774a9..f7629c3d 100644
--- a/opentrack/win32-joystick.hpp
+++ b/opentrack/win32-joystick.hpp
@@ -18,6 +18,7 @@
 #include <QDebug>
 #include <QMutex>
 #include <QMutexLocker>
+#include <QMainWindow>
 
 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<joy_info> 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<QString, std::shared_ptr<joy>> joys;
-        bool first;
+        QMainWindow& fake_main_window;
+        LPDIRECTINPUT8 di;
         
         std::vector<QString> 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<QString, std::shared_ptr<joy>>& joys, bool first, QMutex &mtx);
+        enum_state(std::unordered_map<QString, std::shared_ptr<joy>>& joys, QMutex &mtx, QMainWindow& fake_main_window, LPDIRECTINPUT8 di);
     };
 };
 
-- 
cgit v1.2.3