Revamp wxJoyEvent to simplify handling of joystick events
Previously, wxJoyEvent surfaced the internal state of the joystick changes, forcing consumers of this class to convert the values to the mod and key values used in the rest of the code base. This streamlines the wxJoyEvent API so the events sent to the consumers can be used as-is. In particular, this allows us to remove manual generation of "ghost" events in GameArea. Breaking change: This has the side effect of disabling setting diagonals from a joystick HAT as a discrete control. However, this only ever worked with game controllers not compatible with the newer SDL GameController API, since it handles HATs as 4 discrete buttons. For compatibility purposes, these have been moved 1/8 turn counter-clockwise - i.e. NE is now N. Issue: #745
This commit is contained in:
parent
60d7ead565
commit
a56ea0225a
|
@ -138,55 +138,55 @@ const int num_def_accels = sizeof(default_accels) / sizeof(default_accels[0]);
|
|||
const std::map<wxGameControl, std::set<wxUserInput>> kDefaultBindings = {
|
||||
{ wxGameControl(0, wxGameKey::Up), {
|
||||
WJKB(wxT('W')),
|
||||
WJKB(11, WXJB_BUTTON, 1),
|
||||
WJKB(1, WXJB_AXIS_MINUS, 1),
|
||||
WJKB(3, WXJB_AXIS_MINUS, 1),
|
||||
WJKB(11, wxJoyControl::Button, 1),
|
||||
WJKB(1, wxJoyControl::AxisMinus, 1),
|
||||
WJKB(3, wxJoyControl::AxisMinus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Down), {
|
||||
WJKB(wxT('S')),
|
||||
WJKB(12, WXJB_BUTTON, 1),
|
||||
WJKB(1, WXJB_AXIS_PLUS, 1),
|
||||
WJKB(3, WXJB_AXIS_PLUS, 1),
|
||||
WJKB(12, wxJoyControl::Button, 1),
|
||||
WJKB(1, wxJoyControl::AxisPlus, 1),
|
||||
WJKB(3, wxJoyControl::AxisPlus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Left), {
|
||||
WJKB(wxT('A')),
|
||||
WJKB(13, WXJB_BUTTON, 1),
|
||||
WJKB(0, WXJB_AXIS_MINUS, 1),
|
||||
WJKB(2, WXJB_AXIS_MINUS, 1),
|
||||
WJKB(13, wxJoyControl::Button, 1),
|
||||
WJKB(0, wxJoyControl::AxisMinus, 1),
|
||||
WJKB(2, wxJoyControl::AxisMinus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Right), {
|
||||
WJKB(wxT('D')),
|
||||
WJKB(14, WXJB_BUTTON, 1),
|
||||
WJKB(0, WXJB_AXIS_PLUS, 1),
|
||||
WJKB(2, WXJB_AXIS_PLUS, 1),
|
||||
WJKB(14, wxJoyControl::Button, 1),
|
||||
WJKB(0, wxJoyControl::AxisPlus, 1),
|
||||
WJKB(2, wxJoyControl::AxisPlus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::A), {
|
||||
WJKB(wxT('L')),
|
||||
WJKB(0, WXJB_BUTTON, 1),
|
||||
WJKB(0, wxJoyControl::Button, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::B), {
|
||||
WJKB(wxT('K')),
|
||||
WJKB(1, WXJB_BUTTON, 1),
|
||||
WJKB(1, wxJoyControl::Button, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::L), {
|
||||
WJKB(wxT('I')),
|
||||
WJKB(2, WXJB_BUTTON, 1),
|
||||
WJKB(9, WXJB_BUTTON, 1),
|
||||
WJKB(4, WXJB_AXIS_PLUS, 1),
|
||||
WJKB(2, wxJoyControl::Button, 1),
|
||||
WJKB(9, wxJoyControl::Button, 1),
|
||||
WJKB(4, wxJoyControl::AxisPlus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::R), {
|
||||
WJKB(wxT('O')),
|
||||
WJKB(3, WXJB_BUTTON, 1),
|
||||
WJKB(10, WXJB_BUTTON, 1),
|
||||
WJKB(5, WXJB_AXIS_PLUS, 1),
|
||||
WJKB(3, wxJoyControl::Button, 1),
|
||||
WJKB(10, wxJoyControl::Button, 1),
|
||||
WJKB(5, wxJoyControl::AxisPlus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Select), {
|
||||
WJKB(WXK_BACK),
|
||||
WJKB(4, WXJB_BUTTON, 1),
|
||||
WJKB(4, wxJoyControl::Button, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Start), {
|
||||
WJKB(WXK_RETURN),
|
||||
WJKB(6, WXJB_BUTTON, 1),
|
||||
WJKB(6, wxJoyControl::Button, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::MotionUp), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionDown), {}},
|
||||
|
|
|
@ -1307,27 +1307,7 @@ void GameArea::OnSize(wxSizeEvent& ev)
|
|||
|
||||
void GameArea::OnSDLJoy(wxJoyEvent& ev)
|
||||
{
|
||||
int key = ev.control_index();
|
||||
int mod = wxJoyKeyTextCtrl::DigitalButton(ev);
|
||||
int joy = ev.joystick().player_index();
|
||||
|
||||
// mutually exclusive key types unpress their opposite
|
||||
// TODO: Move creation of these "ghost" events to wxJoyPoller.
|
||||
if (mod == WXJB_AXIS_PLUS) {
|
||||
process_user_input(false, wxUserInput::FromLegacyKeyModJoy(key, WXJB_AXIS_MINUS, joy));
|
||||
process_user_input(ev.control_value() != 0, wxUserInput::FromJoyEvent(ev));
|
||||
} else if (mod == WXJB_AXIS_MINUS) {
|
||||
process_user_input(false, wxUserInput::FromLegacyKeyModJoy(key, WXJB_AXIS_PLUS, joy));
|
||||
process_user_input(ev.control_value() != 0, wxUserInput::FromJoyEvent(ev));
|
||||
} else if (mod >= WXJB_HAT_FIRST && mod <= WXJB_HAT_LAST) {
|
||||
int value = ev.control_value();
|
||||
process_user_input(value & SDL_HAT_UP, wxUserInput::FromLegacyKeyModJoy(key, WXJB_HAT_N, joy));
|
||||
process_user_input(value & SDL_HAT_DOWN, wxUserInput::FromLegacyKeyModJoy(key, WXJB_HAT_S, joy));
|
||||
process_user_input(value & SDL_HAT_RIGHT, wxUserInput::FromLegacyKeyModJoy(key, WXJB_HAT_E, joy));
|
||||
process_user_input(value & SDL_HAT_LEFT, wxUserInput::FromLegacyKeyModJoy(key, WXJB_HAT_W, joy));
|
||||
} else {
|
||||
process_user_input(ev.control_value() != 0, wxUserInput::FromJoyEvent(ev));
|
||||
}
|
||||
process_user_input(ev.pressed(), wxUserInput::FromJoyEvent(ev));
|
||||
|
||||
// tell Linux to turn off the screensaver/screen-blank if joystick button was pressed
|
||||
// this shouldn't be necessary of course
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "opts.h"
|
||||
#include "strutils.h"
|
||||
#include "wx/sdljoy.h"
|
||||
#include "wx/userinput.h"
|
||||
|
||||
// FIXME: suppport analog/digital flag on per-axis basis
|
||||
|
@ -14,69 +15,22 @@ BEGIN_EVENT_TABLE(wxJoyKeyTextCtrl, wxKeyTextCtrl)
|
|||
EVT_SDLJOY(wxJoyKeyTextCtrl::OnJoy)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
int wxJoyKeyTextCtrl::DigitalButton(const wxJoyEvent& event)
|
||||
{
|
||||
int16_t sdlval = event.control_value();
|
||||
wxJoyControl sdltype = event.control();
|
||||
|
||||
switch (sdltype) {
|
||||
case wxJoyControl::Axis:
|
||||
// for val = 0 return arbitrary direction; val means "off"
|
||||
return sdlval > 0 ? WXJB_AXIS_PLUS : WXJB_AXIS_MINUS;
|
||||
|
||||
case wxJoyControl::Hat:
|
||||
|
||||
/* URDL = 1248 */
|
||||
switch (sdlval) {
|
||||
case 1:
|
||||
return WXJB_HAT_N;
|
||||
|
||||
case 2:
|
||||
return WXJB_HAT_E;
|
||||
|
||||
case 3:
|
||||
return WXJB_HAT_NE;
|
||||
|
||||
case 4:
|
||||
return WXJB_HAT_S;
|
||||
|
||||
case 6:
|
||||
return WXJB_HAT_SE;
|
||||
|
||||
case 8:
|
||||
return WXJB_HAT_W;
|
||||
|
||||
case 9:
|
||||
return WXJB_HAT_NW;
|
||||
|
||||
case 12:
|
||||
return WXJB_HAT_SW;
|
||||
|
||||
default:
|
||||
return WXJB_HAT_N; // arbitrary direction; val = 0 means "off"
|
||||
}
|
||||
|
||||
case wxJoyControl::Button:
|
||||
return WXJB_BUTTON;
|
||||
|
||||
default:
|
||||
// unknown ctrl type
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void wxJoyKeyTextCtrl::OnJoy(wxJoyEvent& event)
|
||||
{
|
||||
static wxLongLong last_event = 0;
|
||||
|
||||
// Filter consecutive axis motions within 300ms, as this adds two bindings
|
||||
// +1/-1 instead of the one intended.
|
||||
if (event.control() == wxJoyControl::Axis && wxGetUTCTimeMillis() - last_event < 300)
|
||||
if ((event.control() == wxJoyControl::AxisPlus ||
|
||||
event.control() == wxJoyControl::AxisMinus) &&
|
||||
wxGetUTCTimeMillis() - last_event < 300) {
|
||||
return;
|
||||
}
|
||||
|
||||
last_event = wxGetUTCTimeMillis();
|
||||
|
||||
if (!event.control_value() || DigitalButton(event) < 0)
|
||||
// Control was unpressed, ignore.
|
||||
if (!event.pressed())
|
||||
return;
|
||||
|
||||
wxString nv = wxUserInput::FromJoyEvent(event).ToString();
|
||||
|
@ -109,49 +63,33 @@ wxString wxJoyKeyTextCtrl::ToString(int mod, int key, int joy, bool isConfig)
|
|||
wxString mk;
|
||||
|
||||
switch (mod) {
|
||||
case WXJB_AXIS_PLUS:
|
||||
case wxJoyControl::AxisPlus:
|
||||
mk.Printf(("Axis%d+"), key);
|
||||
break;
|
||||
|
||||
case WXJB_AXIS_MINUS:
|
||||
case wxJoyControl::AxisMinus:
|
||||
mk.Printf(("Axis%d-"), key);
|
||||
break;
|
||||
|
||||
case WXJB_BUTTON:
|
||||
case wxJoyControl::Button:
|
||||
mk.Printf(("Button%d"), key);
|
||||
break;
|
||||
|
||||
case WXJB_HAT_N:
|
||||
case wxJoyControl::HatNorth:
|
||||
mk.Printf(("Hat%dN"), key);
|
||||
break;
|
||||
|
||||
case WXJB_HAT_S:
|
||||
case wxJoyControl::HatSouth:
|
||||
mk.Printf(("Hat%dS"), key);
|
||||
break;
|
||||
|
||||
case WXJB_HAT_W:
|
||||
case wxJoyControl::HatWest:
|
||||
mk.Printf(("Hat%dW"), key);
|
||||
break;
|
||||
|
||||
case WXJB_HAT_E:
|
||||
case wxJoyControl::HatEast:
|
||||
mk.Printf(("Hat%dE"), key);
|
||||
break;
|
||||
|
||||
case WXJB_HAT_NW:
|
||||
mk.Printf(("Hat%dNW"), key);
|
||||
break;
|
||||
|
||||
case WXJB_HAT_NE:
|
||||
mk.Printf(("Hat%dNE"), key);
|
||||
break;
|
||||
|
||||
case WXJB_HAT_SW:
|
||||
mk.Printf(("Hat%dSW"), key);
|
||||
break;
|
||||
|
||||
case WXJB_HAT_SE:
|
||||
mk.Printf(("Hat%dSE"), key);
|
||||
break;
|
||||
}
|
||||
|
||||
s += mk;
|
||||
|
@ -214,12 +152,14 @@ static void CompileRegex()
|
|||
axre.Compile(("Axis([0-9]+)([+-])"), wxRE_EXTENDED | wxRE_ICASE);
|
||||
// \1 is button#
|
||||
butre.Compile(("Button([0-9]+)"), wxRE_EXTENDED | wxRE_ICASE);
|
||||
// \1 is hat#, \3 is N, \4 is S, \5 is E, \6 is W, \7 is NE,
|
||||
// \8 is SE, \9 is SW, \10 is NW
|
||||
hatre.Compile(("Hat([0-9]+)((N|North|U|Up)|(S|South|D|Down)|"
|
||||
"(E|East|R|Right)|(W|West|L|Left)|"
|
||||
"(NE|NorthEast|UR|UpRight)|(SE|SouthEast|DR|DownRight)|"
|
||||
"(SW|SouthWest|DL|DownLeft)|(NW|NorthWest|UL|UpLeft))"),
|
||||
// \1 is hat#, \3 is N, \4 is S, \5 is E, \6 is W
|
||||
// This used to support diagonals as discrete input. For compatibility
|
||||
// reasons, these have been moved a 1/8 turn counter-clockwise.
|
||||
hatre.Compile(("Hat([0-9]+)"
|
||||
"((N|North|U|Up|NE|NorthEast|UR|UpRight)|"
|
||||
"(S|South|D|Down|SW|SouthWest|DL|DownLeft)|"
|
||||
"(E|East|R|Right|SE|SouthEast|DR|DownRight)|"
|
||||
"(W|West|L|Left|NW|NorthWest|UL|UpLeft))"),
|
||||
wxRE_EXTENDED | wxRE_ICASE);
|
||||
}
|
||||
|
||||
|
@ -247,24 +187,20 @@ static bool ParseJoy(const wxString& s, int len, int& mod, int& key, int& joy)
|
|||
axre.GetMatch(&b, &l, 1);
|
||||
key = simple_atoi(p.Mid(b), l);
|
||||
axre.GetMatch(&b, &l, 2);
|
||||
mod = p[b] == wxT('+') ? WXJB_AXIS_PLUS : WXJB_AXIS_MINUS;
|
||||
mod = p[b] == wxT('+') ? wxJoyControl::AxisPlus : wxJoyControl::AxisMinus;
|
||||
} else if (is_ctrl(butre)) {
|
||||
butre.GetMatch(&b, &l, 1);
|
||||
key = simple_atoi(p.Mid(b), l);
|
||||
mod = WXJB_BUTTON;
|
||||
mod = wxJoyControl::Button;
|
||||
} else if (is_ctrl(hatre)) {
|
||||
hatre.GetMatch(&b, &l, 1);
|
||||
key = simple_atoi(p.Mid(b), l);
|
||||
#define check_dir(n, d) if (hatre.GetMatch(&b, &l, n) && l > 0) mod = WXJB_HAT_##d
|
||||
#define check_dir(n, d) if (hatre.GetMatch(&b, &l, n) && l > 0) mod = wxJoyControl::Hat##d
|
||||
|
||||
check_dir(3, N);
|
||||
else check_dir(4, S);
|
||||
else check_dir(5, E);
|
||||
else check_dir(6, W);
|
||||
else check_dir(7, NE);
|
||||
else check_dir(8, SE);
|
||||
else check_dir(9, SW);
|
||||
else check_dir(10, NW);
|
||||
check_dir(3, North);
|
||||
else check_dir(4, South);
|
||||
else check_dir(5, East);
|
||||
else check_dir(6, West);
|
||||
} else {
|
||||
joy = 0;
|
||||
return false;
|
||||
|
|
|
@ -8,34 +8,94 @@
|
|||
|
||||
namespace {
|
||||
|
||||
const std::string SDLEventTypeToDebugString(int32_t event_type) {
|
||||
switch (event_type) {
|
||||
case SDL_CONTROLLERBUTTONDOWN:
|
||||
case SDL_CONTROLLERBUTTONUP:
|
||||
return "SDL_CONTROLLERBUTTON";
|
||||
case SDL_CONTROLLERAXISMOTION:
|
||||
return "SDL_CONTROLLERAXISMOTION";
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
return "SDL_JOYBUTTON";
|
||||
case SDL_JOYAXISMOTION:
|
||||
return "SDL_JOYAXISMOTION";
|
||||
case SDL_JOYHATMOTION:
|
||||
return "SDL_JOYHATMOTION";
|
||||
enum class wxAxisStatus {
|
||||
Neutral = 0,
|
||||
Plus,
|
||||
Minus
|
||||
};
|
||||
|
||||
enum class wxHatStatus {
|
||||
Neutral = 0,
|
||||
North,
|
||||
South,
|
||||
West,
|
||||
East,
|
||||
NorthWest,
|
||||
NorthEast,
|
||||
SouthWest,
|
||||
SouthEast
|
||||
};
|
||||
|
||||
wxAxisStatus AxisValueToStatus(const int16_t& x) {
|
||||
if (x > 0x1fff)
|
||||
return wxAxisStatus::Plus;
|
||||
if (x < -0x1fff)
|
||||
return wxAxisStatus::Minus;
|
||||
return wxAxisStatus::Neutral;
|
||||
}
|
||||
|
||||
wxHatStatus HatValueToStatus(const int16_t& x) {
|
||||
switch (x) {
|
||||
case 1:
|
||||
return wxHatStatus::North;
|
||||
case 2:
|
||||
return wxHatStatus::East;
|
||||
case 3:
|
||||
return wxHatStatus::NorthEast;
|
||||
case 4:
|
||||
return wxHatStatus::South;
|
||||
case 6:
|
||||
return wxHatStatus::SouthEast;
|
||||
case 8:
|
||||
return wxHatStatus::West;
|
||||
case 9:
|
||||
return wxHatStatus::NorthWest;
|
||||
case 12:
|
||||
return wxHatStatus::SouthWest;
|
||||
default:
|
||||
assert(false);
|
||||
return "UNKNOWN SDL EVENT";
|
||||
return wxHatStatus::Neutral;
|
||||
}
|
||||
}
|
||||
|
||||
// Converts an axis value to a direction since we do not need analog controls.
|
||||
static int16_t AxisValueToDirection(int16_t x) {
|
||||
if (x > 0x1fff)
|
||||
return 1;
|
||||
else if (x < -0x1fff)
|
||||
return -1;
|
||||
wxJoyControl AxisStatusToJoyControl(const wxAxisStatus& status) {
|
||||
switch (status) {
|
||||
case wxAxisStatus::Plus:
|
||||
return wxJoyControl::AxisPlus;
|
||||
case wxAxisStatus::Minus:
|
||||
return wxJoyControl::AxisMinus;
|
||||
case wxAxisStatus::Neutral:
|
||||
default:
|
||||
// This should never happen.
|
||||
assert(false);
|
||||
return wxJoyControl::AxisPlus;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
std::set<wxJoyControl> HatStatusToJoyControls(const wxHatStatus& status) {
|
||||
switch (status) {
|
||||
case wxHatStatus::Neutral:
|
||||
return {};
|
||||
case wxHatStatus::North:
|
||||
return {wxJoyControl::HatNorth};
|
||||
case wxHatStatus::South:
|
||||
return {wxJoyControl::HatSouth};
|
||||
case wxHatStatus::West:
|
||||
return {wxJoyControl::HatWest};
|
||||
case wxHatStatus::East:
|
||||
return {wxJoyControl::HatEast};
|
||||
case wxHatStatus::NorthWest:
|
||||
return {wxJoyControl::HatNorth, wxJoyControl::HatWest};
|
||||
case wxHatStatus::NorthEast:
|
||||
return {wxJoyControl::HatNorth, wxJoyControl::HatEast};
|
||||
case wxHatStatus::SouthWest:
|
||||
return {wxJoyControl::HatSouth, wxJoyControl::HatWest};
|
||||
case wxHatStatus::SouthEast:
|
||||
return {wxJoyControl::HatSouth, wxJoyControl::HatEast};
|
||||
default:
|
||||
// This should never happen.
|
||||
assert(false);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -85,12 +145,12 @@ wxJoyEvent::wxJoyEvent(
|
|||
wxJoystick joystick,
|
||||
wxJoyControl control,
|
||||
uint8_t control_index,
|
||||
int16_t control_value) :
|
||||
bool pressed) :
|
||||
wxCommandEvent(wxEVT_JOY),
|
||||
joystick_(joystick),
|
||||
control_(control),
|
||||
control_index_(control_index),
|
||||
control_value_(control_value) {}
|
||||
pressed_(pressed) {}
|
||||
|
||||
// Represents the current state of a joystick. This class takes care of
|
||||
// initializing and destroying SDL resources on construction and destruction so
|
||||
|
@ -109,10 +169,13 @@ public:
|
|||
// Returns true if this object was properly initialized.
|
||||
bool IsValid() const;
|
||||
|
||||
// Processes an SDL event.
|
||||
void ProcessSDLEvent(int32_t event_type,
|
||||
uint8_t control_index,
|
||||
int16_t control_value);
|
||||
// Returns true if `sdl_event` should be processed by this object.
|
||||
bool ShouldProcessEvent(uint32_t sdl_event) const;
|
||||
|
||||
// Processes the corresponding events.
|
||||
void ProcessAxisEvent(uint8_t index, wxAxisStatus status);
|
||||
void ProcessButtonEvent(uint8_t index, bool pressed);
|
||||
void ProcessHatEvent(uint8_t index, wxHatStatus status);
|
||||
|
||||
// Activates or deactivates rumble.
|
||||
void SetRumble(bool activate_rumble);
|
||||
|
@ -137,13 +200,13 @@ private:
|
|||
SDL_Joystick* sdl_joystick_ = nullptr;
|
||||
|
||||
// Current state of Joystick axis.
|
||||
std::unordered_map<uint8_t, int16_t> axis_{};
|
||||
std::unordered_map<uint8_t, wxAxisStatus> axis_{};
|
||||
|
||||
// Current state of Joystick buttons.
|
||||
std::unordered_map<uint8_t, uint8_t> buttons_{};
|
||||
std::unordered_map<uint8_t, bool> buttons_{};
|
||||
|
||||
// Current state of Joystick HAT. Unused for GameControllers.
|
||||
std::unordered_map<uint8_t, uint8_t> hats_{};
|
||||
std::unordered_map<uint8_t, wxHatStatus> hats_{};
|
||||
|
||||
// Set to true to activate joystick rumble.
|
||||
bool rumbling_ = false;
|
||||
|
@ -189,78 +252,132 @@ bool wxSDLJoyState::IsValid() const {
|
|||
return sdl_joystick_;
|
||||
}
|
||||
|
||||
void wxSDLJoyState::ProcessSDLEvent(int32_t event_type,
|
||||
uint8_t control_index,
|
||||
int16_t control_value) {
|
||||
int16_t previous_value = 0;
|
||||
wxJoyControl control;
|
||||
bool value_changed = false;
|
||||
|
||||
switch (event_type) {
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
// Do not process joystick events for game controllers.
|
||||
if (game_controller_) {
|
||||
return;
|
||||
}
|
||||
// Fallthrough.
|
||||
bool wxSDLJoyState::ShouldProcessEvent(uint32_t sdl_event) const {
|
||||
switch(sdl_event) {
|
||||
case SDL_CONTROLLERBUTTONDOWN:
|
||||
case SDL_CONTROLLERBUTTONUP:
|
||||
control = wxJoyControl::Button;
|
||||
previous_value = buttons_[control_index];
|
||||
if (previous_value != control_value) {
|
||||
buttons_[control_index] = control_value;
|
||||
value_changed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_JOYHATMOTION:
|
||||
// Do not process joystick events for game controllers.
|
||||
if (game_controller_) {
|
||||
return;
|
||||
}
|
||||
control = wxJoyControl::Hat;
|
||||
previous_value = hats_[control_index];
|
||||
if (previous_value != control_value) {
|
||||
hats_[control_index] = control_value;
|
||||
value_changed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_JOYAXISMOTION:
|
||||
// Do not process joystick events for game controllers.
|
||||
if (game_controller_) {
|
||||
return;
|
||||
}
|
||||
// Fallthrough.
|
||||
case SDL_CONTROLLERAXISMOTION:
|
||||
control = wxJoyControl::Axis;
|
||||
previous_value = axis_[control_index];
|
||||
if (previous_value != control_value) {
|
||||
axis_[control_index] = control_value;
|
||||
value_changed = true;
|
||||
}
|
||||
break;
|
||||
case SDL_CONTROLLERDEVICEADDED:
|
||||
case SDL_CONTROLLERDEVICEREMOVED:
|
||||
// Always process game controller events.
|
||||
return true;
|
||||
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
case SDL_JOYAXISMOTION:
|
||||
case SDL_JOYHATMOTION:
|
||||
// Only process joystick events if this is not a game controller.
|
||||
return !game_controller_;
|
||||
|
||||
default:
|
||||
// This should never happen.
|
||||
assert(false);
|
||||
// Ignore everything else.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void wxSDLJoyState::ProcessAxisEvent(uint8_t index, wxAxisStatus status) {
|
||||
auto handler = wxGetApp().frame->GetJoyEventHandler();
|
||||
const wxAxisStatus previous_status = axis_[index];
|
||||
|
||||
// Nothing to do if no-op.
|
||||
if (status == previous_status) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value_changed) {
|
||||
wxLogDebug("GOT %s: %s ctrl_idx:%d val:%d prev_val:%d",
|
||||
SDLEventTypeToDebugString(event_type),
|
||||
wx_joystick_.ToString(), control_index, control_value,
|
||||
previous_value);
|
||||
// Update the value.
|
||||
axis_[index] = status;
|
||||
|
||||
auto handler = wxGetApp().frame->GetJoyEventHandler();
|
||||
if (!handler)
|
||||
return;
|
||||
// Nothing more to do if we can't send events.
|
||||
if (!handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
wxQueueEvent(handler,
|
||||
new wxJoyEvent(
|
||||
wx_joystick_, control, control_index, control_value));
|
||||
wxLogDebug("Got Axis motion: %s ctrl_idx:%d val:%d prev_val:%d",
|
||||
wx_joystick_.ToString(), index, status, previous_status);
|
||||
|
||||
if (previous_status != wxAxisStatus::Neutral) {
|
||||
// Send the "unpressed" event.
|
||||
wxQueueEvent(handler, new wxJoyEvent(
|
||||
wx_joystick_, AxisStatusToJoyControl(previous_status), index, false));
|
||||
}
|
||||
|
||||
// We already sent the "unpressed" event so nothing more to do.
|
||||
if (status == wxAxisStatus::Neutral) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the "pressed" event.
|
||||
wxQueueEvent(handler, new wxJoyEvent(
|
||||
wx_joystick_, AxisStatusToJoyControl(status), index, true));
|
||||
|
||||
}
|
||||
|
||||
void wxSDLJoyState::ProcessButtonEvent(uint8_t index, bool status) {
|
||||
auto handler = wxGetApp().frame->GetJoyEventHandler();
|
||||
const bool previous_status = buttons_[index];
|
||||
|
||||
// Nothing to do if no-op.
|
||||
if (status == previous_status) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the value.
|
||||
buttons_[index] = status;
|
||||
|
||||
// Nothing more to do if we can't send events.
|
||||
if (!handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
wxLogDebug("Got Button event: %s ctrl_idx:%d val:%d prev_val:%d",
|
||||
wx_joystick_.ToString(), index, status, previous_status);
|
||||
|
||||
// Send the event.
|
||||
wxQueueEvent(handler, new wxJoyEvent(
|
||||
wx_joystick_, wxJoyControl::Button, index, status));
|
||||
}
|
||||
|
||||
void wxSDLJoyState::ProcessHatEvent(uint8_t index, wxHatStatus status) {
|
||||
auto handler = wxGetApp().frame->GetJoyEventHandler();
|
||||
const wxHatStatus previous_status = hats_[index];
|
||||
|
||||
// Nothing to do if no-op.
|
||||
if (status == previous_status) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the value.
|
||||
hats_[index] = status;
|
||||
|
||||
// Nothing more to do if we can't send events.
|
||||
if (!handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
wxLogDebug("Got Hat event: %s ctrl_idx:%d val:%d prev_val:%d",
|
||||
wx_joystick_.ToString(), index, status, previous_status);
|
||||
|
||||
const std::set<wxJoyControl> old_controls = HatStatusToJoyControls(previous_status);
|
||||
const std::set<wxJoyControl> new_controls = HatStatusToJoyControls(status);
|
||||
|
||||
// Send the "unpressed" events.
|
||||
for (const wxJoyControl& control : old_controls) {
|
||||
if (new_controls.find(control) != new_controls.end()) {
|
||||
// No need to unpress the old direction.
|
||||
continue;
|
||||
}
|
||||
wxQueueEvent(handler, new wxJoyEvent(
|
||||
wx_joystick_, control, index, false));
|
||||
}
|
||||
|
||||
// Send the "pressed" events.
|
||||
for (const wxJoyControl& control : new_controls) {
|
||||
if (old_controls.find(control) != old_controls.end()) {
|
||||
// No need to press the new direction twice.
|
||||
continue;
|
||||
}
|
||||
wxQueueEvent(handler, new wxJoyEvent(
|
||||
wx_joystick_, control, index, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,9 +427,9 @@ void wxJoyPoller::Poll() {
|
|||
case SDL_CONTROLLERBUTTONUP:
|
||||
{
|
||||
wxSDLJoyState* joy_state = FindJoyState(e.cbutton.which);
|
||||
if (joy_state) {
|
||||
joy_state->ProcessSDLEvent(
|
||||
e.type, e.cbutton.button, e.cbutton.state);
|
||||
if (joy_state && joy_state->ShouldProcessEvent(e.type)) {
|
||||
joy_state->ProcessButtonEvent(
|
||||
e.cbutton.button, e.cbutton.state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -320,9 +437,9 @@ void wxJoyPoller::Poll() {
|
|||
case SDL_CONTROLLERAXISMOTION:
|
||||
{
|
||||
wxSDLJoyState* joy_state = FindJoyState(e.caxis.which);
|
||||
if (joy_state) {
|
||||
joy_state->ProcessSDLEvent(
|
||||
e.type, e.caxis.axis, AxisValueToDirection(e.caxis.value));
|
||||
if (joy_state && joy_state->ShouldProcessEvent(e.type)) {
|
||||
joy_state->ProcessAxisEvent(
|
||||
e.caxis.axis, AxisValueToStatus(e.caxis.value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -338,9 +455,9 @@ void wxJoyPoller::Poll() {
|
|||
case SDL_JOYBUTTONUP:
|
||||
{
|
||||
wxSDLJoyState* joy_state = FindJoyState(e.jbutton.which);
|
||||
if (joy_state) {
|
||||
joy_state->ProcessSDLEvent(
|
||||
e.type, e.jbutton.button, e.jbutton.state);
|
||||
if (joy_state && joy_state->ShouldProcessEvent(e.type)) {
|
||||
joy_state->ProcessButtonEvent(
|
||||
e.jbutton.button, e.jbutton.state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -348,9 +465,9 @@ void wxJoyPoller::Poll() {
|
|||
case SDL_JOYAXISMOTION:
|
||||
{
|
||||
wxSDLJoyState* joy_state = FindJoyState(e.jaxis.which);
|
||||
if (joy_state) {
|
||||
joy_state->ProcessSDLEvent(
|
||||
e.type, e.jaxis.axis, AxisValueToDirection(e.jaxis.value));
|
||||
if (joy_state && joy_state->ShouldProcessEvent(e.type)) {
|
||||
joy_state->ProcessAxisEvent(
|
||||
e.jaxis.axis, AxisValueToStatus(e.jaxis.value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -358,9 +475,9 @@ void wxJoyPoller::Poll() {
|
|||
case SDL_JOYHATMOTION:
|
||||
{
|
||||
wxSDLJoyState* joy_state = FindJoyState(e.jhat.which);
|
||||
if (joy_state) {
|
||||
joy_state->ProcessSDLEvent(
|
||||
e.type, e.jhat.hat, e.jhat.value);
|
||||
if (joy_state && joy_state->ShouldProcessEvent(e.type)) {
|
||||
joy_state->ProcessHatEvent(
|
||||
e.jhat.hat, HatValueToStatus(e.jhat.value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ wxUserInput wxUserInput::FromKeyEvent(const wxKeyEvent& event) {
|
|||
// static
|
||||
wxUserInput wxUserInput::FromJoyEvent(const wxJoyEvent& event) {
|
||||
return wxUserInput(Device::Joystick,
|
||||
wxJoyKeyTextCtrl::DigitalButton(event),
|
||||
event.control(),
|
||||
event.control_index(),
|
||||
event.joystick().player_index());
|
||||
}
|
||||
|
|
|
@ -10,22 +10,6 @@
|
|||
#include "wx/sdljoy.h"
|
||||
#include "wx/userinput.h"
|
||||
|
||||
// joystick control types
|
||||
// mod for joysticks
|
||||
enum { WXJB_AXIS_PLUS,
|
||||
WXJB_AXIS_MINUS,
|
||||
WXJB_BUTTON,
|
||||
WXJB_HAT_FIRST,
|
||||
WXJB_HAT_N = WXJB_HAT_FIRST,
|
||||
WXJB_HAT_S,
|
||||
WXJB_HAT_W,
|
||||
WXJB_HAT_E,
|
||||
WXJB_HAT_NW,
|
||||
WXJB_HAT_NE,
|
||||
WXJB_HAT_SW,
|
||||
WXJB_HAT_SE,
|
||||
WXJB_HAT_LAST = WXJB_HAT_SE };
|
||||
|
||||
class wxJoyKeyTextCtrl : public wxKeyTextCtrl {
|
||||
public:
|
||||
// default constructor; required for use with xrc
|
||||
|
@ -36,10 +20,6 @@ public:
|
|||
}
|
||||
virtual ~wxJoyKeyTextCtrl(){};
|
||||
|
||||
// key is event.GetControlIndex(), and joy is event.GetJoy() + 1
|
||||
// mod is derived from GetControlValue() and GetControlType():
|
||||
// convert wxJoyEvent's type+val into mod (WXJB_*)
|
||||
static int DigitalButton(const wxJoyEvent& event);
|
||||
// convert mod+key to accel string, separated by -
|
||||
static wxString ToString(int mod, int key, int joy, bool isConfig = false);
|
||||
// parses single key string into mod+key
|
||||
|
|
|
@ -16,10 +16,15 @@ class wxSDLJoyState;
|
|||
class wxJoyPoller;
|
||||
|
||||
// The different types of supported controls.
|
||||
enum class wxJoyControl {
|
||||
Axis = 0, // Control value is signed 16
|
||||
Hat, // Control value is bitmask NESW/URDL
|
||||
Button // Control value is 0 or 1
|
||||
enum wxJoyControl {
|
||||
AxisPlus = 0,
|
||||
AxisMinus,
|
||||
Button,
|
||||
HatNorth,
|
||||
HatSouth,
|
||||
HatWest,
|
||||
HatEast,
|
||||
Last = HatEast
|
||||
};
|
||||
|
||||
// Abstraction for a single joystick. In the current implementation, this
|
||||
|
@ -66,19 +71,19 @@ public:
|
|||
wxJoystick joystick,
|
||||
wxJoyControl control,
|
||||
uint8_t control_index,
|
||||
int16_t control_value);
|
||||
bool pressed);
|
||||
virtual ~wxJoyEvent() = default;
|
||||
|
||||
wxJoystick joystick() const { return joystick_; }
|
||||
wxJoyControl control() const { return control_; }
|
||||
uint8_t control_index() const { return control_index_; }
|
||||
int16_t control_value() const { return control_value_; }
|
||||
bool pressed() const { return pressed_; }
|
||||
|
||||
private:
|
||||
wxJoystick joystick_;
|
||||
wxJoyControl control_;
|
||||
uint8_t control_index_;
|
||||
int16_t control_value_;
|
||||
bool pressed_;
|
||||
};
|
||||
|
||||
// This is my own SDL-based joystick handler, since wxJoystick is brain-dead.
|
||||
|
|
|
@ -884,7 +884,7 @@ int MainFrame::FilterEvent(wxEvent& event)
|
|||
else if (event.GetEventType() == wxEVT_JOY && !menus_opened && !dialog_opened)
|
||||
{
|
||||
wxJoyEvent& je = (wxJoyEvent&)event;
|
||||
if (je.control_value() == 0) return -1; // joystick button UP
|
||||
if (!je.pressed()) return -1; // joystick button UP
|
||||
wxString label = wxUserInput::FromJoyEvent(je).ToString();
|
||||
wxAcceleratorEntry_v accels = wxGetApp().GetAccels();
|
||||
for (size_t i = 0; i < accels.size(); ++i)
|
||||
|
|
Loading…
Reference in New Issue