summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2017-10-29 20:58:15 +0100
committerStanislaw Halik <sthalik@misaki.pl>2017-10-29 20:58:15 +0100
commit1d994c21ff978daeb8ae72a5ab4b0fad287b9959 (patch)
treefdc6daf8e28e01b6878f6924f4fb0e3056cba6cb
parent33aa2b6bbbf6edbe2d0173a03a9869e7ed7a2660 (diff)
dinput: use buffered polling
Short keyboard and mouse events won't get dropped. We can now decrease the poll interval from 250 Hz to 10Hz.
-rw-r--r--dinput/keybinding-worker.cpp116
-rw-r--r--dinput/keybinding-worker.hpp6
-rw-r--r--dinput/win32-joystick.cpp113
-rw-r--r--dinput/win32-joystick.hpp5
4 files changed, 160 insertions, 80 deletions
diff --git a/dinput/keybinding-worker.cpp b/dinput/keybinding-worker.cpp
index e0d09909..468ef477 100644
--- a/dinput/keybinding-worker.cpp
+++ b/dinput/keybinding-worker.cpp
@@ -8,13 +8,15 @@
#ifdef _WIN32
-#include "keybinding-worker.hpp"
+#include "compat/sleep.hpp"
#include "compat/util.hpp"
-#include <functional>
-#include <windows.h>
+#include "keybinding-worker.hpp"
+
#include <QDebug>
#include <QMutexLocker>
+#include <windows.h>
+
Key::Key() {}
bool Key::should_process()
@@ -65,6 +67,22 @@ bool KeybindingWorker::init()
return false;
}
+ {
+ DIPROPDWORD dipdw;
+ dipdw.dwData = 128;
+ 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!";
+ dinkeyboard->Release();
+ dinkeyboard = 0;
+ return false;
+ }
+ }
+
if (dinkeyboard->Acquire() != DI_OK)
{
dinkeyboard->Release();
@@ -90,9 +108,6 @@ KeybindingWorker& KeybindingWorker::make()
void KeybindingWorker::run()
{
- unsigned char keystate[256] = {0};
- unsigned char old_keystate[256] = {0};
-
while (!isInterruptionRequested())
{
{
@@ -100,21 +115,69 @@ void KeybindingWorker::run()
if (receivers.size())
{
+ /* There are some problems reported on various forums
+ * with regard to key-up events. But that's what I dug up:
+ *
+ * https://www.gamedev.net/forums/topic/633011-keyboard-getdevicedata-buffered-never-releases-keys/
+ *
+ * "Over in the xna forums (http://xboxforums.create.msdn.com/forums/p/108722/642144.aspx#642144)
+ * we discovered this behavior is caused by calling Unacquire in your event processing loop.
+ * Funnily enough only the keyboard seems to be affected."
+ *
+ * Key-up events work on my end.
+ */
+
{
- const HRESULT hr = dinkeyboard->GetDeviceState(256, (LPVOID)keystate);
+ DWORD sz = num_keyboard_states;
+ const HRESULT hr = dinkeyboard->GetDeviceData(sizeof(*keyboard_states), keyboard_states, &sz, 0);
if (hr != DI_OK)
{
- qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError();
+ qDebug() << "Tracker::run GetDeviceData function failed!" << hr;
Sleep(25);
continue;
}
+ else
+ {
+ for (unsigned k = 0; k < sz; k++)
+ {
+ const unsigned idx = keyboard_states[k].dwOfs & 0xff; // defensive programming
+ const bool held = !!(keyboard_states[k].dwData & 0x80);
+
+ switch (idx)
+ {
+ case DIK_LCONTROL:
+ case DIK_LSHIFT:
+ case DIK_LALT:
+ case DIK_RCONTROL:
+ case DIK_RSHIFT:
+ case DIK_RALT:
+ case DIK_LWIN:
+ case DIK_RWIN:
+ break;
+ default:
+ {
+ Key k;
+ k.shift = !!((keystate[DIK_LSHIFT] & 0x80) | (keystate[DIK_RSHIFT] & 0x80));
+ k.alt = !!((keystate[DIK_LALT] & 0x80) | (keystate[DIK_RALT] & 0x80));
+ k.ctrl = !!((keystate[DIK_LCONTROL] & 0x80) | (keystate[DIK_RCONTROL] & 0x80));
+ k.keycode = idx;
+ k.held = held;
+
+ for (auto& r : receivers)
+ (*r)(k);
+ break;
+ }
+ }
+ keystate[idx] = held;
+ }
+ }
}
{
using joy_fn = std::function<void(const QString& guid, int idx, bool held)>;
- joy_fn f = [&](const QString& guid, int idx, bool held) -> void {
+ joy_fn f = [&](const QString& guid, int idx, bool held) {
Key k;
k.keycode = idx;
k.shift = !!(keystate[DIK_LSHIFT] & 0x80 || keystate[DIK_RSHIFT] & 0x80);
@@ -129,43 +192,10 @@ void KeybindingWorker::run()
joy_ctx.poll(f);
}
-
- for (int i = 0; i < 256; i++)
- {
- Key k;
- if (old_keystate[i] != keystate[i])
- {
- const bool held = !!(keystate[i] & 0x80);
- switch (i)
- {
- case DIK_LCONTROL:
- case DIK_LSHIFT:
- case DIK_LALT:
- case DIK_RCONTROL:
- case DIK_RSHIFT:
- case DIK_RALT:
- case DIK_LWIN:
- case DIK_RWIN:
- break;
- default:
- k.shift = !!((keystate[DIK_LSHIFT] & 0x80) || (keystate[DIK_RSHIFT] & 0x80));
- k.alt = !!((keystate[DIK_LALT] & 0x80) || (keystate[DIK_RALT] & 0x80));
- k.ctrl = !!((keystate[DIK_LCONTROL] & 0x80) || (keystate[DIK_RCONTROL] & 0x80));
- k.keycode = i;
- k.held = held;
-
- for (auto& r : receivers)
- (*r)(k);
- break;
- }
- }
- old_keystate[i] = keystate[i];
- }
}
}
- // keypresses get dropped with high values
- Sleep(4);
+ portable::sleep(100);
}
}
diff --git a/dinput/keybinding-worker.hpp b/dinput/keybinding-worker.hpp
index d35ac57d..f7314482 100644
--- a/dinput/keybinding-worker.hpp
+++ b/dinput/keybinding-worker.hpp
@@ -49,6 +49,9 @@ private:
QMainWindow fake_main_window;
dinput_handle::di_t din;
+ unsigned char keystate[256] {};
+ unsigned char old_keystate[256] {};
+
void run() override;
bool init();
KeybindingWorker();
@@ -58,6 +61,9 @@ private:
void remove_receiver(fun* pos);
~KeybindingWorker();
+ static constexpr int num_keyboard_states = 128;
+ DIDEVICEOBJECTDATA keyboard_states[num_keyboard_states];
+
KeybindingWorker(const KeybindingWorker&) = delete;
KeybindingWorker& operator=(KeybindingWorker&) = delete;
public:
diff --git a/dinput/win32-joystick.cpp b/dinput/win32-joystick.cpp
index f954a44e..4adf512d 100644
--- a/dinput/win32-joystick.cpp
+++ b/dinput/win32-joystick.cpp
@@ -11,6 +11,10 @@
#include <QDebug>
+// XXX how many axis update events can we reasonably get in a short time frame?
+enum { num_buffers = 256 };
+DIDEVICEOBJECTDATA win32_joy_ctx::joy::keystate_buffers[num_buffers];
+
QMutex win32_joy_ctx::enum_state::mtx;
win32_joy_ctx::enum_state win32_joy_ctx::enumerator;
@@ -163,59 +167,80 @@ bool win32_joy_ctx::joy::poll(fn f)
return false;
}
- DIJOYSTATE2 js;
- std::memset(&js, 0, sizeof(js));
-
- if (FAILED(hr = joy_handle->GetDeviceState(sizeof(js), &js)))
+ DWORD sz = num_buffers;
+ if (FAILED(hr = joy_handle->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), keystate_buffers, &sz, 0)))
{
//qDebug() << "joy get state failed" << guid << hr;
return false;
}
- for (unsigned i = 0; i < 4; i++)
+ for (unsigned k = 0; k < sz; k++)
{
- using std::round;
-
- unsigned char pos;
- unsigned pos_ = js.rgdwPOV[i];
- if ((pos_ & 0xffff) == 0xffff)
- pos = 0;
- else if (pos_ == ~0u)
- pos = 0;
- else
+ const DIDEVICEOBJECTDATA& event = keystate_buffers[k];
+
+ bool is_pov = false;
+ int i = -1;
+
+ switch (event.dwOfs)
{
- using uc = unsigned char;
- pos = uc(((pos_ / 9000u) % 4u) + 1u);
+ case DIJOFS_POV(0): i = 0, is_pov = true; break;
+ case DIJOFS_POV(2): i = 1, is_pov = true; break;
+ case DIJOFS_POV(3): i = 2, is_pov = true; break;
+ case DIJOFS_POV(4): i = 3, is_pov = true; break;
+ default:
+ if (event.dwOfs >= DIJOFS_BUTTON0 && event.dwOfs <= DIJOFS_BUTTON(127))
+ {
+ unsigned tmp = event.dwOfs;
+ tmp -= DIJOFS_BUTTON0;
+ tmp /= DIJOFS_BUTTON1 - DIJOFS_BUTTON0;
+ tmp &= 127;
+ i = tmp;
+ }
+ break;
}
- const bool state[] =
+ if (is_pov)
{
- pos == 1,
- pos == 2,
- pos == 3,
- pos == 4
- };
+ //qDebug() << "DBG: pov" << i << event.dwData;
- unsigned idx = 128u + i * 4u;
+ using std::round;
- for (unsigned j = 0; j < 4; j++, idx++)
- {
- if (state[j] != pressed[idx])
+ unsigned char pos;
+ unsigned pos_ = event.dwData;
+ if ((pos_ & 0xffff) == 0xffff)
+ pos = 0;
+ else if (pos_ == ~0u)
+ pos = 0;
+ else
{
- f(guid, int(idx), state[j]);
- pressed[idx] = state[j];
+ using uc = unsigned char;
+ pos = uc(((pos_ / 9000u) % 4u) + 1u);
}
- }
- }
- for (int i = 0; i < 128; i++)
- {
- const bool state = !!(js.rgbButtons[i] & 0x80);
- if (state != pressed[i])
+ const bool state[] =
+ {
+ pos == 1,
+ pos == 2,
+ pos == 3,
+ pos == 4
+ };
+
+ i = 128u + i * 4u;
+
+ for (unsigned j = 0; j < 4; j++)
+ {
+ //pressed[i] = state[j];
+ f(guid, i, state[j]);
+ }
+ }
+ else if (i != -1)
{
+ const bool state = !!(event.dwData & 0x80);
+ //qDebug() << "DBG: btn" << i << state;
+ //pressed[i] = state;
f(guid, i, state);
}
- pressed[i] = state;
+
}
return true;
@@ -305,6 +330,23 @@ BOOL CALLBACK win32_joy_ctx::enum_state::EnumJoysticksCallback(const DIDEVICEINS
h->Release();
goto end;
}
+
+ {
+ DIPROPDWORD dipdw;
+ dipdw.dwData = 128;
+ dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
+ dipdw.diph.dwHow = DIPH_DEVICE;
+ dipdw.diph.dwObj = 0;
+ dipdw.diph.dwSize = sizeof(dipdw);
+
+ if (h->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph) != DI_OK)
+ {
+ qDebug() << "setup joystick buffer mode failed!";
+ h->Release();
+ goto end;
+ }
+ }
+
if (FAILED(hr = h->EnumObjects(EnumObjectsCallback, h, DIDFT_ALL)))
{
qDebug() << "enum-objects";
@@ -347,7 +389,6 @@ win32_joy_ctx::joy::joy(LPDIRECTINPUTDEVICE8 handle, const QString &guid, const
: joy_handle(handle), guid(guid), name(name)
{
//qDebug() << "make joy" << guid << name << joy_handle;
- std::memset(pressed, 0, sizeof(pressed));
}
win32_joy_ctx::joy::~joy()
diff --git a/dinput/win32-joystick.hpp b/dinput/win32-joystick.hpp
index 4e72853f..4d2dd344 100644
--- a/dinput/win32-joystick.hpp
+++ b/dinput/win32-joystick.hpp
@@ -43,9 +43,12 @@ struct OTR_DINPUT_EXPORT win32_joy_ctx
{
LPDIRECTINPUTDEVICE8 joy_handle;
QString guid, name;
- bool pressed[128 + 4 * 4];
+ enum { num_pressed_keys = 128 + 4 * 4 };
+ //bool pressed[num_pressed_keys] {};
Timer first_timer;
+ static DIDEVICEOBJECTDATA keystate_buffers[256];
+
joy(LPDIRECTINPUTDEVICE8 handle, const QString& guid, const QString& name);
~joy();