#pragma once #if BOOST_OS_WINDOWS #include "input/api/DirectInput/DirectInputControllerProvider.h" #include "input/api/XInput/XInputControllerProvider.h" #endif #ifdef SUPPORTS_WIIMOTE #include "input/api/Wiimote/WiimoteControllerProvider.h" #endif #include "util/helpers/Singleton.h" #include "input/api/SDL/SDLControllerProvider.h" #include "input/api/Keyboard/KeyboardControllerProvider.h" #include "input/api/DSU/DSUControllerProvider.h" #include "input/api/GameCube/GameCubeControllerProvider.h" #include "input/emulated/VPADController.h" #include "input/emulated/WPADController.h" #include #include class InputManager : public Singleton { friend class Singleton; InputManager(); ~InputManager(); friend class MainWindow; friend class PadViewFrame; public: constexpr static size_t kMaxController = 8; constexpr static size_t kMaxVPADControllers = 2; constexpr static size_t kMaxWPADControllers = 7; void load() noexcept; bool load(size_t player_index, std::string_view filename = {}); bool migrate_config(const fs::path& file_path); void save() noexcept; bool save(size_t player_index, std::string_view filename = {}); bool is_gameprofile_set(size_t player_index) const; EmulatedControllerPtr set_controller(EmulatedControllerPtr controller); EmulatedControllerPtr set_controller(size_t player_index, EmulatedController::Type type); EmulatedControllerPtr set_controller(size_t player_index, EmulatedController::Type type, const std::shared_ptr& controller); EmulatedControllerPtr delete_controller(size_t player_index, bool delete_profile = false); EmulatedControllerPtr get_controller(size_t player_index) const; std::shared_ptr get_vpad_controller(size_t index) const; std::shared_ptr get_wpad_controller(size_t index) const; std::pair get_controller_count() const; bool is_api_available(InputAPI::Type api) const { return !m_api_available[api].empty(); } ControllerProviderPtr get_api_provider(std::string_view api_name) const; ControllerProviderPtr get_api_provider(InputAPI::Type api) const; // will create the provider with the given settings if it doesn't exist yet ControllerProviderPtr get_api_provider(InputAPI::Type api, const ControllerProviderSettings& settings); const auto& get_api_providers() const { return m_api_available; } void apply_game_profile(); void on_device_changed(); static std::vector get_profiles(); static bool is_valid_profilename(const std::string& name); struct MouseInfo { mutable std::shared_mutex m_mutex; glm::ivec2 position{}; bool left_down = false; bool right_down = false; bool left_down_toggle = false; bool right_down_toggle = false; } m_main_mouse{}, m_pad_mouse{}, m_main_touch{}, m_pad_touch{}; glm::ivec2 get_mouse_position(bool pad_window) const; std::optional get_left_down_mouse_info(bool* is_pad); std::optional get_right_down_mouse_info(bool* is_pad); std::atomic m_mouse_wheel; private: void update_thread(); std::thread m_update_thread; std::atomic m_update_thread_shutdown{false}; std::array, InputAPI::MAX> m_api_available{ }; mutable std::shared_mutex m_mutex; std::array m_vpad; std::array m_wpad; std::array m_is_gameprofile_set{}; template void create_provider() // lambda templates only work in c++20 -> define locally in ctor { static_assert(std::is_base_of_v); try { auto controller = std::make_shared(); m_api_available[controller->api()] = std::vector{ controller }; } catch (const std::exception& ex) { cemuLog_log(LogType::Force, ex.what()); } } };