diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 5571f7efb..868a3c9e2 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -45,7 +45,8 @@ static const std::array defaults = { SDL_SCANCODE_L, // indirectly mapped keys - SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT}; + SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, +}; void Config::ReadValues() { // Controls diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp index bde4fef32..e4d4c60fa 100644 --- a/src/citra/emu_window/emu_window_sdl2.cpp +++ b/src/citra/emu_window/emu_window_sdl2.cpp @@ -8,6 +8,7 @@ #define SDL_MAIN_HANDLED #include #include +#include "citra/emu_window/emu_window_sdl2.h" #include "common/logging/log.h" #include "common/scm_rev.h" @@ -18,8 +19,6 @@ #include "input_core/input_core.h" #include "video_core/video_core.h" -#include "citra/emu_window/emu_window_sdl2.h" - void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); motion_emu->Tilt(x, y); diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index ae0263d7a..27bc998a1 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -14,10 +14,8 @@ #include "common/string_util.h" #include "core/core.h" #include "core/settings.h" - #include "input_core/devices/keyboard.h" #include "input_core/input_core.h" - #include "video_core/debug_utils/debug_utils.h" #include "video_core/video_core.h" diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 61d44379d..8164ed439 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -23,7 +23,8 @@ const std::array Config::defaults = Qt::Key_K, Qt::Key_J, Qt::Key_L, // indirectly mapped keys - Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right}; + Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right, +}; const QVariant Config::default_circle_pad_modifier = Qt::Key_F; diff --git a/src/citra_qt/configure_input.cpp b/src/citra_qt/configure_input.cpp index e3dc6d1d7..fe1e5f714 100644 --- a/src/citra_qt/configure_input.cpp +++ b/src/citra_qt/configure_input.cpp @@ -8,7 +8,6 @@ #include "citra_qt/configure_input.h" #include "citra_qt/keybinding_names.h" #include "common/string_util.h" - #include "input_core/devices/keyboard.h" #include "input_core/input_core.h" @@ -19,29 +18,30 @@ ConfigureInput::ConfigureInput(QWidget* parent) // Initialize mapping of input enum to UI button. button_map = { - {std::make_pair(Settings::NativeInput::Values::A, ui->buttonA)}, - {std::make_pair(Settings::NativeInput::Values::B, ui->buttonB)}, - {std::make_pair(Settings::NativeInput::Values::X, ui->buttonX)}, - {std::make_pair(Settings::NativeInput::Values::Y, ui->buttonY)}, - {std::make_pair(Settings::NativeInput::Values::L, ui->buttonL)}, - {std::make_pair(Settings::NativeInput::Values::R, ui->buttonR)}, - {std::make_pair(Settings::NativeInput::Values::ZL, ui->buttonZL)}, - {std::make_pair(Settings::NativeInput::Values::ZR, ui->buttonZR)}, - {std::make_pair(Settings::NativeInput::Values::START, ui->buttonStart)}, - {std::make_pair(Settings::NativeInput::Values::SELECT, ui->buttonSelect)}, - {std::make_pair(Settings::NativeInput::Values::HOME, ui->buttonHome)}, - {std::make_pair(Settings::NativeInput::Values::DUP, ui->buttonDpadUp)}, - {std::make_pair(Settings::NativeInput::Values::DDOWN, ui->buttonDpadDown)}, - {std::make_pair(Settings::NativeInput::Values::DLEFT, ui->buttonDpadLeft)}, - {std::make_pair(Settings::NativeInput::Values::DRIGHT, ui->buttonDpadRight)}, - {std::make_pair(Settings::NativeInput::Values::CUP, ui->buttonCStickUp)}, - {std::make_pair(Settings::NativeInput::Values::CDOWN, ui->buttonCStickDown)}, - {std::make_pair(Settings::NativeInput::Values::CLEFT, ui->buttonCStickLeft)}, - {std::make_pair(Settings::NativeInput::Values::CRIGHT, ui->buttonCStickRight)}, - {std::make_pair(Settings::NativeInput::Values::CIRCLE_UP, ui->buttonCircleUp)}, - {std::make_pair(Settings::NativeInput::Values::CIRCLE_DOWN, ui->buttonCircleDown)}, - {std::make_pair(Settings::NativeInput::Values::CIRCLE_LEFT, ui->buttonCircleLeft)}, - {std::make_pair(Settings::NativeInput::Values::CIRCLE_RIGHT, ui->buttonCircleRight)}}; + {Settings::NativeInput::Values::A, ui->buttonA}, + {Settings::NativeInput::Values::B, ui->buttonB}, + {Settings::NativeInput::Values::X, ui->buttonX}, + {Settings::NativeInput::Values::Y, ui->buttonY}, + {Settings::NativeInput::Values::L, ui->buttonL}, + {Settings::NativeInput::Values::R, ui->buttonR}, + {Settings::NativeInput::Values::ZL, ui->buttonZL}, + {Settings::NativeInput::Values::ZR, ui->buttonZR}, + {Settings::NativeInput::Values::START, ui->buttonStart}, + {Settings::NativeInput::Values::SELECT, ui->buttonSelect}, + {Settings::NativeInput::Values::HOME, ui->buttonHome}, + {Settings::NativeInput::Values::DUP, ui->buttonDpadUp}, + {Settings::NativeInput::Values::DDOWN, ui->buttonDpadDown}, + {Settings::NativeInput::Values::DLEFT, ui->buttonDpadLeft}, + {Settings::NativeInput::Values::DRIGHT, ui->buttonDpadRight}, + {Settings::NativeInput::Values::CUP, ui->buttonCStickUp}, + {Settings::NativeInput::Values::CDOWN, ui->buttonCStickDown}, + {Settings::NativeInput::Values::CLEFT, ui->buttonCStickLeft}, + {Settings::NativeInput::Values::CRIGHT, ui->buttonCStickRight}, + {Settings::NativeInput::Values::CIRCLE_UP, ui->buttonCircleUp}, + {Settings::NativeInput::Values::CIRCLE_DOWN, ui->buttonCircleDown}, + {Settings::NativeInput::Values::CIRCLE_LEFT, ui->buttonCircleLeft}, + {Settings::NativeInput::Values::CIRCLE_RIGHT, ui->buttonCircleRight}, + }; // Attach handle click method to each button click. for (const auto& entry : button_map) { diff --git a/src/input_core/devices/device.cpp b/src/input_core/devices/device.cpp index 06245b22b..669b34204 100644 --- a/src/input_core/devices/device.cpp +++ b/src/input_core/devices/device.cpp @@ -4,4 +4,4 @@ #include "input_core/devices/device.h" -IDevice::~IDevice() = default; +InputDeviceInterface::~InputDeviceInterface() = default; diff --git a/src/input_core/devices/device.h b/src/input_core/devices/device.h index 5928cc1f4..f34d92cef 100644 --- a/src/input_core/devices/device.h +++ b/src/input_core/devices/device.h @@ -10,12 +10,13 @@ #include "core/settings.h" #include "input_core/key_map.h" -class IDevice { +class InputDeviceInterface { public: - virtual ~IDevice(); + virtual ~InputDeviceInterface(); /** - * Initialize IDevice object with device's index and the map of keys that it will listen to. + * Initialize InputDeviceInterface object with device's index and the map of keys that it will + * listen to. * @param number: device number as ordered connected to computer. * @param keymap: vector of PadStates for device to listen for * @return true if successful diff --git a/src/input_core/devices/keyboard.h b/src/input_core/devices/keyboard.h index 6cdb62c84..052ca2401 100644 --- a/src/input_core/devices/keyboard.h +++ b/src/input_core/devices/keyboard.h @@ -27,7 +27,7 @@ struct KeyboardKey { return key < other.key; } }; -class Keyboard : public IDevice { +class Keyboard : public InputDeviceInterface { public: Keyboard(); ~Keyboard(); diff --git a/src/input_core/devices/sdl_gamepad.cpp b/src/input_core/devices/sdl_gamepad.cpp index 7e02ea5fc..dfac21e4c 100644 --- a/src/input_core/devices/sdl_gamepad.cpp +++ b/src/input_core/devices/sdl_gamepad.cpp @@ -10,7 +10,6 @@ #include "common/assert.h" #include "common/logging/log.h" #include "common/string_util.h" - #include "input_core/devices/gamecontrollerdb.h" #include "input_core/devices/sdl_gamepad.h" @@ -82,8 +81,8 @@ bool SDLGamepad::CloseDevice() { return true; } -std::vector> SDLGamepad::GetAllDevices() { - std::vector> devices; +std::vector> SDLGamepad::GetAllDevices() { + std::vector> devices; for (int i = 0; i < 8; i++) { auto gamepad = std::make_shared(); bool success = gamepad->InitDevice( diff --git a/src/input_core/devices/sdl_gamepad.h b/src/input_core/devices/sdl_gamepad.h index ab02602d2..68364b711 100644 --- a/src/input_core/devices/sdl_gamepad.h +++ b/src/input_core/devices/sdl_gamepad.h @@ -7,7 +7,7 @@ #include "input_core/devices/device.h" struct _SDL_GameController; -class SDLGamepad : public IDevice { +class SDLGamepad : public InputDeviceInterface { public: SDLGamepad(); SDLGamepad(int number_, _SDL_GameController* gamepad_); @@ -20,7 +20,7 @@ public: void Clear() override; /// Returns vector of all gamepads connected to computer. Used for keybinding setup - static std::vector> GetAllDevices(); + static std::vector> GetAllDevices(); enum class GamepadInputs { ButtonA, ButtonB, diff --git a/src/input_core/input_core.cpp b/src/input_core/input_core.cpp index 77482240e..62054a32a 100644 --- a/src/input_core/input_core.cpp +++ b/src/input_core/input_core.cpp @@ -9,54 +9,49 @@ #include "core/core_timing.h" #include "core/hw/gpu.h" - #include "input_core/devices/keyboard.h" #include "input_core/devices/sdl_gamepad.h" #include "input_core/input_core.h" -int InputCore::tick_event; -Service::HID::PadState InputCore::pad_state; -std::tuple InputCore::circle_pad; -std::shared_ptr InputCore::main_keyboard; -std::vector> - InputCore::devices; ///< Devices that are handling input for the game -std::map> InputCore::key_mappings; -std::map - InputCore::keys_pressed; ///< keys that were pressed on previous frame. -std::mutex InputCore::pad_state_mutex; -std::mutex InputCore::touch_mutex; -u16 InputCore::touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) -u16 InputCore::touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) -bool InputCore::touch_pressed; ///< True if touchpad area is currently pressed, otherwise false -const float InputCore::input_detect_threshold = +int tick_event; +Service::HID::PadState pad_state; +std::tuple circle_pad; +std::shared_ptr main_keyboard; +std::vector> + devices; ///< Devices that are handling input for the game +std::map> key_mappings; +std::map keys_pressed; ///< keys that were pressed on previous frame. +std::mutex pad_state_mutex; +std::mutex touch_mutex; +u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) +u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) +bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false +const float input_detect_threshold = 0.45; ///< Applies to analog controls being used for digital 3ds inputs. -void InputCore::Init() { - ParseSettings(); - tick_event = CoreTiming::RegisterEvent("InputCore::tick_event", InputTickCallback); - CoreTiming::ScheduleEvent(GPU::frame_ticks, tick_event); -} - -void InputCore::Shutdown() { - CoreTiming::UnscheduleEvent(tick_event, 0); - devices.clear(); -} - -void InputCore::InputTickCallback(u64, int cycles_late) { - std::vector> inputs; - for (auto& device : devices) { - inputs.push_back(device->ProcessInput()); +/** +* Takes two floats and the deadzone and applies formula to +* correct the stick position. +*/ +std::tuple ApplyDeadzone(float x, float y, float dead_zone) { + float magnitude = std::sqrt((x * x) + (y * y)); + if (magnitude < dead_zone) { + x = 0; + y = 0; + } else { + float normalized_x = x / magnitude; + float normalized_y = y / magnitude; + x = normalized_x * ((magnitude - dead_zone) / (1 - dead_zone)); + y = normalized_y * ((magnitude - dead_zone) / (1 - dead_zone)); } - UpdateEmulatorInputs(inputs); - - Service::HID::Update(); - - // Reschedule recurrent event - CoreTiming::ScheduleEvent(GPU::frame_ticks - cycles_late, tick_event); + return std::tuple(x, y); } -void InputCore::UpdateEmulatorInputs( - std::vector> inputs) { +/** +* Loops through all unique input devices, and all bound inputs to update the emulator's input +* status. +*/ +void UpdateEmulatorInputs(std::vector> inputs) { std::lock_guard lock(pad_state_mutex); // Apply deadzone for circle pad @@ -149,14 +144,16 @@ void InputCore::SetTouchState(std::tuple value) { std::tie(touch_x, touch_y, touch_pressed) = value; } -bool InputCore::CheckIfMappingExists(const std::set& unique_mapping, - Settings::InputDeviceMapping mapping_to_check) { +/// Helper method to check if device was already initialized +bool CheckIfMappingExists(const std::set& unique_mapping, + Settings::InputDeviceMapping mapping_to_check) { return std::any_of( unique_mapping.begin(), unique_mapping.end(), [mapping_to_check](const auto& mapping) { return mapping == mapping_to_check; }); } -std::set InputCore::GatherUniqueMappings() { +/// Get unique input mappings from settings +std::set GatherUniqueMappings() { std::set unique_mappings; for (const auto& mapping : Settings::values.input_mappings) { @@ -170,7 +167,8 @@ std::set InputCore::GatherUniqueMappings() { return unique_mappings; } -void InputCore::BuildKeyMapping() { +/// Builds map of input keys to 3ds buttons for unique device +void BuildKeyMapping() { key_mappings.clear(); for (size_t i = 0; i < Settings::values.input_mappings.size(); i++) { auto key = Settings::values.input_mappings[i]; @@ -180,10 +178,11 @@ void InputCore::BuildKeyMapping() { } } -void InputCore::GenerateUniqueDevices() { +/// Generate a device for each unique mapping +void GenerateUniqueDevices() { auto uniqueMappings = GatherUniqueMappings(); devices.clear(); - std::shared_ptr input; + std::shared_ptr input; for (const auto& mapping : uniqueMappings) { switch (mapping.framework) { case Settings::DeviceFramework::SDL: { @@ -202,25 +201,12 @@ void InputCore::GenerateUniqueDevices() { } } -void InputCore::ParseSettings() { +/// Read settings to initialize devices +void ParseSettings() { GenerateUniqueDevices(); BuildKeyMapping(); } -std::tuple InputCore::ApplyDeadzone(float x, float y, float dead_zone) { - float magnitude = std::sqrt((x * x) + (y * y)); - if (magnitude < dead_zone) { - x = 0; - y = 0; - } else { - float normalized_x = x / magnitude; - float normalized_y = y / magnitude; - x = normalized_x * ((magnitude - dead_zone) / (1 - dead_zone)); - y = normalized_y * ((magnitude - dead_zone) / (1 - dead_zone)); - } - return std::tuple(x, y); -} - void InputCore::ReloadSettings() { if (devices.empty()) return; @@ -229,7 +215,7 @@ void InputCore::ReloadSettings() { ParseSettings(); } -std::vector> InputCore::GetAllDevices() { +std::vector> InputCore::GetAllDevices() { auto all_devices = SDLGamepad::GetAllDevices(); auto keyboard = InputCore::GetKeyboard(); all_devices.push_back(keyboard); @@ -261,3 +247,27 @@ Settings::InputDeviceMapping InputCore::DetectInput(int max_time, }; return input_device; } + +void InputTickCallback(u64, int cycles_late) { + std::vector> inputs; + for (auto& device : devices) { + inputs.push_back(device->ProcessInput()); + } + UpdateEmulatorInputs(inputs); + + Service::HID::Update(); + + // Reschedule recurrent event + CoreTiming::ScheduleEvent(GPU::frame_ticks - cycles_late, tick_event); +} + +void InputCore::Init() { + ParseSettings(); + tick_event = CoreTiming::RegisterEvent("InputCore::tick_event", InputTickCallback); + CoreTiming::ScheduleEvent(GPU::frame_ticks, tick_event); +} + +void InputCore::Shutdown() { + CoreTiming::UnscheduleEvent(tick_event, 0); + devices.clear(); +} diff --git a/src/input_core/input_core.h b/src/input_core/input_core.h index 24ad191c9..2871c8d00 100644 --- a/src/input_core/input_core.h +++ b/src/input_core/input_core.h @@ -16,112 +16,64 @@ class Keyboard; -class InputCore { -public: - static void Init(); - static void Shutdown(); +namespace InputCore { +void Init(); +void Shutdown(); - /** - * Threadsafe getter to the current PadState - * @return Service::HID::PadState instance - */ - static Service::HID::PadState GetPadState(); +/** + * Threadsafe getter to the current PadState + * @return Service::HID::PadState instance + */ +Service::HID::PadState GetPadState(); - /** - * Threadsafe setter for the current PadState - * @param state New PadState to overwrite current PadState. - */ - static void SetPadState(const Service::HID::PadState& state); +/** + * Threadsafe setter for the current PadState + * @param state New PadState to overwrite current PadState. + */ +void SetPadState(const Service::HID::PadState& state); - /** - * Getter for current CirclePad - * @return std::tuple CirclePad state - */ - static std::tuple GetCirclePad(); +/** + * Getter for current CirclePad + * @return std::tuple CirclePad state + */ +std::tuple GetCirclePad(); - /** - * Getter for Citra's main keyboard input handler - * @return std::shared_ptr Device Keyboard instance - */ - static std::shared_ptr GetKeyboard(); +/** + * Getter for Citra's main keyboard input handler + * @return std::shared_ptr Device Keyboard instance + */ +std::shared_ptr GetKeyboard(); - /** - * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed). - * Threadsafe. - * @note This should be called by the core emu thread to get a state set by the window thread. - * @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and - * `pressed` is true if the touch screen is currently being pressed - */ - static std::tuple GetTouchState(); +/** + * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed). + * Threadsafe. + * @note This should be called by the core emu thread to get a state set by the window thread. + * @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and + * `pressed` is true if the touch screen is currently being pressed + */ +std::tuple GetTouchState(); - /** - * Threadsafe setter for the current touch screen state. - * @param value New Touch State - */ - static void SetTouchState(std::tuple value); +/** + * Threadsafe setter for the current touch screen state. + * @param value New Touch State + */ +void SetTouchState(std::tuple value); - /** - * Reload input key mapping settings during game-play - */ - static void ReloadSettings(); - /** - * Returns vector of all available devices from user's system. - */ - static std::vector> GetAllDevices(); +/** + * Reload input key mapping settings during game-play + */ +void ReloadSettings(); - /** - * Loops through all devices and detects the first device that produces an input - * @param max_time: maximum amount of time to wait until input detected, in milliseconds. - * @param update_GUI: function to run in while loop to process any gui events. - * @return Settings::InputDeviceMapping of input device - */ - static Settings::InputDeviceMapping DetectInput(int max_time, - std::function update_GUI); +/** + * Returns vector of all available devices from user's system. + */ +std::vector> GetAllDevices(); -private: - static int tick_event; - static Service::HID::PadState pad_state; - static std::tuple circle_pad; - static std::shared_ptr main_keyboard; ///< Keyboard is always active for Citra - static std::vector> - devices; ///< Devices that are handling input for the game - static std::map> key_mappings; - static std::map - keys_pressed; ///< keys that were pressed on previous frame. - static std::mutex pad_state_mutex; - static std::mutex touch_mutex; - static u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) - static u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) - static bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false - static const float input_detect_threshold; - - /** - * Loops through all unique input devices, and all bound inputs to update the emulator's input - * status. - */ - static void UpdateEmulatorInputs( - std::vector> inputs); - - static void InputTickCallback(u64, int cycles_late); - - /** - * Helper methodto check if device was already initialized - */ - static bool CheckIfMappingExists(const std::set& uniqueMapping, - Settings::InputDeviceMapping mappingToCheck); - - static std::set - GatherUniqueMappings(); /// Get unique input mappings from settings - - static void BuildKeyMapping(); /// Builds map of input keys to 3ds buttons for unique device - - static void GenerateUniqueDevices(); /// Generate a device for each unique mapping - - static void ParseSettings(); /// Read settings to initialize devices - - /** - * Takes two floats and the deadzone and applies formula to - * correct the stick position. - */ - static std::tuple ApplyDeadzone(float x, float y, float dead_zone); +/** + * Loops through all devices and detects the first device that produces an input + * @param max_time: maximum amount of time to wait until input detected, in milliseconds. + * @param update_GUI: function to run in while loop to process any gui events. + * @return Settings::InputDeviceMapping of input device + */ +Settings::InputDeviceMapping DetectInput(int max_time, std::function update_GUI); };