diff options
| -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(); | 
