| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 |
- // SPDX-FileCopyrightText: 2017 Citra Emulator Project
- // SPDX-License-Identifier: GPL-2.0-or-later
- #pragma once
- #include <functional>
- #include <memory>
- #include <string>
- #include <unordered_map>
- #include <utility>
- #include <vector>
- #include "common/logging/log.h"
- #include "common/param_package.h"
- #include "common/uuid.h"
- namespace Common::Input {
- // Type of data that is expected to receive or send
- enum class InputType {
- None,
- Battery,
- Button,
- Stick,
- Analog,
- Trigger,
- Motion,
- Touch,
- Color,
- Vibration,
- Nfc,
- IrSensor,
- };
- // Internal battery charge level
- enum class BatteryLevel : u32 {
- None,
- Empty,
- Critical,
- Low,
- Medium,
- Full,
- Charging,
- };
- enum class PollingMode {
- // Constant polling of buttons, analogs and motion data
- Active,
- // Only update on button change, digital analogs
- Passive,
- // Enable near field communication polling
- NFC,
- // Enable infrared camera polling
- IR,
- // Enable ring controller polling
- Ring,
- };
- enum class CameraFormat {
- Size320x240,
- Size160x120,
- Size80x60,
- Size40x30,
- Size20x15,
- None,
- };
- // Different results that can happen from a device request
- enum class DriverResult {
- Success,
- WrongReply,
- Timeout,
- UnsupportedControllerType,
- HandleInUse,
- ErrorReadingData,
- ErrorWritingData,
- NoDeviceDetected,
- InvalidHandle,
- NotSupported,
- Disabled,
- Unknown,
- };
- // Nfc reply from the controller
- enum class NfcState {
- Success,
- NewAmiibo,
- WaitingForAmiibo,
- AmiiboRemoved,
- NotAnAmiibo,
- NotSupported,
- WrongDeviceState,
- WriteFailed,
- Unknown,
- };
- // Hint for amplification curve to be used
- enum class VibrationAmplificationType {
- Linear,
- Exponential,
- };
- // Analog properties for calibration
- struct AnalogProperties {
- // Anything below this value will be detected as zero
- float deadzone{};
- // Anything above this values will be detected as one
- float range{1.0f};
- // Minimum value to be detected as active
- float threshold{0.5f};
- // Drift correction applied to the raw data
- float offset{};
- // Invert direction of the sensor data
- bool inverted{};
- // Invert the state if it's converted to a button
- bool inverted_button{};
- // Press once to activate, press again to release
- bool toggle{};
- };
- // Single analog sensor data
- struct AnalogStatus {
- float value{};
- float raw_value{};
- AnalogProperties properties{};
- };
- // Button data
- struct ButtonStatus {
- Common::UUID uuid{};
- bool value{};
- // Invert value of the button
- bool inverted{};
- // Press once to activate, press again to release
- bool toggle{};
- // Spams the button when active
- bool turbo{};
- // Internal lock for the toggle status
- bool locked{};
- };
- // Internal battery data
- using BatteryStatus = BatteryLevel;
- // Analog and digital joystick data
- struct StickStatus {
- Common::UUID uuid{};
- AnalogStatus x{};
- AnalogStatus y{};
- bool left{};
- bool right{};
- bool up{};
- bool down{};
- };
- // Analog and digital trigger data
- struct TriggerStatus {
- Common::UUID uuid{};
- AnalogStatus analog{};
- ButtonStatus pressed{};
- };
- // 3D vector representing motion input
- struct MotionSensor {
- AnalogStatus x{};
- AnalogStatus y{};
- AnalogStatus z{};
- };
- // Motion data used to calculate controller orientation
- 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{};
- };
- // Data of a single point on a touch screen
- struct TouchStatus {
- ButtonStatus pressed{};
- AnalogStatus x{};
- AnalogStatus y{};
- int id{};
- };
- // Physical controller color in RGB format
- struct BodyColorStatus {
- u32 body{};
- u32 buttons{};
- u32 left_grip{};
- u32 right_grip{};
- };
- // HD rumble data
- struct VibrationStatus {
- f32 low_amplitude{};
- f32 low_frequency{};
- f32 high_amplitude{};
- f32 high_frequency{};
- VibrationAmplificationType type;
- };
- // Physical controller LED pattern
- struct LedStatus {
- bool led_1{};
- bool led_2{};
- bool led_3{};
- bool led_4{};
- };
- // Raw data from camera
- struct CameraStatus {
- CameraFormat format{CameraFormat::None};
- std::vector<u8> data{};
- };
- struct NfcStatus {
- NfcState state{};
- std::vector<u8> data{};
- };
- // 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,
- // Joycon button names
- ButtonLeft,
- ButtonRight,
- ButtonDown,
- ButtonUp,
- ButtonA,
- ButtonB,
- ButtonX,
- ButtonY,
- ButtonPlus,
- ButtonMinus,
- ButtonHome,
- ButtonCapture,
- ButtonStickL,
- ButtonStickR,
- TriggerL,
- TriggerZL,
- TriggerSL,
- TriggerR,
- TriggerZR,
- TriggerSR,
- // GC button names
- TriggerZ,
- ButtonStart,
- // DS4 button names
- L1,
- L2,
- L3,
- R1,
- R2,
- R3,
- Circle,
- Cross,
- Square,
- Triangle,
- Share,
- Options,
- Home,
- Touch,
- // Mouse buttons
- ButtonMouseWheel,
- ButtonBackward,
- ButtonForward,
- ButtonTask,
- ButtonExtra,
- };
- // Callback data consisting of an input type and the equivalent data status
- 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{};
- CameraFormat camera_status{CameraFormat::None};
- NfcState nfc_status{NfcState::Unknown};
- std::vector<u8> raw_data{};
- };
- // Triggered once every input change
- struct InputCallback {
- std::function<void(const CallbackStatus&)> on_change;
- };
- /// An abstract class template for an input device (a button, an analog input, etc.).
- class InputDevice {
- public:
- virtual ~InputDevice() = default;
- // Force input device to update data regardless of the current state
- virtual void ForceUpdate() {}
- // Sets the function to be triggered when input changes
- void SetCallback(InputCallback callback_) {
- callback = std::move(callback_);
- }
- // Triggers the function set in the callback
- void TriggerOnChange(const CallbackStatus& status) {
- 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;
- virtual DriverResult SetLED([[maybe_unused]] const LedStatus& led_status) {
- return DriverResult::NotSupported;
- }
- virtual DriverResult SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) {
- return DriverResult::NotSupported;
- }
- virtual bool IsVibrationEnabled() {
- return false;
- }
- virtual DriverResult SetPollingMode([[maybe_unused]] PollingMode polling_mode) {
- return DriverResult::NotSupported;
- }
- virtual DriverResult SetCameraFormat([[maybe_unused]] CameraFormat camera_format) {
- return DriverResult::NotSupported;
- }
- virtual NfcState SupportsNfc() const {
- return NfcState::NotSupported;
- }
- virtual NfcState WriteNfcData([[maybe_unused]] const std::vector<u8>& data) {
- return NfcState::NotSupported;
- }
- };
- /// 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);
- }
- }
- inline void RegisterInputFactory(const std::string& name,
- std::shared_ptr<Factory<InputDevice>> factory) {
- RegisterFactory<InputDevice>(name, std::move(factory));
- }
- inline void RegisterOutputFactory(const std::string& name,
- std::shared_ptr<Factory<OutputDevice>> factory) {
- RegisterFactory<OutputDevice>(name, std::move(factory));
- }
- /**
- * 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);
- }
- }
- inline void UnregisterInputFactory(const std::string& name) {
- UnregisterFactory<InputDevice>(name);
- }
- inline void UnregisterOutputFactory(const std::string& name) {
- UnregisterFactory<OutputDevice>(name);
- }
- /**
- * Create an input device from given parameters.
- * @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);
- }
- inline std::unique_ptr<InputDevice> CreateInputDeviceFromString(const std::string& params) {
- return CreateDeviceFromString<InputDevice>(params);
- }
- inline std::unique_ptr<OutputDevice> CreateOutputDeviceFromString(const std::string& params) {
- return CreateDeviceFromString<OutputDevice>(params);
- }
- /**
- * Create an input device from given parameters.
- * @tparam InputDeviceType the type of input devices to create
- * @param package A ParamPackage that contains all parameters for creating the device
- */
- template <typename InputDeviceType>
- std::unique_ptr<InputDeviceType> CreateDevice(const 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);
- }
- inline std::unique_ptr<InputDevice> CreateInputDevice(const ParamPackage& package) {
- return CreateDevice<InputDevice>(package);
- }
- inline std::unique_ptr<OutputDevice> CreateOutputDevice(const ParamPackage& package) {
- return CreateDevice<OutputDevice>(package);
- }
- } // namespace Common::Input
|