diff options
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; |