pineapple/src/common/input.h

435 lines
10 KiB
C
Raw Normal View History

2022-07-27 20:06:50 +02:00
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
2021-11-02 05:02:57 +01:00
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include "common/logging/log.h"
#include "common/param_package.h"
2021-11-03 13:04:28 +01:00
#include "common/uuid.h"
2021-11-02 05:02:57 +01:00
namespace Common::Input {
2021-11-04 16:14:42 +01:00
// Type of data that is expected to recieve or send
2021-11-02 05:02:57 +01:00
enum class InputType {
None,
Battery,
Button,
Stick,
Analog,
Trigger,
Motion,
Touch,
Color,
Vibration,
Nfc,
2022-07-25 19:06:59 +02:00
IrSensor,
2021-11-02 05:02:57 +01:00
};
2021-11-04 16:14:42 +01:00
// Internal battery charge level
2021-11-02 05:02:57 +01:00
enum class BatteryLevel : u32 {
None,
Empty,
Critical,
Low,
Medium,
Full,
Charging,
};
enum class PollingMode {
2021-11-04 16:14:42 +01:00
// Constant polling of buttons, analogs and motion data
2021-11-02 05:02:57 +01:00
Active,
2021-11-04 16:14:42 +01:00
// Only update on button change, digital analogs
2021-11-02 05:02:57 +01:00
Pasive,
2021-11-04 16:14:42 +01:00
// Enable near field communication polling
NFC,
// Enable infrared camera polling
2021-11-02 05:02:57 +01:00
IR,
};
2022-07-25 19:06:59 +02:00
enum class CameraFormat {
Size320x240,
Size160x120,
Size80x60,
Size40x30,
Size20x15,
None,
};
2021-11-04 16:14:42 +01:00
// Vibration reply from the controller
2021-11-02 05:02:57 +01:00
enum class VibrationError {
None,
NotSupported,
Disabled,
Unknown,
};
2021-11-04 16:14:42 +01:00
// Polling mode reply from the controller
2021-11-02 05:02:57 +01:00
enum class PollingError {
None,
NotSupported,
Unknown,
};
2022-10-01 02:41:15 +02:00
// Nfc reply from the controller
enum class NfcState {
Success,
NewAmiibo,
WaitingForAmiibo,
AmiiboRemoved,
NotAnAmiibo,
NotSupported,
WrongDeviceState,
WriteFailed,
Unknown,
};
2022-07-25 19:06:59 +02:00
// Ir camera reply from the controller
enum class CameraError {
None,
NotSupported,
Unknown,
};
2021-11-02 05:02:57 +01:00
// Hint for amplification curve to be used
enum class VibrationAmplificationType {
Linear,
Exponential,
2022-05-25 04:31:11 +02:00
Test,
2021-11-02 05:02:57 +01:00
};
2021-11-04 16:14:42 +01:00
// Analog properties for calibration
2021-11-02 05:02:57 +01:00
struct AnalogProperties {
2021-11-04 16:14:42 +01:00
// Anything below this value will be detected as zero
2021-11-02 05:02:57 +01:00
float deadzone{};
2021-11-04 16:14:42 +01:00
// Anyting above this values will be detected as one
2021-11-02 05:02:57 +01:00
float range{1.0f};
2021-11-04 16:14:42 +01:00
// Minimum value to be detected as active
2021-11-02 05:02:57 +01:00
float threshold{0.5f};
2021-11-04 16:14:42 +01:00
// Drift correction applied to the raw data
2021-11-02 05:02:57 +01:00
float offset{};
2021-11-04 16:14:42 +01:00
// Invert direction of the sensor data
2021-11-02 05:02:57 +01:00
bool inverted{};
2022-09-10 09:57:15 +02:00
// Press once to activate, press again to release
bool toggle{};
2021-11-02 05:02:57 +01:00
};
2021-11-04 16:14:42 +01:00
// Single analog sensor data
2021-11-02 05:02:57 +01:00
struct AnalogStatus {
float value{};
float raw_value{};
AnalogProperties properties{};
};
2021-11-04 16:14:42 +01:00
// Button data
2021-11-02 05:02:57 +01:00
struct ButtonStatus {
2021-11-03 13:04:28 +01:00
Common::UUID uuid{};
2021-11-02 05:02:57 +01:00
bool value{};
2022-09-10 09:57:15 +02:00
// Invert value of the button
2021-11-02 05:02:57 +01:00
bool inverted{};
2022-09-10 09:57:15 +02:00
// Press once to activate, press again to release
2021-11-02 05:02:57 +01:00
bool toggle{};
2022-09-10 09:57:15 +02:00
// Internal lock for the toggle status
2021-11-02 05:02:57 +01:00
bool locked{};
};
2021-11-04 16:14:42 +01:00
// Internal battery data
2021-11-02 05:02:57 +01:00
using BatteryStatus = BatteryLevel;
2021-11-04 16:14:42 +01:00
// Analog and digital joystick data
2021-11-02 05:02:57 +01:00
struct StickStatus {
2021-11-03 13:04:28 +01:00
Common::UUID uuid{};
2021-11-02 05:02:57 +01:00
AnalogStatus x{};
AnalogStatus y{};
bool left{};
bool right{};
bool up{};
bool down{};
};
2021-11-04 16:14:42 +01:00
// Analog and digital trigger data
2021-11-02 05:02:57 +01:00
struct TriggerStatus {
2021-11-03 13:04:28 +01:00
Common::UUID uuid{};
2021-11-02 05:02:57 +01:00
AnalogStatus analog{};
ButtonStatus pressed{};
};
2021-11-04 16:14:42 +01:00
// 3D vector representing motion input
2021-11-02 05:02:57 +01:00
struct MotionSensor {
AnalogStatus x{};
AnalogStatus y{};
AnalogStatus z{};
};
2021-11-04 16:14:42 +01:00
// Motion data used to calculate controller orientation
2021-11-02 05:02:57 +01:00
struct MotionStatus {
// Gyroscope vector measurement in radians/s.
MotionSensor gyro{};
// Acceleration vector measurement in G force
MotionSensor accel{};
// Time since last measurement in microseconds
u64 delta_timestamp{};
// Request to update after reading the value
bool force_update{};
};
2021-11-04 16:14:42 +01:00
// Data of a single point on a touch screen
2021-11-02 05:02:57 +01:00
struct TouchStatus {
ButtonStatus pressed{};
AnalogStatus x{};
AnalogStatus y{};
int id{};
};
2021-11-04 16:14:42 +01:00
// Physical controller color in RGB format
2021-11-02 05:02:57 +01:00
struct BodyColorStatus {
u32 body{};
u32 buttons{};
};
2021-11-04 16:14:42 +01:00
// HD rumble data
2021-11-02 05:02:57 +01:00
struct VibrationStatus {
f32 low_amplitude{};
f32 low_frequency{};
f32 high_amplitude{};
f32 high_frequency{};
VibrationAmplificationType type;
};
2021-11-04 16:14:42 +01:00
// Physical controller LED pattern
2021-11-02 05:02:57 +01:00
struct LedStatus {
bool led_1{};
bool led_2{};
bool led_3{};
bool led_4{};
};
2022-07-25 19:06:59 +02:00
// Raw data fom camera
struct CameraStatus {
CameraFormat format{CameraFormat::None};
std::vector<u8> data{};
};
2022-10-01 02:41:15 +02:00
struct NfcStatus {
NfcState state{};
std::vector<u8> data{};
};
2021-11-21 22:14:21 +01:00
// List of buttons to be passed to Qt that can be translated
enum class ButtonNames {
Undefined,
Invalid,
// This will display the engine name instead of the button name
Engine,
// This will display the button by value instead of the button name
Value,
ButtonLeft,
ButtonRight,
ButtonDown,
ButtonUp,
TriggerZ,
TriggerR,
TriggerL,
ButtonA,
ButtonB,
ButtonX,
ButtonY,
ButtonStart,
2021-11-27 00:35:19 +01:00
// DS4 button names
L1,
L2,
L3,
R1,
R2,
R3,
Circle,
Cross,
Square,
Triangle,
Share,
Options,
2022-02-02 08:05:26 +01:00
Home,
Touch,
2022-01-19 04:17:57 +01:00
// Mouse buttons
ButtonMouseWheel,
ButtonBackward,
ButtonForward,
ButtonTask,
ButtonExtra,
2021-11-21 22:14:21 +01:00
};
2021-11-04 16:14:42 +01:00
// Callback data consisting of an input type and the equivalent data status
2021-11-02 05:02:57 +01:00
struct CallbackStatus {
InputType type{InputType::None};
ButtonStatus button_status{};
StickStatus stick_status{};
AnalogStatus analog_status{};
TriggerStatus trigger_status{};
MotionStatus motion_status{};
TouchStatus touch_status{};
BodyColorStatus color_status{};
BatteryStatus battery_status{};
VibrationStatus vibration_status{};
2022-07-25 19:06:59 +02:00
CameraStatus camera_status{};
2022-10-01 02:41:15 +02:00
NfcStatus nfc_status{};
2021-11-02 05:02:57 +01:00
};
2021-11-04 16:14:42 +01:00
// Triggered once every input change
2021-11-02 05:02:57 +01:00
struct InputCallback {
2021-12-15 05:46:01 +01:00
std::function<void(const CallbackStatus&)> on_change;
2021-11-02 05:02:57 +01:00
};
/// An abstract class template for an input device (a button, an analog input, etc.).
class InputDevice {
public:
virtual ~InputDevice() = default;
// Request input device to update if necessary
2021-12-15 05:46:01 +01:00
virtual void SoftUpdate() {}
2021-11-02 05:02:57 +01:00
2021-11-04 16:14:42 +01:00
// Force input device to update data regardless of the current state
2021-12-15 05:46:01 +01:00
virtual void ForceUpdate() {}
2021-11-02 05:02:57 +01:00
2021-11-04 16:14:42 +01:00
// Sets the function to be triggered when input changes
2021-11-02 05:02:57 +01:00
void SetCallback(InputCallback callback_) {
callback = std::move(callback_);
}
2021-11-04 16:14:42 +01:00
// Triggers the function set in the callback
2021-12-15 05:46:01 +01:00
void TriggerOnChange(const CallbackStatus& status) {
2021-11-02 05:02:57 +01:00
if (callback.on_change) {
callback.on_change(status);
}
}
private:
InputCallback callback;
};
/// An abstract class template for an output device (rumble, LED pattern, polling mode).
class OutputDevice {
public:
virtual ~OutputDevice() = default;
2021-12-15 05:46:01 +01:00
virtual void SetLED([[maybe_unused]] const LedStatus& led_status) {}
2021-11-02 05:02:57 +01:00
2021-12-15 05:46:01 +01:00
virtual VibrationError SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) {
2021-11-02 05:02:57 +01:00
return VibrationError::NotSupported;
}
virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) {
return PollingError::NotSupported;
}
2022-07-25 19:06:59 +02:00
virtual CameraError SetCameraFormat([[maybe_unused]] CameraFormat camera_format) {
return CameraError::NotSupported;
}
2022-10-01 02:41:15 +02:00
virtual NfcState SupportsNfc() const {
return NfcState::NotSupported;
}
virtual NfcState WriteNfcData([[maybe_unused]] const std::vector<u8>& data) {
return NfcState::NotSupported;
}
2021-11-02 05:02:57 +01:00
};
/// An abstract class template for a factory that can create input devices.
template <typename InputDeviceType>
class Factory {
public:
virtual ~Factory() = default;
virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0;
};
namespace Impl {
template <typename InputDeviceType>
using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>;
template <typename InputDeviceType>
struct FactoryList {
static FactoryListType<InputDeviceType> list;
};
template <typename InputDeviceType>
FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list;
} // namespace Impl
/**
* Registers an input device factory.
* @tparam InputDeviceType the type of input devices the factory can create
* @param name the name of the factory. Will be used to match the "engine" parameter when creating
* a device
* @param factory the factory object to register
*/
template <typename InputDeviceType>
void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
auto pair = std::make_pair(name, std::move(factory));
if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
LOG_ERROR(Input, "Factory '{}' already registered", name);
}
}
/**
* Unregisters an input device factory.
* @tparam InputDeviceType the type of input devices the factory can create
* @param name the name of the factory to unregister
*/
template <typename InputDeviceType>
void UnregisterFactory(const std::string& name) {
if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
LOG_ERROR(Input, "Factory '{}' not registered", name);
}
}
/**
* Create an input device from given paramters.
* @tparam InputDeviceType the type of input devices to create
* @param params a serialized ParamPackage string that contains all parameters for creating the
* device
*/
template <typename InputDeviceType>
std::unique_ptr<InputDeviceType> CreateDeviceFromString(const std::string& params) {
const Common::ParamPackage package(params);
const std::string engine = package.Get("engine", "null");
const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
const auto pair = factory_list.find(engine);
if (pair == factory_list.end()) {
if (engine != "null") {
LOG_ERROR(Input, "Unknown engine name: {}", engine);
}
return std::make_unique<InputDeviceType>();
}
return pair->second->Create(package);
}
/**
* Create an input device from given paramters.
* @tparam InputDeviceType the type of input devices to create
* @param A ParamPackage that contains all parameters for creating the device
*/
template <typename InputDeviceType>
std::unique_ptr<InputDeviceType> CreateDevice(const Common::ParamPackage package) {
const std::string engine = package.Get("engine", "null");
const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
const auto pair = factory_list.find(engine);
if (pair == factory_list.end()) {
if (engine != "null") {
LOG_ERROR(Input, "Unknown engine name: {}", engine);
}
return std::make_unique<InputDeviceType>();
}
return pair->second->Create(package);
}
} // namespace Common::Input