flycast/core/sdl/dreamlink.h

166 lines
4.9 KiB
C++

/*
Copyright 2024 flyinghead
This file is part of Flycast.
Flycast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Flycast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
// This file contains abstraction layer for access to different kinds of physical controllers
#include "types.h"
#include "emulator.h"
#include "sdl_gamepad.h"
#include <functional>
#include <memory>
#include <array>
#if (defined(_WIN32) || defined(__linux__) || (defined(__APPLE__) && defined(TARGET_OS_MAC))) && !defined(TARGET_UWP)
#define USE_DREAMCASTCONTROLLER 1
#endif
#include <memory>
struct MapleMsg
{
u8 command = 0;
u8 destAP = 0;
u8 originAP = 0;
u8 size = 0;
u8 data[1024];
u32 getDataSize() const {
return size * 4;
}
template<typename T>
void setData(const T& p) {
memcpy(data, &p, sizeof(T));
this->size = (sizeof(T) + 3) / 4;
}
void setWord(const u32& p, int index) {
if (index < 0 || index >= 256) {
return;
}
memcpy(&data[index * 4], &p, sizeof(u32));
if (this->size <= index) {
this->size = index + 1;
}
}
};
static_assert(sizeof(MapleMsg) == 1028);
// Abstract base class for physical controller implementations
class DreamLink
{
public:
DreamLink() = default;
virtual ~DreamLink() = default;
//! Sends a message to the controller, ignoring the response
//! @note The implementation shall be thread safe
virtual bool send(const MapleMsg& msg) = 0;
//! Sends a message to the controller and waits for a response
//! @note The implementation shall be thread safe
virtual bool send(const MapleMsg& txMsg, MapleMsg& rxMsg) = 0;
//! When called, do teardown stuff like reset screen
virtual inline void gameTermination() {}
//! @param[in] forPort The port number to get the function code of (1 or 2)
//! @return the device type for the given port
virtual u32 getFunctionCode(int forPort) const = 0;
//! @param[in] forPort The port number to get the function definitions of (1 or 2)
//! @return the 3 function definitions for the supported function codes
virtual std::array<u32, 3> getFunctionDefinitions(int forPort) const = 0;
//! @return the default bus number to select for this controller or -1 to not select a default
virtual int getDefaultBus() const {
return -1;
}
//! Allows a DreamLink device to dictate the default mapping
virtual void setDefaultMapping(const std::shared_ptr<InputMapping>& mapping) const {
}
//! Allows button names to be defined by a DreamLink device
//! @param[in] code The button code to retrieve name of
//! @return the button name for the given code to override what is defined by the gamepad
//! @return nullptr to fall back to gamepad definitions
virtual const char *getButtonName(u32 code) const {
return nullptr;
}
//! Allows axis names to be defined by a DreamLink device
//! @param[in] code The axis code to retrieve name of
//! @return the axis name for the given code to override what is defined by the gamepad
//! @return nullptr to fall back to gamepad definitions
virtual const char *getAxisName(u32 code) const {
return nullptr;
}
//! @return a unique ID for this DreamLink device or empty string to use default
virtual std::string getUniqueId() const {
return std::string();
}
//! @return the selected bus number of the controller
virtual int getBus() const = 0;
//! Changes the selected maple port is changed by the user
virtual void changeBus(int newBus) = 0;
//! @return the display name of the controller
virtual std::string getName() const = 0;
//! Attempt connection to the hardware controller
virtual void connect() = 0;
//! Disconnect from the hardware controller
virtual void disconnect() = 0;
};
class DreamLinkGamepad : public SDLGamepad
{
public:
DreamLinkGamepad(int maple_port, int joystick_idx, SDL_Joystick* sdl_joystick);
~DreamLinkGamepad();
void set_maple_port(int port) override;
void registered() override;
static bool isDreamcastController(int deviceIndex);
void resetMappingToDefault(bool arcade, bool gamepad) override;
const char *get_button_name(u32 code) override;
const char *get_axis_name(u32 code) override;
protected:
std::shared_ptr<InputMapping> getDefaultMapping() override;
void setBaseDefaultMapping(const std::shared_ptr<InputMapping>& mapping) const;
private:
static void handleEvent(Event event, void *arg);
std::shared_ptr<DreamLink> dreamlink;
bool ltrigPressed = false;
bool rtrigPressed = false;
bool startPressed = false;
std::string device_guid;
};