maple: mutually exclusive btns per controller. better D2A axes

Handle mutually exclusive buttons (U/D, L/R) in each controller.
Track digital X/Y axes state to allow for proper handling of U+D and
L+R. Issue #334
SDL: Ignore key repeat events
This commit is contained in:
Flyinghead 2021-09-07 10:54:00 +02:00
parent 6768901446
commit 5121b0df93
5 changed files with 91 additions and 62 deletions

View File

@ -38,6 +38,12 @@ maple_device::~maple_device()
delete config;
}
static inline void mutualExclusion(u32& keycode, u32 mask)
{
if ((keycode & mask) == 0)
keycode |= mask;
}
/*
Sega Dreamcast Controller
No error checking of any kind, but works just fine
@ -53,7 +59,10 @@ struct maple_sega_controller: maple_base
return 0xfe060f00; // 4 analog axes (0-3) X Y A B Start U D L R
}
virtual u32 transform_kcode(u32 kcode) {
virtual u32 transform_kcode(u32 kcode)
{
mutualExclusion(kcode, DC_DPAD_UP | DC_DPAD_DOWN);
mutualExclusion(kcode, DC_DPAD_LEFT | DC_DPAD_RIGHT);
return kcode | 0xF901; // mask off DPad2, C, D and Z;
}
@ -189,7 +198,10 @@ struct maple_atomiswave_controller: maple_sega_controller
return 0xff663f00; // 6 analog axes, X Y L2/D2(?) A B C Start U D L R
}
u32 transform_kcode(u32 kcode) override {
u32 transform_kcode(u32 kcode) override
{
mutualExclusion(kcode, AWAVE_UP_KEY | AWAVE_DOWN_KEY);
mutualExclusion(kcode, AWAVE_LEFT_KEY | AWAVE_RIGHT_KEY);
return kcode | AWAVE_TRIGGER_KEY;
}
@ -215,7 +227,12 @@ struct maple_sega_twinstick: maple_sega_controller
return 0xfefe0000; // no analog axes, X Y A B D Start U/D/L/R U2/D2/L2/R2
}
u32 transform_kcode(u32 kcode) override {
u32 transform_kcode(u32 kcode) override
{
mutualExclusion(kcode, DC_DPAD_UP | DC_DPAD_DOWN);
mutualExclusion(kcode, DC_DPAD_LEFT | DC_DPAD_RIGHT);
mutualExclusion(kcode, DC_DPAD2_UP | DC_DPAD2_DOWN);
mutualExclusion(kcode, DC_DPAD2_LEFT | DC_DPAD2_RIGHT);
return kcode | 0x0101;
}
@ -247,7 +264,10 @@ struct maple_ascii_stick: maple_sega_controller
return 0xff070000; // no analog axes, X Y Z A B C Start U/D/L/R
}
u32 transform_kcode(u32 kcode) override {
u32 transform_kcode(u32 kcode) override
{
mutualExclusion(kcode, DC_DPAD_UP | DC_DPAD_DOWN);
mutualExclusion(kcode, DC_DPAD_LEFT | DC_DPAD_RIGHT);
return kcode | 0xF800;
}
@ -1214,7 +1234,10 @@ struct maple_mouse : maple_base
struct maple_lightgun : maple_base
{
virtual u32 transform_kcode(u32 kcode) {
virtual u32 transform_kcode(u32 kcode)
{
mutualExclusion(kcode, DC_DPAD_UP | DC_DPAD_DOWN);
mutualExclusion(kcode, DC_DPAD_LEFT | DC_DPAD_RIGHT);
if ((kcode & DC_BTN_RELOAD) == 0)
kcode &= ~DC_BTN_A; // trigger
return kcode | 0xFF01;
@ -1311,6 +1334,8 @@ struct maple_lightgun : maple_base
struct atomiswave_lightgun : maple_lightgun
{
u32 transform_kcode(u32 kcode) override {
mutualExclusion(kcode, AWAVE_UP_KEY | AWAVE_DOWN_KEY);
mutualExclusion(kcode, AWAVE_LEFT_KEY | AWAVE_RIGHT_KEY);
// No need for reload on AW
return (kcode & AWAVE_TRIGGER_KEY) == 0 ? ~AWAVE_BTN0_KEY : ~0;
}

View File

@ -1424,6 +1424,13 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
if ((kcode[p] & (1 << i)) == 0)
buttons[p] |= naomi_button_mapping[i];
#endif
for (u32& button : buttons)
{
if ((button & (NAOMI_UP_KEY | NAOMI_DOWN_KEY)) == (NAOMI_UP_KEY | NAOMI_DOWN_KEY))
button &= ~(NAOMI_UP_KEY | NAOMI_DOWN_KEY);
if ((button & (NAOMI_LEFT_KEY | NAOMI_RIGHT_KEY)) == (NAOMI_LEFT_KEY | NAOMI_RIGHT_KEY))
button &= ~(NAOMI_LEFT_KEY | NAOMI_RIGHT_KEY);
}
JVS_STATUS1(); // status
for (u32 cmdi = 0; cmdi < length_in; )

View File

@ -68,39 +68,7 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
if (key <= DC_BTN_RELOAD)
{
if (pressed)
{
kcode[port] &= ~key;
// Avoid two opposite dpad keys being pressed simultaneously
switch (key)
{
case DC_DPAD_UP:
kcode[port] |= DC_DPAD_DOWN;
break;
case DC_DPAD_DOWN:
kcode[port] |= DC_DPAD_UP;
break;
case DC_DPAD_LEFT:
kcode[port] |= DC_DPAD_RIGHT;
break;
case DC_DPAD_RIGHT:
kcode[port] |= DC_DPAD_LEFT;
break;
case DC_DPAD2_UP:
kcode[port] |= DC_DPAD2_DOWN;
break;
case DC_DPAD2_DOWN:
kcode[port] |= DC_DPAD2_UP;
break;
case DC_DPAD2_LEFT:
kcode[port] |= DC_DPAD2_RIGHT;
break;
case DC_DPAD2_RIGHT:
kcode[port] |= DC_DPAD2_LEFT;
break;
default:
break;
}
}
else
kcode[port] |= key;
#ifdef TEST_AUTOMATION
@ -131,16 +99,36 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
rt[port] = pressed ? 255 : 0;
break;
case EMU_BTN_ANA_UP:
joyy[port] = pressed ? -128 : 0;
break;
case EMU_BTN_ANA_DOWN:
joyy[port] = pressed ? 127 : 0;
{
if (pressed)
digitalToAnalogState[port] |= key;
else
digitalToAnalogState[port] &= ~key;
const u32 upDown = digitalToAnalogState[port] & (EMU_BTN_ANA_UP | EMU_BTN_ANA_DOWN);
if (upDown == 0 || upDown == (EMU_BTN_ANA_UP | EMU_BTN_ANA_DOWN))
joyy[port] = 0;
else if (upDown == EMU_BTN_ANA_UP)
joyy[port] = -128;
else
joyy[port] = 127;
}
break;
case EMU_BTN_ANA_LEFT:
joyx[port] = pressed ? -128 : 0;
break;
case EMU_BTN_ANA_RIGHT:
joyx[port] = pressed ? 127 : 0;
{
if (pressed)
digitalToAnalogState[port] |= key;
else
digitalToAnalogState[port] &= ~key;
const u32 leftRight = digitalToAnalogState[port] & (EMU_BTN_ANA_LEFT | EMU_BTN_ANA_RIGHT);
if (leftRight == 0 || leftRight == (EMU_BTN_ANA_LEFT | EMU_BTN_ANA_RIGHT))
joyx[port] = 0;
else if (leftRight == EMU_BTN_ANA_LEFT)
joyx[port] = -128;
else
joyx[port] = 127;
}
break;
default:
return false;
@ -377,6 +365,8 @@ std::string GamepadDevice::make_mapping_filename(bool instance, int system)
bool GamepadDevice::find_mapping(int system)
{
if (!_remappable)
return true;
std::string mapping_file;
mapping_file = make_mapping_filename(false, system);
@ -395,6 +385,8 @@ bool GamepadDevice::find_mapping(int system)
bool GamepadDevice::find_mapping(const char *custom_mapping /* = nullptr */)
{
if (!_remappable)
return true;
std::string mapping_file;
if (custom_mapping != nullptr)
mapping_file = custom_mapping;

View File

@ -73,7 +73,8 @@ public:
bool find_mapping(int system);
protected:
GamepadDevice(int maple_port, const char *api_name, bool remappable = true)
: _api_name(api_name), _maple_port(maple_port), _input_detected(nullptr), _remappable(remappable)
: _api_name(api_name), _maple_port(maple_port), _input_detected(nullptr), _remappable(remappable),
digitalToAnalogState{}
{
}
@ -108,6 +109,7 @@ private:
double _detection_start_time = 0.0;
input_detected_cb _input_detected;
bool _remappable;
u32 digitalToAnalogState[4];
static std::vector<std::shared_ptr<GamepadDevice>> _gamepads;
static std::mutex _gamepads_mutex;

View File

@ -217,29 +217,32 @@ void input_sdl_handle()
case SDL_KEYDOWN:
case SDL_KEYUP:
checkRawInput();
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_RETURN && (event.key.keysym.mod & KMOD_ALT))
if (event.key.repeat == 0)
{
if (window_fullscreen)
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_RETURN && (event.key.keysym.mod & KMOD_ALT))
{
SDL_SetWindowFullscreen(window, 0);
if (!gameRunning || !mouseCaptured)
SDL_ShowCursor(SDL_ENABLE);
if (window_fullscreen)
{
SDL_SetWindowFullscreen(window, 0);
if (!gameRunning || !mouseCaptured)
SDL_ShowCursor(SDL_ENABLE);
}
else
{
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
if (gameRunning)
SDL_ShowCursor(SDL_DISABLE);
}
window_fullscreen = !window_fullscreen;
}
else
else if (event.type == SDL_KEYDOWN && (event.key.keysym.mod & KMOD_LALT) && (event.key.keysym.mod & KMOD_LCTRL))
{
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
if (gameRunning)
SDL_ShowCursor(SDL_DISABLE);
captureMouse(!mouseCaptured);
}
else if (!config::UseRawInput)
{
sdl_keyboard->keyboard_input(event.key.keysym.scancode, event.type == SDL_KEYDOWN);
}
window_fullscreen = !window_fullscreen;
}
else if (event.type == SDL_KEYDOWN && (event.key.keysym.mod & KMOD_LALT) && (event.key.keysym.mod & KMOD_LCTRL))
{
captureMouse(!mouseCaptured);
}
else if (!config::UseRawInput)
{
sdl_keyboard->keyboard_input(event.key.keysym.scancode, event.type == SDL_KEYDOWN);
}
break;
case SDL_TEXTINPUT: