27 uint8_t press_, uint8_t release_)
29 , deltaX(deltaX_), deltaY(deltaY_)
30 , press(press_), release(release_) {}
31 [[nodiscard]]
int getDeltaX()
const {
return deltaX; }
32 [[nodiscard]]
int getDeltaY()
const {
return deltaY; }
33 [[nodiscard]] uint8_t
getPress()
const {
return press; }
34 [[nodiscard]] uint8_t
getRelease()
const {
return release; }
36 template<
typename Archive>
void serialize(Archive& ar,
unsigned )
38 ar.template serializeBase<StateChange>(*
this);
39 ar.serialize(
"deltaX", deltaX,
46 uint8_t press, release;
53 : eventDistributor(eventDistributor_)
54 , stateChangeDistributor(stateChangeDistributor_)
61 Trackball::unplugHelper(EmuTime::dummy());
67std::string_view Trackball::getName()
const
72std::string_view Trackball::getDescription()
const
74 return "MSX Trackball";
77void Trackball::plugHelper(Connector& , EmuTime::param time)
88void Trackball::unplugHelper(EmuTime::param )
95uint8_t Trackball::read(EmuTime::param time)
116 syncCurrentWithTarget(time);
117 auto delta = (lastValue & 4) ? currentDeltaY : currentDeltaX;
118 return (status & ~0x0F) | ((delta + 8) & 0x0F);
121void Trackball::write(uint8_t value, EmuTime::param time)
123 syncCurrentWithTarget(time);
124 uint8_t diff = lastValue ^ value;
129 targetDeltaX = narrow<int8_t>(std::clamp(targetDeltaX - currentDeltaX, -8, 7));
132 targetDeltaY = narrow<int8_t>(std::clamp(targetDeltaY - currentDeltaY, -8, 7));
138void Trackball::syncCurrentWithTarget(EmuTime::param time)
175 currentDeltaX = targetDeltaX;
176 currentDeltaY = targetDeltaY;
182 auto maxSteps = narrow<int>((time - lastSync) / INTERVAL);
183 lastSync += INTERVAL * maxSteps;
185 if (targetDeltaX >= currentDeltaX) {
186 currentDeltaX = narrow<int8_t>(std::min<int>(currentDeltaX + maxSteps, targetDeltaX));
188 currentDeltaX = narrow<int8_t>(std::max<int>(currentDeltaX - maxSteps, targetDeltaX));
190 if (targetDeltaY >= currentDeltaY) {
191 currentDeltaY = narrow<int8_t>(std::min<int>(currentDeltaY + maxSteps, targetDeltaY));
193 currentDeltaY = narrow<int8_t>(std::max<int>(currentDeltaY - maxSteps, targetDeltaY));
198void Trackball::signalMSXEvent(
const Event& event,
199 EmuTime::param time)
noexcept
202 [&](
const MouseMotionEvent&
e) {
203 constexpr int SCALE = 2;
204 int dx =
e.getX() / SCALE;
205 int dy =
e.getY() / SCALE;
206 if ((dx != 0) || (dy != 0)) {
207 createTrackballStateChange(time, dx, dy, 0, 0);
210 [&](
const MouseButtonDownEvent&
e) {
211 switch (
e.getButton()) {
212 case SDL_BUTTON_LEFT:
213 createTrackballStateChange(time, 0, 0, JOY_BUTTONA, 0);
215 case SDL_BUTTON_RIGHT:
216 createTrackballStateChange(time, 0, 0, JOY_BUTTONB, 0);
223 [&](
const MouseButtonUpEvent&
e) {
224 switch (
e.getButton()) {
225 case SDL_BUTTON_LEFT:
226 createTrackballStateChange(time, 0, 0, 0, JOY_BUTTONA);
228 case SDL_BUTTON_RIGHT:
229 createTrackballStateChange(time, 0, 0, 0, JOY_BUTTONB);
236 [](
const EventBase&) { }
240void Trackball::createTrackballStateChange(
241 EmuTime::param time,
int deltaX,
int deltaY, uint8_t press, uint8_t release)
244 time, deltaX, deltaY, press, release);
248void Trackball::signalStateChange(
const StateChange& event)
250 const auto* ts =
dynamic_cast<const TrackballState*
>(&event);
253 targetDeltaX = narrow<int8_t>(std::clamp(targetDeltaX + ts->getDeltaX(), -8, 7));
254 targetDeltaY = narrow<int8_t>(std::clamp(targetDeltaY + ts->getDeltaY(), -8, 7));
255 status = (status & ~ts->getPress()) | ts->getRelease();
258void Trackball::stopReplay(EmuTime::param time)
noexcept
260 syncCurrentWithTarget(time);
262 uint8_t release = (JOY_BUTTONA | JOY_BUTTONB) & ~status;
263 if ((currentDeltaX != 0) || (currentDeltaY != 0) || (release != 0)) {
264 stateChangeDistributor.distributeNew<TrackballState>(
265 time, -currentDeltaX, -currentDeltaY, uint8_t(0), release);
271template<
typename Archive>
274 if (ar.versionAtLeast(version, 2)) {
275 ar.serialize(
"lastSync", lastSync,
276 "targetDeltaX", targetDeltaX,
277 "targetDeltaY", targetDeltaY,
278 "currentDeltaX", currentDeltaX,
279 "currentDeltaY", currentDeltaY);
281 ar.serialize(
"deltaX", targetDeltaX,
282 "deltaY", targetDeltaY);
283 currentDeltaX = targetDeltaX;
284 currentDeltaY = targetDeltaY;
287 ar.serialize(
"lastValue", lastValue,
290 if constexpr (Archive::IS_LOADER) {
static constexpr EmuDuration msec(unsigned x)
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.
Connector * getConnector() const
Get the connector this Pluggable is plugged into.
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.
uint8_t getRelease() const
TrackballState(EmuTime::param time_, int deltaX_, int deltaY_, uint8_t press_, uint8_t release_)
void serialize(Archive &ar, unsigned)
Trackball(MSXEventDistributor &eventDistributor, StateChangeDistributor &stateChangeDistributor)
void serialize(Archive &ar, unsigned version)
This file implemented 3 utility functions:
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
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)