diff --git a/src/frontend/EmuThread.cpp b/src/frontend/EmuThread.cpp index 20cfa115..83b3e716 100644 --- a/src/frontend/EmuThread.cpp +++ b/src/frontend/EmuThread.cpp @@ -4,10 +4,39 @@ #include "Audio.hpp" EmuThread::EmuThread(std::unique_ptr&& instance_, std::unique_ptr&& wsiPlatform_, std::unique_ptr&& windowInfo_, SettingsWindow& settings) noexcept - : instance(std::move(instance_)), wsiPlatform(std::move(wsiPlatform_)), windowInfo(std::move(windowInfo_)), core(parallel), settings(settings) {} + : instance(std::move(instance_)), wsiPlatform(std::move(wsiPlatform_)), + windowInfo(std::move(windowInfo_)), + controller(SDL_GameControllerClose), + core(parallel), settings(settings) {} [[noreturn]] void EmuThread::run() noexcept { parallel.Init(instance.get(), std::move(wsiPlatform), std::move(windowInfo), core.cpu->GetMem().GetRDRAMPtr()); + SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); + bool controllerConnected = false; + + auto pollEvents = [&]() { + SDL_Event e; + while(SDL_PollEvent(&e)) { + switch(e.type) { + case SDL_CONTROLLERDEVICEADDED: { + const int index = e.cdevice.which; + controller.Construct(SDL_GameControllerOpen, index); + Util::info("Found controller!"); + auto serial = SDL_GameControllerGetSerial(controller.get()); + auto name = SDL_GameControllerName(controller.get()); + auto path = SDL_GameControllerPath(controller.get()); + Util::info("\tName: {}", name ? name : "Not available"); + Util::info("\tSerial: {}", serial ? serial : "Not available"); + Util::info("\tPath: {}", path ? path : "Not available"); + controllerConnected = true; + } break; + case SDL_CONTROLLERDEVICEREMOVED: { + controllerConnected = false; + controller.Destroy(); + } break; + } + } + }; while (true) { if (!core.pause) { @@ -20,5 +49,46 @@ EmuThread::EmuThread(std::unique_ptr&& instance_, std::unique parallel.UpdateScreen(core.cpu->GetMem().mmio.vi, true); } } + + pollEvents(); + + if(controllerConnected) { + n64::PIF& pif = core.cpu->GetMem().mmio.si.pif; + pif.UpdateButton(0, n64::Controller::Key::A, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_A)); + pif.UpdateButton(0, n64::Controller::Key::B, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_X)); + pif.UpdateButton(0, n64::Controller::Key::Z, SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_TRIGGERLEFT) == SDL_JOYSTICK_AXIS_MAX); + pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_START)); + pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_DPAD_UP)); + pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_DPAD_DOWN)); + pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_DPAD_LEFT)); + pif.UpdateButton(0, n64::Controller::Key::DRight, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_DPAD_RIGHT)); + pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_LEFTSHOULDER)); + pif.UpdateButton(0, n64::Controller::Key::RT, SDL_GameControllerGetButton(controller.get(), SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)); + pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_RIGHTY) <= -127); + pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_RIGHTY) >= 127); + pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_RIGHTX) <= -127); + pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_RIGHTX) >= 127); + + float xclamped = SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_AXIS_LEFTX); + if(xclamped < 0) { + xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN)); + } else { + xclamped /= SDL_JOYSTICK_AXIS_MAX; + } + + xclamped *= 86; + + float yclamped = SDL_GameControllerGetAxis(controller.get(), SDL_CONTROLLER_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); + } } } \ No newline at end of file diff --git a/src/frontend/EmuThread.hpp b/src/frontend/EmuThread.hpp index d3b8707d..6963aeee 100644 --- a/src/frontend/EmuThread.hpp +++ b/src/frontend/EmuThread.hpp @@ -4,6 +4,7 @@ #include #include #include +#include class EmuThread : public QThread { @@ -16,6 +17,7 @@ public: [[noreturn]] void run() noexcept override; + Util::AutoRelease controller; ParallelRDP parallel; n64::Core core; SettingsWindow& settings; diff --git a/src/frontend/InputSettings.cpp b/src/frontend/InputSettings.cpp index 3ca56cc9..ef46ad09 100644 --- a/src/frontend/InputSettings.cpp +++ b/src/frontend/InputSettings.cpp @@ -62,8 +62,8 @@ InputSettings::InputSettings(nlohmann::json& settings) : settings(settings), QWi for (int i = 0; i < 18; i++) { connect(kb_buttons[i], &QPushButton::pressed, this, [&, i]() { - for (int i = 0; i < 18; i++) { - kb_buttons[i]->setEnabled(false); + for (auto kb_button : kb_buttons) { + kb_button->setEnabled(false); } grabKeyboard(); grabbing = true; @@ -71,16 +71,16 @@ InputSettings::InputSettings(nlohmann::json& settings) : settings(settings), QWi }); } - QHBoxLayout* AB = new QHBoxLayout; - QHBoxLayout* ZStart = new QHBoxLayout; - QHBoxLayout* LR = new QHBoxLayout; - QHBoxLayout* DupDdown = new QHBoxLayout; - QHBoxLayout* DleftDright = new QHBoxLayout; - QHBoxLayout* CupCdown = new QHBoxLayout; - QHBoxLayout* CleftCright = new QHBoxLayout; - QHBoxLayout* AupAdown = new QHBoxLayout; - QHBoxLayout* AleftAright = new QHBoxLayout; - QVBoxLayout* mainLayout = new QVBoxLayout; + auto AB = new QHBoxLayout; + auto ZStart = new QHBoxLayout; + auto LR = new QHBoxLayout; + auto DupDdown = new QHBoxLayout; + auto DleftDright = new QHBoxLayout; + auto CupCdown = new QHBoxLayout; + auto CleftCright = new QHBoxLayout; + auto AupAdown = new QHBoxLayout; + auto AleftAright = new QHBoxLayout; + auto mainLayout = new QVBoxLayout; AB->addWidget(n64_button_labels[0]); AB->addWidget(kb_buttons[0]); @@ -139,8 +139,8 @@ void InputSettings::keyPressEvent(QKeyEvent* e) { kb_buttons[which_grabbing]->setText(k); grabbing = false; which_grabbing = -1; - for (int i = 0; i < 18; i++) { - kb_buttons[i]->setEnabled(true); + for (auto kb_button : kb_buttons) { + kb_button->setEnabled(true); } releaseKeyboard(); emit modified(); diff --git a/src/utils/MemoryHelpers.hpp b/src/utils/MemoryHelpers.hpp index e8ea391a..b2f19b65 100644 --- a/src/utils/MemoryHelpers.hpp +++ b/src/utils/MemoryHelpers.hpp @@ -3,8 +3,43 @@ #include #include #include +#include namespace Util { +template +struct AutoRelease { + AutoRelease(void (*dtor)(T*)) : dtor(dtor) { } + + AutoRelease(T* (*ctor)(Args...), void (*dtor)(T*), Args... args) : dtor(dtor) { + thing = ctor(args...); + } + + T* get() { return thing; } + + void Construct(T* (*ctor)(Args...), Args... args) { + if(thing) { + dtor(thing); + } + + thing = ctor(args...); + } + + void Destroy() { + if(thing) { + dtor(thing); + } + } + + ~AutoRelease() { + if(thing) { + dtor(thing); + } + } +private: + T* thing = nullptr; + void (*dtor)(T*) = nullptr; +}; + template static FORCE_INLINE T ReadAccess(const u8* data, u32 index) { if constexpr (sizeof(T) == 8) {