diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-01-25 23:31:09 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-01-25 23:53:29 +0100 |
commit | 0907114710af7bf50629fffc3a0a823b62eac08e (patch) | |
tree | 60b6581d9e920b1856568b981a1d0d1be81c8f50 | |
parent | 5194e9456674d4058a1e80ee2650e0804fe4a56a (diff) |
dinput: add mouse keybinding support
Issue: #583
-rw-r--r-- | dinput/keybinding-worker.cpp | 93 | ||||
-rw-r--r-- | dinput/keybinding-worker.hpp | 11 |
2 files changed, 79 insertions, 25 deletions
diff --git a/dinput/keybinding-worker.cpp b/dinput/keybinding-worker.cpp index fc30bcd3..5acdc65a 100644 --- a/dinput/keybinding-worker.cpp +++ b/dinput/keybinding-worker.cpp @@ -17,6 +17,13 @@ #include <dinput.h> +static void destroy(IDirectInputDevice8A*& dev) +{ + if (dev) + dev->Release(); + dev = nullptr; +} + Key::Key() = default; bool Key::should_process() @@ -35,16 +42,13 @@ KeybindingWorker::~KeybindingWorker() requestInterruption(); wait(); - if (dinkeyboard) - { - dinkeyboard->Unacquire(); - dinkeyboard->Release(); - } + destroy(dinkeyboard); + destroy(dinmouse); } -bool KeybindingWorker::init() +bool KeybindingWorker::init_(IDirectInputDevice8A*& dev, const char* name, const GUID& guid, const DIDATAFORMAT& fmt) { - if (dinkeyboard) + if (dev) return true; if (!din) @@ -53,24 +57,39 @@ bool KeybindingWorker::init() goto fail; } - if (din->CreateDevice(GUID_SysKeyboard, &dinkeyboard, nullptr) != DI_OK) + if (auto hr = din->CreateDevice(guid, &dev, nullptr); hr != DI_OK) { - qDebug() << "dinput: create keyboard failed" << GetLastError(); + qDebug() << "dinput: create" << name << "failed" << (void*)hr; goto fail; } - if (dinkeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK) + if (auto hr = dev->SetDataFormat(&fmt); hr != DI_OK) { - qDebug() << "dinput: keyboard SetDataFormat" << GetLastError(); + qDebug() << "dinput:" << name << "SetDataFormat" << (void*)hr; goto fail; } - if (dinkeyboard->SetCooperativeLevel((HWND) fake_main_window.winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) + if (auto hr = dev->SetCooperativeLevel((HWND) fake_main_window.winId(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + hr != DI_OK) { - qDebug() << "dinput: keyboard SetCooperativeLevel" << GetLastError(); + qDebug() << "dinput:" << name << "SetCooperativeLevel" << (void*)hr; goto fail; } + return true; +fail: + destroy(dev); + return false; +} + +bool KeybindingWorker::init() +{ + bool ret = init_(dinkeyboard, "keyboard", GUID_SysKeyboard, c_dfDIKeyboard) && + init_(dinmouse, "mouse", GUID_SysMouse, c_dfDIMouse2); + + if (!ret) + goto fail; + { DIPROPDWORD dipdw; dipdw.dwData = num_keyboard_states; @@ -79,9 +98,9 @@ bool KeybindingWorker::init() dipdw.diph.dwObj = 0; dipdw.diph.dwSize = sizeof(dipdw); - if (dinkeyboard->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph) != DI_OK) + if (auto hr = dinkeyboard->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph); hr != DI_OK) { - qDebug() << "dinput: DIPROP_BUFFERSIZE"; + qDebug() << "dinput: keyboard DIPROP_BUFFERSIZE" << (void*)hr; goto fail; } } @@ -89,11 +108,8 @@ bool KeybindingWorker::init() return true; fail: - if (dinkeyboard) - { - dinkeyboard->Release(); - dinkeyboard = nullptr; - } + destroy(dinkeyboard); + destroy(dinmouse); return false; } @@ -125,6 +141,7 @@ void KeybindingWorker::run() bool ok = true; ok &= run_keyboard_nolock(); + ok &= run_mouse_nolock(); ok &= run_joystick_nolock(); if (!ok) @@ -136,6 +153,38 @@ void KeybindingWorker::run() } } +bool KeybindingWorker::run_mouse_nolock() +{ + DIMOUSESTATE2 state; + + if (!di_t::poll_device(dinmouse)) + eval_once(qDebug() << "dinput: mouse poll failed"); + + if (auto hr = dinmouse->GetDeviceState(sizeof(state), &state); hr != DI_OK) + { + eval_once(qDebug() << "dinput: mouse GetDeviceState failed" << (void*) hr << GetLastError); + return false; + } + + Key k; + k.guid = QStringLiteral("mouse"); + + for (int i = first_mouse_button; i < num_mouse_buttons; i++) + { + const bool new_state = state.rgbButtons[i] & 0x80; + k.held = new_state; + k.keycode = i; + bool& old_state = mouse_state[i - first_mouse_button]; + if (old_state != new_state) + { + for (auto& r : receivers) + (*r)(k); + } + old_state = new_state; + } + return true; +} + bool KeybindingWorker::run_keyboard_nolock() { /* There are some problems reported on various forums @@ -153,7 +202,7 @@ bool KeybindingWorker::run_keyboard_nolock() if (!di_t::poll_device(dinkeyboard)) eval_once(qDebug() << "dinput: keyboard poll failed"); - DIDEVICEOBJECTDATA keyboard_states[num_keyboard_states] = {}; + DIDEVICEOBJECTDATA keyboard_states[num_keyboard_states]; DWORD sz = num_keyboard_states; HRESULT hr = dinkeyboard->GetDeviceData(sizeof(*keyboard_states), keyboard_states, &sz, 0); @@ -166,7 +215,7 @@ bool KeybindingWorker::run_keyboard_nolock() for (unsigned k = 0; k < sz; k++) { - const unsigned idx = keyboard_states[k].dwOfs & 0xff; // defensive programming + const int idx = keyboard_states[k].dwOfs & 0xff; // defensive programming const bool held = !!(keyboard_states[k].dwData & 0x80); switch (idx) diff --git a/dinput/keybinding-worker.hpp b/dinput/keybinding-worker.hpp index 6b21bd01..1c22ca17 100644 --- a/dinput/keybinding-worker.hpp +++ b/dinput/keybinding-worker.hpp @@ -45,7 +45,11 @@ struct OTR_DINPUT_EXPORT KeybindingWorker : private QThread KeybindingWorker& operator=(KeybindingWorker&) = delete; private: - IDirectInputDevice8A* dinkeyboard = nullptr; + static constexpr int num_keyboard_states = 64; + static constexpr int num_mouse_buttons = 8; + static constexpr int first_mouse_button = 3; + + IDirectInputDevice8A* dinkeyboard = nullptr, *dinmouse = nullptr; win32_joy_ctx joy_ctx; std::vector<std::unique_ptr<fun>> receivers; QMutex mtx; @@ -53,20 +57,21 @@ private: di_t din; bool keystate[256] {}; + bool mouse_state[num_mouse_buttons - first_mouse_button] = {}; void run() override; bool run_keyboard_nolock(); bool run_joystick_nolock(); + bool run_mouse_nolock(); bool init(); + bool init_(IDirectInputDevice8A*& dev, const char* name, const GUID& guid, const DIDATAFORMAT& fmt); KeybindingWorker(); static KeybindingWorker& make(); fun* add_receiver(fun& receiver); void remove_receiver(fun* pos); ~KeybindingWorker() override; - - static constexpr int num_keyboard_states = 64; public: class Token { |