Initial commit

This commit is contained in:
Gericom
2025-11-22 17:21:45 +01:00
commit 5d6f67c612
517 changed files with 63025 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
#pragma once
#include "InputKey.h"
/// @brief Interface for a source of key input.
class IInputSource
{
public:
virtual ~IInputSource() { }
virtual InputKey Sample() const = 0;
};

View File

@@ -0,0 +1,45 @@
#pragma once
enum class InputKey : u16
{
None = 0,
A = 1 << 0,
B = 1 << 1,
Select = 1 << 2,
Start = 1 << 3,
DpadRight = 1 << 4,
DpadLeft = 1 << 5,
DpadUp = 1 << 6,
DpadDown = 1 << 7,
R = 1 << 8,
L = 1 << 9,
X = 1 << 10,
Y = 1 << 11,
Debug = 1 << 13
};
inline InputKey operator&(InputKey lhs, InputKey rhs)
{
return static_cast<InputKey>(static_cast<u16>(lhs) & static_cast<u16>(rhs));
}
inline InputKey operator|(InputKey lhs, InputKey rhs)
{
return static_cast<InputKey>(static_cast<u16>(lhs) | static_cast<u16>(rhs));
}
inline InputKey operator~(InputKey lhs)
{
return static_cast<InputKey>(~static_cast<u16>(lhs));
}
inline InputKey operator^(InputKey lhs, InputKey rhs)
{
return static_cast<InputKey>(static_cast<u16>(lhs) ^ static_cast<u16>(rhs));
}
inline InputKey operator|=(InputKey& lhs, InputKey rhs)
{
lhs = lhs | rhs; // don't use |= to prevent recursion
return lhs;
}

View File

@@ -0,0 +1,58 @@
#pragma once
#include "InputKey.h"
class InputProvider
{
public:
/// @brief Returns a bitmask of the keys currently being held.
/// @return A bitmask of the keys currently being held.
InputKey GetCurrentKeys() const { return _currentKeys; }
/// @brief Returns whether any of the keys in the given \p mask is currently being held.
/// @param mask The mask to check for.
/// @return \c true if any of the keys in the \p mask is being held, or \c false otherwise.
bool Current(InputKey mask) const { return static_cast<bool>(_currentKeys & mask); }
/// @brief Returns a bitmask of the keys that went from unpressed to pressed in the latest update.
/// @return A bitmask of the keys that went from unpressed to pressed in the latest update.
InputKey GetTriggeredKeys() const
{
return _triggeredKeys;
}
/// @brief Returns whether any of the keys in the given \p mask went from unpressed to pressed in the latest update.
/// @param mask The mask to check for.
/// @return \c true if any of the keys in the \p mask went from unpressed to pressed
/// in the latest update, or \c false otherwise.
bool Triggered(InputKey mask) const { return static_cast<bool>(_triggeredKeys & mask); }
/// @brief Returns a bitmask of the keys that went from pressed to unpressed in the latest update.
/// @return A bitmask of the keys that went from pressed to unpressed in the latest update.
InputKey GetReleasedKeys() const { return _releasedKeys; }
/// @brief Returns whether any of the keys in the given \p mask went from pressed to unpressed in the latest update.
/// @param mask The mask to check for.
/// @return \c true if any of the keys in the \p mask went from pressed to unpressed
/// in the latest update, or \c false otherwise.
bool Released(InputKey mask) const { return static_cast<bool>(_releasedKeys & mask); }
/// @brief Updates the input provider.
virtual void Update() = 0;
/// @brief Resets the input provider.
virtual void Reset()
{
_currentKeys = InputKey::None;
_triggeredKeys = InputKey::None;
_releasedKeys = InputKey::None;
}
protected:
InputKey _currentKeys;
InputKey _triggeredKeys;
InputKey _releasedKeys;
InputProvider()
: _currentKeys(InputKey::None), _triggeredKeys(InputKey::None), _releasedKeys(InputKey::None) { }
};

View File

@@ -0,0 +1,58 @@
#include "common.h"
#include "InputRepeater.h"
void InputRepeater::Update()
{
_inputProvider->Update();
InputKey curKeys = _inputProvider->GetCurrentKeys();
InputKey repKeys = InputKey::None;
if (_state == State::Idle)
{
if (static_cast<bool>(curKeys & _repeatMask))
{
_state = State::FirstRepeat;
_frameCounter = 0;
repKeys = curKeys & _repeatMask;
}
}
else if (_state == State::FirstRepeat)
{
if (static_cast<bool>(curKeys & _repeatMask))
{
if (++_frameCounter >= _firstRepeatDelayFrames)
{
_state = State::NextRepeat;
_frameCounter = 0;
repKeys = curKeys & _repeatMask;
}
}
else
_state = State::Idle;
}
else if (_state == State::NextRepeat)
{
if (static_cast<bool>(curKeys & _repeatMask))
{
if (++_frameCounter >= _nextRepeatDelayFrames)
{
_frameCounter = 0;
repKeys = curKeys & _repeatMask;
}
}
else
_state = State::Idle;
}
InputKey lastRepKeys = _currentKeys & _repeatMask;
_currentKeys = curKeys | repKeys;
_triggeredKeys = _inputProvider->GetTriggeredKeys() | repKeys;
_releasedKeys = _inputProvider->GetReleasedKeys() | (lastRepKeys & (lastRepKeys ^ repKeys));
}
void InputRepeater::Reset()
{
InputProvider::Reset();
_inputProvider->Reset();
_state = State::Idle;
_frameCounter = 0;
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "InputProvider.h"
/// @brief Input provider that wraps another input provider and adds key repetition on top of it.
class InputRepeater : public InputProvider
{
public:
InputRepeater(InputProvider* inputProvider, InputKey repeatMask, u16 firstRepeatDelay, u16 nextRepeatDelay)
: _inputProvider(inputProvider), _state(State::Idle)
, _frameCounter(0), _repeatMask(repeatMask)
, _firstRepeatDelayFrames(firstRepeatDelay)
, _nextRepeatDelayFrames(nextRepeatDelay) { }
void Update() override;
void Reset() override;
private:
enum class State
{
Idle,
FirstRepeat,
NextRepeat
};
InputProvider* _inputProvider;
State _state;
u16 _frameCounter;
InputKey _repeatMask;
u16 _firstRepeatDelayFrames;
u16 _nextRepeatDelayFrames;
};

View File

@@ -0,0 +1,17 @@
#pragma once
#include "common.h"
#include <nds/input.h>
#include "IInputSource.h"
#include "sharedMemory.h"
/// @brief Input source from the physical DS buttons.
class PadInputSource : public IInputSource
{
public:
InputKey Sample() const override
{
u16 arm9Mask = (~REG_KEYINPUT & 0x3FF);
u16 arm7Mask = (~SHARED_KEY_XY & 0xB);
return static_cast<InputKey>((arm9Mask | (arm7Mask << 10)));
}
};

View File

@@ -0,0 +1,22 @@
#include "common.h"
#include "SampledInputProvider.h"
void SampledInputProvider::Update()
{
InputKey curKeys = _currentKeys;
InputKey trig = InputKey::None;
InputKey rel = InputKey::None;
while (_inputBufferReadPtr != _inputBufferWritePtr)
{
InputKey nextKeys = _inputBuffer[_inputBufferReadPtr];
trig |= (nextKeys ^ curKeys) & nextKeys;
rel |= (nextKeys ^ curKeys) & curKeys;
curKeys = nextKeys;
_inputBufferReadPtr = (_inputBufferReadPtr + 1) & 3;
}
_triggeredKeys = trig;
_releasedKeys = rel;
_currentKeys = curKeys;
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "InputProvider.h"
#include "IInputSource.h"
/// @brief Input provider providing input from an \see IInputSource.
class SampledInputProvider : public InputProvider
{
public:
explicit SampledInputProvider(const IInputSource* inputSource)
: _inputSource(inputSource), _inputBufferReadPtr(0), _inputBufferWritePtr(0) { }
void Update() override;
/// @brief Samples the input source.
void Sample()
{
_inputBuffer[_inputBufferWritePtr] = _inputSource->Sample();
_inputBufferWritePtr = (_inputBufferWritePtr + 1) & 3;
}
void Reset() override
{
InputProvider::Reset();
_inputBufferReadPtr = 0;
_inputBufferWritePtr = 0;
}
private:
const IInputSource* _inputSource;
InputKey _inputBuffer[4];
u8 _inputBufferReadPtr;
u8 _inputBufferWritePtr;
};