diff options
Diffstat (limited to 'dinput')
-rw-r--r-- | dinput/keybinding-worker.cpp | 116 | ||||
-rw-r--r-- | dinput/keybinding-worker.hpp | 6 | ||||
-rw-r--r-- | dinput/win32-joystick.cpp | 113 | ||||
-rw-r--r-- | dinput/win32-joystick.hpp | 5 |
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(); |