18static constexpr int THRESHOLD = 32768 / 4;
20static constexpr int THRESHOLD = 32768 / 10;
27#ifdef SDL_JOYSTICK_DISABLED
28 (void)eventDistributor;
29 (void)stateChangeDistributor;
32 for (
auto i :
xrange(SDL_NumJoysticks())) {
33 if (SDL_Joystick* joystick = SDL_JoystickOpen(i)) {
42 std::make_unique<JoyMega>(
44 stateChangeDistributor,
57 unsigned press_,
unsigned release_)
59 , joyNum(joyNum_), press(press_), release(release_)
61 assert((press != 0) || (release != 0));
62 assert((press & release) == 0);
65 [[nodiscard]]
unsigned getPress()
const {
return press; }
66 [[nodiscard]]
unsigned getRelease()
const {
return release; }
68 template<
typename Archive>
void serialize(Archive& ar,
unsigned )
70 ar.template serializeBase<StateChange>(*
this);
71 ar.serialize(
"joyNum", joyNum,
77 unsigned press, release;
81#ifndef SDL_JOYSTICK_DISABLED
88 SDL_Joystick* joystick_)
89 : eventDistributor(eventDistributor_)
90 , stateChangeDistributor(stateChangeDistributor_)
92 , joyNum(SDL_JoystickInstanceID(joystick_))
94 , desc(SDL_JoystickName(joystick_))
95 , lastTime(EmuTime::zero())
97 const_cast<std::string&
>(name)[7] =
char(
'1' + joyNum);
105 SDL_JoystickClose(joystick);
122 status = calcInitialState();
126 cycleMask = (status & 0x800) ? 7 : 1;
129void JoyMega::plugHelper2()
150 case 0:
case 2:
case 4:
152 return (status & 0x00f) | ((status & 0x060) >> 1);
155 return (status & 0x013) | ((status & 0x080) >> 2);
158 return (status & 0x010) | ((status & 0x080) >> 2);
161 return ((status & 0x400) >> 10) |
162 ((status & 0xA00) >> 8) |
163 ((status & 0x100) >> 6) |
164 ((status & 0x060) >> 1);
167 return (status & 0x010) | ((status & 0x080) >> 2) | 0x0f;
177 if (((value >> 2) & 1) != (cycle & 1)) {
178 cycle = (cycle + 1) & cycleMask;
180 assert(((value >> 2) & 1) == (cycle & 1));
183void JoyMega::checkTime(EmuTime::param time)
191static constexpr unsigned encodeButton(
unsigned button, uint8_t cycleMask)
193 unsigned n = (cycleMask == 7) ? 7 : 3;
194 return 1 << (4 + (button & n));
197unsigned JoyMega::calcInitialState()
199 unsigned result = 0xfff;
200 int xAxis = SDL_JoystickGetAxis(joystick, 0);
201 if (xAxis < -THRESHOLD) {
203 }
else if (xAxis > THRESHOLD) {
204 result &= ~JOY_RIGHT;
207 int yAxis = SDL_JoystickGetAxis(joystick, 1);
208 if (yAxis < -THRESHOLD) {
210 }
else if (yAxis > THRESHOLD) {
216 result &= ~encodeButton(button, 7);
223void JoyMega::signalMSXEvent(
const Event& event, EmuTime::param time)
noexcept
225 const auto* joyEvent = get_if<JoystickEvent>(event);
226 if (!joyEvent)
return;
230 if (joyEvent->getJoystick() != joyNum)
return;
233 [&](
const JoystickAxisMotionEvent&
e) {
234 int value =
e.getValue();
235 switch (
e.getAxis() & 1) {
237 if (value < -THRESHOLD) {
239 createEvent(time, JOY_LEFT, JOY_RIGHT);
240 }
else if (value > THRESHOLD) {
242 createEvent(time, JOY_RIGHT, JOY_LEFT);
245 createEvent(time, 0, JOY_LEFT | JOY_RIGHT);
249 if (value < -THRESHOLD) {
251 createEvent(time, JOY_UP, JOY_DOWN);
252 }
else if (value > THRESHOLD) {
254 createEvent(time, JOY_DOWN, JOY_UP);
257 createEvent(time, 0, JOY_UP | JOY_DOWN);
265 [&](
const JoystickButtonDownEvent&
e) {
266 createEvent(time, encodeButton(
e.getButton(), cycleMask), 0);
268 [&](
const JoystickButtonUpEvent&
e) {
269 createEvent(time, 0, encodeButton(
e.getButton(), cycleMask));
275void JoyMega::createEvent(EmuTime::param time,
unsigned press,
unsigned release)
277 unsigned newStatus = (status & ~press) | release;
278 createEvent(time, newStatus);
281void JoyMega::createEvent(EmuTime::param time,
unsigned newStatus)
283 unsigned diff = status ^ newStatus;
289 unsigned press = status & diff;
290 unsigned release = newStatus & diff;
292 time, joyNum, press, release);
296void JoyMega::signalStateChange(
const StateChange& event)
298 const auto* js =
dynamic_cast<const JoyMegaState*
>(&event);
306 if (js->getJoystick() != joyNum)
return;
308 status = (status & ~js->getPress()) | js->getRelease();
311void JoyMega::stopReplay(EmuTime::param time)
noexcept
313 createEvent(time, calcInitialState());
316template<
typename Archive>
319 ar.serialize(
"lastTime", lastTime,
322 "cycleMask", cycleMask);
323 if constexpr (Archive::IS_LOADER) {
Represents something you can plug devices into.
static constexpr EmuDuration usec(unsigned x)
unsigned getPress() const
unsigned getRelease() const
JoyMegaState(EmuTime::param time_, int joyNum_, unsigned press_, unsigned release_)
void serialize(Archive &ar, unsigned)
void unplugHelper(EmuTime::param time) override
JoyMega(MSXEventDistributor &eventDistributor, StateChangeDistributor &stateChangeDistributor, SDL_Joystick *joystick)
uint8_t read(EmuTime::param time) override
Read from the joystick device.
std::string_view getName() const override
Name used to identify this pluggable.
static void registerAll(MSXEventDistributor &eventDistributor, StateChangeDistributor &stateChangeDistributor, PluggingController &controller)
void plugHelper(Connector &connector, EmuTime::param time) override
std::string_view getDescription() const override
Description for this pluggable.
void write(uint8_t value, EmuTime::param time) override
Write a value to the joystick device.
void serialize(Archive &ar, unsigned version)
static constexpr unsigned X_AXIS
static constexpr unsigned Y_AXIS
void registerEventListener(MSXEventListener &listener)
Registers a given object to receive certain events.
void unregisterEventListener(MSXEventListener &listener)
Unregisters a previously registered event listener.
bool isPluggedIn() const
Returns true if this pluggable is currently plugged into a connector.
Central administration of Connectors and Pluggables.
void registerPluggable(std::unique_ptr< Pluggable > pluggable)
Add a Pluggable to the registry.
void registerListener(StateChangeListener &listener)
(Un)registers the given object to receive state change events.
void distributeNew(EmuTime::param time, Args &&...args)
Deliver the event to all registered listeners MSX input devices should call the distributeNew() versi...
void unregisterListener(StateChangeListener &listener)
Base class for all external MSX state changing events.
This file implemented 3 utility functions:
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
auto visit(Visitor &&visitor, const Event &event)
REGISTER_POLYMORPHIC_CLASS(StateChange, AutofireStateChange, "AutofireStateChange")
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)