diff --git a/src/frontend/ImGuiImpl/Combobox.hpp b/src/frontend/ImGuiImpl/Combobox.hpp index 9a1d7893..d022f17d 100644 --- a/src/frontend/ImGuiImpl/Combobox.hpp +++ b/src/frontend/ImGuiImpl/Combobox.hpp @@ -71,6 +71,7 @@ struct Combobox { bool isEnabled() { return enabled; } const std::string& getCurrentlySelected() { return items[current_index].getLabel(); } + const int& getCurrentlySelectedIndex() { return current_index; } void setCurrentIndex(int v) { current_index = v; } int getCurrentIndex() { return current_index; } diff --git a/src/frontend/InputSettings.cpp b/src/frontend/InputSettings.cpp index 3bedf400..0d61847d 100644 --- a/src/frontend/InputSettings.cpp +++ b/src/frontend/InputSettings.cpp @@ -29,8 +29,9 @@ void InputSettings::UnregisterEventWatchers() { bool InputSettings::render() { if(devices.render()) { auto currentlySelectedDevice = devices.getCurrentlySelected(); + currentlySelectedDeviceIndex = devices.getCurrentlySelectedIndex(); JSONSetField(settings, "input", "Device", currentlySelectedDevice); - selectedDeviceIsNotKeyboard = currentlySelectedDevice == "Keyboard/Mouse"; + selectedDeviceIsNotKeyboard = currentlySelectedDevice != "Keyboard/Mouse"; modified = true; } @@ -76,12 +77,13 @@ bool QueryDevices(void *userdata, SDL_Event *event) { { const auto index = event->gdevice.which; - const auto gamepad = SDL_OpenGamepad(index); + auto gamepad = SDL_OpenGamepad(index); Util::info("Found controller!"); const auto serial = SDL_GetGamepadSerial(gamepad); const auto name = SDL_GetGamepadName(gamepad); const auto path = SDL_GetGamepadPath(gamepad); + _this->gamepads[index] = gamepad; if (name) { if (!_this->gamepadIndexes.contains(index)) { _this->gamepadIndexes[index] = name; @@ -98,16 +100,16 @@ bool QueryDevices(void *userdata, SDL_Event *event) { } _this->devices.addItem({path}); } - - SDL_CloseGamepad(gamepad); } return true; case SDL_EVENT_GAMEPAD_REMOVED: { const auto index = event->gdevice.which; - if (_this->gamepadIndexes.contains(index)) + if (_this->gamepadIndexes.contains(index)) { _this->devices.removeItem(_this->gamepadIndexes[index]); + SDL_CloseGamepad(_this->gamepads[index]); + } } return true; default: diff --git a/src/frontend/InputSettings.hpp b/src/frontend/InputSettings.hpp index 3bdf42e4..425e529e 100644 --- a/src/frontend/InputSettings.hpp +++ b/src/frontend/InputSettings.hpp @@ -7,8 +7,10 @@ class InputSettings final { public: + std::unordered_map gamepads{}; bool grabbing = false; int whichGrabbing = -1; + int currentlySelectedDeviceIndex = -1; std::unordered_map gamepadIndexes{}; std::array kbButtons = { diff --git a/src/frontend/KaizenGui.cpp b/src/frontend/KaizenGui.cpp index 7097df5d..b42051f0 100644 --- a/src/frontend/KaizenGui.cpp +++ b/src/frontend/KaizenGui.cpp @@ -4,8 +4,12 @@ #include #include +bool HandleInput(void *userdata, SDL_Event *event); + KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_shared()), vulkanWidget(core, window.getHandle()), emuThread(core, fpsCounter, vulkanWidget, settingsWindow) { gui::Initialize(core->parallel.wsi, window.getHandle()); + + SDL_AddEventWatch(HandleInput, this); actionPause.setFunc([&]() { if(ImGui::IsItemClicked()) { @@ -82,6 +86,94 @@ KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_sha KaizenGui::~KaizenGui() { gui::Cleanup(); + SDL_RemoveEventWatch(HandleInput, this); + SDL_Quit(); +} + +bool HandleInput(void *userdata, SDL_Event *event) { + auto _this = (KaizenGui*)userdata; + InputSettings& inputSettings = _this->settingsWindow.inputSettings; + n64::PIF &pif = _this->core->cpu->GetMem().mmio.si.pif; + switch(event->type) { + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + if(!inputSettings.selectedDeviceIsNotKeyboard) + return false; + { + _this->core->pause = true; + pif.UpdateButton(0, n64::Controller::Key::Z, SDL_GetGamepadAxis(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_AXIS_LEFT_TRIGGER) == SDL_JOYSTICK_AXIS_MAX); + pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GetGamepadAxis(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_AXIS_RIGHTY) <= -127); + pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GetGamepadAxis(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_AXIS_RIGHTY) >= 127); + pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GetGamepadAxis(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_AXIS_RIGHTX) <= -127); + pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GetGamepadAxis(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_AXIS_RIGHTX) >= 127); + + float xclamped = SDL_GetGamepadAxis(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_AXIS_LEFTX); + if (xclamped < 0) { + xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MAX)); + } else { + xclamped /= SDL_JOYSTICK_AXIS_MAX; + } + + xclamped *= 86; + + float yclamped = SDL_GetGamepadAxis(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_AXIS_LEFTY); + if (yclamped < 0) { + yclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN)); + } else { + yclamped /= SDL_JOYSTICK_AXIS_MAX; + } + + yclamped *= 86; + + pif.UpdateAxis(0, n64::Controller::Axis::Y, -yclamped); + pif.UpdateAxis(0, n64::Controller::Axis::X, xclamped); + _this->core->pause = false; + } + return true; + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + if(!inputSettings.selectedDeviceIsNotKeyboard) + return false; + { + _this->core->pause = true; + pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_BUTTON_SOUTH)); + pif.UpdateButton(0, n64::Controller::Key::B, SDL_GetGamepadButton(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_BUTTON_WEST)); + pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GetGamepadButton(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_BUTTON_START)); + pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GetGamepadButton(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_BUTTON_DPAD_UP)); + pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GetGamepadButton(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_BUTTON_DPAD_DOWN)); + pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GetGamepadButton(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_BUTTON_DPAD_LEFT)); + pif.UpdateButton(0, n64::Controller::Key::DRight, SDL_GetGamepadButton(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_BUTTON_DPAD_RIGHT)); + pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GetGamepadButton(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_BUTTON_LEFT_SHOULDER)); + pif.UpdateButton(0, n64::Controller::Key::RT, SDL_GetGamepadButton(inputSettings.gamepads[inputSettings.currentlySelectedDeviceIndex], SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER)); + _this->core->pause = false; + } + return true; + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + if(inputSettings.selectedDeviceIsNotKeyboard) + return false; + { + _this->core->pause = true; + auto keys = SDL_GetKeyboardState(nullptr); + pif.UpdateButton(0, n64::Controller::Key::Z, keys[SDL_SCANCODE_Z]); + pif.UpdateButton(0, n64::Controller::Key::CUp, keys[SDL_SCANCODE_HOME]); + pif.UpdateButton(0, n64::Controller::Key::CDown, keys[SDL_SCANCODE_END]); + pif.UpdateButton(0, n64::Controller::Key::CLeft, keys[SDL_SCANCODE_DELETE]); + pif.UpdateButton(0, n64::Controller::Key::CRight, keys[SDL_SCANCODE_PAGEDOWN]); + pif.UpdateButton(0, n64::Controller::Key::A, keys[SDL_SCANCODE_X]); + pif.UpdateButton(0, n64::Controller::Key::B, keys[SDL_SCANCODE_C]); + pif.UpdateButton(0, n64::Controller::Key::Start, keys[SDL_SCANCODE_RETURN]); + pif.UpdateButton(0, n64::Controller::Key::DUp, keys[SDL_SCANCODE_I]); + pif.UpdateButton(0, n64::Controller::Key::DDown, keys[SDL_SCANCODE_K]); + pif.UpdateButton(0, n64::Controller::Key::DLeft, keys[SDL_SCANCODE_J]); + pif.UpdateButton(0, n64::Controller::Key::DRight, keys[SDL_SCANCODE_L]); + pif.UpdateButton(0, n64::Controller::Key::LT, keys[SDL_SCANCODE_A]); + pif.UpdateButton(0, n64::Controller::Key::RT, keys[SDL_SCANCODE_S]); + pif.UpdateAxis(0, n64::Controller::Axis::Y, keys[SDL_SCANCODE_UP] ? 86 : keys[SDL_SCANCODE_DOWN] ? -86 : 0); + pif.UpdateAxis(0, n64::Controller::Axis::X, keys[SDL_SCANCODE_LEFT] ? -86 : keys[SDL_SCANCODE_RIGHT] ? 86 : 0); + _this->core->pause = false; + } + return true; + default: return false; + } } void KaizenGui::RenderUI() { diff --git a/src/frontend/KaizenGui.hpp b/src/frontend/KaizenGui.hpp index 4eac0716..aa92a478 100644 --- a/src/frontend/KaizenGui.hpp +++ b/src/frontend/KaizenGui.hpp @@ -27,7 +27,6 @@ public: void LoadROM(const std::string &path) noexcept; private: bool quit = false; - void handleEvents(); std::function emuExitFunc; void RenderUI(); }; diff --git a/src/frontend/SettingsWindow.hpp b/src/frontend/SettingsWindow.hpp index e5917416..cdba8a6a 100644 --- a/src/frontend/SettingsWindow.hpp +++ b/src/frontend/SettingsWindow.hpp @@ -12,8 +12,8 @@ class SettingsWindow final { nlohmann::json settings; CPUSettings cpuSettings{settings}; AudioSettings audioSettings{settings}; - InputSettings inputSettings{settings}; public: + InputSettings inputSettings{settings}; gui::PopupWindow popup{"Emulator Settings"}; bool render(); SettingsWindow();