Refactor pointing devices, include Thomas' patch for movement inconsistencies.

This commit is contained in:
Christian Speckner 2017-07-30 15:18:13 +02:00
parent aebe8fabc6
commit 218da3576c
8 changed files with 269 additions and 615 deletions

View File

@ -1,122 +0,0 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "Event.hxx"
#include "System.hxx"
#include "TIA.hxx"
#include "AmigaMouse.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AmigaMouse::AmigaMouse(Jack jack, const Event& event, const System& system)
: Controller(jack, event, system, Controller::AmigaMouse),
myHCounter(0),
myVCounter(0),
myMouseEnabled(false)
{
// This code in ::read() is set up to always return IOPortA values in
// the lower 4 bits data value
// As such, the jack type (left or right) isn't necessary here
myTrakBallCountH = myTrakBallCountV = 0;
myTrakBallLinesH = myTrakBallLinesV = 1;
myTrakBallLeft = myTrakBallDown = myScanCountV = myScanCountH =
myCountV = myCountH = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 AmigaMouse::read()
{
int scanline = mySystem.tia().scanlines();
if(myScanCountV > scanline) myScanCountV = 0;
if(myScanCountH > scanline) myScanCountH = 0;
while((myScanCountV + myTrakBallLinesV) < scanline)
{
if(myTrakBallCountV)
{
if(myTrakBallDown) myCountV--;
else myCountV++;
myTrakBallCountV--;
}
myScanCountV += myTrakBallLinesV;
}
while((myScanCountH + myTrakBallLinesH) < scanline)
{
if(myTrakBallCountH)
{
if(myTrakBallLeft) myCountH--;
else myCountH++;
myTrakBallCountH--;
}
myScanCountH += myTrakBallLinesH;
}
myCountV &= 0x03;
myCountH &= 0x03;
static constexpr uInt32 ourTableH[4] = { 0x00, 0x10, 0x50, 0x40 };
static constexpr uInt32 ourTableV[4] = { 0x00, 0x80, 0xa0, 0x20 };
uInt8 IOPortA = ourTableV[myCountV] | ourTableH[myCountH];
myDigitalPinState[One] = IOPortA & 0x10;
myDigitalPinState[Two] = IOPortA & 0x20;
myDigitalPinState[Three] = IOPortA & 0x40;
myDigitalPinState[Four] = IOPortA & 0x80;
return (IOPortA >> 4);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AmigaMouse::update()
{
if(!myMouseEnabled)
return;
// Get the current mouse position
myHCounter = myEvent.get(Event::MouseAxisXValue);
myVCounter = myEvent.get(Event::MouseAxisYValue);
if(myVCounter < 0) myTrakBallLeft = 1;
else myTrakBallLeft = 0;
if(myHCounter < 0) myTrakBallDown = 0;
else myTrakBallDown = 1;
myTrakBallCountH = abs(myVCounter >> 1);
myTrakBallCountV = abs(myHCounter >> 1);
myTrakBallLinesH = mySystem.tia().height() / (myTrakBallCountH + 1);
if(myTrakBallLinesH == 0) myTrakBallLinesH = 1;
myTrakBallLinesV = mySystem.tia().height() / (myTrakBallCountV + 1);
if(myTrakBallLinesV == 0) myTrakBallLinesV = 1;
// Get mouse button state
myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
(myEvent.get(Event::MouseButtonRightValue) == 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool AmigaMouse::setMouseControl(
Controller::Type xtype, int xid, Controller::Type ytype, int yid)
{
// Currently, the various trakball controllers take full control of the
// mouse, and use both mouse buttons for the single fire button
// As well, there's no separate setting for x and y axis, so any
// combination of Controller and id is valid
myMouseEnabled = (xtype == myType || ytype == myType) &&
(xid != -1 || yid != -1);
return true;
}

View File

@ -18,93 +18,28 @@
#ifndef AMIGAMOUSE_HXX
#define AMIGAMOUSE_HXX
#include "bspf.hxx"
#include "Control.hxx"
#include "Event.hxx"
#include "PointingDevice.hxx"
/**
Trakball-like controller emulating the original Amiga mouse.
This code was heavily borrowed from z26.
namespace {
@author Stephen Anthony & z26 team
*/
class AmigaMouse : public Controller
{
public:
/**
Create a new Amiga Mouse controller plugged into the specified jack
class AmigaMouseHelper {
@param jack The jack the controller is plugged into
@param event The event object to use for events
@param system The system using this controller
*/
AmigaMouse(Jack jack, const Event& event, const System& system);
virtual ~AmigaMouse() = default;
public:
static uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) {
static constexpr uInt32 ourTableH[4] = { 0x00, 0x10, 0x50, 0x40 };
static constexpr uInt32 ourTableV[4] = { 0x00, 0x80, 0xa0, 0x20 };
public:
using Controller::read;
return ourTableV[countV] | ourTableH[countH];
}
/**
Read the entire state of all digital pins for this controller.
Note that this method must use the lower 4 bits, and zero the upper bits.
public:
static constexpr Controller::Type controllerType = Controller::AmigaMouse;
@return The state of all digital pins
*/
uInt8 read() override;
static constexpr uInt8 counterDivide = 2;
};
/**
Update the entire digital and analog pin state according to the
events currently set.
*/
void update() override;
}
/**
Determines how this controller will treat values received from the
X/Y axis and left/right buttons of the mouse. Since not all controllers
use the mouse the same way (or at all), it's up to the specific class to
decide how to use this data.
typedef PointingDevice<AmigaMouseHelper> AmigaMouse;
In the current implementation, the left button is tied to the X axis,
and the right one tied to the Y axis.
@param xtype The controller to use for x-axis data
@param xid The controller ID to use for x-axis data (-1 for no id)
@param ytype The controller to use for y-axis data
@param yid The controller ID to use for y-axis data (-1 for no id)
@return Whether the controller supports using the mouse
*/
bool setMouseControl(Controller::Type xtype, int xid,
Controller::Type ytype, int yid) override;
private:
// Counter to iterate through the gray codes
int myHCounter, myVCounter;
// How many new horizontal and vertical values this frame
int myTrakBallCountH, myTrakBallCountV;
// How many lines to wait before sending new horz and vert val
int myTrakBallLinesH, myTrakBallLinesV;
// Was TrakBall moved left or moved right instead
int myTrakBallLeft;
// Was TrakBall moved down or moved up instead
int myTrakBallDown;
int myScanCountH, myScanCountV, myCountH, myCountV;
// Whether to use the mouse to emulate this controller
int myMouseEnabled;
private:
// Following constructors and assignment operators not supported
AmigaMouse() = delete;
AmigaMouse(const AmigaMouse&) = delete;
AmigaMouse(AmigaMouse&&) = delete;
AmigaMouse& operator=(const AmigaMouse&) = delete;
AmigaMouse& operator=(AmigaMouse&&) = delete;
};
#endif
#endif // AMIGAMOUSE_HXX

View File

@ -1,122 +0,0 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "Event.hxx"
#include "System.hxx"
#include "TIA.hxx"
#include "AtariMouse.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AtariMouse::AtariMouse(Jack jack, const Event& event, const System& system)
: Controller(jack, event, system, Controller::AtariMouse),
myHCounter(0),
myVCounter(0),
myMouseEnabled(false)
{
// This code in ::read() is set up to always return IOPortA values in
// the lower 4 bits data value
// As such, the jack type (left or right) isn't necessary here
myTrakBallCountH = myTrakBallCountV = 0;
myTrakBallLinesH = myTrakBallLinesV = 1;
myTrakBallLeft = myTrakBallDown = myScanCountV = myScanCountH =
myCountV = myCountH = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 AtariMouse::read()
{
int scanline = mySystem.tia().scanlines();
if(myScanCountV > scanline) myScanCountV = 0;
if(myScanCountH > scanline) myScanCountH = 0;
while((myScanCountV + myTrakBallLinesV) < scanline)
{
if(myTrakBallCountV)
{
if(myTrakBallDown) myCountV--;
else myCountV++;
myTrakBallCountV--;
}
myScanCountV += myTrakBallLinesV;
}
while((myScanCountH + myTrakBallLinesH) < scanline)
{
if(myTrakBallCountH)
{
if(myTrakBallLeft) myCountH--;
else myCountH++;
myTrakBallCountH--;
}
myScanCountH += myTrakBallLinesH;
}
myCountV &= 0x03;
myCountH &= 0x03;
static constexpr uInt32 ourTableH[4] = { 0x00, 0x80, 0xc0, 0x40 };
static constexpr uInt32 ourTableV[4] = { 0x00, 0x10, 0x30, 0x20 };
uInt8 IOPortA = ourTableV[myCountV] | ourTableH[myCountH];
myDigitalPinState[One] = IOPortA & 0x10;
myDigitalPinState[Two] = IOPortA & 0x20;
myDigitalPinState[Three] = IOPortA & 0x40;
myDigitalPinState[Four] = IOPortA & 0x80;
return (IOPortA >> 4);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AtariMouse::update()
{
if(!myMouseEnabled)
return;
// Get the current mouse position
myHCounter = myEvent.get(Event::MouseAxisXValue);
myVCounter = myEvent.get(Event::MouseAxisYValue);
if(myVCounter < 0) myTrakBallLeft = 1;
else myTrakBallLeft = 0;
if(myHCounter < 0) myTrakBallDown = 0;
else myTrakBallDown = 1;
myTrakBallCountH = abs(myVCounter >> 1);
myTrakBallCountV = abs(myHCounter >> 1);
myTrakBallLinesH = mySystem.tia().height() / (myTrakBallCountH + 1);
if(myTrakBallLinesH == 0) myTrakBallLinesH = 1;
myTrakBallLinesV = mySystem.tia().height() / (myTrakBallCountV + 1);
if(myTrakBallLinesV == 0) myTrakBallLinesV = 1;
// Get mouse button state
myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
(myEvent.get(Event::MouseButtonRightValue) == 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool AtariMouse::setMouseControl(
Controller::Type xtype, int xid, Controller::Type ytype, int yid)
{
// Currently, the various trakball controllers take full control of the
// mouse, and use both mouse buttons for the single fire button
// As well, there's no separate setting for x and y axis, so any
// combination of Controller and id is valid
myMouseEnabled = (xtype == myType || ytype == myType) &&
(xid != -1 || yid != -1);
return true;
}

View File

@ -18,93 +18,28 @@
#ifndef ATARIMOUSE_HXX
#define ATARIMOUSE_HXX
#include "bspf.hxx"
#include "Control.hxx"
#include "Event.hxx"
#include "PointingDevice.hxx"
/**
Trakball-like controller emulating the Atari ST mouse.
This code was heavily borrowed from z26.
namespace {
@author Stephen Anthony & z26 team
*/
class AtariMouse : public Controller
{
public:
/**
Create a new AtariMouse controller plugged into the specified jack
class AtariMouseHelper {
@param jack The jack the controller is plugged into
@param event The event object to use for events
@param system The system using this controller
*/
AtariMouse(Jack jack, const Event& event, const System& system);
virtual ~AtariMouse() = default;
public:
static uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) {
static constexpr uInt32 ourTableH[4] = { 0x00, 0x80, 0xc0, 0x40 };
static constexpr uInt32 ourTableV[4] = { 0x00, 0x10, 0x30, 0x20 };
public:
using Controller::read;
return ourTableV[countV] | ourTableH[countH];
}
/**
Read the entire state of all digital pins for this controller.
Note that this method must use the lower 4 bits, and zero the upper bits.
public:
static constexpr Controller::Type controllerType = Controller::AtariMouse;
@return The state of all digital pins
*/
uInt8 read() override;
static constexpr uInt8 counterDivide = 2;
};
/**
Update the entire digital and analog pin state according to the
events currently set.
*/
void update() override;
}
/**
Determines how this controller will treat values received from the
X/Y axis and left/right buttons of the mouse. Since not all controllers
use the mouse the same way (or at all), it's up to the specific class to
decide how to use this data.
typedef PointingDevice<AtariMouseHelper> AtariMouse;
In the current implementation, the left button is tied to the X axis,
and the right one tied to the Y axis.
@param xtype The controller to use for x-axis data
@param xid The controller ID to use for x-axis data (-1 for no id)
@param ytype The controller to use for y-axis data
@param yid The controller ID to use for y-axis data (-1 for no id)
@return Whether the controller supports using the mouse
*/
bool setMouseControl(Controller::Type xtype, int xid,
Controller::Type ytype, int yid) override;
private:
// Counter to iterate through the gray codes
int myHCounter, myVCounter;
// How many new horizontal and vertical values this frame
int myTrakBallCountH, myTrakBallCountV;
// How many lines to wait before sending new horz and vert val
int myTrakBallLinesH, myTrakBallLinesV;
// Was TrakBall moved left or moved right instead
int myTrakBallLeft;
// Was TrakBall moved down or moved up instead
int myTrakBallDown;
int myScanCountH, myScanCountV, myCountH, myCountV;
// Whether to use the mouse to emulate this controller
int myMouseEnabled;
private:
// Following constructors and assignment operators not supported
AtariMouse() = delete;
AtariMouse(const AtariMouse&) = delete;
AtariMouse(AtariMouse&&) = delete;
AtariMouse& operator=(const AtariMouse&) = delete;
AtariMouse& operator=(AtariMouse&&) = delete;
};
#endif
#endif // ATARIMOUSE_HXX

View File

@ -0,0 +1,220 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef POINTING_DEVICE_HXX
#define POINTING_DEVICE_HXX
#include "bspf.hxx"
#include "Control.hxx"
#include "Event.hxx"
/**
Common controller class for pointing devices (Atari Mouse, Amiga Mouse, TrakBall)
This code was heavily borrowed from z26.
@author Stephen Anthony & z26 team
*/
template<class T> class PointingDevice : public Controller
{
public:
PointingDevice(Jack jack, const Event& event, const System& system);
virtual ~PointingDevice() = default;
public:
using Controller::read;
/**
Read the entire state of all digital pins for this controller.
Note that this method must use the lower 4 bits, and zero the upper bits.
@return The state of all digital pins
*/
uInt8 read() override;
/**
Update the entire digital and analog pin state according to the
events currently set.
*/
void update() override;
/**
Determines how this controller will treat values received from the
X/Y axis and left/right buttons of the mouse. Since not all controllers
use the mouse the same way (or at all), it's up to the specific class to
decide how to use this data.
In the current implementation, the left button is tied to the X axis,
and the right one tied to the Y axis.
@param xtype The controller to use for x-axis data
@param xid The controller ID to use for x-axis data (-1 for no id)
@param ytype The controller to use for y-axis data
@param yid The controller ID to use for y-axis data (-1 for no id)
@return Whether the controller supports using the mouse
*/
bool setMouseControl(Controller::Type xtype, int xid,
Controller::Type ytype, int yid) override;
private:
// Counter to iterate through the gray codes
int myHCounter, myVCounter;
int myHCounterRemainder, myVCounterRemainder;
// How many new horizontal and vertical values this frame
int myTrakBallCountH, myTrakBallCountV;
// How many lines to wait before sending new horz and vert val
int myTrakBallLinesH, myTrakBallLinesV;
// Was TrakBall moved left or moved right instead
uInt8 myTrakBallLeft;
// Was TrakBall moved down or moved up instead
uInt8 myTrakBallDown;
uInt8 myCountH, myCountV;
int myScanCountH, myScanCountV;
// Whether to use the mouse to emulate this controller
bool myMouseEnabled;
private:
// Following constructors and assignment operators not supported
PointingDevice() = delete;
PointingDevice(const PointingDevice<T>&) = delete;
PointingDevice(PointingDevice<T>&&) = delete;
PointingDevice& operator=(const PointingDevice<T>&) = delete;
PointingDevice& operator=(PointingDevice<T>&&) = delete;
};
// ############################################################################
// Implementation
// ############################################################################
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<class T>
PointingDevice<T>::PointingDevice(Jack jack, const Event& event, const System& system)
: Controller(jack, event, system, T::controllerType),
myHCounter(0),
myVCounter(0),
myHCounterRemainder(0),
myVCounterRemainder(0),
myMouseEnabled(false)
{
// This code in ::read() is set up to always return IOPortA values in
// the lower 4 bits data value
// As such, the jack type (left or right) isn't necessary here
myTrakBallCountH = myTrakBallCountV = 0;
myTrakBallLinesH = myTrakBallLinesV = 1;
myTrakBallLeft = myTrakBallDown = myScanCountV = myScanCountH =
myCountV = myCountH = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<class T>
uInt8 PointingDevice<T>::read()
{
int scanline = mySystem.tia().scanlines();
if(myScanCountV > scanline) myScanCountV = 0;
if(myScanCountH > scanline) myScanCountH = 0;
while((myScanCountV + myTrakBallLinesV) < scanline)
{
if(myTrakBallCountV)
{
if(myTrakBallDown) myCountV--;
else myCountV++;
myTrakBallCountV--;
}
myScanCountV += myTrakBallLinesV;
}
while((myScanCountH + myTrakBallLinesH) < scanline)
{
if(myTrakBallCountH)
{
if(myTrakBallLeft) myCountH--;
else myCountH++;
myTrakBallCountH--;
}
myScanCountH += myTrakBallLinesH;
}
myCountV &= 0x03;
myCountH &= 0x03;
uInt8 ioPortA = T::ioPortA(myCountH, myCountV, myTrakBallLeft, myTrakBallDown);
myDigitalPinState[One] = ioPortA & 0x10;
myDigitalPinState[Two] = ioPortA & 0x20;
myDigitalPinState[Three] = ioPortA & 0x40;
myDigitalPinState[Four] = ioPortA & 0x80;
return (ioPortA >> 4);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<class T>
void PointingDevice<T>::update()
{
if(!myMouseEnabled)
return;
// Get the current mouse position
myHCounter = myEvent.get(Event::MouseAxisXValue) + myHCounterRemainder;
myVCounter = myEvent.get(Event::MouseAxisYValue) + myVCounterRemainder;
if(myVCounter < 0) myTrakBallLeft = 1;
else myTrakBallLeft = 0;
if(myHCounter < 0) myTrakBallDown = 0;
else myTrakBallDown = 1;
myHCounterRemainder = myHCounter % T::counterDivide;
myVCounterRemainder = myVCounter % T::counterDivide;
myTrakBallCountH = abs(myVCounter / T::counterDivide);
myTrakBallCountV = abs(myHCounter / T::counterDivide);
myTrakBallLinesH = mySystem.tia().height() / (myTrakBallCountH + 1);
if(myTrakBallLinesH == 0) myTrakBallLinesH = 1;
myTrakBallLinesV = mySystem.tia().height() / (myTrakBallCountV + 1);
if(myTrakBallLinesV == 0) myTrakBallLinesV = 1;
// Get mouse button state
myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
(myEvent.get(Event::MouseButtonRightValue) == 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<class T>
bool PointingDevice<T>::setMouseControl(
Controller::Type xtype, int xid, Controller::Type ytype, int yid)
{
// Currently, the various trakball controllers take full control of the
// mouse, and use both mouse buttons for the single fire button
// As well, there's no separate setting for x and y axis, so any
// combination of Controller and id is valid
myMouseEnabled = (xtype == myType || ytype == myType) &&
(xid != -1 || yid != -1);
return true;
}
#endif // POINTING_DEVICE_HXX

View File

@ -1,125 +0,0 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include <cstdlib>
#include "Event.hxx"
#include "System.hxx"
#include "TIA.hxx"
#include "TrakBall.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TrakBall::TrakBall(Jack jack, const Event& event, const System& system)
: Controller(jack, event, system, Controller::TrakBall),
myHCounter(0),
myVCounter(0),
myMouseEnabled(false)
{
// This code in ::read() is set up to always return IOPortA values in
// the lower 4 bits data value
// As such, the jack type (left or right) isn't necessary here
myTrakBallCountH = myTrakBallCountV = 0;
myTrakBallLinesH = myTrakBallLinesV = 1;
myTrakBallLeft = myTrakBallDown = myScanCountV = myScanCountH =
myCountV = myCountH = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TrakBall::read()
{
int scanline = mySystem.tia().scanlines();
if(myScanCountV > scanline) myScanCountV = 0;
if(myScanCountH > scanline) myScanCountH = 0;
while((myScanCountV + myTrakBallLinesV) < scanline)
{
if(myTrakBallCountV)
{
if(myTrakBallDown) myCountV--;
else myCountV++;
myTrakBallCountV--;
}
myScanCountV += myTrakBallLinesV;
}
while((myScanCountH + myTrakBallLinesH) < scanline)
{
if(myTrakBallCountH)
{
if(myTrakBallLeft) myCountH--;
else myCountH++;
myTrakBallCountH--;
}
myScanCountH += myTrakBallLinesH;
}
myCountV &= 0x03;
myCountH &= 0x03;
static constexpr uInt32 ourTableH[2][2] = {{ 0x40, 0x00 }, { 0xc0, 0x80 }};
static constexpr uInt32 ourTableV[2][2] = {{ 0x00, 0x10 }, { 0x20, 0x30 }};
uInt8 IOPortA = ourTableV[myCountV & 0x01][myTrakBallDown] |
ourTableH[myCountH & 0x01][myTrakBallLeft];
myDigitalPinState[One] = IOPortA & 0x10;
myDigitalPinState[Two] = IOPortA & 0x20;
myDigitalPinState[Three] = IOPortA & 0x40;
myDigitalPinState[Four] = IOPortA & 0x80;
return (IOPortA >> 4);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TrakBall::update()
{
if(!myMouseEnabled)
return;
// Get the current mouse position
myHCounter = myEvent.get(Event::MouseAxisXValue);
myVCounter = myEvent.get(Event::MouseAxisYValue);
if(myVCounter < 0) myTrakBallLeft = 1;
else myTrakBallLeft = 0;
if(myHCounter < 0) myTrakBallDown = 0;
else myTrakBallDown = 1;
myTrakBallCountH = abs(myVCounter >> 2); // Extra div by 2, since trakball has
myTrakBallCountV = abs(myHCounter >> 2); // half spatial resolution as ST/Amiga mouse
myTrakBallLinesH = mySystem.tia().height() / (myTrakBallCountH + 1);
if(myTrakBallLinesH == 0) myTrakBallLinesH = 1;
myTrakBallLinesV = mySystem.tia().height() / (myTrakBallCountV + 1);
if(myTrakBallLinesV == 0) myTrakBallLinesV = 1;
// Get mouse button state
myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
(myEvent.get(Event::MouseButtonRightValue) == 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TrakBall::setMouseControl(
Controller::Type xtype, int xid, Controller::Type ytype, int yid)
{
// Currently, the various trakball controllers take full control of the
// mouse, and use both mouse buttons for the single fire button
// As well, there's no separate setting for x and y axis, so any
// combination of Controller and id is valid
myMouseEnabled = (xtype == myType || ytype == myType) &&
(xid != -1 || yid != -1);
return true;
}

View File

@ -18,93 +18,29 @@
#ifndef TRAKBALL_HXX
#define TRAKBALL_HXX
#include "bspf.hxx"
#include "Control.hxx"
#include "Event.hxx"
#include "PointingDevice.hxx"
/**
Emulates the standard trakball controller, sometimes known as the 'CX22'
controller. This code was heavily borrowed from z26.
namespace {
@author Stephen Anthony & z26 team
*/
class TrakBall : public Controller
{
public:
/**
Create a new TrakBall controller plugged into the specified jack
class TrakBallHelper {
@param jack The jack the controller is plugged into
@param event The event object to use for events
@param system The system using this controller
*/
TrakBall(Jack jack, const Event& event, const System& system);
virtual ~TrakBall() = default;
public:
static uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) {
static constexpr uInt32 ourTableH[2][2] = {{ 0x40, 0x00 }, { 0xc0, 0x80 }};
static constexpr uInt32 ourTableV[2][2] = {{ 0x00, 0x10 }, { 0x20, 0x30 }};
public:
using Controller::read;
return ourTableV[countV & 0x01][down] |
ourTableH[countH & 0x01][left];
}
/**
Read the entire state of all digital pins for this controller.
Note that this method must use the lower 4 bits, and zero the upper bits.
public:
static constexpr Controller::Type controllerType = Controller::TrakBall;
@return The state of all digital pins
*/
uInt8 read() override;
static constexpr uInt8 counterDivide = 4;
};
/**
Update the entire digital and analog pin state according to the
events currently set.
*/
void update() override;
}
/**
Determines how this controller will treat values received from the
X/Y axis and left/right buttons of the mouse. Since not all controllers
use the mouse the same way (or at all), it's up to the specific class to
decide how to use this data.
typedef PointingDevice<TrakBallHelper> TrakBall;
In the current implementation, the left button is tied to the X axis,
and the right one tied to the Y axis.
@param xtype The controller to use for x-axis data
@param xid The controller ID to use for x-axis data (-1 for no id)
@param ytype The controller to use for y-axis data
@param yid The controller ID to use for y-axis data (-1 for no id)
@return Whether the controller supports using the mouse
*/
bool setMouseControl(Controller::Type xtype, int xid,
Controller::Type ytype, int yid) override;
private:
// Counter to iterate through the gray codes
int myHCounter, myVCounter;
// How many new horizontal and vertical values this frame
int myTrakBallCountH, myTrakBallCountV;
// How many lines to wait before sending new horz and vert val
int myTrakBallLinesH, myTrakBallLinesV;
// Was TrakBall moved left or moved right instead
int myTrakBallLeft;
// Was TrakBall moved down or moved up instead
int myTrakBallDown;
int myScanCountH, myScanCountV, myCountH, myCountV;
// Whether to use the mouse to emulate this controller
int myMouseEnabled;
private:
// Following constructors and assignment operators not supported
TrakBall() = delete;
TrakBall(const TrakBall&) = delete;
TrakBall(TrakBall&&) = delete;
TrakBall& operator=(const TrakBall&) = delete;
TrakBall& operator=(TrakBall&&) = delete;
};
#endif
#endif // TRAKBALL_HXX

View File

@ -77,9 +77,6 @@ MODULE_OBJS := \
src/emucore/System.o \
src/emucore/TIASnd.o \
src/emucore/TIASurface.o \
src/emucore/AmigaMouse.o \
src/emucore/AtariMouse.o \
src/emucore/TrakBall.o \
src/emucore/Thumbulator.o
MODULE_DIRS += \