32 byte x_,
byte y_,
bool touch_,
bool button_)
34 ,
x(x_), y(y_), touch(touch_), button(button_) {}
35 [[nodiscard]]
byte getX()
const {
return x; }
36 [[nodiscard]]
byte getY()
const {
return y; }
37 [[nodiscard]]
bool getTouch()
const {
return touch; }
38 [[nodiscard]]
bool getButton()
const {
return button; }
40 template<
typename Archive>
void serialize(Archive& ar,
unsigned )
42 ar.template serializeBase<StateChange>(*
this);
59 : eventDistributor(eventDistributor_)
60 , stateChangeDistributor(stateChangeDistributor_)
62 , transformSetting(commandController,
63 "touchpad_transform_matrix",
64 "2x3 matrix to transform host mouse coordinates to "
65 "MSX touchpad coordinates, see manual for details",
66 "{ 256 0 0 } { 0 256 0 }")
67 , start(EmuTime::zero())
69 ,
x(0), y(0), touch(false), button(false)
70 , shift(0), channel(0), last(0)
75 parseTransformMatrix(interp, newValue);
78 "Invalid transformation matrix: ",
e.getMessage());
82 parseTransformMatrix(interp, transformSetting.
getValue());
85 std::cerr <<
e.getMessage() <<
'\n';
87 m[0][0] = 256.0f; m[1][0] = 0.0f; m[2][0] = 0.0f;
88 m[0][1] = 0.0f; m[1][1] = 256.0f; m[2][1] = 0.0f;
95 Touchpad::unplugHelper(EmuTime::dummy());
104 for (
auto i :
xrange(2)) {
106 if (row.getListLength(interp) != 3) {
107 throw CommandException(
"each row must have 3 elements");
109 for (
auto j :
xrange(3)) {
110 m[j][i] = row.getListIndex(interp, j).getDouble(interp);
116 std::string_view Touchpad::getName()
const
121 std::string_view Touchpad::getDescription()
const
123 return "MSX Touchpad";
126 void Touchpad::plugHelper(
Connector& , EmuTime::param )
132 void Touchpad::unplugHelper(EmuTime::param )
147 byte Touchpad::read(EmuTime::param time)
150 if (touch) result &= ~
SENSE;
151 if (button) result &= ~
BUTTON;
157 if ((time - start) > delta) {
161 if (shift & 0x80) result |=
SO;
162 if (last &
CS) result |=
SO;
164 return result | 0x30;
167 void Touchpad::write(
byte value, EmuTime::param time)
169 byte diff = last ^ value;
181 shift = (channel == 0) ? (touch ? x : 0)
182 : (channel == 3) ? (touch ? y : 148)
186 if (((value & (
CS |
SCK)) ==
SCK) && (diff &
SCK)) {
189 shift |= (value &
SI) != 0;
199 return clamp(xy, 0, 255);
203 void Touchpad::signalMSXEvent(
const Event& event,
204 EmuTime::param time) noexcept
210 [&](
const MouseMotionEvent&
e) {
211 pos = transformCoords(
ivec2(
e.getAbsX(),
e.getAbsY()));
213 [&](
const MouseButtonDownEvent&
e) {
214 switch (
e.getButton()) {
226 [&](
const MouseButtonUpEvent&
e) {
227 switch (
e.getButton()) {
239 [](
const EventBase&) { }
242 if ((pos != hostPos) || (b != hostButtons)) {
245 createTouchpadStateChange(
246 time, pos[0], pos[1],
247 (hostButtons & 1) != 0,
248 (hostButtons & 2) != 0);
252 void Touchpad::createTouchpadStateChange(
253 EmuTime::param time,
byte x_,
byte y_,
bool touch_,
bool button_)
256 time, x_, y_, touch_, button_);
260 void Touchpad::signalStateChange(
const StateChange& event)
262 if (
const auto* ts =
dynamic_cast<const TouchpadState*
>(&event)) {
265 touch = ts->getTouch();
266 button = ts->getButton();
270 void Touchpad::stopReplay(EmuTime::param time) noexcept
273 if (
x || y || touch || button) {
274 stateChangeDistributor.distributeNew<TouchpadState>(
275 time, 0, 0,
false,
false);
280 template<
typename Archive>
285 ar.serialize(
"start", start,
294 if constexpr (Archive::IS_LOADER) {
static constexpr EmuDuration duration(unsigned ticks)
Calculates the duration of the given number of ticks at this clock's frequency.
virtual Interpreter & getInterpreter()=0
Represents the output window/screen of openMSX.
OutputSurface * getOutputSurface()
static constexpr int RD_PIN4
static constexpr int RD_PIN3
static constexpr int RD_PIN2
static constexpr int WR_PIN8
static constexpr int WR_PIN7
static constexpr int RD_PIN1
static constexpr int WR_PIN6
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 setChecker(std::function< void(TclObject &)> checkFunc_)
Set value-check-callback.
const TclObject & getValue() const final
Gets the current value of this setting as a TclObject.
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.
unsigned getListLength(Interpreter &interp) const
TclObject getListIndex(Interpreter &interp, unsigned index) const
void serialize(Archive &ar, unsigned)
TouchpadState(EmuTime::param time_, byte x_, byte y_, bool touch_, bool button_)
void serialize(Archive &ar, unsigned version)
constexpr vecN< N, T > clamp(const vecN< N, T > &x, const vecN< N, T > &minVal, const vecN< N, T > &maxVal)
This file implemented 3 utility functions:
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
auto visit(Visitor &&visitor, const Event &event)
constexpr KeyMatrixPosition x
Keyboard bindings.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)