openMSX
Paddle.cc
Go to the documentation of this file.
1#include "Paddle.hh"
4#include "Event.hh"
5#include "StateChange.hh"
6#include "serialize.hh"
7#include "serialize_meta.hh"
8#include <algorithm>
9
10namespace openmsx {
11
12class PaddleState final : public StateChange
13{
14public:
15 PaddleState() = default; // for serialize
16 PaddleState(EmuTime::param time_, int delta_)
17 : StateChange(time_), delta(delta_) {}
18 [[nodiscard]] int getDelta() const { return delta; }
19
20 template<typename Archive> void serialize(Archive& ar, unsigned /*version*/)
21 {
22 ar.template serializeBase<StateChange>(*this);
23 ar.serialize("delta", delta);
24 }
25private:
26 int delta;
27};
29
30
32 StateChangeDistributor& stateChangeDistributor_)
33 : eventDistributor(eventDistributor_)
34 , stateChangeDistributor(stateChangeDistributor_)
35{
36}
37
39{
40 if (isPluggedIn()) {
41 Paddle::unplugHelper(EmuTime::dummy());
42 }
43}
44
45
46// Pluggable
47std::string_view Paddle::getName() const
48{
49 return "paddle";
50}
51
52std::string_view Paddle::getDescription() const
53{
54 return "MSX Paddle";
55}
56
57void Paddle::plugHelper(Connector& /*connector*/, EmuTime::param /*time*/)
58{
59 eventDistributor.registerEventListener(*this);
60 stateChangeDistributor.registerListener(*this);
61}
62
63void Paddle::unplugHelper(EmuTime::param /*time*/)
64{
65 stateChangeDistributor.unregisterListener(*this);
66 eventDistributor.unregisterEventListener(*this);
67}
68
69// JoystickDevice
70uint8_t Paddle::read(EmuTime::param time)
71{
72 // The loop in the BIOS routine that reads the paddle status takes
73 // 41 Z80 cycles per iteration.
74 static constexpr auto TICK = EmuDuration::hz(3579545) * 41;
75
76 assert(time >= lastPulse);
77 bool before = (time - lastPulse) < (TICK * analogValue);
78 bool output = before && !(lastInput & 4);
79 return output ? 0x3F : 0x3E; // pin1 (up)
80}
81
82void Paddle::write(uint8_t value, EmuTime::param time)
83{
84 uint8_t diff = lastInput ^ value;
85 lastInput = value;
86 if ((diff & 4) && !(lastInput & 4)) { // high->low edge
87 lastPulse = time;
88 }
89}
90
91// MSXEventListener
92void Paddle::signalMSXEvent(const Event& event,
93 EmuTime::param time) noexcept
94{
95 visit(overloaded{
96 [&](const MouseMotionEvent& e) {
97 constexpr int SCALE = 2;
98 if (int delta = e.getX() / SCALE) {
99 stateChangeDistributor.distributeNew<PaddleState>(
100 time, delta);
101 }
102 },
103 [](const EventBase&) { /*ignore*/ }
104 }, event);
105}
106
107// StateChangeListener
108void Paddle::signalStateChange(const StateChange& event)
109{
110 const auto* ps = dynamic_cast<const PaddleState*>(&event);
111 if (!ps) return;
112 analogValue = narrow_cast<uint8_t>(std::clamp(analogValue + ps->getDelta(), 0, 255));
113}
114
115void Paddle::stopReplay(EmuTime::param /*time*/) noexcept
116{
117}
118
119template<typename Archive>
120void Paddle::serialize(Archive& ar, unsigned /*version*/)
121{
122 ar.serialize("lastPulse", lastPulse,
123 "analogValue", analogValue,
124 "lastInput", lastInput);
125
126 if constexpr (Archive::IS_LOADER) {
127 if (isPluggedIn()) {
128 plugHelper(*getConnector(), EmuTime::dummy());
129 }
130 }
131}
134
135} // namespace openmsx
static constexpr EmuDuration hz(unsigned x)
void registerEventListener(MSXEventListener &listener)
Registers a given object to receive certain events.
void unregisterEventListener(MSXEventListener &listener)
Unregisters a previously registered event listener.
void serialize(Archive &ar, unsigned)
Definition Paddle.cc:20
PaddleState(EmuTime::param time_, int delta_)
Definition Paddle.cc:16
int getDelta() const
Definition Paddle.cc:18
Paddle(MSXEventDistributor &eventDistributor, StateChangeDistributor &stateChangeDistributor)
Definition Paddle.cc:31
~Paddle() override
Definition Paddle.cc:38
void serialize(Archive &ar, unsigned version)
Definition Paddle.cc:120
bool isPluggedIn() const
Returns true if this pluggable is currently plugged into a connector.
Definition Pluggable.hh:49
Connector * getConnector() const
Get the connector this Pluggable is plugged into.
Definition Pluggable.hh:43
void registerListener(StateChangeListener &listener)
(Un)registers the given object to receive state change events.
void unregisterListener(StateChangeListener &listener)
Base class for all external MSX state changing events.
constexpr double e
Definition Math.hh:21
This file implemented 3 utility functions:
Definition Autofire.cc:11
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, Rs232NetEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
Definition Event.hh:445
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define REGISTER_POLYMORPHIC_INITIALIZER(BASE, CLASS, NAME)
#define REGISTER_POLYMORPHIC_CLASS(BASE, CLASS, NAME)