2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-12-14 07:26:09 +00:00

SDL controller input

This commit is contained in:
2022-02-07 20:48:08 -05:00
parent 938852afd8
commit a1482b4743
19 changed files with 554 additions and 268 deletions

View File

@@ -16,7 +16,7 @@ enum class EIOPort { Zero, One, Two, Three };
enum class EMotorState { Stop, Rumble, StopHard };
class CInputGenerator : public boo::DeviceFinder {
class CInputGenerator /*: public boo::DeviceFinder*/ {
enum class EStatusChange { NoChange = 0, Connected = 1, Disconnected = 2 };
/* When the sticks are used as logical (digital) input,
@@ -25,10 +25,14 @@ class CInputGenerator : public boo::DeviceFinder {
float m_leftDiv;
float m_rightDiv;
CKeyboardMouseControllerData m_data;
SAuroraControllerState m_state;
CFinalInput m_lastUpdate;
const CFinalInput& getFinalInput(unsigned idx, float dt) {
m_lastUpdate = CFinalInput(idx, dt, m_data, m_lastUpdate);
auto input = CFinalInput(idx, dt, m_data, m_lastUpdate);
// Merge controller input with kb/m input
input |= CFinalInput(idx, dt, m_state, m_lastUpdate, m_leftDiv, m_rightDiv);
m_lastUpdate = input;
return m_lastUpdate;
}
@@ -36,13 +40,22 @@ class CInputGenerator : public boo::DeviceFinder {
public:
CInputGenerator(float leftDiv, float rightDiv)
: boo::DeviceFinder({dev_typeid(DolphinSmashAdapter)}), m_leftDiv(leftDiv), m_rightDiv(rightDiv) {}
: /*boo::DeviceFinder({dev_typeid(DolphinSmashAdapter)}),*/ m_leftDiv(leftDiv), m_rightDiv(rightDiv) {}
~CInputGenerator() override {
if (smashAdapter) {
smashAdapter->setCallback(nullptr);
smashAdapter->closeDevice();
}
// ~CInputGenerator() override {
// if (smashAdapter) {
// smashAdapter->setCallback(nullptr);
// smashAdapter->closeDevice();
// }
// }
void controllerButton(uint32_t idx, aurora::ControllerButton button, bool pressed) noexcept {
// TODO check idx
m_state.m_btns.set(size_t(button), pressed);
}
void controllerAxis(uint32_t idx, aurora::ControllerAxis axis, int16_t value) noexcept {
// TODO check idx
m_state.m_axes[size_t(axis)] = value;
}
/* Keyboard and mouse events are delivered on the main game
@@ -79,103 +92,77 @@ public:
void reset() { m_data.m_accumScroll.zeroOut(); }
/* Input via the smash adapter is received asynchronously on a USB
* report thread. This class atomically exchanges that data to the
* game thread as needed */
struct DolphinSmashAdapterCallback : boo::IDolphinSmashAdapterCallback {
std::array<std::atomic<EStatusChange>, 4> m_statusChanges;
std::array<bool, 4> m_connected{};
std::array<boo::DolphinControllerState, 4> m_states;
std::mutex m_stateLock;
void controllerConnected(unsigned idx, boo::EDolphinControllerType) override {
/* Controller thread */
m_statusChanges[idx].store(EStatusChange::Connected);
}
void controllerDisconnected(unsigned idx) override {
/* Controller thread */
std::unique_lock lk{m_stateLock};
m_statusChanges[idx].store(EStatusChange::Disconnected);
m_states[idx].reset();
}
void controllerUpdate(unsigned idx, boo::EDolphinControllerType,
const boo::DolphinControllerState& state) override {
/* Controller thread */
std::unique_lock lk{m_stateLock};
m_states[idx] = state;
}
// /* Input via the smash adapter is received asynchronously on a USB
// * report thread. This class atomically exchanges that data to the
// * game thread as needed */
// struct DolphinSmashAdapterCallback : boo::IDolphinSmashAdapterCallback {
// std::array<std::atomic<EStatusChange>, 4> m_statusChanges;
// std::array<bool, 4> m_connected{};
// std::array<boo::DolphinControllerState, 4> m_states;
// std::mutex m_stateLock;
// void controllerConnected(unsigned idx, boo::EDolphinControllerType) override {
// /* Controller thread */
// m_statusChanges[idx].store(EStatusChange::Connected);
// }
// void controllerDisconnected(unsigned idx) override {
// /* Controller thread */
// std::unique_lock lk{m_stateLock};
// m_statusChanges[idx].store(EStatusChange::Disconnected);
// m_states[idx].reset();
// }
// void controllerUpdate(unsigned idx, boo::EDolphinControllerType,
// const boo::DolphinControllerState& state) override {
// /* Controller thread */
// std::unique_lock lk{m_stateLock};
// m_states[idx] = state;
// }
//
// std::array<CFinalInput, 4> m_lastUpdates;
// const CFinalInput& getFinalInput(unsigned idx, float dt, float leftDiv, float rightDiv) {
// /* Game thread */
// std::unique_lock lk{m_stateLock};
// boo::DolphinControllerState state = m_states[idx];
// lk.unlock();
// state.clamp(); /* PADClamp equivalent */
// m_lastUpdates[idx] = CFinalInput(idx, dt, state, m_lastUpdates[idx], leftDiv, rightDiv);
// return m_lastUpdates[idx];
// }
// EStatusChange getStatusChange(unsigned idx, bool& connected) {
// /* Game thread */
// EStatusChange ch = m_statusChanges[idx].exchange(EStatusChange::NoChange);
// if (ch == EStatusChange::Connected)
// m_connected[idx] = true;
// else if (ch == EStatusChange::Disconnected)
// m_connected[idx] = false;
// connected = m_connected[idx];
// return ch;
// }
// } m_dolphinCb;
std::array<CFinalInput, 4> m_lastUpdates;
const CFinalInput& getFinalInput(unsigned idx, float dt, float leftDiv, float rightDiv) {
/* Game thread */
std::unique_lock lk{m_stateLock};
boo::DolphinControllerState state = m_states[idx];
lk.unlock();
state.clamp(); /* PADClamp equivalent */
m_lastUpdates[idx] = CFinalInput(idx, dt, state, m_lastUpdates[idx], leftDiv, rightDiv);
return m_lastUpdates[idx];
}
EStatusChange getStatusChange(unsigned idx, bool& connected) {
/* Game thread */
EStatusChange ch = m_statusChanges[idx].exchange(EStatusChange::NoChange);
if (ch == EStatusChange::Connected)
m_connected[idx] = true;
else if (ch == EStatusChange::Disconnected)
m_connected[idx] = false;
connected = m_connected[idx];
return ch;
}
} m_dolphinCb;
/* Device connection/disconnection events are handled on a separate thread
* using the relevant OS API. This thread blocks in a loop until an event is
* received. Device pointers should only be manipulated by this thread using
* the deviceConnected() and deviceDisconnected() callbacks. */
std::shared_ptr<boo::DolphinSmashAdapter> smashAdapter;
void deviceConnected(boo::DeviceToken& tok) override {
/* Device listener thread */
if (!smashAdapter) {
auto dev = tok.openAndGetDevice();
if (dev && dev->getTypeHash() == dev_typeid(DolphinSmashAdapter)) {
smashAdapter = std::static_pointer_cast<boo::DolphinSmashAdapter>(tok.openAndGetDevice());
smashAdapter->setCallback(&m_dolphinCb);
}
}
}
void deviceDisconnected(boo::DeviceToken&, boo::DeviceBase* device) override {
if (smashAdapter.get() == device)
smashAdapter.reset();
}
// /* Device connection/disconnection events are handled on a separate thread
// * using the relevant OS API. This thread blocks in a loop until an event is
// * received. Device pointers should only be manipulated by this thread using
// * the deviceConnected() and deviceDisconnected() callbacks. */
// std::shared_ptr<boo::DolphinSmashAdapter> smashAdapter;
// void deviceConnected(boo::DeviceToken& tok) override {
// /* Device listener thread */
// if (!smashAdapter) {
// auto dev = tok.openAndGetDevice();
// if (dev && dev->getTypeHash() == dev_typeid(DolphinSmashAdapter)) {
// smashAdapter = std::static_pointer_cast<boo::DolphinSmashAdapter>(tok.openAndGetDevice());
// smashAdapter->setCallback(&m_dolphinCb);
// }
// }
// }
// void deviceDisconnected(boo::DeviceToken&, boo::DeviceBase* device) override {
// if (smashAdapter.get() == device)
// smashAdapter.reset();
// }
void SetMotorState(EIOPort port, EMotorState state) {
if (smashAdapter) {
switch (state) {
case EMotorState::Stop:
smashAdapter->stopRumble(unsigned(port));
break;
case EMotorState::Rumble:
smashAdapter->startRumble(unsigned(port));
break;
case EMotorState::StopHard:
smashAdapter->stopRumble(unsigned(port), true);
break;
}
}
// TODO aurora
}
void ControlAllMotors(const std::array<EMotorState, 4>& states) {
if (smashAdapter) {
for (size_t i = 0; i < states.size(); ++i) {
switch (states[i]) {
case EMotorState::Stop:
smashAdapter->stopRumble(i);
break;
case EMotorState::Rumble:
smashAdapter->startRumble(i);
break;
case EMotorState::StopHard:
smashAdapter->stopRumble(i, true);
break;
}
}
}
// TODO aurora
}
/* This is where the game thread enters */