diff options
| author | Fernando S <fsahmkow27@gmail.com> | 2021-11-27 11:52:08 +0100 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-27 11:52:08 +0100 | 
| commit | 564f10527745f870621c08bbb5d16badee0ed861 (patch) | |
| tree | e8ac8dee60086facf1837393882865f5df18c95e /src/common | |
| parent | 157985f55616c39c5605168f4e6cf50fd7384320 (diff) | |
| parent | 182cd9004f75df21979d0edd47910fecbd129b63 (diff) | |
Merge pull request #7255 from german77/kraken
Project Kraken: Input rewrite
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/common/input.h | 372 | ||||
| -rw-r--r-- | src/common/settings.h | 12 | ||||
| -rw-r--r-- | src/common/settings_input.h | 65 | 
4 files changed, 420 insertions, 30 deletions
| diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 23d43a394..919da4a53 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -73,6 +73,7 @@ add_library(common STATIC      hex_util.h      host_memory.cpp      host_memory.h +    input.h      intrusive_red_black_tree.h      literals.h      logging/backend.cpp diff --git a/src/common/input.h b/src/common/input.h new file mode 100644 index 000000000..eaee0bdea --- /dev/null +++ b/src/common/input.h @@ -0,0 +1,372 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <functional> +#include <memory> +#include <string> +#include <unordered_map> +#include <utility> +#include "common/logging/log.h" +#include "common/param_package.h" +#include "common/uuid.h" + +namespace Common::Input { + +// Type of data that is expected to recieve or send +enum class InputType { +    None, +    Battery, +    Button, +    Stick, +    Analog, +    Trigger, +    Motion, +    Touch, +    Color, +    Vibration, +    Nfc, +    Ir, +}; + +// 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 +    Pasive, +    // Enable near field communication polling +    NFC, +    // Enable infrared camera polling +    IR, +}; + +// Vibration reply from the controller +enum class VibrationError { +    None, +    NotSupported, +    Disabled, +    Unknown, +}; + +// Polling mode reply from the controller +enum class PollingError { +    None, +    NotSupported, +    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{}; +    // Anyting 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{}; +}; + +// Single analog sensor data +struct AnalogStatus { +    float value{}; +    float raw_value{}; +    AnalogProperties properties{}; +}; + +// Button data +struct ButtonStatus { +    Common::UUID uuid{}; +    bool value{}; +    bool inverted{}; +    bool toggle{}; +    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{}; +}; + +// 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{}; +}; + +// 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, + +    // DS4 button names +    L1, +    L2, +    L3, +    R1, +    R2, +    R3, +    Circle, +    Cross, +    Square, +    Triangle, +    Share, +    Options, +}; + +// 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{}; +}; + +// Triggered once every input change +struct InputCallback { +    std::function<void(CallbackStatus)> on_change; +}; + +/// 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 +    virtual void SoftUpdate() { +        return; +    } + +    // Force input device to update data regardless of the current state +    virtual void ForceUpdate() { +        return; +    } + +    // 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(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 void SetLED([[maybe_unused]] LedStatus led_status) { +        return; +    } + +    virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) { +        return VibrationError::NotSupported; +    } + +    virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) { +        return PollingError::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); +    } +} + +/** + * 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 diff --git a/src/common/settings.h b/src/common/settings.h index fa4aa8747..e4e049f67 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -6,7 +6,6 @@  #include <algorithm>  #include <array> -#include <atomic>  #include <map>  #include <optional>  #include <string> @@ -560,25 +559,19 @@ struct Values {      Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};      Setting<bool> motion_enabled{true, "motion_enabled"}; -    BasicSetting<std::string> motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01", -                                            "motion_device"};      BasicSetting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"}; +    BasicSetting<bool> enable_udp_controller{false, "enable_udp_controller"};      BasicSetting<bool> pause_tas_on_load{true, "pause_tas_on_load"};      BasicSetting<bool> tas_enable{false, "tas_enable"};      BasicSetting<bool> tas_loop{false, "tas_loop"}; -    BasicSetting<bool> tas_swap_controllers{true, "tas_swap_controllers"};      BasicSetting<bool> mouse_panning{false, "mouse_panning"};      BasicRangedSetting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};      BasicSetting<bool> mouse_enabled{false, "mouse_enabled"}; -    std::string mouse_device; -    MouseButtonsRaw mouse_buttons;      BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};      BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"}; -    KeyboardKeysRaw keyboard_keys; -    KeyboardModsRaw keyboard_mods;      BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"};      ButtonsRaw debug_pad_buttons; @@ -586,14 +579,11 @@ struct Values {      TouchscreenInput touchscreen; -    BasicSetting<bool> use_touch_from_button{false, "use_touch_from_button"};      BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850",                                             "touch_device"};      BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"};      std::vector<TouchFromButtonMap> touch_from_button_maps; -    std::atomic_bool is_device_reload_pending{true}; -      // Data Storage      BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"};      BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"}; diff --git a/src/common/settings_input.h b/src/common/settings_input.h index 609600582..9e3df7376 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -62,11 +62,22 @@ enum Values : int {  constexpr int STICK_HID_BEGIN = LStick;  constexpr int STICK_HID_END = NumAnalogs; -constexpr int NUM_STICKS_HID = NumAnalogs;  extern const std::array<const char*, NumAnalogs> mapping;  } // namespace NativeAnalog +namespace NativeTrigger { +enum Values : int { +    LTrigger, +    RTrigger, + +    NumTriggers, +}; + +constexpr int TRIGGER_HID_BEGIN = LTrigger; +constexpr int TRIGGER_HID_END = NumTriggers; +} // namespace NativeTrigger +  namespace NativeVibration {  enum Values : int {      LeftVibrationDevice, @@ -115,10 +126,20 @@ constexpr int NUM_MOUSE_HID = NumMouseButtons;  extern const std::array<const char*, NumMouseButtons> mapping;  } // namespace NativeMouseButton +namespace NativeMouseWheel { +enum Values { +    X, +    Y, + +    NumMouseWheels, +}; + +extern const std::array<const char*, NumMouseWheels> mapping; +} // namespace NativeMouseWheel +  namespace NativeKeyboard {  enum Keys {      None, -    Error,      A = 4,      B, @@ -156,22 +177,22 @@ enum Keys {      N8,      N9,      N0, -    Enter, +    Return,      Escape,      Backspace,      Tab,      Space,      Minus, -    Equal, -    LeftBrace, -    RightBrace, -    Backslash, +    Plus, +    OpenBracket, +    CloseBracket, +    Pipe,      Tilde,      Semicolon, -    Apostrophe, -    Grave, +    Quote, +    Backquote,      Comma, -    Dot, +    Period,      Slash,      CapsLockKey, @@ -188,7 +209,7 @@ enum Keys {      F11,      F12, -    SystemRequest, +    PrintScreen,      ScrollLockKey,      Pause,      Insert, @@ -257,8 +278,18 @@ enum Keys {      ScrollLockActive,      KPComma, -    KPLeftParenthesis, -    KPRightParenthesis, +    Ro = 0x87, +    KatakanaHiragana, +    Yen, +    Henkan, +    Muhenkan, +    NumPadCommaPc98, + +    HangulEnglish = 0x90, +    Hanja, +    KatakanaKey, +    HiraganaKey, +    ZenkakuHankaku,      LeftControlKey = 0xE0,      LeftShiftKey, @@ -307,6 +338,8 @@ enum Modifiers {      CapsLock,      ScrollLock,      NumLock, +    Katakana, +    Hiragana,      NumKeyboardMods,  }; @@ -324,11 +357,6 @@ constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;  using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;  using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;  using MotionsRaw = std::array<std::string, NativeMotion::NumMotions>; -using VibrationsRaw = std::array<std::string, NativeVibration::NumVibrations>; - -using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>; -using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>; -using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;  constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;  constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; @@ -349,7 +377,6 @@ struct PlayerInput {      ControllerType controller_type;      ButtonsRaw buttons;      AnalogsRaw analogs; -    VibrationsRaw vibrations;      MotionsRaw motions;      bool vibration_enabled; | 
