mirror of https://github.com/stella-emu/stella.git
249 lines
9.6 KiB
C++
249 lines
9.6 KiB
C++
//============================================================================
|
|
//
|
|
// 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-2025 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 PHYSICAL_JOYSTICK_HANDLER_HXX
|
|
#define PHYSICAL_JOYSTICK_HANDLER_HXX
|
|
|
|
#include <map>
|
|
|
|
class OSystem;
|
|
class EventHandler;
|
|
class Event;
|
|
|
|
#include "bspf.hxx"
|
|
#include "EventHandlerConstants.hxx"
|
|
#include "PhysicalJoystick.hxx"
|
|
#include "Variant.hxx"
|
|
#include "json_lib.hxx"
|
|
|
|
using PhysicalJoystickPtr = shared_ptr<PhysicalJoystick>;
|
|
|
|
/**
|
|
This class handles all physical joystick-related operations in Stella.
|
|
|
|
It is responsible for adding/accessing/removing PhysicalJoystick objects,
|
|
and getting/setting events associated with joystick actions (button presses,
|
|
axis/hat actions, etc).
|
|
|
|
Essentially, this class is an extension of the EventHandler class, but
|
|
handling only joystick-specific functionality.
|
|
|
|
@author Stephen Anthony, Thomas Jentzsch
|
|
*/
|
|
class PhysicalJoystickHandler
|
|
{
|
|
public:
|
|
struct MinStrickInfo
|
|
{
|
|
string name;
|
|
int ID;
|
|
PhysicalJoystick::Port port;
|
|
|
|
explicit MinStrickInfo(string_view _name, int _id, PhysicalJoystick::Port _port)
|
|
: name{_name}, ID{_id}, port{_port} {}
|
|
};
|
|
using MinStrickInfoList = std::vector<MinStrickInfo>;
|
|
|
|
private:
|
|
struct StickInfo
|
|
{
|
|
// NOTE: For all future linting exercises
|
|
// Make sure to *NEVER* use brace initialization or std::move
|
|
// on the 'mapping' instance variable; there lay dragons ...
|
|
// https://json.nlohmann.me/home/faq/#brace-initialization-yields-arrays
|
|
explicit StickInfo(nlohmann::json map, PhysicalJoystickPtr stick = nullptr)
|
|
: mapping(map), joy{std::move(stick)} {} // NOLINT
|
|
|
|
nlohmann::json mapping;
|
|
PhysicalJoystickPtr joy;
|
|
|
|
friend ostream& operator<<(ostream& os, const StickInfo& si) {
|
|
os << " joy: " << si.joy << "\n map: " << si.mapping;
|
|
return os;
|
|
}
|
|
};
|
|
|
|
public:
|
|
PhysicalJoystickHandler(OSystem& system, EventHandler& handler, Event& event);
|
|
|
|
static nlohmann::json convertLegacyMapping(string_view mapping);
|
|
|
|
/** Return stick ID on success, -1 on failure. */
|
|
int add(const PhysicalJoystickPtr& stick);
|
|
bool remove(int id);
|
|
bool remove(string_view name);
|
|
void setPort(string_view name, PhysicalJoystick::Port port);
|
|
bool mapStelladaptors(string_view saport, int ID = -1);
|
|
bool hasStelladaptors() const;
|
|
void setDefaultMapping(Event::Type event, EventMode mode);
|
|
|
|
/** define mappings for current controllers */
|
|
void defineControllerMappings(Controller::Type type, Controller::Jack port,
|
|
const Properties& properties,
|
|
Controller::Type qtType1 = Controller::Type::Unknown,
|
|
Controller::Type qtType2 = Controller::Type::Unknown);
|
|
/** enable mappings for emulation mode */
|
|
void enableEmulationMappings();
|
|
|
|
void eraseMapping(Event::Type event, EventMode mode);
|
|
void saveMapping();
|
|
string getMappingDesc(Event::Type, EventMode mode) const;
|
|
|
|
/** Bind a physical joystick event to a virtual event/action. */
|
|
bool addJoyMapping(Event::Type event, EventMode mode, int stick,
|
|
int button, JoyAxis axis, JoyDir adir);
|
|
bool addJoyHatMapping(Event::Type event, EventMode mode, int stick,
|
|
int button, int hat, JoyHatDir hdir);
|
|
|
|
/** Handle a physical joystick event. */
|
|
void handleAxisEvent(int stick, int axis, int value);
|
|
void handleBtnEvent(int stick, int button, bool pressed);
|
|
void handleHatEvent(int stick, int hat, int value);
|
|
|
|
Event::Type eventForAxis(EventMode mode, int stick, JoyAxis axis, JoyDir adir, int button) const {
|
|
const PhysicalJoystickPtr& j = joy(stick);
|
|
return j->joyMap.get(mode, button, axis, adir);
|
|
}
|
|
Event::Type eventForButton(EventMode mode, int stick, int button) const {
|
|
const PhysicalJoystickPtr& j = joy(stick);
|
|
return j->joyMap.get(mode, button);
|
|
}
|
|
Event::Type eventForHat(EventMode mode, int stick, int hat, JoyHatDir hatDir, int button) const {
|
|
const PhysicalJoystickPtr& j = joy(stick);
|
|
return j->joyMap.get(mode, button, hat, hatDir);
|
|
}
|
|
|
|
/** Returns a list containing minimal controller info (name, ID, port). */
|
|
MinStrickInfoList minStickList() const;
|
|
|
|
void changeDigitalDeadZone(int direction = +1);
|
|
void changeAnalogPaddleDeadZone(int direction = +1);
|
|
void changeAnalogPaddleSensitivity(int direction = +1);
|
|
void changeAnalogPaddleLinearity(int direction = +1);
|
|
void changePaddleDejitterAveraging(int direction = +1);
|
|
void changePaddleDejitterReaction(int direction = +1);
|
|
void changeDigitalPaddleSensitivity(int direction = +1);
|
|
void changeMousePaddleSensitivity(int direction = +1);
|
|
void changeMouseTrackballSensitivity(int direction = +1);
|
|
void changeDrivingSensitivity(int direction = +1);
|
|
|
|
private:
|
|
using StickDatabase = std::map<string, StickInfo, std::less<>>;
|
|
using StickList = std::map<int, PhysicalJoystickPtr>;
|
|
|
|
OSystem& myOSystem; // NOLINT: we want a reference here
|
|
EventHandler& myHandler; // NOLINT: we want a reference here
|
|
Event& myEvent; // NOLINT: we want a reference here
|
|
|
|
// Contains all joysticks that Stella knows about, indexed by name
|
|
StickDatabase myDatabase;
|
|
|
|
// Contains only joysticks that are currently available, indexed by id
|
|
StickList mySticks;
|
|
|
|
// Get joystick corresponding to given id (or nullptr if it doesn't exist)
|
|
// Make this inline so it's as fast as possible
|
|
PhysicalJoystickPtr joy(int id) const {
|
|
const auto& i = mySticks.find(id);
|
|
return i != mySticks.cend() ? i->second : nullptr;
|
|
}
|
|
|
|
// Add stick to stick database
|
|
void addToDatabase(const PhysicalJoystickPtr& stick);
|
|
|
|
// Set default mapping for given joystick when no mappings already exist
|
|
void setStickDefaultMapping(int stick, Event::Type event, EventMode mode,
|
|
bool updateDefaults = false);
|
|
|
|
friend ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh);
|
|
|
|
static constexpr JoyDir convertAxisValue(int value) {
|
|
return value == static_cast<int>(JoyDir::NONE)
|
|
? JoyDir::NONE
|
|
: value > 0 ? JoyDir::POS : JoyDir::NEG;
|
|
}
|
|
|
|
// Handle regular axis events (besides special Stelladaptor handling)
|
|
void handleRegularAxisEvent(const PhysicalJoystickPtr& j,
|
|
int stick, int axis, int value);
|
|
|
|
// Structures used for action menu items
|
|
struct EventMapping {
|
|
Event::Type event{Event::NoType};
|
|
int button{0};
|
|
JoyAxis axis{JoyAxis::NONE};
|
|
JoyDir adir{JoyDir::NONE};
|
|
int hat{JOY_CTRL_NONE};
|
|
JoyHatDir hdir{JoyHatDir::CENTER};
|
|
};
|
|
using EventMappingArray = std::vector<EventMapping>;
|
|
|
|
void setDefaultAction(int stick,
|
|
EventMapping map, Event::Type event = Event::NoType,
|
|
EventMode mode = EventMode::kEmulationMode,
|
|
bool updateDefaults = false);
|
|
|
|
/** return event mode for given property */
|
|
static EventMode getMode(const Properties& properties, PropType propType);
|
|
/** return event mode for given controller type */
|
|
static EventMode getMode(Controller::Type type);
|
|
|
|
/** returns the event's controller mode */
|
|
static EventMode getEventMode(Event::Type event, EventMode mode);
|
|
/** Checks event type. */
|
|
static bool isJoystickEvent(Event::Type event);
|
|
static bool isPaddleEvent(Event::Type event);
|
|
static bool isKeyboardEvent(Event::Type event);
|
|
static bool isDrivingEvent(Event::Type event);
|
|
static bool isCommonEvent(Event::Type event);
|
|
|
|
void enableCommonMappings();
|
|
|
|
void enableMappings(const Event::EventSet& events, EventMode mode);
|
|
void enableMapping(Event::Type event, EventMode mode);
|
|
|
|
private:
|
|
EventMode myLeftMode{EventMode::kEmulationMode};
|
|
EventMode myRightMode{EventMode::kEmulationMode};
|
|
// Additional modes for QuadTari controller
|
|
EventMode myLeft2ndMode{EventMode::kEmulationMode};
|
|
EventMode myRight2ndMode{EventMode::kEmulationMode};
|
|
|
|
// Controller menu and common emulation mappings
|
|
static EventMappingArray DefaultMenuMapping;
|
|
static EventMappingArray DefaultCommonMapping;
|
|
// Controller specific mappings
|
|
static EventMappingArray DefaultLeftJoystickMapping;
|
|
static EventMappingArray DefaultRightJoystickMapping;
|
|
static EventMappingArray DefaultLeftPaddlesMapping;
|
|
static EventMappingArray DefaultRightPaddlesMapping;
|
|
static EventMappingArray DefaultLeftAPaddlesMapping;
|
|
static EventMappingArray DefaultLeftBPaddlesMapping;
|
|
static EventMappingArray DefaultRightAPaddlesMapping;
|
|
static EventMappingArray DefaultRightBPaddlesMapping;
|
|
static EventMappingArray DefaultLeftKeyboardMapping;
|
|
static EventMappingArray DefaultRightKeyboardMapping;
|
|
static EventMappingArray DefaultLeftDrivingMapping;
|
|
static EventMappingArray DefaultRightDrivingMapping;
|
|
|
|
static constexpr int NUM_PORTS = 2;
|
|
static constexpr int NUM_SA_AXIS = 2;
|
|
static const Event::Type SA_Axis[NUM_PORTS][NUM_SA_AXIS];
|
|
};
|
|
|
|
#endif
|