added autofire (resolves #676)

This commit is contained in:
thrust26 2020-07-25 10:19:07 +02:00
parent 78419f10d6
commit 41f501868a
22 changed files with 247 additions and 76 deletions

View File

@ -14,6 +14,8 @@
6.2.1 to 6.3 (XXXX XX, 2020) 6.2.1 to 6.3 (XXXX XX, 2020)
* Added autofire.
* Added new interface palette 'Dark'. (TODO: DOC) * Added new interface palette 'Dark'. (TODO: DOC)
* Extended global hotkeys for debug options. * Extended global hotkeys for debug options.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -2379,6 +2379,11 @@
faster movement.</td> faster movement.</td>
</tr> </tr>
<tr>
<td><pre>-autofirerate &lt;0 - 30&gt;</pre></td>
<td>Automatic trigger rate of the fire buttons in Hz (0 = disabled)</td>
</tr>
<tr> <tr>
<td><pre>-joyallow4 &lt;1|0&gt;</pre></td> <td><pre>-joyallow4 &lt;1|0&gt;</pre></td>
<td>Allow all 4 directions on a joystick to be pressed <td>Allow all 4 directions on a joystick to be pressed
@ -3302,6 +3307,7 @@
<tr><td>Analog paddle) Dejitter averaging</td><td>Strength of paddle input averaging, suppresses mouse jitter</td><td>-dejitter.base</td></tr> <tr><td>Analog paddle) Dejitter averaging</td><td>Strength of paddle input averaging, suppresses mouse jitter</td><td>-dejitter.base</td></tr>
<tr><td>(Analog paddle) Dejitter reaction</td><td>Strength of paddle reaction to fast paddle movements, suppresses mouse jitter</td><td>-dejitter.diff</td></tr> <tr><td>(Analog paddle) Dejitter reaction</td><td>Strength of paddle reaction to fast paddle movements, suppresses mouse jitter</td><td>-dejitter.diff</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>Digital paddle sensitivity</td><td>Sensitivity used when emulating a paddle using a digital device</td><td>-dsense</td></tr>
<tr><td>Autofire rate</td><td>Automatic trigger rate of the fire buttons in Hz</td><td>-autofirerate</td></tr>
<tr><td>Allow all 4 directions ...</td><td>Allow all 4 joystick directions to be pressed simultaneously</td><td>-joyallow4</td></tr> <tr><td>Allow all 4 directions ...</td><td>Allow all 4 joystick directions to be pressed simultaneously</td><td>-joyallow4</td></tr>
<tr><td>Use modifier key combos</td><td>Enable using modifier keys in keyboard actions</td><td>-modcombo</td></tr> <tr><td>Use modifier key combos</td><td>Enable using modifier keys in keyboard actions</td><td>-modcombo</td></tr>
<tr><td>Swap Stelladaptor ports</td><td>Swap the order of the detected Stelladaptors/2600-daptors (see <b>Advanced Configuration - <a href="#Adaptor">Stelladaptor/2600-daptor Support</a></b>)</td><td>-saport</td></tr> <tr><td>Swap Stelladaptor ports</td><td>Swap the order of the detected Stelladaptors/2600-daptors (see <b>Advanced Configuration - <a href="#Adaptor">Stelladaptor/2600-daptor Support</a></b>)</td><td>-saport</td></tr>

View File

@ -534,6 +534,9 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultCommo
{Event::ToggleContSnapshots, KBDK_S, MOD3}, {Event::ToggleContSnapshots, KBDK_S, MOD3},
{Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3}, {Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3},
#endif #endif
{Event::DecreaseAutoFire, KBDK_A, KBDM_SHIFT | KBDM_CTRL},
{Event::IncreaseAutoFire, KBDK_A, KBDM_CTRL },
{Event::HandleMouseControl, KBDK_0, KBDM_CTRL}, {Event::HandleMouseControl, KBDK_0, KBDM_CTRL},
{Event::ToggleGrabMouse, KBDK_G, KBDM_CTRL}, {Event::ToggleGrabMouse, KBDK_G, KBDM_CTRL},
{Event::ToggleSAPortOrder, KBDK_1, KBDM_CTRL}, {Event::ToggleSAPortOrder, KBDK_1, KBDM_CTRL},

View File

@ -59,7 +59,7 @@ void BoosterGrip::update()
setPin(DigitalPin::Two, myEvent.get(myDownEvent) == 0); setPin(DigitalPin::Two, myEvent.get(myDownEvent) == 0);
setPin(DigitalPin::Three, myEvent.get(myLeftEvent) == 0); setPin(DigitalPin::Three, myEvent.get(myLeftEvent) == 0);
setPin(DigitalPin::Four, myEvent.get(myRightEvent) == 0); setPin(DigitalPin::Four, myEvent.get(myRightEvent) == 0);
setPin(DigitalPin::Six, myEvent.get(myFireEvent) == 0); bool firePressed = myEvent.get(myFireEvent) != 0;
// The CBS Booster-grip has two more buttons on it. These buttons are // The CBS Booster-grip has two more buttons on it. These buttons are
// connected to the inputs usually used by paddles. // connected to the inputs usually used by paddles.
@ -120,11 +120,12 @@ void BoosterGrip::update()
} }
} }
// Get mouse button state // Get mouse button state
if(myEvent.get(Event::MouseButtonLeftValue)) firePressed = firePressed
setPin(DigitalPin::Six, false); || myEvent.get(Event::MouseButtonLeftValue);
if(myEvent.get(Event::MouseButtonRightValue)) if(myEvent.get(Event::MouseButtonRightValue))
setPin(AnalogPin::Nine, MIN_RESISTANCE); setPin(AnalogPin::Nine, MIN_RESISTANCE);
} }
setPin(DigitalPin::Six, !getAutoFireState(firePressed));
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -434,7 +434,7 @@ void Console::setFormat(uInt32 format, bool force)
setTIAProperties(); setTIAProperties();
initializeVideo(); // takes care of refreshing the screen initializeVideo(); // takes care of refreshing the screen
initializeAudio(); // ensure that audio synthesis is set up to match emulation speed initializeAudio(); // ensure that audio synthesis is set up to match emulation rate
myOSystem.resetFps(); // Reset FPS measurement myOSystem.resetFps(); // Reset FPS measurement
myOSystem.frameBuffer().showMessage(message); myOSystem.frameBuffer().showMessage(message);
@ -492,7 +492,7 @@ void Console::toggleTurbo()
myOSystem.settings().setValue("turbo", !enabled); myOSystem.settings().setValue("turbo", !enabled);
// update speed // update rate
initializeAudio(); initializeAudio();
// update VSync // update VSync
@ -870,6 +870,30 @@ unique_ptr<Controller> Console::getControllerPort(const Controller::Type type,
return controller; return controller;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::changeAutoFireRate(int direction)
{
const Int32 scanlines = std::max<Int32>(tia().scanlinesLastFrame(), 240);
const bool isNTSC = scanlines <= 287;
int rate = myOSystem.settings().getInt("autofirerate");
rate = BSPF::clamp(rate + direction, 0, isNTSC ? 30 : 25);
myOSystem.settings().setValue("autofirerate", rate);
Controller::setAutoFireRate(rate);
ostringstream val;
if(rate)
val << rate << " Hz";
else
{
val << "Off";
}
myOSystem.frameBuffer().showMessage("Autofire rate", val.str(), rate, 0, isNTSC ? 30 : 25);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
float Console::getFramerate() const float Console::getFramerate() const
{ {

View File

@ -318,6 +318,11 @@ class Console : public Serializable, public ConsoleIO
*/ */
void setTIAProperties(); void setTIAProperties();
/**
Change the autofire speed for all controllers
*/
void changeAutoFireRate(int direction = +1);
private: private:
/** /**
* Define console timing based on current display format * Define console timing based on current display format

View File

@ -147,3 +147,14 @@ Controller::Type Controller::getType(const string& propName)
return Type::Unknown; return Type::Unknown;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Controller::setAutoFireRate(int rate, bool isNTSC)
{
rate = BSPF::clamp(rate, 0, isNTSC ? 30 : 25);
AUTO_FIRE_RATE = 32 * 1024 * rate / (isNTSC ? 60 : 50);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int Controller::AUTO_FIRE_RATE = 0;

View File

@ -272,6 +272,14 @@ class Controller : public Serializable
*/ */
static Type getType(const string& propName); static Type getType(const string& propName);
/**
Sets the auto fire rate. 0 disables auto fire.
@param speed Auto fire rate (0..30/25) in Hz
@param isNTSC NTSC or PAL frame rate
*/
static void setAutoFireRate(int rate, bool isNTSC = true);
public: public:
/// Constant which represents maximum resistance for analog pins /// Constant which represents maximum resistance for analog pins
static constexpr Int32 MAX_RESISTANCE = 0x7FFFFFFF; static constexpr Int32 MAX_RESISTANCE = 0x7FFFFFFF;
@ -310,6 +318,44 @@ class Controller : public Serializable
setPin(AnalogPin::Nine, MAX_RESISTANCE); setPin(AnalogPin::Nine, MAX_RESISTANCE);
} }
/**
Checks for the next auto fire event.
@param pressed True if the fire button is current pressed
@return The result of the auto fire event check
*/
inline bool getAutoFireState(bool pressed)
{
if(AUTO_FIRE_RATE && pressed)
{
myFireDelay -= AUTO_FIRE_RATE;
if(myFireDelay <= 0)
myFireDelay += 32 * 1024;
return myFireDelay > 16 * 1024;
}
myFireDelay = 0;
return pressed;
}
/**
Checks for the next auto fire event for paddle 1.
@param pressed True if the fire button is current pressed
@return The result of the auto fire event check
*/
inline bool getAutoFireStateP1(bool pressed)
{
if(AUTO_FIRE_RATE && pressed)
{
myFireDelayP1 -= AUTO_FIRE_RATE;
if(myFireDelayP1 <= 0)
myFireDelayP1 += 32 * 1024;
return myFireDelayP1 > 16 * 1024;
}
myFireDelayP1 = 0;
return pressed;
}
protected: protected:
/// Specifies which jack the controller is plugged in /// Specifies which jack the controller is plugged in
const Jack myJack; const Jack myJack;
@ -326,6 +372,13 @@ class Controller : public Serializable
/// The callback that is dispatched whenver an analog pin has changed /// The callback that is dispatched whenver an analog pin has changed
onAnalogPinUpdateCallback myOnAnalogPinUpdateCallback{nullptr}; onAnalogPinUpdateCallback myOnAnalogPinUpdateCallback{nullptr};
/// Defines the speed of the auto fire
static int AUTO_FIRE_RATE;
/// Delay[frames] until the next fire event
int myFireDelay{0};
int myFireDelayP1{0}; // required for paddles only
private: private:
/// The boolean value on each digital pin /// The boolean value on each digital pin
std::array<bool, 5> myDigitalPinState{true, true, true, true, true}; std::array<bool, 5> myDigitalPinState{true, true, true, true, true};

View File

@ -50,7 +50,8 @@ Driving::Driving(Jack jack, const Event& event, const System& system)
void Driving::update() void Driving::update()
{ {
// Digital events (from keyboard or joystick hats & buttons) // Digital events (from keyboard or joystick hats & buttons)
setPin(DigitalPin::Six, myEvent.get(myFireEvent) == 0); bool firePressed = myEvent.get(myFireEvent) != 0;
int d_axis = myEvent.get(myXAxisValue); int d_axis = myEvent.get(myXAxisValue);
if(myEvent.get(myCCWEvent) != 0 || d_axis < -16384) --myCounter; if(myEvent.get(myCCWEvent) != 0 || d_axis < -16384) --myCounter;
else if(myEvent.get(myCWEvent) != 0 || d_axis > 16384) ++myCounter; else if(myEvent.get(myCWEvent) != 0 || d_axis > 16384) ++myCounter;
@ -61,9 +62,9 @@ void Driving::update()
int m_axis = myEvent.get(Event::MouseAxisXMove); int m_axis = myEvent.get(Event::MouseAxisXMove);
if(m_axis < -2) --myCounter; if(m_axis < -2) --myCounter;
else if(m_axis > 2) ++myCounter; else if(m_axis > 2) ++myCounter;
if(myEvent.get(Event::MouseButtonLeftValue) || firePressed = firePressed
myEvent.get(Event::MouseButtonRightValue)) || myEvent.get(Event::MouseButtonLeftValue)
setPin(DigitalPin::Six, false); || myEvent.get(Event::MouseButtonRightValue);
} }
else else
{ {
@ -74,18 +75,19 @@ void Driving::update()
int m_axis = myEvent.get(Event::MouseAxisXMove); int m_axis = myEvent.get(Event::MouseAxisXMove);
if(m_axis < -2) --myCounter; if(m_axis < -2) --myCounter;
else if(m_axis > 2) ++myCounter; else if(m_axis > 2) ++myCounter;
if(myEvent.get(Event::MouseButtonLeftValue)) firePressed = firePressed
setPin(DigitalPin::Six, false); || myEvent.get(Event::MouseButtonLeftValue);
} }
if(myControlIDY > -1) if(myControlIDY > -1)
{ {
int m_axis = myEvent.get(Event::MouseAxisYMove); int m_axis = myEvent.get(Event::MouseAxisYMove);
if(m_axis < -2) --myCounter; if(m_axis < -2) --myCounter;
else if(m_axis > 2) ++myCounter; else if(m_axis > 2) ++myCounter;
if(myEvent.get(Event::MouseButtonRightValue)) firePressed = firePressed
setPin(DigitalPin::Six, false); || myEvent.get(Event::MouseButtonRightValue);
} }
} }
setPin(DigitalPin::Six, !getAutoFireState(firePressed));
// Only consider the lower-most bits (corresponding to pins 1 & 2) // Only consider the lower-most bits (corresponding to pins 1 & 2)
myGrayIndex = Int32(myCounter * SENSITIVITY / 4.0F) & 0b11; myGrayIndex = Int32(myCounter * SENSITIVITY / 4.0F) & 0b11;

View File

@ -126,6 +126,7 @@ class Event
// add new events from here to avoid that user remapped events get overwritten // add new events from here to avoid that user remapped events get overwritten
PreviousSettingGroup, NextSettingGroup, PreviousSettingGroup, NextSettingGroup,
TogglePlayBackMode, TogglePlayBackMode,
DecreaseAutoFire, IncreaseAutoFire,
LastType LastType
}; };

View File

@ -102,6 +102,7 @@ void EventHandler::initialize()
Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense")); Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense"));
PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense")); PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense"));
Driving::setSensitivity(myOSystem.settings().getInt("dcsense")); Driving::setSensitivity(myOSystem.settings().getInt("dcsense"));
Controller::setAutoFireRate(myOSystem.settings().getInt("autofirerate"));
#ifdef GUI_SUPPORT #ifdef GUI_SUPPORT
// Set quick select delay when typing characters in listwidgets // Set quick select delay when typing characters in listwidgets
@ -1249,6 +1250,14 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
return; return;
#endif #endif
case Event::DecreaseAutoFire:
if(pressed) myOSystem.console().changeAutoFireRate(-1);
return;
case Event::IncreaseAutoFire:
if(pressed) myOSystem.console().changeAutoFireRate(+1);
return;
case Event::HandleMouseControl: case Event::HandleMouseControl:
if (pressed && !repeated) handleMouseControl(); if (pressed && !repeated) handleMouseControl();
return; return;
@ -2558,6 +2567,8 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { {
{ Event::VolumeDecrease, "Decrease volume", "" }, { Event::VolumeDecrease, "Decrease volume", "" },
{ Event::VolumeIncrease, "Increase volume", "" }, { Event::VolumeIncrease, "Increase volume", "" },
{ Event::DecreaseAutoFire, "Decrease auto fire speed", "" },
{ Event::IncreaseAutoFire, "Increase auto fire speed", "" },
{ Event::HandleMouseControl, "Switch mouse emulation modes", "" }, { Event::HandleMouseControl, "Switch mouse emulation modes", "" },
{ Event::ToggleGrabMouse, "Toggle grab mouse", "" }, { Event::ToggleGrabMouse, "Toggle grab mouse", "" },
{ Event::ToggleSAPortOrder, "Swap Stelladaptor port ordering", "" }, { Event::ToggleSAPortOrder, "Swap Stelladaptor port ordering", "" },
@ -2627,6 +2638,7 @@ const Event::EventSet EventHandler::MiscEvents = {
Event::TakeSnapshot, Event::ToggleContSnapshots, Event::ToggleContSnapshotsFrame, Event::TakeSnapshot, Event::ToggleContSnapshots, Event::ToggleContSnapshotsFrame,
// Event::MouseAxisXMove, Event::MouseAxisYMove, // Event::MouseAxisXMove, Event::MouseAxisYMove,
// Event::MouseButtonLeftValue, Event::MouseButtonRightValue, // Event::MouseButtonLeftValue, Event::MouseButtonRightValue,
Event::DecreaseAutoFire, Event::IncreaseAutoFire,
Event::HandleMouseControl, Event::ToggleGrabMouse, Event::HandleMouseControl, Event::ToggleGrabMouse,
Event::ToggleSAPortOrder, Event::PreviousMultiCartRom, Event::ToggleSAPortOrder, Event::PreviousMultiCartRom,
Event::PreviousSettingGroup, Event::NextSettingGroup, Event::PreviousSettingGroup, Event::NextSettingGroup,

View File

@ -558,7 +558,7 @@ class EventHandler
#else #else
REFRESH_SIZE = 0, REFRESH_SIZE = 0,
#endif #endif
EMUL_ACTIONLIST_SIZE = 160 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE, EMUL_ACTIONLIST_SIZE = 162 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE,
MENU_ACTIONLIST_SIZE = 18 MENU_ACTIONLIST_SIZE = 18
; ;

View File

@ -53,7 +53,7 @@ void Genesis::update()
setPin(DigitalPin::Two, myEvent.get(myDownEvent) == 0); setPin(DigitalPin::Two, myEvent.get(myDownEvent) == 0);
setPin(DigitalPin::Three, myEvent.get(myLeftEvent) == 0); setPin(DigitalPin::Three, myEvent.get(myLeftEvent) == 0);
setPin(DigitalPin::Four, myEvent.get(myRightEvent) == 0); setPin(DigitalPin::Four, myEvent.get(myRightEvent) == 0);
setPin(DigitalPin::Six, myEvent.get(myFire1Event) == 0); bool firePressed = myEvent.get(myFire1Event) != 0;
// The Genesis has one more button (C) that can be read by the 2600 // The Genesis has one more button (C) that can be read by the 2600
// However, it seems to work opposite to the BoosterGrip controller, // However, it seems to work opposite to the BoosterGrip controller,
@ -88,11 +88,12 @@ void Genesis::update()
} }
} }
// Get mouse button state // Get mouse button state
if(myEvent.get(Event::MouseButtonLeftValue)) firePressed = firePressed
setPin(DigitalPin::Six, false); || myEvent.get(Event::MouseButtonLeftValue);
if(myEvent.get(Event::MouseButtonRightValue)) if(myEvent.get(Event::MouseButtonRightValue))
setPin(AnalogPin::Five, MAX_RESISTANCE); setPin(AnalogPin::Five, MAX_RESISTANCE);
} }
setPin(DigitalPin::Six, !getAutoFireState(firePressed));
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -52,7 +52,7 @@ void Joystick::update()
setPin(DigitalPin::Two, myEvent.get(myDownEvent) == 0); setPin(DigitalPin::Two, myEvent.get(myDownEvent) == 0);
setPin(DigitalPin::Three, myEvent.get(myLeftEvent) == 0); setPin(DigitalPin::Three, myEvent.get(myLeftEvent) == 0);
setPin(DigitalPin::Four, myEvent.get(myRightEvent) == 0); setPin(DigitalPin::Four, myEvent.get(myRightEvent) == 0);
setPin(DigitalPin::Six, myEvent.get(myFireEvent) == 0); bool firePressed = myEvent.get(myFireEvent) != 0;
// Axis events (usually generated by the Stelladaptor) // Axis events (usually generated by the Stelladaptor)
int xaxis = myEvent.get(myXAxisValue); int xaxis = myEvent.get(myXAxisValue);
@ -102,10 +102,11 @@ void Joystick::update()
} }
} }
// Get mouse button state // Get mouse button state
if(myEvent.get(Event::MouseButtonLeftValue) || firePressed = firePressed
myEvent.get(Event::MouseButtonRightValue)) || myEvent.get(Event::MouseButtonLeftValue)
setPin(DigitalPin::Six, false); || myEvent.get(Event::MouseButtonRightValue);
} }
setPin(DigitalPin::Six, !getAutoFireState(firePressed));
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -116,10 +116,12 @@ bool Lightgun::read(DigitalPin pin)
void Lightgun::update() void Lightgun::update()
{ {
// Digital events (from keyboard or joystick hats & buttons) // Digital events (from keyboard or joystick hats & buttons)
setPin(DigitalPin::One, myEvent.get(Event::JoystickZeroFire) == 0); bool firePressed = myEvent.get(Event::JoystickZeroFire) != 0;
// We allow left and right mouse buttons for fire button // We allow left and right mouse buttons for fire button
if(myEvent.get(Event::MouseButtonLeftValue) || firePressed = firePressed
myEvent.get(Event::MouseButtonRightValue)) || myEvent.get(Event::MouseButtonLeftValue)
setPin(DigitalPin::One, false); || myEvent.get(Event::MouseButtonRightValue);
setPin(DigitalPin::One, !getAutoFireState(firePressed));
} }

View File

@ -186,8 +186,8 @@ void Paddles::update()
setPin(DigitalPin::Four, true); setPin(DigitalPin::Four, true);
// Digital events (from keyboard or joystick hats & buttons) // Digital events (from keyboard or joystick hats & buttons)
setPin(DigitalPin::Three, myEvent.get(myP1FireEvent) == 0); bool firePressedP0 = myEvent.get(myP0FireEvent) != 0;
setPin(DigitalPin::Four, myEvent.get(myP0FireEvent) == 0); bool firePressedP1 = myEvent.get(myP1FireEvent) != 0;
// Paddle movement is a very difficult thing to accurately emulate, // Paddle movement is a very difficult thing to accurately emulate,
// since it originally came from an analog device that had very // since it originally came from an analog device that had very
@ -269,9 +269,14 @@ void Paddles::update()
myCharge[myMPaddleID] = BSPF::clamp(myCharge[myMPaddleID] - myCharge[myMPaddleID] = BSPF::clamp(myCharge[myMPaddleID] -
(myEvent.get(myAxisMouseMotion) * MOUSE_SENSITIVITY), (myEvent.get(myAxisMouseMotion) * MOUSE_SENSITIVITY),
TRIGMIN, TRIGRANGE); TRIGMIN, TRIGRANGE);
if(myEvent.get(Event::MouseButtonLeftValue) || if(myMPaddleID == 0)
myEvent.get(Event::MouseButtonRightValue)) firePressedP0 = firePressedP0
setPin(ourButtonPin[myMPaddleID], false); || myEvent.get(Event::MouseButtonLeftValue)
|| myEvent.get(Event::MouseButtonRightValue);
else
firePressedP1 = firePressedP1
|| myEvent.get(Event::MouseButtonLeftValue)
|| myEvent.get(Event::MouseButtonRightValue);
} }
else else
{ {
@ -282,18 +287,30 @@ void Paddles::update()
myCharge[myMPaddleIDX] = BSPF::clamp(myCharge[myMPaddleIDX] - myCharge[myMPaddleIDX] = BSPF::clamp(myCharge[myMPaddleIDX] -
(myEvent.get(Event::MouseAxisXMove) * MOUSE_SENSITIVITY), (myEvent.get(Event::MouseAxisXMove) * MOUSE_SENSITIVITY),
TRIGMIN, TRIGRANGE); TRIGMIN, TRIGRANGE);
if(myEvent.get(Event::MouseButtonLeftValue))
setPin(ourButtonPin[myMPaddleIDX], false); if(myMPaddleIDX == 0)
firePressedP0 = firePressedP0
|| myEvent.get(Event::MouseButtonLeftValue);
else
firePressedP1 = firePressedP1
|| myEvent.get(Event::MouseButtonLeftValue);
} }
if(myMPaddleIDY > -1) if(myMPaddleIDY > -1)
{ {
myCharge[myMPaddleIDY] = BSPF::clamp(myCharge[myMPaddleIDY] - myCharge[myMPaddleIDY] = BSPF::clamp(myCharge[myMPaddleIDY] -
(myEvent.get(Event::MouseAxisYMove) * MOUSE_SENSITIVITY), (myEvent.get(Event::MouseAxisYMove) * MOUSE_SENSITIVITY),
TRIGMIN, TRIGRANGE); TRIGMIN, TRIGRANGE);
if(myEvent.get(Event::MouseButtonRightValue))
setPin(ourButtonPin[myMPaddleIDY], false); if(myMPaddleIDY == 0)
firePressedP0 = firePressedP0
|| myEvent.get(Event::MouseButtonRightValue);
else
firePressedP1 = firePressedP1
|| myEvent.get(Event::MouseButtonRightValue);
} }
} }
setPin(DigitalPin::Four, !getAutoFireState(firePressedP0));
setPin(DigitalPin::Three, !getAutoFireStateP1(firePressedP1));
// Finally, consider digital input, where movement happens // Finally, consider digital input, where movement happens
// until a digital event is released // until a digital event is released
@ -449,8 +466,3 @@ int Paddles::DIGITAL_DISTANCE = -1;
int Paddles::MOUSE_SENSITIVITY = -1; int Paddles::MOUSE_SENSITIVITY = -1;
int Paddles::DEJITTER_BASE = 0; int Paddles::DEJITTER_BASE = 0;
int Paddles::DEJITTER_DIFF = 0; int Paddles::DEJITTER_DIFF = 0;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const std::array<Controller::DigitalPin, 2> Paddles::ourButtonPin = {
DigitalPin::Four, DigitalPin::Three
};

View File

@ -190,10 +190,6 @@ class Paddles : public Controller
static int DEJITTER_BASE, DEJITTER_DIFF; static int DEJITTER_BASE, DEJITTER_DIFF;
static int MOUSE_SENSITIVITY; static int MOUSE_SENSITIVITY;
// Lookup table for associating paddle buttons with controller pins
// Yes, this is hideously complex
static const std::array<Controller::DigitalPin, 2> ourButtonPin;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported
Paddles() = delete; Paddles() = delete;

View File

@ -92,9 +92,8 @@ void PointingDevice::update()
setPin(DigitalPin::Six, myEvent.get(Event::JoystickZeroFire) == 0); setPin(DigitalPin::Six, myEvent.get(Event::JoystickZeroFire) == 0);
// We allow left and right mouse buttons for fire button // We allow left and right mouse buttons for fire button
if(myEvent.get(Event::MouseButtonLeftValue) || setPin(DigitalPin::Six, !getAutoFireState(
myEvent.get(Event::MouseButtonRightValue)) myEvent.get(Event::MouseButtonLeftValue) || myEvent.get(Event::MouseButtonRightValue)));
setPin(DigitalPin::Six, false);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -100,6 +100,7 @@ Settings::Settings()
setPermanent("combomap", ""); setPermanent("combomap", "");
setPermanent("joydeadzone", "13"); setPermanent("joydeadzone", "13");
setPermanent("joyallow4", "false"); setPermanent("joyallow4", "false");
setPermanent("autofirerate", "0");
setPermanent("usemouse", "analog"); setPermanent("usemouse", "analog");
setPermanent("grabmouse", "true"); setPermanent("grabmouse", "true");
setPermanent("cursor", "2"); setPermanent("cursor", "2");
@ -481,6 +482,7 @@ void Settings::usage() const
<< " -tsense <1-20> Sensitivity of mouse emulated trackball movement\n" << " -tsense <1-20> Sensitivity of mouse emulated trackball movement\n"
<< " -dcsense <1-20> Sensitivity of digital emulated driving controller\n" << " -dcsense <1-20> Sensitivity of digital emulated driving controller\n"
<< " movement\n" << " movement\n"
<< " -autofirerate <0-30> Set fire button's autofire rate (0 means off)\n"
<< " -saport <lr|rl> How to assign virtual ports to multiple\n" << " -saport <lr|rl> How to assign virtual ports to multiple\n"
<< " Stelladaptor/2600-daptors\n" << " Stelladaptor/2600-daptors\n"
<< " -modcombo <1|0> Enable modifer key combos\n" << " -modcombo <1|0> Enable modifer key combos\n"

View File

@ -134,7 +134,7 @@ void InputDialog::addDevicePortTab()
xpos += fontWidth * 2; xpos += fontWidth * 2;
// Add analog paddle sensitivity // Add analog paddle sensitivity
ypos += lineHeight + VGAP; ypos += lineHeight;
myPaddleSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight, myPaddleSpeed = new SliderWidget(myTab, _font, xpos, ypos - 1, 13 * fontWidth, lineHeight,
"Sensitivity", "Sensitivity",
lwidth - fontWidth * 2, kPSpeedChanged, 4 * fontWidth, "%"); lwidth - fontWidth * 2, kPSpeedChanged, 4 * fontWidth, "%");
@ -172,6 +172,14 @@ void InputDialog::addDevicePortTab()
myDPaddleSpeed->setTickmarkIntervals(4); myDPaddleSpeed->setTickmarkIntervals(4);
wid.push_back(myDPaddleSpeed); wid.push_back(myDPaddleSpeed);
ypos += lineHeight + VGAP * 4;
myAutoFireRate = new SliderWidget(myTab, _font, HBORDER, ypos - 1, 13 * fontWidth, lineHeight,
"Autofire rate",
lwidth, kAutoFireChanged, 5 * fontWidth, "Hz");
myAutoFireRate->setMinValue(0); myAutoFireRate->setMaxValue(30);
myAutoFireRate->setTickmarkIntervals(6);
wid.push_back(myAutoFireRate);
// Add 'allow all 4 directions' for joystick // Add 'allow all 4 directions' for joystick
ypos += lineHeight + VGAP * 4; ypos += lineHeight + VGAP * 4;
myAllowAll4 = new CheckboxWidget(myTab, _font, HBORDER, ypos, myAllowAll4 = new CheckboxWidget(myTab, _font, HBORDER, ypos,
@ -315,38 +323,43 @@ void InputDialog::addMouseTab()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputDialog::loadConfig() void InputDialog::loadConfig()
{ {
Settings& settings = instance().settings();
// Left & right ports // Left & right ports
mySAPort->setState(instance().settings().getString("saport") == "rl"); mySAPort->setState(settings.getString("saport") == "rl");
// Use mouse as a controller // Use mouse as a controller
myMouseControl->setSelected( myMouseControl->setSelected(
instance().settings().getString("usemouse"), "analog"); settings.getString("usemouse"), "analog");
handleMouseControlState(); handleMouseControlState();
// Mouse cursor state // Mouse cursor state
myCursorState->setSelected(instance().settings().getString("cursor"), "2"); myCursorState->setSelected(settings.getString("cursor"), "2");
handleCursorState(); handleCursorState();
// Joystick deadzone // Joystick deadzone
myDeadzone->setValue(instance().settings().getInt("joydeadzone")); myDeadzone->setValue(settings.getInt("joydeadzone"));
// Paddle speed (analog) // Paddle speed (analog)
myPaddleSpeed->setValue(instance().settings().getInt("psense")); myPaddleSpeed->setValue(settings.getInt("psense"));
// Paddle dejitter (analog) // Paddle dejitter (analog)
myDejitterBase->setValue(instance().settings().getInt("dejitter.base")); myDejitterBase->setValue(settings.getInt("dejitter.base"));
myDejitterDiff->setValue(instance().settings().getInt("dejitter.diff")); myDejitterDiff->setValue(settings.getInt("dejitter.diff"));
// Paddle speed (digital and mouse) // Paddle speed (digital and mouse)
myDPaddleSpeed->setValue(instance().settings().getInt("dsense")); myDPaddleSpeed->setValue(settings.getInt("dsense"));
myMPaddleSpeed->setValue(instance().settings().getInt("msense")); myMPaddleSpeed->setValue(settings.getInt("msense"));
// Trackball speed // Trackball speed
myTrackBallSpeed->setValue(instance().settings().getInt("tsense")); myTrackBallSpeed->setValue(settings.getInt("tsense"));
// Driving controller speed // Driving controller speed
myDrivingSpeed->setValue(instance().settings().getInt("dcsense")); myDrivingSpeed->setValue(settings.getInt("dcsense"));
// Autofire rate
myAutoFireRate->setValue(settings.getInt("autofirerate"));
// AtariVox serial port // AtariVox serial port
myAVoxPort->setText(instance().settings().getString("avoxport")); myAVoxPort->setText(settings.getString("avoxport"));
// EEPROM erase (only enable in emulation mode and for valid controllers) // EEPROM erase (only enable in emulation mode and for valid controllers)
if(instance().hasConsole()) if(instance().hasConsole())
@ -361,13 +374,13 @@ void InputDialog::loadConfig()
myEraseEEPROMButton->setEnabled(false); myEraseEEPROMButton->setEnabled(false);
// Allow all 4 joystick directions // Allow all 4 joystick directions
myAllowAll4->setState(instance().settings().getBool("joyallow4")); myAllowAll4->setState(settings.getBool("joyallow4"));
// Grab mouse // Grab mouse
myGrabMouse->setState(instance().settings().getBool("grabmouse")); myGrabMouse->setState(settings.getBool("grabmouse"));
// Enable/disable modifier key-combos // Enable/disable modifier key-combos
myModCombo->setState(instance().settings().getBool("modcombo")); myModCombo->setState(settings.getBool("modcombo"));
myTab->loadConfig(); myTab->loadConfig();
} }
@ -375,70 +388,77 @@ void InputDialog::loadConfig()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputDialog::saveConfig() void InputDialog::saveConfig()
{ {
Settings& settings = instance().settings();
// Left & right ports // Left & right ports
instance().eventHandler().mapStelladaptors(mySAPort->getState() ? "rl": "lr"); instance().eventHandler().mapStelladaptors(mySAPort->getState() ? "rl": "lr");
// Use mouse as a controller // Use mouse as a controller
const string& usemouse = myMouseControl->getSelectedTag().toString(); const string& usemouse = myMouseControl->getSelectedTag().toString();
instance().settings().setValue("usemouse", usemouse); settings.setValue("usemouse", usemouse);
instance().eventHandler().setMouseControllerMode(usemouse); instance().eventHandler().setMouseControllerMode(usemouse);
// Joystick deadzone // Joystick deadzone
int deadzone = myDeadzone->getValue(); int deadzone = myDeadzone->getValue();
instance().settings().setValue("joydeadzone", deadzone); settings.setValue("joydeadzone", deadzone);
Joystick::setDeadZone(deadzone); Joystick::setDeadZone(deadzone);
// Paddle speed (analog) // Paddle speed (analog)
int sensitivity = myPaddleSpeed->getValue(); int sensitivity = myPaddleSpeed->getValue();
instance().settings().setValue("psense", sensitivity); settings.setValue("psense", sensitivity);
Paddles::setAnalogSensitivity(sensitivity); Paddles::setAnalogSensitivity(sensitivity);
// Paddle speed (digital and mouse) // Paddle speed (digital and mouse)
int dejitter = myDejitterBase->getValue(); int dejitter = myDejitterBase->getValue();
instance().settings().setValue("dejitter.base", dejitter); settings.setValue("dejitter.base", dejitter);
Paddles::setDejitterBase(dejitter); Paddles::setDejitterBase(dejitter);
dejitter = myDejitterDiff->getValue(); dejitter = myDejitterDiff->getValue();
instance().settings().setValue("dejitter.diff", dejitter); settings.setValue("dejitter.diff", dejitter);
Paddles::setDejitterDiff(dejitter); Paddles::setDejitterDiff(dejitter);
sensitivity = myDPaddleSpeed->getValue(); sensitivity = myDPaddleSpeed->getValue();
instance().settings().setValue("dsense", sensitivity); settings.setValue("dsense", sensitivity);
Paddles::setDigitalSensitivity(sensitivity); Paddles::setDigitalSensitivity(sensitivity);
sensitivity = myMPaddleSpeed->getValue(); sensitivity = myMPaddleSpeed->getValue();
instance().settings().setValue("msense", sensitivity); settings.setValue("msense", sensitivity);
Paddles::setMouseSensitivity(sensitivity); Paddles::setMouseSensitivity(sensitivity);
// Trackball speed // Trackball speed
sensitivity = myTrackBallSpeed->getValue(); sensitivity = myTrackBallSpeed->getValue();
instance().settings().setValue("tsense", sensitivity); settings.setValue("tsense", sensitivity);
PointingDevice::setSensitivity(sensitivity); PointingDevice::setSensitivity(sensitivity);
// Driving controller speed // Driving controller speed
sensitivity = myDrivingSpeed->getValue(); sensitivity = myDrivingSpeed->getValue();
instance().settings().setValue("dcsense", sensitivity); settings.setValue("dcsense", sensitivity);
Driving::setSensitivity(sensitivity); Driving::setSensitivity(sensitivity);
// Autofire rate
int rate = myAutoFireRate->getValue();
settings.setValue("autofirerate", rate);
Controller::setAutoFireRate(rate);
// AtariVox serial port // AtariVox serial port
instance().settings().setValue("avoxport", myAVoxPort->getText()); settings.setValue("avoxport", myAVoxPort->getText());
// Allow all 4 joystick directions // Allow all 4 joystick directions
bool allowall4 = myAllowAll4->getState(); bool allowall4 = myAllowAll4->getState();
instance().settings().setValue("joyallow4", allowall4); settings.setValue("joyallow4", allowall4);
instance().eventHandler().allowAllDirections(allowall4); instance().eventHandler().allowAllDirections(allowall4);
// Grab mouse and hide cursor // Grab mouse and hide cursor
const string& cursor = myCursorState->getSelectedTag().toString(); const string& cursor = myCursorState->getSelectedTag().toString();
instance().settings().setValue("cursor", cursor); settings.setValue("cursor", cursor);
// only allow grab mouse if cursor is hidden in emulation // only allow grab mouse if cursor is hidden in emulation
int state = myCursorState->getSelected(); int state = myCursorState->getSelected();
bool enableGrab = state != 1 && state != 3; bool enableGrab = state != 1 && state != 3;
bool grab = enableGrab ? myGrabMouse->getState() : false; bool grab = enableGrab ? myGrabMouse->getState() : false;
instance().settings().setValue("grabmouse", grab); settings.setValue("grabmouse", grab);
instance().frameBuffer().enableGrabMouse(grab); instance().frameBuffer().enableGrabMouse(grab);
// Enable/disable modifier key-combos // Enable/disable modifier key-combos
instance().settings().setValue("modcombo", myModCombo->getState()); settings.setValue("modcombo", myModCombo->getState());
instance().eventHandler().saveKeyMapping(); instance().eventHandler().saveKeyMapping();
instance().eventHandler().saveJoyMapping(); instance().eventHandler().saveJoyMapping();
@ -477,6 +497,8 @@ void InputDialog::setDefaults()
myDejitterBase->setValue(0); myDejitterBase->setValue(0);
myDejitterDiff->setValue(0); myDejitterDiff->setValue(0);
#endif #endif
// Autofire rate
myAutoFireRate->setValue(0);
// AtariVox serial port // AtariVox serial port
myAVoxPort->setText(""); myAVoxPort->setText("");
@ -659,6 +681,10 @@ void InputDialog::handleCommand(CommandSender* sender, int cmd,
myTrackBallSpeed->setValueLabel(myTrackBallSpeed->getValue() * 10); myTrackBallSpeed->setValueLabel(myTrackBallSpeed->getValue() * 10);
break; break;
case kAutoFireChanged:
updateAutoFireRate();
break;
case kDBButtonPressed: case kDBButtonPressed:
if(!myJoyDialog) if(!myJoyDialog)
{ {
@ -726,6 +752,15 @@ void InputDialog::updateDejitterReaction()
myDejitterDiff->setValueLabel(strength ? std::to_string(strength) : "Off"); myDejitterDiff->setValueLabel(strength ? std::to_string(strength) : "Off");
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputDialog::updateAutoFireRate()
{
int rate = myAutoFireRate->getValue();
myAutoFireRate->setValueLabel(rate ? std::to_string(rate) : "Off");
myAutoFireRate->setValueUnit(rate ? " Hz" : "");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputDialog::handleMouseControlState() void InputDialog::handleMouseControlState()
{ {

View File

@ -66,6 +66,7 @@ class InputDialog : public Dialog
void handleCursorState(); void handleCursorState();
void updateDejitterAveraging(); void updateDejitterAveraging();
void updateDejitterReaction(); void updateDejitterReaction();
void updateAutoFireRate();
void eraseEEPROM(); void eraseEEPROM();
private: private:
@ -75,6 +76,7 @@ class InputDialog : public Dialog
kDejitterAvChanged = 'JAch', kDejitterAvChanged = 'JAch',
kDejitterReChanged = 'JRch', kDejitterReChanged = 'JRch',
kDPSpeedChanged = 'PDch', kDPSpeedChanged = 'PDch',
kAutoFireChanged = 'AFch',
kTBSpeedChanged = 'TBch', kTBSpeedChanged = 'TBch',
kDCSpeedChanged = 'DCch', kDCSpeedChanged = 'DCch',
kDBButtonPressed = 'DBbp', kDBButtonPressed = 'DBbp',
@ -99,6 +101,7 @@ class InputDialog : public Dialog
SliderWidget* myDejitterBase{nullptr}; SliderWidget* myDejitterBase{nullptr};
SliderWidget* myDejitterDiff{nullptr}; SliderWidget* myDejitterDiff{nullptr};
SliderWidget* myDPaddleSpeed{nullptr}; SliderWidget* myDPaddleSpeed{nullptr};
SliderWidget* myAutoFireRate{nullptr};
CheckboxWidget* myAllowAll4{nullptr}; CheckboxWidget* myAllowAll4{nullptr};
CheckboxWidget* myModCombo{nullptr}; CheckboxWidget* myModCombo{nullptr};