diff --git a/src/wx/widgets/sdljoy.cpp b/src/wx/widgets/sdljoy.cpp index 65751341..4505e1b0 100644 --- a/src/wx/widgets/sdljoy.cpp +++ b/src/wx/widgets/sdljoy.cpp @@ -2,7 +2,6 @@ #include "wx/sdljoy.h" #include "SDL.h" #include -#include #include #include "../common/range.hpp" #include "../common/contains.h" @@ -26,7 +25,7 @@ wxSDLJoy::~wxSDLJoy() // SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } -static int axisval(int x) +static int16_t axisval(int16_t x) { if (x > 0x1fff) return 1; @@ -41,6 +40,8 @@ void wxSDLJoy::Poll() wxEvtHandler* handler = evthandler ? evthandler : wxWindow::FindFocus(); SDL_Event e; + bool got_event = false; + while (SDL_PollEvent(&e)) { switch (e.type) { case SDL_CONTROLLERBUTTONDOWN: @@ -51,9 +52,9 @@ void wxSDLJoy::Poll() if (contains(joystate, joy)) { auto but = e.cbutton.button; auto val = e.cbutton.state; - auto prev_val = !val; + auto prev_val = joystate[joy].button[but]; - if (handler) { + if (handler && val != prev_val) { wxSDLJoyEvent ev(wxEVT_SDLJOY); ev.joy = joy; ev.ctrl_type = WXSDLJOY_BUTTON; @@ -64,8 +65,13 @@ void wxSDLJoy::Poll() handler->ProcessEvent(ev); } + joystate[joy].button[but] = val; + wxLogDebug("GOT SDL_CONTROLLERBUTTON: joy:%d but:%d val:%d prev_val:%d", joy, but, val, prev_val); } + + got_event = true; + break; } case SDL_CONTROLLERAXISMOTION: @@ -92,6 +98,9 @@ void wxSDLJoy::Poll() wxLogDebug("GOT SDL_CONTROLLERAXISMOTION: joy:%d axis:%d val:%d prev_val:%d", joy, axis, val, prev_val); } } + + got_event = true; + break; } case SDL_CONTROLLERDEVICEADDED: @@ -105,6 +114,9 @@ void wxSDLJoy::Poll() systemScreenMessage(wxString::Format(_("Connected game controller %d"), joy + 1)); } + + got_event = true; + break; } case SDL_CONTROLLERDEVICEREMOVED: @@ -116,10 +128,71 @@ void wxSDLJoy::Poll() systemScreenMessage(wxString::Format(_("Disconnected game controller %d"), joy + 1)); } + + got_event = true; + break; } } } + + // I am only doing this shit because hotplug support is fucking broken in SDL right now. + + bool do_poll = false; + wxLongLong tm = wxGetUTCTimeMillis(); + + if (got_event) + last_poll = tm; + else if (tm - last_poll > POLL_TIME_MS) { + do_poll = true; + last_poll = tm; + } + + if (do_poll) { + for (auto&& joy : joystate) { + for (uint8_t but = 0; but < SDL_CONTROLLER_BUTTON_MAX; but++) { + auto last_state = joy.second.button[but]; + auto state = SDL_GameControllerGetButton(joy.second.dev, static_cast(but)); + + if (last_state != state) { + if (handler) { + wxSDLJoyEvent ev(wxEVT_SDLJOY); + ev.joy = joy.first; + ev.ctrl_type = WXSDLJOY_BUTTON; + ev.ctrl_idx = but; + ev.ctrl_val = state; + ev.prev_val = last_state; + + handler->ProcessEvent(ev); + } + + joy.second.button[but] = state; + + wxLogDebug("POLLED SDL_CONTROLLERBUTTON: joy:%d but:%d val:%d prev_val:%d", joy.first, but, state, last_state); + } + } + + for (uint8_t axis = 0; axis < SDL_CONTROLLER_AXIS_MAX; axis++) { + auto val = axisval(SDL_GameControllerGetAxis(joy.second.dev, static_cast(axis))); + auto prev_val = joy.second.axis[axis]; + + if (handler && val != prev_val) { + wxSDLJoyEvent ev(wxEVT_SDLJOY); + ev.joy = joy.first; + ev.ctrl_type = WXSDLJOY_AXIS; + ev.ctrl_idx = axis; + ev.ctrl_val = val; + ev.prev_val = prev_val; + + handler->ProcessEvent(ev); + + joy.second.axis[axis] = val; + + wxLogDebug("POLLED SDL_CONTROLLERAXISMOTION: joy:%d axis:%d val:%d prev_val:%d", joy.first, axis, val, prev_val); + } + } + } + } } void wxSDLJoy::ConnectController(uint8_t joy) diff --git a/src/wx/widgets/wx/sdljoy.h b/src/wx/widgets/wx/sdljoy.h index b91e01fe..82551aa2 100644 --- a/src/wx/widgets/wx/sdljoy.h +++ b/src/wx/widgets/wx/sdljoy.h @@ -9,8 +9,10 @@ // // The target window will receive EVT_SDLJOY events of type wxSDLJoyEvent. +#include #include #include +#include #include #include #include @@ -18,7 +20,8 @@ struct wxSDLJoyState { SDL_GameController* dev = nullptr; - std::unordered_map axis; + std::array axis{}; + std::array button{}; }; class wxSDLJoy : public wxTimer { @@ -52,10 +55,15 @@ protected: void Notify(); void ConnectController(uint8_t joy); void DisconnectController(uint8_t joy); + + const uint8_t POLL_TIME_MS = 10; + private: std::unordered_map joystate; wxEvtHandler* evthandler; bool add_all = false, rumbling = false; + + wxLongLong last_poll = wxGetUTCTimeMillis(); }; enum {