mirror of https://github.com/stella-emu/stella.git
Refactor pointing devices, include Thomas' patch for movement inconsistencies.
This commit is contained in:
parent
aebe8fabc6
commit
218da3576c
|
@ -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;
|
|
||||||
}
|
|
|
@ -18,93 +18,28 @@
|
||||||
#ifndef AMIGAMOUSE_HXX
|
#ifndef AMIGAMOUSE_HXX
|
||||||
#define AMIGAMOUSE_HXX
|
#define AMIGAMOUSE_HXX
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "PointingDevice.hxx"
|
||||||
#include "Control.hxx"
|
|
||||||
#include "Event.hxx"
|
|
||||||
|
|
||||||
/**
|
namespace {
|
||||||
Trakball-like controller emulating the original Amiga mouse.
|
|
||||||
This code was heavily borrowed from z26.
|
|
||||||
|
|
||||||
@author Stephen Anthony & z26 team
|
class AmigaMouseHelper {
|
||||||
*/
|
|
||||||
class AmigaMouse : public Controller
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
Create a new Amiga Mouse controller plugged into the specified jack
|
|
||||||
|
|
||||||
@param jack The jack the controller is plugged into
|
public:
|
||||||
@param event The event object to use for events
|
static uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) {
|
||||||
@param system The system using this controller
|
static constexpr uInt32 ourTableH[4] = { 0x00, 0x10, 0x50, 0x40 };
|
||||||
*/
|
static constexpr uInt32 ourTableV[4] = { 0x00, 0x80, 0xa0, 0x20 };
|
||||||
AmigaMouse(Jack jack, const Event& event, const System& system);
|
|
||||||
virtual ~AmigaMouse() = default;
|
|
||||||
|
|
||||||
public:
|
return ourTableV[countV] | ourTableH[countH];
|
||||||
using Controller::read;
|
}
|
||||||
|
|
||||||
/**
|
public:
|
||||||
Read the entire state of all digital pins for this controller.
|
static constexpr Controller::Type controllerType = Controller::AmigaMouse;
|
||||||
Note that this method must use the lower 4 bits, and zero the upper bits.
|
|
||||||
|
|
||||||
@return The state of all digital pins
|
static constexpr uInt8 counterDivide = 2;
|
||||||
*/
|
};
|
||||||
uInt8 read() override;
|
|
||||||
|
|
||||||
/**
|
}
|
||||||
Update the entire digital and analog pin state according to the
|
|
||||||
events currently set.
|
|
||||||
*/
|
|
||||||
void update() override;
|
|
||||||
|
|
||||||
/**
|
typedef PointingDevice<AmigaMouseHelper> AmigaMouse;
|
||||||
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,
|
#endif // AMIGAMOUSE_HXX
|
||||||
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
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -18,93 +18,28 @@
|
||||||
#ifndef ATARIMOUSE_HXX
|
#ifndef ATARIMOUSE_HXX
|
||||||
#define ATARIMOUSE_HXX
|
#define ATARIMOUSE_HXX
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "PointingDevice.hxx"
|
||||||
#include "Control.hxx"
|
|
||||||
#include "Event.hxx"
|
|
||||||
|
|
||||||
/**
|
namespace {
|
||||||
Trakball-like controller emulating the Atari ST mouse.
|
|
||||||
This code was heavily borrowed from z26.
|
|
||||||
|
|
||||||
@author Stephen Anthony & z26 team
|
class AtariMouseHelper {
|
||||||
*/
|
|
||||||
class AtariMouse : public Controller
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
Create a new AtariMouse controller plugged into the specified jack
|
|
||||||
|
|
||||||
@param jack The jack the controller is plugged into
|
public:
|
||||||
@param event The event object to use for events
|
static uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) {
|
||||||
@param system The system using this controller
|
static constexpr uInt32 ourTableH[4] = { 0x00, 0x80, 0xc0, 0x40 };
|
||||||
*/
|
static constexpr uInt32 ourTableV[4] = { 0x00, 0x10, 0x30, 0x20 };
|
||||||
AtariMouse(Jack jack, const Event& event, const System& system);
|
|
||||||
virtual ~AtariMouse() = default;
|
|
||||||
|
|
||||||
public:
|
return ourTableV[countV] | ourTableH[countH];
|
||||||
using Controller::read;
|
}
|
||||||
|
|
||||||
/**
|
public:
|
||||||
Read the entire state of all digital pins for this controller.
|
static constexpr Controller::Type controllerType = Controller::AtariMouse;
|
||||||
Note that this method must use the lower 4 bits, and zero the upper bits.
|
|
||||||
|
|
||||||
@return The state of all digital pins
|
static constexpr uInt8 counterDivide = 2;
|
||||||
*/
|
};
|
||||||
uInt8 read() override;
|
|
||||||
|
|
||||||
/**
|
}
|
||||||
Update the entire digital and analog pin state according to the
|
|
||||||
events currently set.
|
|
||||||
*/
|
|
||||||
void update() override;
|
|
||||||
|
|
||||||
/**
|
typedef PointingDevice<AtariMouseHelper> AtariMouse;
|
||||||
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,
|
#endif // ATARIMOUSE_HXX
|
||||||
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
|
|
||||||
|
|
|
@ -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
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -18,93 +18,29 @@
|
||||||
#ifndef TRAKBALL_HXX
|
#ifndef TRAKBALL_HXX
|
||||||
#define TRAKBALL_HXX
|
#define TRAKBALL_HXX
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "PointingDevice.hxx"
|
||||||
#include "Control.hxx"
|
|
||||||
#include "Event.hxx"
|
|
||||||
|
|
||||||
/**
|
namespace {
|
||||||
Emulates the standard trakball controller, sometimes known as the 'CX22'
|
|
||||||
controller. This code was heavily borrowed from z26.
|
|
||||||
|
|
||||||
@author Stephen Anthony & z26 team
|
class TrakBallHelper {
|
||||||
*/
|
|
||||||
class TrakBall : public Controller
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
Create a new TrakBall controller plugged into the specified jack
|
|
||||||
|
|
||||||
@param jack The jack the controller is plugged into
|
public:
|
||||||
@param event The event object to use for events
|
static uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) {
|
||||||
@param system The system using this controller
|
static constexpr uInt32 ourTableH[2][2] = {{ 0x40, 0x00 }, { 0xc0, 0x80 }};
|
||||||
*/
|
static constexpr uInt32 ourTableV[2][2] = {{ 0x00, 0x10 }, { 0x20, 0x30 }};
|
||||||
TrakBall(Jack jack, const Event& event, const System& system);
|
|
||||||
virtual ~TrakBall() = default;
|
|
||||||
|
|
||||||
public:
|
return ourTableV[countV & 0x01][down] |
|
||||||
using Controller::read;
|
ourTableH[countH & 0x01][left];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
public:
|
||||||
Read the entire state of all digital pins for this controller.
|
static constexpr Controller::Type controllerType = Controller::TrakBall;
|
||||||
Note that this method must use the lower 4 bits, and zero the upper bits.
|
|
||||||
|
|
||||||
@return The state of all digital pins
|
static constexpr uInt8 counterDivide = 4;
|
||||||
*/
|
};
|
||||||
uInt8 read() override;
|
|
||||||
|
|
||||||
/**
|
}
|
||||||
Update the entire digital and analog pin state according to the
|
|
||||||
events currently set.
|
|
||||||
*/
|
|
||||||
void update() override;
|
|
||||||
|
|
||||||
/**
|
typedef PointingDevice<TrakBallHelper> TrakBall;
|
||||||
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,
|
#endif // TRAKBALL_HXX
|
||||||
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
|
|
||||||
|
|
|
@ -77,9 +77,6 @@ MODULE_OBJS := \
|
||||||
src/emucore/System.o \
|
src/emucore/System.o \
|
||||||
src/emucore/TIASnd.o \
|
src/emucore/TIASnd.o \
|
||||||
src/emucore/TIASurface.o \
|
src/emucore/TIASurface.o \
|
||||||
src/emucore/AmigaMouse.o \
|
|
||||||
src/emucore/AtariMouse.o \
|
|
||||||
src/emucore/TrakBall.o \
|
|
||||||
src/emucore/Thumbulator.o
|
src/emucore/Thumbulator.o
|
||||||
|
|
||||||
MODULE_DIRS += \
|
MODULE_DIRS += \
|
||||||
|
|
Loading…
Reference in New Issue