Updated PointingDevice (trakball and friends)
- changed from templates back to inheritance (sorry DirtyHairy :)) - added 'tsense' commandline argument and associated UI - updated docs and screenshots for new functionality
|
@ -16,6 +16,8 @@
|
|||
|
||||
* Improved emulation of Trakball controller, eliminating bias in left/
|
||||
right directions. Thanks to Thomas Jentzsch for the idea and code.
|
||||
Related to this, added 'tsense' commandline argument and associated
|
||||
UI item, to allow changing sensitivity of mouse trackball emulation.
|
||||
|
||||
* Fixed an annoying bug in Linux, where Alt-Tab'ing out of a window and
|
||||
then back again would pass a 'Tab' key event to the app, which in
|
||||
|
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 7.8 KiB |
|
@ -2703,6 +2703,7 @@
|
|||
<tr><td>Joy deadzone size</td><td>Deadzone area for axes on joysticks/gamepads</td><td>-joydeadzone</td></tr>
|
||||
<tr><td>Digital paddle sensitivity</td><td>Sensitivity used when emulating a paddle using a digital device</td><td>-dsense</td></tr>
|
||||
<tr><td>Mouse paddle sensitivity</td><td>Sensitivity used when emulating a paddle using a mouse</td><td>-msense</td></tr>
|
||||
<tr><td>Trackball sensitivity</td><td>Sensitivity used when emulating a trackball device using a mouse</td><td>-tsense</td></tr>
|
||||
<tr><td>Allow all 4 ...</td><td>Allow all 4 joystick directions to be pressed simultaneously</td><td>-joyallow4</td></tr>
|
||||
<tr><td>Grab mouse ...</td><td>Keep mouse in window in emulation mode</td><td>-grabmouse</td></tr>
|
||||
<tr><td>Use Control key combos</td><td>Enable using Control key in keyboard actions</td><td>-ctrlcombo</td></tr>
|
||||
|
|
|
@ -20,24 +20,31 @@
|
|||
|
||||
#include "PointingDevice.hxx"
|
||||
|
||||
namespace {
|
||||
class AmigaMouse : public PointingDevice
|
||||
{
|
||||
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)
|
||||
: PointingDevice(jack, event, system, Controller::AmigaMouse,
|
||||
trackballSensitivity) { }
|
||||
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 };
|
||||
protected:
|
||||
uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override
|
||||
{
|
||||
static constexpr uInt32 ourTableH[4] = { 0x00, 0x80, 0xa0, 0x20 };
|
||||
static constexpr uInt32 ourTableV[4] = { 0x00, 0x10, 0x50, 0x40 };
|
||||
|
||||
return ourTableV[countV] | ourTableH[countH];
|
||||
}
|
||||
return ourTableH[countH] | ourTableV[countV];
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr Controller::Type controllerType = Controller::AmigaMouse;
|
||||
static constexpr double trackballSensitivity = 0.8; // TODO: make configurable
|
||||
};
|
||||
}
|
||||
|
||||
using AmigaMouse = PointingDevice<AmigaMouseHelper>;
|
||||
static constexpr float trackballSensitivity = 0.8;
|
||||
};
|
||||
|
||||
#endif // AMIGAMOUSE_HXX
|
||||
|
|
|
@ -20,24 +20,31 @@
|
|||
|
||||
#include "PointingDevice.hxx"
|
||||
|
||||
namespace {
|
||||
class AtariMouse : public PointingDevice
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new Atari Mouse 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)
|
||||
: PointingDevice(jack, event, system, Controller::AtariMouse,
|
||||
trackballSensitivity) { }
|
||||
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 };
|
||||
protected:
|
||||
uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override
|
||||
{
|
||||
static constexpr uInt32 ourTableH[4] = { 0x00, 0x10, 0x30, 0x20 };
|
||||
static constexpr uInt32 ourTableV[4] = { 0x00, 0x80, 0xc0, 0x40 };
|
||||
|
||||
return ourTableV[countV] | ourTableH[countH];
|
||||
}
|
||||
return ourTableH[countH] | ourTableV[countV];
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr Controller::Type controllerType = Controller::AtariMouse;
|
||||
static constexpr double trackballSensitivity = 0.8; // TODO: make configurable
|
||||
};
|
||||
}
|
||||
|
||||
using AtariMouse = PointingDevice<AtariMouseHelper>;
|
||||
static constexpr float trackballSensitivity = 0.8;
|
||||
};
|
||||
|
||||
#endif // ATARIMOUSE_HXX
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "OSystem.hxx"
|
||||
#include "Joystick.hxx"
|
||||
#include "Paddles.hxx"
|
||||
#include "PointingDevice.hxx"
|
||||
#include "PropsSet.hxx"
|
||||
#include "ListWidget.hxx"
|
||||
#include "ScrollBarWidget.hxx"
|
||||
|
@ -95,6 +96,7 @@ void EventHandler::initialize()
|
|||
Joystick::setDeadZone(myOSystem.settings().getInt("joydeadzone"));
|
||||
Paddles::setDigitalSensitivity(myOSystem.settings().getInt("dsense"));
|
||||
Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense"));
|
||||
PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense"));
|
||||
|
||||
// Set quick select delay when typing characters in listwidgets
|
||||
ListWidget::setQuickSelectDelay(myOSystem.settings().getInt("listdelay"));
|
||||
|
|
|
@ -127,12 +127,12 @@ class Paddles : public Controller
|
|||
|
||||
// Range of values over which digital and mouse movement is scaled
|
||||
// to paddle resistance
|
||||
static const int TRIGMIN = 1;
|
||||
static const int TRIGMAX = 4096;
|
||||
static constexpr int TRIGMIN = 1;
|
||||
static constexpr int TRIGMAX = 4096;
|
||||
static int TRIGRANGE; // This one is variable for the upper range
|
||||
|
||||
static const int MAX_DIGITAL_SENSE = 20;
|
||||
static const int MAX_MOUSE_SENSE = 20;
|
||||
static constexpr int MAX_DIGITAL_SENSE = 20;
|
||||
static constexpr int MAX_MOUSE_SENSE = 20;
|
||||
static int DIGITAL_SENSITIVITY, DIGITAL_DISTANCE;
|
||||
static int MOUSE_SENSITIVITY;
|
||||
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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 "Control.hxx"
|
||||
#include "Event.hxx"
|
||||
#include "System.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
#include "PointingDevice.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PointingDevice::PointingDevice(Jack jack, const Event& event,
|
||||
const System& system, Controller::Type type,
|
||||
float sensitivity)
|
||||
: Controller(jack, event, system, type),
|
||||
mySensitivity(sensitivity),
|
||||
myHCounterRemainder(0.0), myVCounterRemainder(0.0),
|
||||
myTrackBallLinesH(1), myTrackBallLinesV(1),
|
||||
myTrackBallLeft(false), myTrackBallDown(false),
|
||||
myCountH(0), myCountV(0),
|
||||
myScanCountH(0), myScanCountV(0),
|
||||
myFirstScanOffsetH(0), myFirstScanOffsetV(0),
|
||||
myMouseEnabled(false)
|
||||
{
|
||||
// The 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
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 PointingDevice::read()
|
||||
{
|
||||
int scanline = mySystem.tia().scanlines();
|
||||
|
||||
// Loop over all missed changes
|
||||
while(myScanCountH < scanline)
|
||||
{
|
||||
if(myTrackBallLeft) myCountH--;
|
||||
else myCountH++;
|
||||
|
||||
// Define scanline of next change
|
||||
myScanCountH += myTrackBallLinesH;
|
||||
}
|
||||
|
||||
// Loop over all missed changes
|
||||
while(myScanCountV < scanline)
|
||||
{
|
||||
if(myTrackBallDown) myCountV--;
|
||||
else myCountV++;
|
||||
|
||||
// Define scanline of next change
|
||||
myScanCountV += myTrackBallLinesV;
|
||||
}
|
||||
|
||||
myCountH &= 0x03;
|
||||
myCountV &= 0x03;
|
||||
|
||||
uInt8 portA = ioPortA(myCountH, myCountV, myTrackBallLeft, myTrackBallDown);
|
||||
|
||||
myDigitalPinState[One] = portA & 0x10;
|
||||
myDigitalPinState[Two] = portA & 0x20;
|
||||
myDigitalPinState[Three] = portA & 0x40;
|
||||
myDigitalPinState[Four] = portA & 0x80;
|
||||
|
||||
return (portA >> 4);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PointingDevice::update()
|
||||
{
|
||||
if(!myMouseEnabled)
|
||||
return;
|
||||
|
||||
// Update horizontal direction
|
||||
updateDirection( myEvent.get(Event::MouseAxisXValue), myHCounterRemainder,
|
||||
myTrackBallLeft, myTrackBallLinesH, myScanCountH, myFirstScanOffsetH);
|
||||
|
||||
// Update vertical direction
|
||||
updateDirection(-myEvent.get(Event::MouseAxisYValue), myVCounterRemainder,
|
||||
myTrackBallDown, myTrackBallLinesV, myScanCountV, myFirstScanOffsetV);
|
||||
|
||||
// Get mouse button state
|
||||
myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
|
||||
(myEvent.get(Event::MouseButtonRightValue) == 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PointingDevice::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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PointingDevice::setSensitivity(int sensitivity)
|
||||
{
|
||||
BSPF::clamp(sensitivity, 1, 20, 10);
|
||||
TB_SENSITIVITY = sensitivity / 10.0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PointingDevice::updateDirection(const int& counter, float& counterRemainder,
|
||||
bool& trackBallDir, int& trackBallLines, int& scanCount, int& firstScanOffset)
|
||||
{
|
||||
// Apply sensitivity and calculate remainder
|
||||
float fTrackBallCount = counter * mySensitivity * TB_SENSITIVITY + counterRemainder;
|
||||
int trackBallCount = std::lround(fTrackBallCount);
|
||||
counterRemainder = fTrackBallCount - trackBallCount;
|
||||
|
||||
if(trackBallCount)
|
||||
{
|
||||
trackBallDir = (trackBallCount > 0);
|
||||
trackBallCount = abs(trackBallCount);
|
||||
|
||||
// Calculate lines to wait between sending new horz/vert values
|
||||
trackBallLines = mySystem.tia().scanlinesLastFrame() / trackBallCount;
|
||||
|
||||
// Set lower limit in case of (unrealistic) ultra fast mouse movements
|
||||
if (trackBallLines == 0) trackBallLines = 1;
|
||||
|
||||
// Define scanline of first change
|
||||
scanCount = (trackBallLines * firstScanOffset) >> 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prevent any change
|
||||
scanCount = INT_MAX;
|
||||
|
||||
// Define offset factor for first change, move randomly forward by up to 1/8th
|
||||
firstScanOffset = (((firstScanOffset << 3) + rand() %
|
||||
(1 << 12)) >> 3) & ((1 << 12) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
float PointingDevice::TB_SENSITIVITY = 1.0;
|
|
@ -18,22 +18,23 @@
|
|||
#ifndef POINTING_DEVICE_HXX
|
||||
#define POINTING_DEVICE_HXX
|
||||
|
||||
class Controller;
|
||||
class Event;
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Control.hxx"
|
||||
#include "Event.hxx"
|
||||
|
||||
/**
|
||||
Common controller class for pointing devices (Atari Mouse, Amiga Mouse, Trak-Ball)
|
||||
This code was heavily borrowed from z26.
|
||||
|
||||
@author Stephen Anthony, Thomas Jentzsch & z26 team
|
||||
Template-ification by Christian Speckner
|
||||
*/
|
||||
template<class T>
|
||||
class PointingDevice : public Controller
|
||||
{
|
||||
public:
|
||||
PointingDevice(Jack jack, const Event& event, const System& system);
|
||||
PointingDevice(Jack jack, const Event& event,
|
||||
const System& system, Controller::Type type,
|
||||
float sensitivity);
|
||||
virtual ~PointingDevice() = default;
|
||||
|
||||
public:
|
||||
|
@ -72,13 +73,28 @@ class PointingDevice : public Controller
|
|||
bool setMouseControl(Controller::Type xtype, int xid,
|
||||
Controller::Type ytype, int yid) override;
|
||||
|
||||
/**
|
||||
Sets the sensitivity for analog emulation of trackball movement
|
||||
using a mouse.
|
||||
|
||||
@param sensitivity Value from 1 to 20, with larger values causing
|
||||
more movement (10 represents the baseline)
|
||||
*/
|
||||
static void setSensitivity(int sensitivity);
|
||||
|
||||
protected:
|
||||
// Each derived class must implement this, to determine how its
|
||||
// IOPortA values are calculated
|
||||
virtual uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) = 0;
|
||||
|
||||
private:
|
||||
void updateDirection(const int& counter, double& counterRemainder,
|
||||
void updateDirection(const int& counter, float& counterRemainder,
|
||||
bool& trackBallDir, int& trackBallLines,
|
||||
int& scanCount, int& firstScanOffset);
|
||||
|
||||
private:
|
||||
double myHCounterRemainder, myVCounterRemainder;
|
||||
// Mouse input to sensitivity emulation
|
||||
float mySensitivity, myHCounterRemainder, myVCounterRemainder;
|
||||
|
||||
// How many lines to wait between sending new horz and vert values
|
||||
int myTrackBallLinesH, myTrackBallLinesV;
|
||||
|
@ -101,143 +117,17 @@ class PointingDevice : public Controller
|
|||
// Whether to use the mouse to emulate this controller
|
||||
bool myMouseEnabled;
|
||||
|
||||
private:
|
||||
// User-defined sensitivity; adjustable since end-users may have different
|
||||
// mouse speeds
|
||||
static float TB_SENSITIVITY;
|
||||
|
||||
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;
|
||||
PointingDevice(const PointingDevice&) = delete;
|
||||
PointingDevice(PointingDevice&&) = delete;
|
||||
PointingDevice& operator=(const PointingDevice&) = delete;
|
||||
PointingDevice& operator=(PointingDevice&&) = delete;
|
||||
};
|
||||
|
||||
// ############################################################################
|
||||
// Implementation
|
||||
// ############################################################################
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
template<class T>
|
||||
PointingDevice<T>::PointingDevice(Jack jack, const Event& event, const System& system)
|
||||
: Controller(jack, event, system, T::controllerType),
|
||||
myHCounterRemainder(0.0), myVCounterRemainder(0.0),
|
||||
myTrackBallLinesH(1), myTrackBallLinesV(1),
|
||||
myTrackBallLeft(false), myTrackBallDown(false),
|
||||
myCountH(0), myCountV(0),
|
||||
myScanCountH(0), myScanCountV(0),
|
||||
myFirstScanOffsetH(0), myFirstScanOffsetV(0),
|
||||
myMouseEnabled(false)
|
||||
{
|
||||
// The 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
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
template<class T>
|
||||
uInt8 PointingDevice<T>::read()
|
||||
{
|
||||
int scanline = mySystem.tia().scanlines();
|
||||
|
||||
// Loop over all missed changes
|
||||
while(myScanCountH < scanline)
|
||||
{
|
||||
if(myTrackBallLeft) myCountH--;
|
||||
else myCountH++;
|
||||
|
||||
// Define scanline of next change
|
||||
myScanCountH += myTrackBallLinesH;
|
||||
}
|
||||
|
||||
// Loop over all missed changes
|
||||
while(myScanCountV < scanline)
|
||||
{
|
||||
if(myTrackBallDown) myCountV--;
|
||||
else myCountV++;
|
||||
|
||||
// Define scanline of next change
|
||||
myScanCountV += myTrackBallLinesV;
|
||||
}
|
||||
|
||||
myCountH &= 0x03;
|
||||
myCountV &= 0x03;
|
||||
|
||||
uInt8 ioPortA = T::ioPortA(myCountV, myCountH, myTrackBallDown, myTrackBallLeft);
|
||||
|
||||
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;
|
||||
|
||||
// Update horizontal direction
|
||||
updateDirection( myEvent.get(Event::MouseAxisXValue), myHCounterRemainder,
|
||||
myTrackBallLeft, myTrackBallLinesH, myScanCountH, myFirstScanOffsetH);
|
||||
|
||||
// Update vertical direction
|
||||
updateDirection(-myEvent.get(Event::MouseAxisYValue), myVCounterRemainder,
|
||||
myTrackBallDown, myTrackBallLinesV, myScanCountV, myFirstScanOffsetV);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
template<class T>
|
||||
void PointingDevice<T>::updateDirection(const int& counter, double& counterRemainder,
|
||||
bool& trackBallDir, int& trackBallLines, int& scanCount, int& firstScanOffset)
|
||||
{
|
||||
// Apply sensitivity and calculate remainder
|
||||
float fTrackBallCount = counter * T::trackballSensitivity + counterRemainder;
|
||||
int trackBallCount = std::lround(fTrackBallCount);
|
||||
counterRemainder = fTrackBallCount - trackBallCount;
|
||||
|
||||
if(trackBallCount)
|
||||
{
|
||||
trackBallDir = (trackBallCount > 0);
|
||||
trackBallCount = abs(trackBallCount);
|
||||
|
||||
// Calculate lines to wait between sending new horz/vert values
|
||||
trackBallLines = mySystem.tia().scanlinesLastFrame() / trackBallCount;
|
||||
|
||||
// Set lower limit in case of (unrealistic) ultra fast mouse movements
|
||||
if (trackBallLines == 0) trackBallLines = 1;
|
||||
|
||||
// Define scanline of first change
|
||||
scanCount = (trackBallLines * firstScanOffset) >> 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prevent any change
|
||||
scanCount = INT_MAX;
|
||||
|
||||
// Define offset factor for first change, move randomly forward by up to 1/8th
|
||||
firstScanOffset = (((firstScanOffset << 3) + rand() %
|
||||
(1 << 12)) >> 3) & ((1 << 12) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // POINTING_DEVICE_HXX
|
||||
|
|
|
@ -90,6 +90,7 @@ Settings::Settings(OSystem& osystem)
|
|||
setInternal("cursor", "2");
|
||||
setInternal("dsense", "10");
|
||||
setInternal("msense", "10");
|
||||
setInternal("tsense", "10");
|
||||
setInternal("saport", "lr");
|
||||
setInternal("ctrlcombo", "true");
|
||||
|
||||
|
@ -309,12 +310,16 @@ void Settings::validate()
|
|||
setInternal("cursor", "2");
|
||||
|
||||
i = getInt("dsense");
|
||||
if(i < 1) setInternal("dsense", "1");
|
||||
else if(i > 20) setInternal("dsense", "10");
|
||||
if(i < 1 || i > 20)
|
||||
setInternal("dsense", "10");
|
||||
|
||||
i = getInt("msense");
|
||||
if(i < 1) setInternal("msense", "1");
|
||||
else if(i > 20) setInternal("msense", "15");
|
||||
if(i < 1 || i > 20)
|
||||
setInternal("msense", "10");
|
||||
|
||||
i = getInt("tsense");
|
||||
if(i < 1 || i > 20)
|
||||
setInternal("tsense", "10");
|
||||
|
||||
i = getInt("ssinterval");
|
||||
if(i < 1) setInternal("ssinterval", "2");
|
||||
|
@ -413,6 +418,7 @@ void Settings::usage() const
|
|||
<< " -cursor <0,1,2,3> Set cursor state in UI/emulation modes\n"
|
||||
<< " -dsense <number> Sensitivity of digital emulated paddle movement (1-20)\n"
|
||||
<< " -msense <number> Sensitivity of mouse emulated paddle movement (1-20)\n"
|
||||
<< " -tsense <number> Sensitivity of mouse emulated trackball movement (1-20)\n"
|
||||
<< " -saport <lr|rl> How to assign virtual ports to multiple Stelladaptor/2600-daptors\n"
|
||||
<< " -ctrlcombo <1|0> Use key combos involving the Control key (Control-Q for quit may be disabled!)\n"
|
||||
<< " -autoslot <1|0> Automatically switch to next save slot when state saving\n"
|
||||
|
|
|
@ -20,24 +20,32 @@
|
|||
|
||||
#include "PointingDevice.hxx"
|
||||
|
||||
namespace {
|
||||
class TrakBall : public PointingDevice
|
||||
{
|
||||
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)
|
||||
: PointingDevice(jack, event, system, Controller::TrakBall,
|
||||
trackballSensitivity) { }
|
||||
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 }};
|
||||
protected:
|
||||
uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) override
|
||||
{
|
||||
static constexpr uInt32 ourTableH[2][2] = {{ 0x00, 0x10 }, { 0x20, 0x30 }};
|
||||
static constexpr uInt32 ourTableV[2][2] = {{ 0x40, 0x00 }, { 0xc0, 0x80 }};
|
||||
|
||||
return ourTableV[countV & 0x01][down] | ourTableH[countH & 0x01][left];
|
||||
}
|
||||
return ourTableH[countH & 0x01][left] | ourTableV[countV & 0x01][down];
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr Controller::Type controllerType = Controller::TrakBall;
|
||||
static constexpr double trackballSensitivity = 0.4; // 50% of Atari and Amiga mouse; TODO: make configurable
|
||||
};
|
||||
}
|
||||
|
||||
using TrakBall = PointingDevice<TrakBallHelper>;
|
||||
// 50% of Atari and Amiga mouse
|
||||
static constexpr float trackballSensitivity = 0.4;
|
||||
};
|
||||
|
||||
#endif // TRAKBALL_HXX
|
||||
|
|
|
@ -67,6 +67,7 @@ MODULE_OBJS := \
|
|||
src/emucore/MD5.o \
|
||||
src/emucore/OSystem.o \
|
||||
src/emucore/Paddles.o \
|
||||
src/emucore/PointingDevice.o \
|
||||
src/emucore/Props.o \
|
||||
src/emucore/PropsSet.o \
|
||||
src/emucore/SaveKey.o \
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "OSystem.hxx"
|
||||
#include "Joystick.hxx"
|
||||
#include "Paddles.hxx"
|
||||
#include "PointingDevice.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "EventMappingWidget.hxx"
|
||||
#include "EditTextWidget.hxx"
|
||||
|
@ -45,7 +46,7 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent,
|
|||
|
||||
// Set real dimensions
|
||||
_w = std::min(50 * fontWidth + 10, max_w);
|
||||
_h = std::min(15 * (lineHeight + 4) + 14, max_h);
|
||||
_h = std::min(16 * (lineHeight + 4) + 14, max_h);
|
||||
|
||||
// The tab widget
|
||||
xpos = 2; ypos = vBorder;
|
||||
|
@ -164,8 +165,8 @@ void InputDialog::addDevicePortTab(const GUI::Font& font)
|
|||
// Add paddle speed (digital emulation)
|
||||
xpos = 5; ypos += lineHeight + 4;
|
||||
myDPaddleSpeed = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight,
|
||||
"Digital paddle sensitivity ",
|
||||
lwidth, kDPSpeedChanged);
|
||||
"Digital paddle sensitivity ",
|
||||
lwidth, kDPSpeedChanged);
|
||||
myDPaddleSpeed->setMinValue(1); myDPaddleSpeed->setMaxValue(20);
|
||||
xpos += myDPaddleSpeed->getWidth() + 5;
|
||||
myDPaddleLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight,
|
||||
|
@ -176,8 +177,8 @@ void InputDialog::addDevicePortTab(const GUI::Font& font)
|
|||
// Add paddle speed (mouse emulation)
|
||||
xpos = 5; ypos += lineHeight + 4;
|
||||
myMPaddleSpeed = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight,
|
||||
"Mouse paddle sensitivity ",
|
||||
lwidth, kMPSpeedChanged);
|
||||
"Mouse paddle sensitivity ",
|
||||
lwidth, kMPSpeedChanged);
|
||||
myMPaddleSpeed->setMinValue(1); myMPaddleSpeed->setMaxValue(20);
|
||||
xpos += myMPaddleSpeed->getWidth() + 5;
|
||||
myMPaddleLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight,
|
||||
|
@ -185,6 +186,18 @@ void InputDialog::addDevicePortTab(const GUI::Font& font)
|
|||
myMPaddleSpeed->setFlags(WIDGET_CLEARBG);
|
||||
wid.push_back(myMPaddleSpeed);
|
||||
|
||||
// Add trackball speed
|
||||
xpos = 5; ypos += lineHeight + 4;
|
||||
myTrackBallSpeed = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight,
|
||||
"Trackball sensitivity ",
|
||||
lwidth, kTBSpeedChanged);
|
||||
myTrackBallSpeed->setMinValue(1); myTrackBallSpeed->setMaxValue(20);
|
||||
xpos += myTrackBallSpeed->getWidth() + 5;
|
||||
myTrackBallLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight,
|
||||
"", kTextAlignLeft);
|
||||
myTrackBallSpeed->setFlags(WIDGET_CLEARBG);
|
||||
wid.push_back(myTrackBallSpeed);
|
||||
|
||||
// Add 'allow all 4 directions' for joystick
|
||||
xpos = 10; ypos += lineHeight + 12;
|
||||
myAllowAll4 = new CheckboxWidget(myTab, font, xpos, ypos,
|
||||
|
@ -240,6 +253,10 @@ void InputDialog::loadConfig()
|
|||
myMPaddleSpeed->setValue(instance().settings().getInt("msense"));
|
||||
myMPaddleLabel->setLabel(instance().settings().getString("msense"));
|
||||
|
||||
// Trackball speed
|
||||
myTrackBallSpeed->setValue(instance().settings().getInt("tsense"));
|
||||
myTrackBallLabel->setLabel(instance().settings().getString("tsense"));
|
||||
|
||||
// AtariVox serial port
|
||||
myAVoxPort->setText(instance().settings().getString("avoxport"));
|
||||
|
||||
|
@ -279,6 +296,11 @@ void InputDialog::saveConfig()
|
|||
instance().settings().setValue("msense", sensitivity);
|
||||
Paddles::setMouseSensitivity(sensitivity);
|
||||
|
||||
// Trackball speed
|
||||
sensitivity = myTrackBallSpeed->getValue();
|
||||
instance().settings().setValue("tsense", sensitivity);
|
||||
PointingDevice::setSensitivity(sensitivity);
|
||||
|
||||
// AtariVox serial port
|
||||
instance().settings().setValue("avoxport", myAVoxPort->getText());
|
||||
|
||||
|
@ -330,6 +352,8 @@ void InputDialog::setDefaults()
|
|||
myDPaddleLabel->setLabel("10");
|
||||
myMPaddleSpeed->setValue(10);
|
||||
myMPaddleLabel->setLabel("10");
|
||||
myTrackBallSpeed->setValue(10);
|
||||
myTrackBallLabel->setLabel("10");
|
||||
|
||||
// AtariVox serial port
|
||||
myAVoxPort->setText("");
|
||||
|
@ -433,6 +457,10 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd,
|
|||
myMPaddleLabel->setValue(myMPaddleSpeed->getValue());
|
||||
break;
|
||||
|
||||
case kTBSpeedChanged:
|
||||
myTrackBallLabel->setValue(myTrackBallSpeed->getValue());
|
||||
break;
|
||||
|
||||
case kDBButtonPressed:
|
||||
if(!myJoyDialog)
|
||||
myJoyDialog = make_unique<JoystickDialog>
|
||||
|
|
|
@ -57,6 +57,7 @@ class InputDialog : public Dialog
|
|||
kDeadzoneChanged = 'DZch',
|
||||
kDPSpeedChanged = 'PDch',
|
||||
kMPSpeedChanged = 'PMch',
|
||||
kTBSpeedChanged = 'TBch',
|
||||
kDBButtonPressed = 'DBbp'
|
||||
};
|
||||
|
||||
|
@ -75,8 +76,10 @@ class InputDialog : public Dialog
|
|||
StaticTextWidget* myDeadzoneLabel;
|
||||
SliderWidget* myDPaddleSpeed;
|
||||
SliderWidget* myMPaddleSpeed;
|
||||
SliderWidget* myTrackBallSpeed;
|
||||
StaticTextWidget* myDPaddleLabel;
|
||||
StaticTextWidget* myMPaddleLabel;
|
||||
StaticTextWidget* myTrackBallLabel;
|
||||
CheckboxWidget* myAllowAll4;
|
||||
CheckboxWidget* myGrabMouse;
|
||||
CheckboxWidget* myCtrlCombo;
|
||||
|
|