diff options
Diffstat (limited to 'dinput')
-rw-r--r-- | dinput/dinput.cpp | 62 | ||||
-rw-r--r-- | dinput/dinput.hpp | 26 | ||||
-rw-r--r-- | dinput/keybinding-worker.cpp | 29 | ||||
-rw-r--r-- | dinput/keybinding-worker.hpp | 17 | ||||
-rw-r--r-- | dinput/win32-joystick.cpp | 82 | ||||
-rw-r--r-- | dinput/win32-joystick.hpp | 17 |
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 { |