mirror of https://github.com/AxioDL/metaforce.git
Initial virtual PAD API
This commit is contained in:
parent
a96fe24260
commit
9cedce737f
|
@ -1,24 +1,5 @@
|
|||
#include "Runtime/Input/CDolphinController.hpp"
|
||||
|
||||
namespace PAD {
|
||||
// clang-format off
|
||||
enum BUTTON : u16 {
|
||||
LEFT = 0x0001,
|
||||
RIGHT = 0x0002,
|
||||
DOWN = 0x0004,
|
||||
UP = 0x0008,
|
||||
TRIGGER_Z = 0x0010,
|
||||
TRIGGER_R = 0x0020,
|
||||
TRIGGER_L = 0x0040,
|
||||
BUTTON_A = 0x0100,
|
||||
BUTTON_B = 0x0200,
|
||||
BUTTON_X = 0x0400,
|
||||
BUTTON_Y = 0x0800,
|
||||
BUTTON_START = 0x1000,
|
||||
};
|
||||
// clang-format on
|
||||
} // namespace PAD
|
||||
|
||||
namespace metaforce {
|
||||
CDolphinController::CDolphinController() {
|
||||
static bool sIsInitialized = false;
|
||||
|
@ -78,7 +59,7 @@ void CDolphinController::ProcessAxis(u32 controller, EJoyAxis axis) {
|
|||
|
||||
static constexpr std::array<u16, size_t(EButton::MAX)> mButtonMapping{
|
||||
PAD::BUTTON_A, PAD::BUTTON_B, PAD::BUTTON_X, PAD::BUTTON_Y, PAD::BUTTON_START, PAD::TRIGGER_Z,
|
||||
PAD::UP, PAD::RIGHT, PAD::DOWN, PAD::LEFT, PAD::TRIGGER_L, PAD::TRIGGER_R,
|
||||
PAD::BUTTON_UP, PAD::BUTTON_RIGHT, PAD::BUTTON_DOWN, PAD::BUTTON_LEFT, PAD::TRIGGER_L, PAD::TRIGGER_R,
|
||||
};
|
||||
|
||||
void CDolphinController::ProcessButtons(u32 controller) {
|
||||
|
|
|
@ -2,19 +2,8 @@
|
|||
|
||||
#include "Runtime/Input/IController.hpp"
|
||||
|
||||
|
||||
namespace metaforce {
|
||||
struct PADStatus {
|
||||
u16 x0_buttons;
|
||||
s8 x2_stickX;
|
||||
s8 x3_stickY;
|
||||
s8 x4_substickX;
|
||||
s8 x5_substickY;
|
||||
u8 x6_triggerL;
|
||||
u8 x7_triggerR;
|
||||
u8 x8_analogA;
|
||||
u8 x9_analogB;
|
||||
s8 xa_err;
|
||||
};
|
||||
|
||||
class CDolphinController : public IController {
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <magic_enum.hpp>
|
||||
|
||||
namespace metaforce {
|
||||
static logvisor::Module Log("CInputGenerator");
|
||||
|
||||
void CInputGenerator::Update(float dt, CArchitectureQueue& queue) {
|
||||
if (m_firstFrame) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
set(INPUT_SOURCES
|
||||
PAD.hpp
|
||||
IController.hpp DolphinIController.cpp
|
||||
CControllerAxis.hpp
|
||||
CControllerButton.hpp
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#pragma once
|
||||
#include "Runtime/Input/PAD.hpp"
|
||||
|
||||
|
||||
namespace metaforce {
|
||||
enum class EIOPort {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "aurora/pad.hpp"
|
||||
|
||||
using PADStatus = PAD::Status;
|
||||
using PADButton = PAD::BUTTON;
|
|
@ -0,0 +1,80 @@
|
|||
#pragma once
|
||||
#include "aurora/common.hpp"
|
||||
|
||||
namespace PAD {
|
||||
struct Status {
|
||||
u16 x0_buttons;
|
||||
s8 x2_stickX;
|
||||
s8 x3_stickY;
|
||||
s8 x4_substickX;
|
||||
s8 x5_substickY;
|
||||
u8 x6_triggerL;
|
||||
u8 x7_triggerR;
|
||||
u8 x8_analogA;
|
||||
u8 x9_analogB;
|
||||
s8 xa_err;
|
||||
};
|
||||
|
||||
enum BUTTON : u16 {
|
||||
BUTTON_LEFT = 0x0001,
|
||||
BUTTON_RIGHT = 0x0002,
|
||||
BUTTON_DOWN = 0x0004,
|
||||
BUTTON_UP = 0x0008,
|
||||
TRIGGER_Z = 0x0010,
|
||||
TRIGGER_R = 0x0020,
|
||||
TRIGGER_L = 0x0040,
|
||||
BUTTON_A = 0x0100,
|
||||
BUTTON_B = 0x0200,
|
||||
BUTTON_X = 0x0400,
|
||||
BUTTON_Y = 0x0800,
|
||||
BUTTON_START = 0x1000,
|
||||
};
|
||||
|
||||
enum ERROR : s8 {
|
||||
ERR_NONE = 0,
|
||||
ERR_NO_CONTROLLER = -1,
|
||||
ERR_NOT_READY = -2,
|
||||
ERR_TRANSFER = -3,
|
||||
};
|
||||
|
||||
enum MOTOR : u32 {
|
||||
MOTOR_STOP = 0,
|
||||
MOTOR_RUMBLE = 1,
|
||||
MOTOR_STOP_HARD = 2,
|
||||
};
|
||||
enum CHAN : u32 {
|
||||
CHAN0_BIT = 0x80000000,
|
||||
CHAN1_BIT = 0x40000000,
|
||||
CHAN2_BIT = 0x20000000,
|
||||
CHAN3_BIT = 0x10000000,
|
||||
};
|
||||
} // namespace PAD
|
||||
|
||||
namespace SI {
|
||||
constexpr u32 ERROR_NO_RESPONSE = 0x0008;
|
||||
constexpr u32 TYPE_GC = 0x08000000;
|
||||
constexpr u32 GC_STANDARD = 0x01000000;
|
||||
constexpr u32 GC_WIRELESS = 0x80000000;
|
||||
constexpr u32 WIRELESS_STATE = 0x02000000;
|
||||
constexpr u32 WIRELESS_FIX_ID = 0x00100000;
|
||||
constexpr u32 GC_CONTROLLER = (TYPE_GC | GC_STANDARD);
|
||||
constexpr u32 GC_RECEIVER = (TYPE_GC | GC_WIRELESS);
|
||||
constexpr u32 GC_WAVEBIRD = (TYPE_GC | GC_WIRELESS | GC_STANDARD | WIRELESS_STATE | WIRELESS_FIX_ID);
|
||||
} // namespace SI
|
||||
|
||||
using PADSamplingCallback = void (*)(void);
|
||||
constexpr bool PADButtonDown(u16 lastButton, u16 button) { return ((lastButton ^ button) & button) != 0; }
|
||||
constexpr bool PADButtonUp(u16 lastButton, u16 button) { return ((lastButton ^ button) & lastButton) != 0; }
|
||||
void PADClamp(PAD::Status* status);
|
||||
void PADClampCircle(PAD::Status* status);
|
||||
void PADInit();
|
||||
bool PADIsBarrel(s32 chan);
|
||||
u32 PADRead(PAD::Status* status);
|
||||
bool PADRecalibrate(u32 mask);
|
||||
bool PADReset(u32 mask);
|
||||
void PADSetAnalog(u32 mode);
|
||||
void PADSetSpec(s32 spec);
|
||||
void PADSetSamplingCallback(PADSamplingCallback callback);
|
||||
void PADControlAllMotors(const u32* commands);
|
||||
|
||||
u32 SIProbe(s32 chan);
|
|
@ -1,4 +1,6 @@
|
|||
#include "input.hpp"
|
||||
#include "aurora/pad.hpp"
|
||||
|
||||
#include <SDL_haptic.h>
|
||||
|
||||
#include <absl/container/btree_map.h>
|
||||
|
@ -13,9 +15,30 @@ struct GameController {
|
|||
bool m_isGameCube = false;
|
||||
Sint32 m_index = -1;
|
||||
bool m_hasRumble = false;
|
||||
constexpr bool operator==(const GameController&) const = default;
|
||||
};
|
||||
absl::flat_hash_map<Uint32, GameController> g_GameControllers;
|
||||
|
||||
GameController get_controller_for_player(u32 player) {
|
||||
for (const auto& [which, controller] : g_GameControllers) {
|
||||
if (player_index(which) == player) {
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Sint32 get_instance_for_player(u32 player) {
|
||||
for (const auto& [which, controller] : g_GameControllers) {
|
||||
if (player_index(which) == player) {
|
||||
return which;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::optional<std::string> remap_controller_layout(std::string_view mapping) {
|
||||
std::string newMapping;
|
||||
newMapping.reserve(mapping.size());
|
||||
|
@ -319,3 +342,109 @@ MouseButton translate_mouse_button_state(Uint8 state) noexcept {
|
|||
}
|
||||
|
||||
} // namespace aurora::input
|
||||
|
||||
void PADSetSpec(u32 spec) {}
|
||||
void PADInit() {}
|
||||
|
||||
static const std::array<std::pair<SDL_GameControllerButton, PAD::BUTTON>, 12> mMapping{{
|
||||
{SDL_CONTROLLER_BUTTON_A, PAD::BUTTON_A},
|
||||
{SDL_CONTROLLER_BUTTON_B, PAD::BUTTON_B},
|
||||
{SDL_CONTROLLER_BUTTON_X, PAD::BUTTON_X},
|
||||
{SDL_CONTROLLER_BUTTON_Y, PAD::BUTTON_Y},
|
||||
{SDL_CONTROLLER_BUTTON_START, PAD::BUTTON_START},
|
||||
{SDL_CONTROLLER_BUTTON_BACK, PAD::TRIGGER_Z},
|
||||
{SDL_CONTROLLER_BUTTON_LEFTSHOULDER, PAD::TRIGGER_L},
|
||||
{SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, PAD::TRIGGER_R},
|
||||
{SDL_CONTROLLER_BUTTON_DPAD_UP, PAD::BUTTON_UP},
|
||||
{SDL_CONTROLLER_BUTTON_DPAD_DOWN, PAD::BUTTON_DOWN},
|
||||
{SDL_CONTROLLER_BUTTON_DPAD_LEFT, PAD::BUTTON_LEFT},
|
||||
{SDL_CONTROLLER_BUTTON_DPAD_RIGHT, PAD::BUTTON_RIGHT},
|
||||
}};
|
||||
|
||||
u32 PADRead(PAD::Status* status) {
|
||||
u32 rumbleSupport = 0;
|
||||
for (u32 i = 0; i < 4; ++i) {
|
||||
memset(&status[i], 0, sizeof(PAD::Status));
|
||||
auto controller = aurora::input::get_controller_for_player(i);
|
||||
if (controller == aurora::input::GameController{}) {
|
||||
status[i].xa_err = PAD::ERR_NO_CONTROLLER;
|
||||
continue;
|
||||
}
|
||||
status[i].xa_err = PAD::ERR_NONE;
|
||||
std::for_each(mMapping.begin(), mMapping.end(), [&controller, &i, &status](const auto& pair) {
|
||||
if (SDL_GameControllerGetButton(controller.m_controller, pair.first)) {
|
||||
status[i].x0_buttons |= pair.second;
|
||||
}
|
||||
});
|
||||
|
||||
Sint16 x = SDL_GameControllerGetAxis(controller.m_controller, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
Sint16 y = SDL_GameControllerGetAxis(controller.m_controller, SDL_CONTROLLER_AXIS_LEFTY);
|
||||
x /= 256;
|
||||
y = (-(y + 1u)) / 256u;
|
||||
|
||||
status[i].x2_stickX = static_cast<s8>(x);
|
||||
status[i].x3_stickY = static_cast<s8>(y);
|
||||
|
||||
x = SDL_GameControllerGetAxis(controller.m_controller, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||
y = SDL_GameControllerGetAxis(controller.m_controller, SDL_CONTROLLER_AXIS_RIGHTY);
|
||||
x /= 256;
|
||||
y = (-(y + 1u)) / 256u;
|
||||
|
||||
status[i].x4_substickX = static_cast<s8>(x);
|
||||
status[i].x5_substickY = static_cast<s8>(y);
|
||||
|
||||
x = SDL_GameControllerGetAxis(controller.m_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
||||
y = SDL_GameControllerGetAxis(controller.m_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
||||
x /= 128;
|
||||
y = (-(y + 1u)) / 128u;
|
||||
|
||||
status[i].x6_triggerL = static_cast<s8>(x);
|
||||
status[i].x7_triggerR = static_cast<s8>(y);
|
||||
|
||||
|
||||
if (controller.m_hasRumble) {
|
||||
// Nintendo... why are these bits backwards? >.>
|
||||
rumbleSupport |= PAD::CHAN3_BIT << (3 - i);
|
||||
}
|
||||
}
|
||||
return rumbleSupport;
|
||||
}
|
||||
|
||||
void PADControlAllMotors(const u32* commands) {
|
||||
for (u32 i = 0; i < 4; ++i) {
|
||||
auto controller = aurora::input::get_controller_for_player(i);
|
||||
auto instance = aurora::input::get_instance_for_player(i);
|
||||
if (controller == aurora::input::GameController{}) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (controller.m_isGameCube) {
|
||||
if (commands[i] == PAD::MOTOR_STOP) {
|
||||
aurora::input::controller_rumble(instance, 0, 1, 0);
|
||||
} else if (commands[i] == PAD::MOTOR_RUMBLE) {
|
||||
aurora::input::controller_rumble(instance, 1, 1, 0);
|
||||
} else if (commands[i] == PAD::MOTOR_STOP_HARD) {
|
||||
aurora::input::controller_rumble(instance, 0, 0, 0);
|
||||
}
|
||||
} else {
|
||||
// TODO: Figure out sane values for generic controllers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u32 SIProbe(s32 chan) {
|
||||
const auto controller = aurora::input::get_controller_for_player(chan);
|
||||
if (controller == aurora::input::GameController{}){
|
||||
return SI::ERROR_NO_RESPONSE;
|
||||
}
|
||||
|
||||
if (controller.m_isGameCube) {
|
||||
auto level = SDL_JoystickCurrentPowerLevel(SDL_GameControllerGetJoystick(controller.m_controller));
|
||||
if (level == SDL_JOYSTICK_POWER_UNKNOWN) {
|
||||
return SI::GC_WAVEBIRD;
|
||||
}
|
||||
}
|
||||
|
||||
return SI::GC_CONTROLLER;
|
||||
}
|
Loading…
Reference in New Issue