summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-01-25 23:31:09 +0100
committerStanislaw Halik <sthalik@misaki.pl>2022-01-25 23:53:29 +0100
commit0907114710af7bf50629fffc3a0a823b62eac08e (patch)
tree60b6581d9e920b1856568b981a1d0d1be81c8f50
parent5194e9456674d4058a1e80ee2650e0804fe4a56a (diff)
dinput: add mouse keybinding support
Issue: #583
-rw-r--r--dinput/keybinding-worker.cpp93
-rw-r--r--dinput/keybinding-worker.hpp11
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
{