summaryrefslogtreecommitdiffhomepage
path: root/dinput
diff options
context:
space:
mode:
Diffstat (limited to 'dinput')
-rw-r--r--dinput/dinput.cpp62
-rw-r--r--dinput/dinput.hpp26
-rw-r--r--dinput/keybinding-worker.cpp29
-rw-r--r--dinput/keybinding-worker.hpp17
-rw-r--r--dinput/win32-joystick.cpp82
-rw-r--r--dinput/win32-joystick.hpp17
6 files changed, 114 insertions, 119 deletions
diff --git a/dinput/dinput.cpp b/dinput/dinput.cpp
index 8a3d0f4a..22781a32 100644
--- a/dinput/dinput.cpp
+++ b/dinput/dinput.cpp
@@ -1,21 +1,23 @@
#include "dinput.hpp"
+#include "compat/macros.hpp"
+
#include <QDebug>
-std::atomic<int> di_t::refcnt;
-std::atomic_flag di_t::init_lock = ATOMIC_FLAG_INIT;
+int di_t::refcnt{0};
diptr di_t::handle;
+QMutex di_t::lock;
diptr di_t::init_di_()
{
CoInitialize(nullptr);
diptr di = nullptr;
- if (HRESULT hr = DirectInput8Create(GetModuleHandle(nullptr),
- DIRECTINPUT_VERSION,
- IID_IDirectInput8,
- (void**)&di,
- nullptr);
- !SUCCEEDED(hr))
+ HRESULT hr = DirectInput8Create(GetModuleHandle(nullptr),
+ DIRECTINPUT_VERSION,
+ IID_IDirectInput8,
+ (void**)&di,
+ nullptr);
+ if (!SUCCEEDED(hr))
{
qDebug() << "can't make dinput:" << (void*)(LONG_PTR)hr;
qDebug() << "crashing!";
@@ -32,28 +34,24 @@ di_t::di_t()
void di_t::ref_di()
{
- while (init_lock.test_and_set()) { /* busy loop */ }
+ QMutexLocker l(&lock);
if (!handle)
handle = init_di_();
++refcnt;
-
- init_lock.clear();
}
void di_t::unref_di()
{
+ QMutexLocker l(&lock);
+
const int refcnt_ = --refcnt;
if (refcnt_ == 0)
{
- while (init_lock.test_and_set()) { /* busy loop */ }
-
qDebug() << "exit: di handle";
handle->Release();
-
- init_lock.clear();
}
}
@@ -62,3 +60,37 @@ di_t::~di_t()
unref_di();
}
+bool di_t::poll_device(LPDIRECTINPUTDEVICE8 dev)
+{
+ HRESULT hr;
+
+ switch (dev->Poll())
+ {
+ case DI_OK:
+ case DI_NOEFFECT:
+ return true;
+ default:
+ break;
+ }
+
+ switch (hr = dev->Acquire())
+ {
+ default:
+ break;
+ case DI_OK:
+ case S_FALSE:
+ switch (hr = dev->Poll())
+ {
+ case DI_OK:
+ case DI_NOEFFECT:
+ return true;
+ default:
+ break;
+ }
+ break;
+ }
+
+ eval_once(qDebug() << "dinput: device poll failed:" << (void*)hr);
+
+ return false;
+}
diff --git a/dinput/dinput.hpp b/dinput/dinput.hpp
index a9241504..394084e2 100644
--- a/dinput/dinput.hpp
+++ b/dinput/dinput.hpp
@@ -8,15 +8,19 @@
#pragma once
-#include "export.hpp"
+#include <QMutex>
-#include <atomic>
+#include "export.hpp"
#undef DIRECTINPUT_VERSION
#define DIRECTINPUT_VERSION 0x800
#include <dinput.h>
+// XXX TODO -sh 20190209
+// keybinding_worker and joystick context are badly named
+// add namespaces and rename, including inner joystick device struct
+
using diptr = IDirectInput8A*;
class OTR_DINPUT_EXPORT di_t final
@@ -25,8 +29,8 @@ class OTR_DINPUT_EXPORT di_t final
static void ref_di();
static diptr handle;
- static std::atomic<int> refcnt;
- static std::atomic_flag init_lock;
+ static int refcnt;
+ static QMutex lock;
static diptr init_di_();
public:
@@ -36,16 +40,8 @@ public:
di_t& operator=(const di_t&) = default;
diptr operator->() const { return handle; }
- operator bool() { return handle != nullptr; }
+ operator bool() const { return handle != nullptr; }
+ operator diptr() const { return handle; }
- // for debugging bad usages. must use a dependent name.
- template<typename t = void>
- explicit operator void*() const
- {
- static_assert(sizeof(t) == -1);
- static_assert(sizeof(t) == 0);
-
- return nullptr;
- }
+ static bool poll_device(LPDIRECTINPUTDEVICE8 dev);
};
-
diff --git a/dinput/keybinding-worker.cpp b/dinput/keybinding-worker.cpp
index a3331323..3d792778 100644
--- a/dinput/keybinding-worker.cpp
+++ b/dinput/keybinding-worker.cpp
@@ -48,12 +48,12 @@ bool KeybindingWorker::init()
}
if (din->CreateDevice(GUID_SysKeyboard, &dinkeyboard, nullptr) != DI_OK) {
- qDebug() << "setup CreateDevice function failed!" << GetLastError();
+ qDebug() << "dinput: create keyboard failed" << GetLastError();
return false;
}
if (dinkeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK) {
- qDebug() << "setup SetDataFormat function failed!" << GetLastError();
+ qDebug() << "dinput: keyboard SetDataFormat" << GetLastError();
dinkeyboard->Release();
dinkeyboard = nullptr;
return false;
@@ -62,34 +62,26 @@ bool KeybindingWorker::init()
if (dinkeyboard->SetCooperativeLevel((HWND) fake_main_window.winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) {
dinkeyboard->Release();
dinkeyboard = nullptr;
- qDebug() << "setup SetCooperativeLevel function failed!" << GetLastError();
+ qDebug() << "dinput: keyboard SetCooperativeLevel" << GetLastError();
return false;
}
{
DIPROPDWORD dipdw;
- dipdw.dwData = 128;
+ dipdw.dwData = num_keyboard_states;
dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.diph.dwObj = 0;
dipdw.diph.dwSize = sizeof(dipdw);
if ( dinkeyboard->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph) != DI_OK)
{
- qDebug() << "setup keyboard buffer mode failed!";
+ qDebug() << "dinput: DIPROP_BUFFERSIZE";
dinkeyboard->Release();
dinkeyboard = nullptr;
return false;
}
}
- if (dinkeyboard->Acquire() != DI_OK)
- {
- dinkeyboard->Release();
- dinkeyboard = nullptr;
- qDebug() << "setup dinkeyboard Acquire failed!" << GetLastError();
- return false;
- }
-
return true;
}
@@ -142,12 +134,15 @@ bool KeybindingWorker::run_keyboard_nolock()
* Key-up events work on my end.
*/
+ if (!di_t::poll_device(dinkeyboard))
+ eval_once(qDebug() << "dinput: keyboard poll failed");
+
DWORD sz = num_keyboard_states;
- const HRESULT hr = dinkeyboard->GetDeviceData(sizeof(*keyboard_states), keyboard_states, &sz, 0);
+ HRESULT hr = dinkeyboard->GetDeviceData(sizeof(*keyboard_states), keyboard_states, &sz, 0);
- if (hr != DI_OK)
+ if (FAILED(hr))
{
- eval_once(qDebug() << "dinput: keyboard GetDeviceData failed" << hr);
+ eval_once(qDebug() << "dinput: keyboard GetDeviceData failed" << (void*)hr);
return false;
}
@@ -210,7 +205,7 @@ bool KeybindingWorker::run_joystick_nolock()
return true;
}
-KeybindingWorker::fun* KeybindingWorker::_add_receiver(fun& receiver)
+KeybindingWorker::fun* KeybindingWorker::add_receiver(fun& receiver)
{
QMutexLocker l(&mtx);
receivers.push_back(std::make_unique<fun>(receiver));
diff --git a/dinput/keybinding-worker.hpp b/dinput/keybinding-worker.hpp
index fad9ec7e..7b9dd259 100644
--- a/dinput/keybinding-worker.hpp
+++ b/dinput/keybinding-worker.hpp
@@ -24,13 +24,13 @@
struct OTR_DINPUT_EXPORT Key
{
QString guid;
+ Timer timer;
int keycode = 0;
bool shift = false;
bool ctrl = false;
bool alt = false;
bool held = true;
bool enabled = true;
- Timer timer;
public:
Key();
@@ -41,6 +41,9 @@ struct OTR_DINPUT_EXPORT KeybindingWorker : private QThread
{
using fun = std::function<void(const Key&)>;
+ KeybindingWorker(const KeybindingWorker&) = delete;
+ KeybindingWorker& operator=(KeybindingWorker&) = delete;
+
private:
LPDIRECTINPUTDEVICE8 dinkeyboard { nullptr };
win32_joy_ctx joy_ctx;
@@ -50,7 +53,6 @@ private:
di_t din;
bool keystate[256] {};
- bool old_keystate[256] {};
void run() override;
bool run_keyboard_nolock();
@@ -60,15 +62,12 @@ private:
KeybindingWorker();
static KeybindingWorker& make();
- fun* _add_receiver(fun &receiver);
+ fun* add_receiver(fun& receiver);
void remove_receiver(fun* pos);
- ~KeybindingWorker();
+ ~KeybindingWorker() override;
- static constexpr int num_keyboard_states = 16;
+ static constexpr int num_keyboard_states = 64;
DIDEVICEOBJECTDATA keyboard_states[num_keyboard_states] {};
-
- KeybindingWorker(const KeybindingWorker&) = delete;
- KeybindingWorker& operator=(KeybindingWorker&) = delete;
public:
class Token
{
@@ -83,7 +82,7 @@ public:
}
Token(fun receiver)
{
- pos = make()._add_receiver(receiver);
+ pos = make().add_receiver(receiver);
}
};
};
diff --git a/dinput/win32-joystick.cpp b/dinput/win32-joystick.cpp
index 4da5c57d..0f2687fe 100644
--- a/dinput/win32-joystick.cpp
+++ b/dinput/win32-joystick.cpp
@@ -3,19 +3,12 @@
#include "win32-joystick.hpp"
#include "compat/macros.hpp"
-// doesn't play well with Qt Creator clang code model
-#if defined Q_CREATOR_RUN && defined _MSC_VER
-# undef offsetof
-# define offsetof(type, member) __builtin_offsetof(type, member)
-#else
-# include <cstddef>
-#endif
-
+#include <cstddef>
#include <algorithm>
#include <cmath>
+#include <iterator>
#include <QWidget>
-
#include <QDebug>
#include <objbase.h>
@@ -54,33 +47,15 @@ bool win32_joy_ctx::poll_axis(const QString &guid, int* axes)
return false;
auto& j = iter->second;
-
auto& joy_handle = j->joy_handle;
- bool ok = false;
- HRESULT hr;
-
- if (!FAILED(hr = joy_handle->Poll()))
- ok = true;
-
- if (!ok && FAILED(hr = joy_handle->Acquire()))
- {
- (void)0;
- //qDebug() << "joy acquire failed" << hr;
- }
+ DIJOYSTATE2 js = {};
- if (!ok)
- {
- (void)joy_handle->Unacquire();
- Sleep(100);
+ if (!di_t::poll_device(joy_handle))
continue;
- }
-
- DIJOYSTATE2 js = {};
- if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js)))
+ if (FAILED(joy_handle->GetDeviceState(sizeof(js), &js)))
{
- //qDebug() << "joy get state failed" << guid << hr;
- Sleep(500);
+ //qDebug() << "joy get state failed" << guid;
continue;
}
@@ -96,7 +71,7 @@ bool win32_joy_ctx::poll_axis(const QString &guid, int* axes)
js.rglSlider[1]
};
- for (int i = 0; i < 8; i++)
+ for (unsigned i = 0; i < std::size(values); i++)
axes[i] = values[i];
return true;
@@ -133,11 +108,12 @@ void win32_joy_ctx::refresh()
QString win32_joy_ctx::guid_to_string(const GUID& guid)
{
- char buf[40] = {0};
- wchar_t szGuidW[40] = {0};
+ char buf[40] = {};
+ wchar_t szGuidW[40] = {};
- StringFromGUID2(guid, szGuidW, 40);
- WideCharToMultiByte(0, 0, szGuidW, -1, buf, 40, nullptr, nullptr);
+ StringFromGUID2(guid, szGuidW, sizeof(buf));
+ WideCharToMultiByte(0, 0, szGuidW, -1, buf, sizeof(buf), nullptr, nullptr);
+ buf[sizeof(buf)-1] = 0;
return QString(buf);
}
@@ -158,19 +134,18 @@ bool win32_joy_ctx::joy::poll(fn const& f)
{
HRESULT hr;
- (void) joy_handle->Acquire();
-
- if (FAILED(hr = joy_handle->Poll()))
+ if (!di_t::poll_device(joy_handle))
{
- //qDebug() << "joy acquire failed" << guid << hr;
- (void) joy_handle->Unacquire();
+ eval_once(qDebug() << "joy poll failed" << guid << (void*)hr);
+ //(void)joy_handle->Unacquire();
+ //Sleep(0);
return false;
}
DWORD sz = num_buffers;
if (FAILED(hr = joy_handle->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), keystate_buffers, &sz, 0)))
{
- eval_once(qDebug() << "joy get state failed" << guid << hr);
+ eval_once(qDebug() << "joy GetDeviceData failed" << guid << (void*)hr);
return false;
}
@@ -195,7 +170,7 @@ bool win32_joy_ctx::joy::poll(fn const& f)
default:
if (event.dwOfs >= BUTTON_OFFSET(0) && event.dwOfs <= BUTTON_OFFSET(max_buttons - 1))
{
- i = event.dwOfs - BUTTON_OFFSET(0);
+ i = int(event.dwOfs - BUTTON_OFFSET(0));
i /= sizeof(DIJOYSTATE2().rgbButtons[0]);
i %= max_buttons; // defensive programming
}
@@ -254,7 +229,7 @@ void win32_joy_ctx::enum_state::refresh()
if (!di)
{
- qDebug() << "can't create dinput";
+ qDebug() << "dinput: can't create dinput";
return;
}
@@ -265,7 +240,7 @@ void win32_joy_ctx::enum_state::refresh()
this,
DIEDFL_ATTACHEDONLY)))
{
- eval_once(qDebug() << "failed enum joysticks" << hr);
+ eval_once(qDebug() << "dinput: failed enum joysticks" << (void*)hr);
return;
}
@@ -298,12 +273,12 @@ BOOL CALLBACK win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINS
LPDIRECTINPUTDEVICE8 h;
if (FAILED(hr = state.di->CreateDevice(pdidInstance->guidInstance, &h, nullptr)))
{
- qDebug() << "createdevice" << guid << hr;
+ qDebug() << "dinput: failed joystick CreateDevice" << guid << (void*)hr;
goto end;
}
- if (FAILED(h->SetDataFormat(&c_dfDIJoystick2)))
+ if (FAILED(hr = h->SetDataFormat(&c_dfDIJoystick2)))
{
- qDebug() << "format";
+ qDebug() << "dinput: failed joystick SetDataFormat" << (void*)hr;
h->Release();
goto end;
}
@@ -328,7 +303,7 @@ BOOL CALLBACK win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINS
if (h->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph) != DI_OK)
{
- qDebug() << "setup joystick buffer mode failed!";
+ qDebug() << "dinput: joystick DIPROP_BUFFERSIZE";
h->Release();
goto end;
}
@@ -336,7 +311,7 @@ BOOL CALLBACK win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINS
if (FAILED(hr = h->EnumObjects(EnumObjectsCallback, h, DIDFT_ALL)))
{
- qDebug() << "enum-objects";
+ qDebug() << "dinput: joystick EnumObjects";
h->Release();
goto end;
}
@@ -352,8 +327,8 @@ BOOL CALLBACK win32_joy_ctx::enum_state::EnumObjectsCallback(const DIDEVICEOBJEC
if (pdidoi->dwType & DIDFT_AXIS)
{
DIPROPRANGE diprg = {};
- diprg.diph.dwSize = sizeof( DIPROPRANGE );
- diprg.diph.dwHeaderSize = sizeof( DIPROPHEADER );
+ 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;
@@ -363,7 +338,7 @@ BOOL CALLBACK win32_joy_ctx::enum_state::EnumObjectsCallback(const DIDEVICEOBJEC
if (FAILED(hr = reinterpret_cast<LPDIRECTINPUTDEVICE8>(ctx)->SetProperty(DIPROP_RANGE, &diprg.diph)))
{
- qDebug() << "DIPROP_RANGE" << hr;
+ qDebug() << "dinput: failed joystick DIPROP_RANGE" << (void*)hr;
return DIENUM_STOP;
}
}
@@ -384,5 +359,4 @@ win32_joy_ctx::joy::~joy()
}
} // ns win32_joy_impl
-
#endif
diff --git a/dinput/win32-joystick.hpp b/dinput/win32-joystick.hpp
index 1eef5bfa..331e4968 100644
--- a/dinput/win32-joystick.hpp
+++ b/dinput/win32-joystick.hpp
@@ -23,24 +23,24 @@
namespace win32_joy_impl {
-static constexpr inline unsigned max_buttons = std::size(DIJOYSTATE2().rgbButtons);
-static constexpr inline unsigned max_pov_hats = std::size(DIJOYSTATE2().rgdwPOV);
+static constexpr unsigned max_buttons = std::size(DIJOYSTATE2().rgbButtons);
+static constexpr unsigned max_pov_hats = std::size(DIJOYSTATE2().rgdwPOV);
-static constexpr inline unsigned pov_hat_directions = 8;
+static constexpr unsigned pov_hat_directions = 8;
// cf. https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416628(v=vs.85)
// see also remarks on the page
// no need to check for pos == unsigned(-1) || pos == 0xffff,
// this logic doesn't require that
-static constexpr inline unsigned value_per_pov_hat_direction = 36000 / pov_hat_directions;
-static constexpr inline unsigned max_buttons_and_pov_hats = max_buttons + max_pov_hats * pov_hat_directions;
+static constexpr unsigned value_per_pov_hat_direction = 36000 / pov_hat_directions;
+static constexpr unsigned max_buttons_and_pov_hats = max_buttons + max_pov_hats * pov_hat_directions;
//static_assert(pov_hat_directions == 4 || pov_hat_directions == 8);
// XXX how many axis update events can we reasonably get in a short time frame?
-static constexpr inline unsigned num_buffers = 16;
+static constexpr unsigned num_buffers = 16;
-#define WIN32_JOY_DEBUG
+//#define WIN32_JOY_DEBUG
struct OTR_DINPUT_EXPORT win32_joy_ctx final
{
@@ -51,7 +51,6 @@ struct OTR_DINPUT_EXPORT win32_joy_ctx final
LPDIRECTINPUTDEVICE8 joy_handle;
QString guid, name;
bool last_state[max_buttons_and_pov_hats] {};
- Timer first_timer;
static DIDEVICEOBJECTDATA keystate_buffers[num_buffers];
@@ -64,7 +63,7 @@ struct OTR_DINPUT_EXPORT win32_joy_ctx final
using joys_t = std::unordered_map<QString, std::shared_ptr<joy>>;
- static constexpr inline int joy_axis_size = 65536;
+ static constexpr int joy_axis_size = 65536;
struct joy_info
{