From 5121b0df9354c395f1d887cc6717973c2a50bf69 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Tue, 7 Sep 2021 10:54:00 +0200 Subject: [PATCH] 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 --- core/hw/maple/maple_devs.cpp | 35 +++++++++++++++--- core/hw/maple/maple_jvs.cpp | 7 ++++ core/input/gamepad_device.cpp | 68 ++++++++++++++++------------------- core/input/gamepad_device.h | 4 ++- core/sdl/sdl.cpp | 39 ++++++++++---------- 5 files changed, 91 insertions(+), 62 deletions(-) diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 0db4e1c6e..cff451dea 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -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; } diff --git a/core/hw/maple/maple_jvs.cpp b/core/hw/maple/maple_jvs.cpp index 7abd4b056..a81e8f3bb 100644 --- a/core/hw/maple/maple_jvs.cpp +++ b/core/hw/maple/maple_jvs.cpp @@ -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; ) diff --git a/core/input/gamepad_device.cpp b/core/input/gamepad_device.cpp index ebbd50680..fb00dcce4 100644 --- a/core/input/gamepad_device.cpp +++ b/core/input/gamepad_device.cpp @@ -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; diff --git a/core/input/gamepad_device.h b/core/input/gamepad_device.h index ef1f07863..02ad06e25 100644 --- a/core/input/gamepad_device.h +++ b/core/input/gamepad_device.h @@ -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> _gamepads; static std::mutex _gamepads_mutex; diff --git a/core/sdl/sdl.cpp b/core/sdl/sdl.cpp index 627fdd81d..7c2327a36 100644 --- a/core/sdl/sdl.cpp +++ b/core/sdl/sdl.cpp @@ -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: