From c9e7c4d02d3a67e6e9bd6de0fab97e65a9e5946c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=9A=93?= Date: Thu, 1 May 2025 22:49:18 -0400 Subject: [PATCH] Stub out the rest of the input bindings in libretro builds --- binding-sandbox/input-binding.cpp | 311 ++++++++++++++++++++++++++++++ binding-sandbox/input-binding.h | 1 + src/display/graphics.cpp | 10 +- src/input/input-retro.cpp | 90 +++++++++ src/input/input.cpp | 7 +- src/input/input.h | 57 +++++- 6 files changed, 460 insertions(+), 16 deletions(-) diff --git a/binding-sandbox/input-binding.cpp b/binding-sandbox/input-binding.cpp index 78d56818..6e2fa80f 100644 --- a/binding-sandbox/input-binding.cpp +++ b/binding-sandbox/input-binding.cpp @@ -25,6 +25,7 @@ using namespace mkxp_sandbox; VALUE mkxp_sandbox::input_module; +VALUE mkxp_sandbox::input_controller_module; static VALUE symhash; @@ -335,9 +336,296 @@ static VALUE mouse_in_window(VALUE self) { return SANDBOX_BOOL_TO_VALUE(mkxp_retro::input->mouseInWindow()); } +static VALUE raw_key_states(VALUE self) { + struct coro : boost::asio::coroutine { + VALUE ary; + uint32_t i; + uint32_t len; + + VALUE operator()(VALUE self) { + BOOST_ASIO_CORO_REENTER (this) { + len = mkxp_retro::input->rawKeyStatesLength(); + SANDBOX_AWAIT_AND_SET(ary, rb_ary_new_capa, len); + for (i = 0; i < len; ++i) { + SANDBOX_AWAIT(rb_ary_push, ary, SANDBOX_BOOL_TO_VALUE(mkxp_retro::input->rawKeyStates()[i])); + } + } + + return ary; + } + }; + + return sb()->bind()()(self); +} + +static VALUE controller_connected(VALUE self) { + return SANDBOX_BOOL_TO_VALUE(mkxp_retro::input->getControllerConnected()); +} + +static VALUE controller_name(VALUE self) { + return sb()->bind()()(mkxp_retro::input->getControllerName()); +} + +#define POWERCASE(power) \ + if (level == (int32_t)SDL_JOYSTICK_POWER_##power) { \ + SANDBOX_AWAIT_AND_SET(id, rb_intern, #power); \ + SANDBOX_AWAIT_AND_SET(value, rb_id2sym, id); \ + return value; \ + } + +static VALUE controller_power_level(VALUE self) { + struct coro : boost::asio::coroutine { + VALUE value; + ID id; + int32_t level; + + VALUE operator()(VALUE self) { + BOOST_ASIO_CORO_REENTER (this) { + level = mkxp_retro::input->getControllerPowerLevel(); + POWERCASE(UNKNOWN); + POWERCASE(EMPTY); + POWERCASE(LOW); + POWERCASE(MEDIUM); + POWERCASE(FULL); + POWERCASE(WIRED); + value = SANDBOX_NIL; + } + + return value; + } + }; + + return sb()->bind()()(self); +} + +#define DEF_AXES(enum1, enum2, name) \ + static VALUE controller_axes_##name(VALUE self) { \ + struct coro : boost::asio::coroutine { \ + VALUE ary; \ + VALUE value; \ + VALUE operator()(VALUE self) { \ + BOOST_ASIO_CORO_REENTER (this) { \ + SANDBOX_AWAIT_AND_SET(ary, rb_ary_new_capa, 2); \ + SANDBOX_AWAIT_AND_SET(value, rb_ll2inum, mkxp_retro::input->getControllerAxisValue(SDL_CONTROLLER_AXIS_##enum1)); \ + SANDBOX_AWAIT(rb_ary_push, ary, value); \ + SANDBOX_AWAIT_AND_SET(value, rb_ll2inum, mkxp_retro::input->getControllerAxisValue(SDL_CONTROLLER_AXIS_##enum2)); \ + SANDBOX_AWAIT(rb_ary_push, ary, value); \ + } \ + return ary; \ + } \ + }; \ + return sb()->bind()()(self); \ + } + +DEF_AXES(LEFTX, LEFTY, left); +DEF_AXES(RIGHTX, RIGHTY, right); +DEF_AXES(TRIGGERLEFT, TRIGGERRIGHT, trigger); + +static VALUE controller_raw_button_states(VALUE self) { + struct coro : boost::asio::coroutine { + VALUE ary; + uint32_t i; + uint32_t len; + + VALUE operator()(VALUE self) { + BOOST_ASIO_CORO_REENTER (this) { + len = mkxp_retro::input->rawButtonStatesLength(); + SANDBOX_AWAIT_AND_SET(ary, rb_ary_new_capa, len); + for (i = 0; i < len; ++i) { + SANDBOX_AWAIT(rb_ary_push, ary, SANDBOX_BOOL_TO_VALUE(mkxp_retro::input->rawButtonStates()[i])); + } + } + + return ary; + } + }; + + return sb()->bind()()(self); +} + +static VALUE controller_raw_axes(VALUE self) { + struct coro : boost::asio::coroutine { + VALUE ary; + VALUE value; + uint32_t i; + uint32_t len; + + VALUE operator()(VALUE self) { + BOOST_ASIO_CORO_REENTER (this) { + len = mkxp_retro::input->rawAxesLength(); + SANDBOX_AWAIT_AND_SET(ary, rb_ary_new_capa, len); + for (i = 0; i < len; ++i) { + SANDBOX_AWAIT_AND_SET(value, rb_float_new, mkxp_retro::input->rawAxes()[i] / 32767.0); + SANDBOX_AWAIT(rb_ary_push, ary, value); + } + } + + return ary; + } + }; + + return sb()->bind()()(self); +} + +static VALUE controller_pressex(VALUE self, VALUE code) { + struct coro : boost::asio::coroutine { + int32_t button; + + VALUE operator()(VALUE self, VALUE code) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(button, get_button_arg, code); + return SANDBOX_BOOL_TO_VALUE(mkxp_retro::input->controllerIsPressedEx(button)); + } + + return SANDBOX_UNDEF; + } + }; + + return sb()->bind()()(self, code); +} + +static VALUE controller_triggerex(VALUE self, VALUE code) { + struct coro : boost::asio::coroutine { + int32_t button; + + VALUE operator()(VALUE self, VALUE code) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(button, get_button_arg, code); + return SANDBOX_BOOL_TO_VALUE(mkxp_retro::input->controllerIsTriggeredEx(button)); + } + + return SANDBOX_UNDEF; + } + }; + + return sb()->bind()()(self, code); +} + +static VALUE controller_repeatex(VALUE self, VALUE code) { + struct coro : boost::asio::coroutine { + int32_t button; + + VALUE operator()(VALUE self, VALUE code) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(button, get_button_arg, code); + return SANDBOX_BOOL_TO_VALUE(mkxp_retro::input->controllerIsRepeatedEx(button)); + } + + return SANDBOX_UNDEF; + } + }; + + return sb()->bind()()(self, code); +} + +static VALUE controller_releaseex(VALUE self, VALUE code) { + struct coro : boost::asio::coroutine { + int32_t button; + + VALUE operator()(VALUE self, VALUE code) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(button, get_button_arg, code); + return SANDBOX_BOOL_TO_VALUE(mkxp_retro::input->controllerIsReleasedEx(button)); + } + + return SANDBOX_UNDEF; + } + }; + + return sb()->bind()()(self, code); +} + +static VALUE controller_repeatcount(VALUE self, VALUE code) { + struct coro : boost::asio::coroutine { + int32_t button; + int32_t count; + VALUE value; + + VALUE operator()(VALUE self, VALUE code) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(button, get_button_arg, code); + count = mkxp_retro::input->controllerRepeatcount(button); + SANDBOX_AWAIT_AND_SET(value, rb_ll2inum, count); + } + + return value; + } + }; + + return sb()->bind()()(self, code); +} + +static VALUE controller_timeex(VALUE self, VALUE code) { + struct coro : boost::asio::coroutine { + int32_t button; + double time; + VALUE value; + + VALUE operator()(VALUE self, VALUE code) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(button, get_button_arg, code); + time = mkxp_retro::input->controllerRepeatTimeEx(button); + SANDBOX_AWAIT_AND_SET(value, rb_float_new, time); + } + + return value; + } + }; + + return sb()->bind()()(self, code); +} + +static VALUE get_text_input(VALUE self) { + return SANDBOX_BOOL_TO_VALUE(mkxp_retro::input->getTextInputMode()); +} + +static VALUE set_text_input(VALUE self, VALUE value) { + mkxp_retro::input->setTextInputMode(value); + return value; +} + +static VALUE gets_(VALUE self) { + struct coro : boost::asio::coroutine { + VALUE value; + + VALUE operator()(VALUE self) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(value, rb_str_new_cstr, mkxp_retro::input->getText()); + mkxp_retro::input->clearText(); + } + + return value; + } + }; + + return sb()->bind()()(self); +} + +static VALUE get_clipboard(VALUE self) { + return sb()->bind()()(mkxp_retro::input->getClipboardText()); +} + +static VALUE set_clipboard(VALUE self, VALUE value) { + struct coro : boost::asio::coroutine { + wasm_ptr_t ptr; + + VALUE operator()(VALUE self, VALUE value) { + BOOST_ASIO_CORO_REENTER (this) { + SANDBOX_AWAIT_AND_SET(ptr, rb_string_value_cstr, &value); + mkxp_retro::input->setClipboardText((const char *)(**sb() + ptr)); + } + + return value; + } + }; + + return sb()->bind()()(self, value); +} + void input_binding_init::operator()() { BOOST_ASIO_CORO_REENTER (this) { SANDBOX_AWAIT_AND_SET(input_module, rb_define_module, "Input"); + SANDBOX_AWAIT(rb_define_module_function, input_module, "delta", (VALUE (*)(ANYARGS))delta, 0); SANDBOX_AWAIT(rb_define_module_function, input_module, "update", (VALUE (*)(ANYARGS))update, 0); SANDBOX_AWAIT(rb_define_module_function, input_module, "press?", (VALUE (*)(ANYARGS))press, 1); @@ -361,6 +649,29 @@ void input_binding_init::operator()() { SANDBOX_AWAIT(rb_define_module_function, input_module, "mouse_in_window", (VALUE (*)(ANYARGS))mouse_in_window, 0); SANDBOX_AWAIT(rb_define_module_function, input_module, "mouse_in_window?", (VALUE (*)(ANYARGS))mouse_in_window, 0); + SANDBOX_AWAIT(rb_define_module_function, input_module, "raw_key_states", (VALUE (*)(ANYARGS))raw_key_states, 0); + + SANDBOX_AWAIT_AND_SET(input_controller_module, rb_define_module_under, input_module, "Controller"); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "connected?", (VALUE (*)(ANYARGS))controller_connected, 0); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "name", (VALUE (*)(ANYARGS))controller_name, 0); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "power_level", (VALUE (*)(ANYARGS))controller_power_level, 0); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "axes_left", (VALUE (*)(ANYARGS))controller_axes_left, 0); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "axes_right", (VALUE (*)(ANYARGS))controller_axes_right, 0); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "axes_trigger", (VALUE (*)(ANYARGS))controller_axes_trigger, 0); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "raw_button_states", (VALUE (*)(ANYARGS))controller_raw_button_states, 0); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "raw_axes", (VALUE (*)(ANYARGS))controller_raw_axes, 0); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "pressex?", (VALUE (*)(ANYARGS))controller_pressex, 1); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "triggerex?", (VALUE (*)(ANYARGS))controller_triggerex, 1); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "repeatex?", (VALUE (*)(ANYARGS))controller_repeatex, 1); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "releaseex?", (VALUE (*)(ANYARGS))controller_releaseex, 1); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "repeatcount", (VALUE (*)(ANYARGS))controller_repeatcount, 1); + SANDBOX_AWAIT(rb_define_module_function, input_controller_module, "timeex?", (VALUE (*)(ANYARGS))controller_timeex, 1); + + SANDBOX_INIT_MODULE_PROP_BIND(input_module, text_input); + SANDBOX_AWAIT(rb_define_module_function, input_module, "gets", (VALUE (*)(ANYARGS))gets_, 0); + + SANDBOX_INIT_MODULE_PROP_BIND(input_module, clipboard); + if (rgssVer >= 3) { SANDBOX_AWAIT_AND_SET(symhash, rb_hash_new); diff --git a/binding-sandbox/input-binding.h b/binding-sandbox/input-binding.h index 5bfb1e33..2d90a425 100644 --- a/binding-sandbox/input-binding.h +++ b/binding-sandbox/input-binding.h @@ -26,6 +26,7 @@ namespace mkxp_sandbox { extern VALUE input_module; + extern VALUE input_controller_module; struct input_binding_init : boost::asio::coroutine { void operator()(); diff --git a/src/display/graphics.cpp b/src/display/graphics.cpp index 75192e9b..51acad40 100644 --- a/src/display/graphics.cpp +++ b/src/display/graphics.cpp @@ -1245,14 +1245,17 @@ bool Graphics::update(bool checkForShutdown) { p->threadData->rqWindowAdjust.wait(); p->last_update = shState->runTime(); -#ifndef MKXPZ_RETRO // update Input.repeat timing, rounding the framerate to the nearest 2 { static const double mult = 2.0; double afr = std::abs(averageFrameRate()); // abs shouldn't be necessary but that's ok afr += mult / 2; afr -= std::fmod(afr, mult); +#ifdef MKXPZ_RETRO // TODO: merge into shState + mkxp_retro::input->recalcRepeat(std::floor(afr)); +#else shState->input().recalcRepeat(std::floor(afr)); +#endif // MKXPZ_RETRO } if (checkForShutdown) @@ -1261,11 +1264,10 @@ bool Graphics::update(bool checkForShutdown) { p->checkSyncLock(); -# ifdef MKXPZ_STEAM +#ifdef MKXPZ_STEAM if (STEAMSHIM_alive()) STEAMSHIM_pump(); -# endif // MKXPZ_STEAM -#endif // MKXPZ_RETRO +#endif // MKXPZ_STEAM if (p->frozen) return false; diff --git a/src/input/input-retro.cpp b/src/input/input-retro.cpp index 1b15a91a..b810fcfd 100644 --- a/src/input/input-retro.cpp +++ b/src/input/input-retro.cpp @@ -238,6 +238,11 @@ Input::Input() p = new InputPrivate(); } +void Input::recalcRepeat(unsigned int fps) +{ + // TODO +} + double Input::getDelta() { return 0.0; // TODO @@ -329,6 +334,11 @@ bool Input::controllerIsReleasedEx(int button) return false; // TODO } +unsigned int Input::controllerRepeatcount(int button) +{ + return 0; // TODO +} + bool Input::controllerIsRepeatedEx(int button) { return false; // TODO @@ -339,6 +349,41 @@ double Input::controllerRepeatTimeEx(int button) return 0.0; // TODO } +uint8_t *Input::rawKeyStates() +{ + return nullptr; // TODO +} + +unsigned int Input::rawKeyStatesLength() +{ + return 0; // TODO +} + +uint8_t *Input::rawButtonStates() +{ + return nullptr; // TODO +} + +unsigned int Input::rawButtonStatesLength() +{ + return 0; // TODO +} + +int16_t *Input::rawAxes() +{ + return nullptr; // TODO +} + +unsigned int Input::rawAxesLength() +{ + return 0; // TODO +} + +short Input::getControllerAxisValue(SDL_GameControllerAxis axis) +{ + return 0; // TODO +} + int Input::dir4Value() { switch (p->currDir4) { @@ -384,6 +429,51 @@ bool Input::mouseInWindow() return p->mouseInWindow; } +bool Input::getControllerConnected() +{ + return true; +} + +const char *Input::getControllerName() +{ + return "RetroPad"; +} + +int Input::getControllerPowerLevel() +{ + return (int)SDL_JOYSTICK_POWER_UNKNOWN; +} + +bool Input::getTextInputMode() +{ + return false; +} + +void Input::setTextInputMode(bool mode) +{ + +} + +const char *Input::getText() +{ + return ""; +} + +void Input::clearText() +{ + +} + +const char *Input::getClipboardText() +{ + return ""; +} + +void Input::setClipboardText(const char *text) +{ + +} + Input::~Input() { delete p; diff --git a/src/input/input.cpp b/src/input/input.cpp index ef7f8e47..f4373a1b 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -1491,15 +1491,16 @@ void Input::clearText() shState->eThread().textInputBuffer.clear(); } -char *Input::getClipboardText() +const char *Input::getClipboardText() { - char *tx = SDL_GetClipboardText(); + // FIXME: this doesn't appear to be freed anywhere + const char *tx = SDL_GetClipboardText(); if (!tx) throw Exception(Exception::SDLError, "Failed to get clipboard text: %s", SDL_GetError()); return tx; } -void Input::setClipboardText(char *text) +void Input::setClipboardText(const char *text) { if (SDL_SetClipboardText(text) < 0) throw Exception(Exception::SDLError, "Failed to set clipboard text: %s", SDL_GetError()); diff --git a/src/input/input.h b/src/input/input.h index 4f93672f..0c5b4cfb 100644 --- a/src/input/input.h +++ b/src/input/input.h @@ -27,7 +27,52 @@ #include #include -#ifndef MKXPZ_RETRO +#ifdef MKXPZ_RETRO +enum SDL_GameControllerAxis +{ + SDL_CONTROLLER_AXIS_LEFTX = 0, + SDL_CONTROLLER_AXIS_LEFTY = 1, + SDL_CONTROLLER_AXIS_RIGHTX = 2, + SDL_CONTROLLER_AXIS_RIGHTY = 3, + SDL_CONTROLLER_AXIS_TRIGGERLEFT = 4, + SDL_CONTROLLER_AXIS_TRIGGERRIGHT = 5, +}; + +enum SDL_GameControllerButton +{ + SDL_CONTROLLER_BUTTON_A = 0, + SDL_CONTROLLER_BUTTON_B = 1, + SDL_CONTROLLER_BUTTON_X = 2, + SDL_CONTROLLER_BUTTON_Y = 3, + SDL_CONTROLLER_BUTTON_BACK = 4, + SDL_CONTROLLER_BUTTON_GUIDE = 5, + SDL_CONTROLLER_BUTTON_START = 6, + SDL_CONTROLLER_BUTTON_LEFTSTICK = 7, + SDL_CONTROLLER_BUTTON_RIGHTSTICK = 8, + SDL_CONTROLLER_BUTTON_LEFTSHOULDER = 9, + SDL_CONTROLLER_BUTTON_RIGHTSHOULDER = 10, + SDL_CONTROLLER_BUTTON_DPAD_UP = 11, + SDL_CONTROLLER_BUTTON_DPAD_DOWN = 12, + SDL_CONTROLLER_BUTTON_DPAD_LEFT = 13, + SDL_CONTROLLER_BUTTON_DPAD_RIGHT = 14, + SDL_CONTROLLER_BUTTON_MISC1 = 15, + SDL_CONTROLLER_BUTTON_PADDLE1 = 16, + SDL_CONTROLLER_BUTTON_PADDLE2 = 17, + SDL_CONTROLLER_BUTTON_PADDLE3 = 18, + SDL_CONTROLLER_BUTTON_PADDLE4 = 19, + SDL_CONTROLLER_BUTTON_TOUCHPAD = 20, +}; + +enum SDL_JoystickPowerLevel +{ + SDL_JOYSTICK_POWER_UNKNOWN = 0, + SDL_JOYSTICK_POWER_EMPTY = 1, + SDL_JOYSTICK_POWER_LOW = 2, + SDL_JOYSTICK_POWER_MEDIUM = 3, + SDL_JOYSTICK_POWER_FULL = 4, + SDL_JOYSTICK_POWER_WIRED = 5, +}; +#else #include extern std::unordered_map vKeyToScancode; extern std::unordered_map strToScancode; @@ -59,9 +104,7 @@ public: MouseX1 = 41, MouseX2 = 42 }; -#ifndef MKXPZ_RETRO void recalcRepeat(unsigned int fps); -#endif // MKXPZ_RETRO double getDelta(); void update(); @@ -87,7 +130,6 @@ public: unsigned int controllerRepeatcount(int button); double controllerRepeatTimeEx(int button); -#ifndef MKXPZ_RETRO uint8_t *rawKeyStates(); unsigned int rawKeyStatesLength(); uint8_t *rawButtonStates(); @@ -96,7 +138,6 @@ public: unsigned int rawAxesLength(); short getControllerAxisValue(SDL_GameControllerAxis axis); -#endif // MKXPZ_RETRO int dir4Value(); int dir8Value(); @@ -106,7 +147,6 @@ public: int scrollV(); bool mouseInWindow(); -#ifndef MKXPZ_RETRO bool getControllerConnected(); const char *getControllerName(); int getControllerPowerLevel(); @@ -116,12 +156,11 @@ public: const char *getText(); void clearText(); - char *getClipboardText(); - void setClipboardText(char *text); + const char *getClipboardText(); + void setClipboardText(const char *text); const char *getAxisName(SDL_GameControllerAxis axis); const char *getButtonName(SDL_GameControllerButton button); -#endif // MKXPZ_RETRO #ifdef MKXPZ_RETRO Input();