diff options
Diffstat (limited to 'src/core/frontend')
| -rw-r--r-- | src/core/frontend/applets/controller.cpp | 45 | ||||
| -rw-r--r-- | src/core/frontend/applets/controller.h | 8 | ||||
| -rw-r--r-- | src/core/frontend/emu_window.cpp | 98 | ||||
| -rw-r--r-- | src/core/frontend/emu_window.h | 30 | ||||
| -rw-r--r-- | src/core/frontend/framebuffer_layout.cpp | 7 | ||||
| -rw-r--r-- | src/core/frontend/framebuffer_layout.h | 11 | ||||
| -rw-r--r-- | src/core/frontend/input.h | 217 | ||||
| -rw-r--r-- | src/core/frontend/input_interpreter.cpp | 62 | ||||
| -rw-r--r-- | src/core/frontend/input_interpreter.h | 144 |
9 files changed, 46 insertions, 576 deletions
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 03bbedf8b..6dbd38ffa 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp | |||
| @@ -5,16 +5,15 @@ | |||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/frontend/applets/controller.h" | 7 | #include "core/frontend/applets/controller.h" |
| 8 | #include "core/hle/service/hid/controllers/npad.h" | 8 | #include "core/hid/emulated_controller.h" |
| 9 | #include "core/hle/service/hid/hid.h" | 9 | #include "core/hid/hid_core.h" |
| 10 | #include "core/hle/service/sm/sm.h" | 10 | #include "core/hid/hid_types.h" |
| 11 | 11 | ||
| 12 | namespace Core::Frontend { | 12 | namespace Core::Frontend { |
| 13 | 13 | ||
| 14 | ControllerApplet::~ControllerApplet() = default; | 14 | ControllerApplet::~ControllerApplet() = default; |
| 15 | 15 | ||
| 16 | DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_) | 16 | DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_core{hid_core_} {} |
| 17 | : service_manager{service_manager_} {} | ||
| 18 | 17 | ||
| 19 | DefaultControllerApplet::~DefaultControllerApplet() = default; | 18 | DefaultControllerApplet::~DefaultControllerApplet() = default; |
| 20 | 19 | ||
| @@ -22,24 +21,20 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb | |||
| 22 | const ControllerParameters& parameters) const { | 21 | const ControllerParameters& parameters) const { |
| 23 | LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); | 22 | LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); |
| 24 | 23 | ||
| 25 | auto& npad = | ||
| 26 | service_manager.GetService<Service::HID::Hid>("hid") | ||
| 27 | ->GetAppletResource() | ||
| 28 | ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); | ||
| 29 | |||
| 30 | auto& players = Settings::values.players.GetValue(); | ||
| 31 | |||
| 32 | const std::size_t min_supported_players = | 24 | const std::size_t min_supported_players = |
| 33 | parameters.enable_single_mode ? 1 : parameters.min_players; | 25 | parameters.enable_single_mode ? 1 : parameters.min_players; |
| 34 | 26 | ||
| 35 | // Disconnect Handheld first. | 27 | // Disconnect Handheld first. |
| 36 | npad.DisconnectNpadAtIndex(8); | 28 | auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); |
| 29 | handheld->Disconnect(); | ||
| 37 | 30 | ||
| 38 | // Deduce the best configuration based on the input parameters. | 31 | // Deduce the best configuration based on the input parameters. |
| 39 | for (std::size_t index = 0; index < players.size() - 2; ++index) { | 32 | for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) { |
| 33 | auto* controller = hid_core.GetEmulatedControllerByIndex(index); | ||
| 34 | |||
| 40 | // First, disconnect all controllers regardless of the value of keep_controllers_connected. | 35 | // First, disconnect all controllers regardless of the value of keep_controllers_connected. |
| 41 | // This makes it easy to connect the desired controllers. | 36 | // This makes it easy to connect the desired controllers. |
| 42 | npad.DisconnectNpadAtIndex(index); | 37 | controller->Disconnect(); |
| 43 | 38 | ||
| 44 | // Only connect the minimum number of required players. | 39 | // Only connect the minimum number of required players. |
| 45 | if (index >= min_supported_players) { | 40 | if (index >= min_supported_players) { |
| @@ -49,27 +44,27 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb | |||
| 49 | // Connect controllers based on the following priority list from highest to lowest priority: | 44 | // Connect controllers based on the following priority list from highest to lowest priority: |
| 50 | // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld | 45 | // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld |
| 51 | if (parameters.allow_pro_controller) { | 46 | if (parameters.allow_pro_controller) { |
| 52 | npad.AddNewControllerAt( | 47 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); |
| 53 | npad.MapSettingsTypeToNPad(Settings::ControllerType::ProController), index); | 48 | controller->Connect(); |
| 54 | } else if (parameters.allow_dual_joycons) { | 49 | } else if (parameters.allow_dual_joycons) { |
| 55 | npad.AddNewControllerAt( | 50 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); |
| 56 | npad.MapSettingsTypeToNPad(Settings::ControllerType::DualJoyconDetached), index); | 51 | controller->Connect(); |
| 57 | } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { | 52 | } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { |
| 58 | // Assign left joycons to even player indices and right joycons to odd player indices. | 53 | // Assign left joycons to even player indices and right joycons to odd player indices. |
| 59 | // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and | 54 | // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and |
| 60 | // a right Joycon for Player 2 in 2 Player Assist mode. | 55 | // a right Joycon for Player 2 in 2 Player Assist mode. |
| 61 | if (index % 2 == 0) { | 56 | if (index % 2 == 0) { |
| 62 | npad.AddNewControllerAt( | 57 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft); |
| 63 | npad.MapSettingsTypeToNPad(Settings::ControllerType::LeftJoycon), index); | 58 | controller->Connect(); |
| 64 | } else { | 59 | } else { |
| 65 | npad.AddNewControllerAt( | 60 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight); |
| 66 | npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index); | 61 | controller->Connect(); |
| 67 | } | 62 | } |
| 68 | } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && | 63 | } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && |
| 69 | !Settings::values.use_docked_mode.GetValue()) { | 64 | !Settings::values.use_docked_mode.GetValue()) { |
| 70 | // We should *never* reach here under any normal circumstances. | 65 | // We should *never* reach here under any normal circumstances. |
| 71 | npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld), | 66 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); |
| 72 | index); | 67 | controller->Connect(); |
| 73 | } else { | 68 | } else { |
| 74 | UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); | 69 | UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); |
| 75 | } | 70 | } |
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h index b0626a0f9..014bc8901 100644 --- a/src/core/frontend/applets/controller.h +++ b/src/core/frontend/applets/controller.h | |||
| @@ -8,8 +8,8 @@ | |||
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | 10 | ||
| 11 | namespace Service::SM { | 11 | namespace Core::HID { |
| 12 | class ServiceManager; | 12 | class HIDCore; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | namespace Core::Frontend { | 15 | namespace Core::Frontend { |
| @@ -44,14 +44,14 @@ public: | |||
| 44 | 44 | ||
| 45 | class DefaultControllerApplet final : public ControllerApplet { | 45 | class DefaultControllerApplet final : public ControllerApplet { |
| 46 | public: | 46 | public: |
| 47 | explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_); | 47 | explicit DefaultControllerApplet(HID::HIDCore& hid_core_); |
| 48 | ~DefaultControllerApplet() override; | 48 | ~DefaultControllerApplet() override; |
| 49 | 49 | ||
| 50 | void ReconfigureControllers(std::function<void()> callback, | 50 | void ReconfigureControllers(std::function<void()> callback, |
| 51 | const ControllerParameters& parameters) const override; | 51 | const ControllerParameters& parameters) const override; |
| 52 | 52 | ||
| 53 | private: | 53 | private: |
| 54 | Service::SM::ServiceManager& service_manager; | 54 | HID::HIDCore& hid_core; |
| 55 | }; | 55 | }; |
| 56 | 56 | ||
| 57 | } // namespace Core::Frontend | 57 | } // namespace Core::Frontend |
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index e1f7e5886..57c6ffc43 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp | |||
| @@ -3,87 +3,23 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <mutex> | 5 | #include <mutex> |
| 6 | #include "common/settings.h" | ||
| 7 | #include "core/frontend/emu_window.h" | 6 | #include "core/frontend/emu_window.h" |
| 8 | #include "core/frontend/input.h" | ||
| 9 | 7 | ||
| 10 | namespace Core::Frontend { | 8 | namespace Core::Frontend { |
| 11 | 9 | ||
| 12 | GraphicsContext::~GraphicsContext() = default; | 10 | GraphicsContext::~GraphicsContext() = default; |
| 13 | 11 | ||
| 14 | class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>, | ||
| 15 | public std::enable_shared_from_this<TouchState> { | ||
| 16 | public: | ||
| 17 | std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage&) override { | ||
| 18 | return std::make_unique<Device>(shared_from_this()); | ||
| 19 | } | ||
| 20 | |||
| 21 | std::mutex mutex; | ||
| 22 | |||
| 23 | Input::TouchStatus status; | ||
| 24 | |||
| 25 | private: | ||
| 26 | class Device : public Input::TouchDevice { | ||
| 27 | public: | ||
| 28 | explicit Device(std::weak_ptr<TouchState>&& touch_state_) : touch_state(touch_state_) {} | ||
| 29 | Input::TouchStatus GetStatus() const override { | ||
| 30 | if (auto state = touch_state.lock()) { | ||
| 31 | std::lock_guard guard{state->mutex}; | ||
| 32 | return state->status; | ||
| 33 | } | ||
| 34 | return {}; | ||
| 35 | } | ||
| 36 | |||
| 37 | private: | ||
| 38 | std::weak_ptr<TouchState> touch_state; | ||
| 39 | }; | ||
| 40 | }; | ||
| 41 | |||
| 42 | EmuWindow::EmuWindow() { | 12 | EmuWindow::EmuWindow() { |
| 43 | // TODO: Find a better place to set this. | 13 | // TODO: Find a better place to set this. |
| 44 | config.min_client_area_size = | 14 | config.min_client_area_size = |
| 45 | std::make_pair(Layout::MinimumSize::Width, Layout::MinimumSize::Height); | 15 | std::make_pair(Layout::MinimumSize::Width, Layout::MinimumSize::Height); |
| 46 | active_config = config; | 16 | active_config = config; |
| 47 | touch_state = std::make_shared<TouchState>(); | ||
| 48 | Input::RegisterFactory<Input::TouchDevice>("emu_window", touch_state); | ||
| 49 | } | ||
| 50 | |||
| 51 | EmuWindow::~EmuWindow() { | ||
| 52 | Input::UnregisterFactory<Input::TouchDevice>("emu_window"); | ||
| 53 | } | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout | ||
| 57 | * @param layout FramebufferLayout object describing the framebuffer size and screen positions | ||
| 58 | * @param framebuffer_x Framebuffer x-coordinate to check | ||
| 59 | * @param framebuffer_y Framebuffer y-coordinate to check | ||
| 60 | * @return True if the coordinates are within the touchpad, otherwise false | ||
| 61 | */ | ||
| 62 | static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, u32 framebuffer_x, | ||
| 63 | u32 framebuffer_y) { | ||
| 64 | return (framebuffer_y >= layout.screen.top && framebuffer_y < layout.screen.bottom && | ||
| 65 | framebuffer_x >= layout.screen.left && framebuffer_x < layout.screen.right); | ||
| 66 | } | ||
| 67 | |||
| 68 | std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const { | ||
| 69 | new_x = std::max(new_x, framebuffer_layout.screen.left); | ||
| 70 | new_x = std::min(new_x, framebuffer_layout.screen.right - 1); | ||
| 71 | |||
| 72 | new_y = std::max(new_y, framebuffer_layout.screen.top); | ||
| 73 | new_y = std::min(new_y, framebuffer_layout.screen.bottom - 1); | ||
| 74 | |||
| 75 | return std::make_pair(new_x, new_y); | ||
| 76 | } | 17 | } |
| 77 | 18 | ||
| 78 | void EmuWindow::TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id) { | 19 | EmuWindow::~EmuWindow() {} |
| 79 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { | ||
| 80 | return; | ||
| 81 | } | ||
| 82 | if (id >= touch_state->status.size()) { | ||
| 83 | return; | ||
| 84 | } | ||
| 85 | 20 | ||
| 86 | std::lock_guard guard{touch_state->mutex}; | 21 | std::pair<f32, f32> EmuWindow::MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const { |
| 22 | std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); | ||
| 87 | const float x = | 23 | const float x = |
| 88 | static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) / | 24 | static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) / |
| 89 | static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left); | 25 | static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left); |
| @@ -91,31 +27,17 @@ void EmuWindow::TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id) { | |||
| 91 | static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) / | 27 | static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) / |
| 92 | static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); | 28 | static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); |
| 93 | 29 | ||
| 94 | touch_state->status[id] = std::make_tuple(x, y, true); | 30 | return std::make_pair(x, y); |
| 95 | } | ||
| 96 | |||
| 97 | void EmuWindow::TouchReleased(size_t id) { | ||
| 98 | if (id >= touch_state->status.size()) { | ||
| 99 | return; | ||
| 100 | } | ||
| 101 | std::lock_guard guard{touch_state->mutex}; | ||
| 102 | touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false); | ||
| 103 | } | 31 | } |
| 104 | 32 | ||
| 105 | void EmuWindow::TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id) { | 33 | std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const { |
| 106 | if (id >= touch_state->status.size()) { | 34 | new_x = std::max(new_x, framebuffer_layout.screen.left); |
| 107 | return; | 35 | new_x = std::min(new_x, framebuffer_layout.screen.right - 1); |
| 108 | } | ||
| 109 | |||
| 110 | if (!std::get<2>(touch_state->status[id])) { | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | 36 | ||
| 114 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { | 37 | new_y = std::max(new_y, framebuffer_layout.screen.top); |
| 115 | std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); | 38 | new_y = std::min(new_y, framebuffer_layout.screen.bottom - 1); |
| 116 | } | ||
| 117 | 39 | ||
| 118 | TouchPressed(framebuffer_x, framebuffer_y, id); | 40 | return std::make_pair(new_x, new_y); |
| 119 | } | 41 | } |
| 120 | 42 | ||
| 121 | void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height) { | 43 | void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height) { |
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 8a86a1d27..e413a520a 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -113,28 +113,6 @@ public: | |||
| 113 | virtual bool IsShown() const = 0; | 113 | virtual bool IsShown() const = 0; |
| 114 | 114 | ||
| 115 | /** | 115 | /** |
| 116 | * Signal that a touch pressed event has occurred (e.g. mouse click pressed) | ||
| 117 | * @param framebuffer_x Framebuffer x-coordinate that was pressed | ||
| 118 | * @param framebuffer_y Framebuffer y-coordinate that was pressed | ||
| 119 | * @param id Touch event ID | ||
| 120 | */ | ||
| 121 | void TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id); | ||
| 122 | |||
| 123 | /** | ||
| 124 | * Signal that a touch released event has occurred (e.g. mouse click released) | ||
| 125 | * @param id Touch event ID | ||
| 126 | */ | ||
| 127 | void TouchReleased(size_t id); | ||
| 128 | |||
| 129 | /** | ||
| 130 | * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) | ||
| 131 | * @param framebuffer_x Framebuffer x-coordinate | ||
| 132 | * @param framebuffer_y Framebuffer y-coordinate | ||
| 133 | * @param id Touch event ID | ||
| 134 | */ | ||
| 135 | void TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id); | ||
| 136 | |||
| 137 | /** | ||
| 138 | * Returns currently active configuration. | 116 | * Returns currently active configuration. |
| 139 | * @note Accesses to the returned object need not be consistent because it may be modified in | 117 | * @note Accesses to the returned object need not be consistent because it may be modified in |
| 140 | * another thread | 118 | * another thread |
| @@ -212,6 +190,11 @@ protected: | |||
| 212 | client_area_height = size.second; | 190 | client_area_height = size.second; |
| 213 | } | 191 | } |
| 214 | 192 | ||
| 193 | /** | ||
| 194 | * Converts a screen postion into the equivalent touchscreen position. | ||
| 195 | */ | ||
| 196 | std::pair<f32, f32> MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const; | ||
| 197 | |||
| 215 | WindowSystemInfo window_info; | 198 | WindowSystemInfo window_info; |
| 216 | 199 | ||
| 217 | private: | 200 | private: |
| @@ -237,9 +220,6 @@ private: | |||
| 237 | WindowConfig config; ///< Internal configuration (changes pending for being applied in | 220 | WindowConfig config; ///< Internal configuration (changes pending for being applied in |
| 238 | /// ProcessConfigurationChanges) | 221 | /// ProcessConfigurationChanges) |
| 239 | WindowConfig active_config; ///< Internal active configuration | 222 | WindowConfig active_config; ///< Internal active configuration |
| 240 | |||
| 241 | class TouchState; | ||
| 242 | std::shared_ptr<TouchState> touch_state; | ||
| 243 | }; | 223 | }; |
| 244 | 224 | ||
| 245 | } // namespace Core::Frontend | 225 | } // namespace Core::Frontend |
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 4b58b672a..26a5b12aa 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp | |||
| @@ -25,7 +25,12 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) { | |||
| 25 | ASSERT(height > 0); | 25 | ASSERT(height > 0); |
| 26 | // The drawing code needs at least somewhat valid values for both screens | 26 | // The drawing code needs at least somewhat valid values for both screens |
| 27 | // so just calculate them both even if the other isn't showing. | 27 | // so just calculate them both even if the other isn't showing. |
| 28 | FramebufferLayout res{width, height, false, {}}; | 28 | FramebufferLayout res{ |
| 29 | .width = width, | ||
| 30 | .height = height, | ||
| 31 | .screen = {}, | ||
| 32 | .is_srgb = false, | ||
| 33 | }; | ||
| 29 | 34 | ||
| 30 | const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width); | 35 | const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width); |
| 31 | const float emulation_aspect_ratio = EmulationAspectRatio( | 36 | const float emulation_aspect_ratio = EmulationAspectRatio( |
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 2e36c0163..8e341e4e2 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h | |||
| @@ -35,17 +35,8 @@ enum class AspectRatio { | |||
| 35 | struct FramebufferLayout { | 35 | struct FramebufferLayout { |
| 36 | u32 width{ScreenUndocked::Width}; | 36 | u32 width{ScreenUndocked::Width}; |
| 37 | u32 height{ScreenUndocked::Height}; | 37 | u32 height{ScreenUndocked::Height}; |
| 38 | bool is_srgb{}; | ||
| 39 | |||
| 40 | Common::Rectangle<u32> screen; | 38 | Common::Rectangle<u32> screen; |
| 41 | 39 | bool is_srgb{}; | |
| 42 | /** | ||
| 43 | * Returns the ration of pixel size of the screen, compared to the native size of the undocked | ||
| 44 | * Switch screen. | ||
| 45 | */ | ||
| 46 | float GetScalingRatio() const { | ||
| 47 | return static_cast<float>(screen.GetWidth()) / ScreenUndocked::Width; | ||
| 48 | } | ||
| 49 | }; | 40 | }; |
| 50 | 41 | ||
| 51 | /** | 42 | /** |
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h deleted file mode 100644 index f1747c5b2..000000000 --- a/src/core/frontend/input.h +++ /dev/null | |||
| @@ -1,217 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <functional> | ||
| 8 | #include <memory> | ||
| 9 | #include <string> | ||
| 10 | #include <tuple> | ||
| 11 | #include <unordered_map> | ||
| 12 | #include <utility> | ||
| 13 | #include "common/logging/log.h" | ||
| 14 | #include "common/param_package.h" | ||
| 15 | #include "common/quaternion.h" | ||
| 16 | #include "common/vector_math.h" | ||
| 17 | |||
| 18 | namespace Input { | ||
| 19 | |||
| 20 | enum class AnalogDirection : u8 { | ||
| 21 | RIGHT, | ||
| 22 | LEFT, | ||
| 23 | UP, | ||
| 24 | DOWN, | ||
| 25 | }; | ||
| 26 | struct AnalogProperties { | ||
| 27 | float deadzone; | ||
| 28 | float range; | ||
| 29 | float threshold; | ||
| 30 | }; | ||
| 31 | template <typename StatusType> | ||
| 32 | struct InputCallback { | ||
| 33 | std::function<void(StatusType)> on_change; | ||
| 34 | }; | ||
| 35 | |||
| 36 | /// An abstract class template for an input device (a button, an analog input, etc.). | ||
| 37 | template <typename StatusType> | ||
| 38 | class InputDevice { | ||
| 39 | public: | ||
| 40 | virtual ~InputDevice() = default; | ||
| 41 | virtual StatusType GetStatus() const { | ||
| 42 | return {}; | ||
| 43 | } | ||
| 44 | virtual StatusType GetRawStatus() const { | ||
| 45 | return GetStatus(); | ||
| 46 | } | ||
| 47 | virtual AnalogProperties GetAnalogProperties() const { | ||
| 48 | return {}; | ||
| 49 | } | ||
| 50 | virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const { | ||
| 51 | return {}; | ||
| 52 | } | ||
| 53 | virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low, | ||
| 54 | [[maybe_unused]] f32 amp_high, | ||
| 55 | [[maybe_unused]] f32 freq_high) const { | ||
| 56 | return {}; | ||
| 57 | } | ||
| 58 | void SetCallback(InputCallback<StatusType> callback_) { | ||
| 59 | callback = std::move(callback_); | ||
| 60 | } | ||
| 61 | void TriggerOnChange() { | ||
| 62 | if (callback.on_change) { | ||
| 63 | callback.on_change(GetStatus()); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | private: | ||
| 68 | InputCallback<StatusType> callback; | ||
| 69 | }; | ||
| 70 | |||
| 71 | /// An abstract class template for a factory that can create input devices. | ||
| 72 | template <typename InputDeviceType> | ||
| 73 | class Factory { | ||
| 74 | public: | ||
| 75 | virtual ~Factory() = default; | ||
| 76 | virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0; | ||
| 77 | }; | ||
| 78 | |||
| 79 | namespace Impl { | ||
| 80 | |||
| 81 | template <typename InputDeviceType> | ||
| 82 | using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>; | ||
| 83 | |||
| 84 | template <typename InputDeviceType> | ||
| 85 | struct FactoryList { | ||
| 86 | static FactoryListType<InputDeviceType> list; | ||
| 87 | }; | ||
| 88 | |||
| 89 | template <typename InputDeviceType> | ||
| 90 | FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list; | ||
| 91 | |||
| 92 | } // namespace Impl | ||
| 93 | |||
| 94 | /** | ||
| 95 | * Registers an input device factory. | ||
| 96 | * @tparam InputDeviceType the type of input devices the factory can create | ||
| 97 | * @param name the name of the factory. Will be used to match the "engine" parameter when creating | ||
| 98 | * a device | ||
| 99 | * @param factory the factory object to register | ||
| 100 | */ | ||
| 101 | template <typename InputDeviceType> | ||
| 102 | void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) { | ||
| 103 | auto pair = std::make_pair(name, std::move(factory)); | ||
| 104 | if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) { | ||
| 105 | LOG_ERROR(Input, "Factory '{}' already registered", name); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | /** | ||
| 110 | * Unregisters an input device factory. | ||
| 111 | * @tparam InputDeviceType the type of input devices the factory can create | ||
| 112 | * @param name the name of the factory to unregister | ||
| 113 | */ | ||
| 114 | template <typename InputDeviceType> | ||
| 115 | void UnregisterFactory(const std::string& name) { | ||
| 116 | if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) { | ||
| 117 | LOG_ERROR(Input, "Factory '{}' not registered", name); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | /** | ||
| 122 | * Create an input device from given paramters. | ||
| 123 | * @tparam InputDeviceType the type of input devices to create | ||
| 124 | * @param params a serialized ParamPackage string contains all parameters for creating the device | ||
| 125 | */ | ||
| 126 | template <typename InputDeviceType> | ||
| 127 | std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) { | ||
| 128 | const Common::ParamPackage package(params); | ||
| 129 | const std::string engine = package.Get("engine", "null"); | ||
| 130 | const auto& factory_list = Impl::FactoryList<InputDeviceType>::list; | ||
| 131 | const auto pair = factory_list.find(engine); | ||
| 132 | if (pair == factory_list.end()) { | ||
| 133 | if (engine != "null") { | ||
| 134 | LOG_ERROR(Input, "Unknown engine name: {}", engine); | ||
| 135 | } | ||
| 136 | return std::make_unique<InputDeviceType>(); | ||
| 137 | } | ||
| 138 | return pair->second->Create(package); | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * A button device is an input device that returns bool as status. | ||
| 143 | * true for pressed; false for released. | ||
| 144 | */ | ||
| 145 | using ButtonDevice = InputDevice<bool>; | ||
| 146 | |||
| 147 | /** | ||
| 148 | * An analog device is an input device that returns a tuple of x and y coordinates as status. The | ||
| 149 | * coordinates are within the unit circle. x+ is defined as right direction, and y+ is defined as up | ||
| 150 | * direction | ||
| 151 | */ | ||
| 152 | using AnalogDevice = InputDevice<std::tuple<float, float>>; | ||
| 153 | |||
| 154 | /** | ||
| 155 | * A vibration device is an input device that returns an unsigned byte as status. | ||
| 156 | * It represents whether the vibration device supports vibration or not. | ||
| 157 | * If the status returns 1, it supports vibration. Otherwise, it does not support vibration. | ||
| 158 | */ | ||
| 159 | using VibrationDevice = InputDevice<u8>; | ||
| 160 | |||
| 161 | /** | ||
| 162 | * A motion status is an object that returns a tuple of accelerometer state vector, | ||
| 163 | * gyroscope state vector, rotation state vector, orientation state matrix and quaterion state | ||
| 164 | * vector. | ||
| 165 | * | ||
| 166 | * For both 3D vectors: | ||
| 167 | * x+ is the same direction as RIGHT on D-pad. | ||
| 168 | * y+ is normal to the touch screen, pointing outward. | ||
| 169 | * z+ is the same direction as UP on D-pad. | ||
| 170 | * | ||
| 171 | * For accelerometer state vector | ||
| 172 | * Units: g (gravitational acceleration) | ||
| 173 | * | ||
| 174 | * For gyroscope state vector: | ||
| 175 | * Orientation is determined by right-hand rule. | ||
| 176 | * Units: deg/sec | ||
| 177 | * | ||
| 178 | * For rotation state vector | ||
| 179 | * Units: rotations | ||
| 180 | * | ||
| 181 | * For orientation state matrix | ||
| 182 | * x vector | ||
| 183 | * y vector | ||
| 184 | * z vector | ||
| 185 | * | ||
| 186 | * For quaternion state vector | ||
| 187 | * xyz vector | ||
| 188 | * w float | ||
| 189 | */ | ||
| 190 | using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>, | ||
| 191 | std::array<Common::Vec3f, 3>, Common::Quaternion<f32>>; | ||
| 192 | |||
| 193 | /** | ||
| 194 | * A motion device is an input device that returns a motion status object | ||
| 195 | */ | ||
| 196 | using MotionDevice = InputDevice<MotionStatus>; | ||
| 197 | |||
| 198 | /** | ||
| 199 | * A touch status is an object that returns an array of 16 tuple elements of two floats and a bool. | ||
| 200 | * The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is | ||
| 201 | * pressed. | ||
| 202 | */ | ||
| 203 | using TouchStatus = std::array<std::tuple<float, float, bool>, 16>; | ||
| 204 | |||
| 205 | /** | ||
| 206 | * A touch device is an input device that returns a touch status object | ||
| 207 | */ | ||
| 208 | using TouchDevice = InputDevice<TouchStatus>; | ||
| 209 | |||
| 210 | /** | ||
| 211 | * A mouse device is an input device that returns a tuple of two floats and four ints. | ||
| 212 | * The first two floats are X and Y device coordinates of the mouse (from 0-1). | ||
| 213 | * The s32s are the mouse wheel. | ||
| 214 | */ | ||
| 215 | using MouseDevice = InputDevice<std::tuple<float, float, s32, s32>>; | ||
| 216 | |||
| 217 | } // namespace Input | ||
diff --git a/src/core/frontend/input_interpreter.cpp b/src/core/frontend/input_interpreter.cpp deleted file mode 100644 index 9f6a90e8f..000000000 --- a/src/core/frontend/input_interpreter.cpp +++ /dev/null | |||
| @@ -1,62 +0,0 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/frontend/input_interpreter.h" | ||
| 7 | #include "core/hle/service/hid/controllers/npad.h" | ||
| 8 | #include "core/hle/service/hid/hid.h" | ||
| 9 | #include "core/hle/service/sm/sm.h" | ||
| 10 | |||
| 11 | InputInterpreter::InputInterpreter(Core::System& system) | ||
| 12 | : npad{system.ServiceManager() | ||
| 13 | .GetService<Service::HID::Hid>("hid") | ||
| 14 | ->GetAppletResource() | ||
| 15 | ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} { | ||
| 16 | ResetButtonStates(); | ||
| 17 | } | ||
| 18 | |||
| 19 | InputInterpreter::~InputInterpreter() = default; | ||
| 20 | |||
| 21 | void InputInterpreter::PollInput() { | ||
| 22 | const u32 button_state = npad.GetAndResetPressState(); | ||
| 23 | |||
| 24 | previous_index = current_index; | ||
| 25 | current_index = (current_index + 1) % button_states.size(); | ||
| 26 | |||
| 27 | button_states[current_index] = button_state; | ||
| 28 | } | ||
| 29 | |||
| 30 | void InputInterpreter::ResetButtonStates() { | ||
| 31 | previous_index = 0; | ||
| 32 | current_index = 0; | ||
| 33 | |||
| 34 | button_states[0] = 0xFFFFFFFF; | ||
| 35 | |||
| 36 | for (std::size_t i = 1; i < button_states.size(); ++i) { | ||
| 37 | button_states[i] = 0; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | bool InputInterpreter::IsButtonPressed(HIDButton button) const { | ||
| 42 | return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | bool InputInterpreter::IsButtonPressedOnce(HIDButton button) const { | ||
| 46 | const bool current_press = | ||
| 47 | (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; | ||
| 48 | const bool previous_press = | ||
| 49 | (button_states[previous_index] & (1U << static_cast<u8>(button))) != 0; | ||
| 50 | |||
| 51 | return current_press && !previous_press; | ||
| 52 | } | ||
| 53 | |||
| 54 | bool InputInterpreter::IsButtonHeld(HIDButton button) const { | ||
| 55 | u32 held_buttons{button_states[0]}; | ||
| 56 | |||
| 57 | for (std::size_t i = 1; i < button_states.size(); ++i) { | ||
| 58 | held_buttons &= button_states[i]; | ||
| 59 | } | ||
| 60 | |||
| 61 | return (held_buttons & (1U << static_cast<u8>(button))) != 0; | ||
| 62 | } | ||
diff --git a/src/core/frontend/input_interpreter.h b/src/core/frontend/input_interpreter.h deleted file mode 100644 index 9495e3daf..000000000 --- a/src/core/frontend/input_interpreter.h +++ /dev/null | |||
| @@ -1,144 +0,0 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::HID { | ||
| 16 | class Controller_NPad; | ||
| 17 | } | ||
| 18 | |||
| 19 | enum class HIDButton : u8 { | ||
| 20 | A, | ||
| 21 | B, | ||
| 22 | X, | ||
| 23 | Y, | ||
| 24 | LStick, | ||
| 25 | RStick, | ||
| 26 | L, | ||
| 27 | R, | ||
| 28 | ZL, | ||
| 29 | ZR, | ||
| 30 | Plus, | ||
| 31 | Minus, | ||
| 32 | |||
| 33 | DLeft, | ||
| 34 | DUp, | ||
| 35 | DRight, | ||
| 36 | DDown, | ||
| 37 | |||
| 38 | LStickLeft, | ||
| 39 | LStickUp, | ||
| 40 | LStickRight, | ||
| 41 | LStickDown, | ||
| 42 | |||
| 43 | RStickLeft, | ||
| 44 | RStickUp, | ||
| 45 | RStickRight, | ||
| 46 | RStickDown, | ||
| 47 | |||
| 48 | LeftSL, | ||
| 49 | LeftSR, | ||
| 50 | |||
| 51 | RightSL, | ||
| 52 | RightSR, | ||
| 53 | }; | ||
| 54 | |||
| 55 | /** | ||
| 56 | * The InputInterpreter class interfaces with HID to retrieve button press states. | ||
| 57 | * Input is intended to be polled every 50ms so that a button is considered to be | ||
| 58 | * held down after 400ms has elapsed since the initial button press and subsequent | ||
| 59 | * repeated presses occur every 50ms. | ||
| 60 | */ | ||
| 61 | class InputInterpreter { | ||
| 62 | public: | ||
| 63 | explicit InputInterpreter(Core::System& system); | ||
| 64 | virtual ~InputInterpreter(); | ||
| 65 | |||
| 66 | /// Gets a button state from HID and inserts it into the array of button states. | ||
| 67 | void PollInput(); | ||
| 68 | |||
| 69 | /// Resets all the button states to their defaults. | ||
| 70 | void ResetButtonStates(); | ||
| 71 | |||
| 72 | /** | ||
| 73 | * Checks whether the button is pressed. | ||
| 74 | * | ||
| 75 | * @param button The button to check. | ||
| 76 | * | ||
| 77 | * @returns True when the button is pressed. | ||
| 78 | */ | ||
| 79 | [[nodiscard]] bool IsButtonPressed(HIDButton button) const; | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Checks whether any of the buttons in the parameter list is pressed. | ||
| 83 | * | ||
| 84 | * @tparam HIDButton The buttons to check. | ||
| 85 | * | ||
| 86 | * @returns True when at least one of the buttons is pressed. | ||
| 87 | */ | ||
| 88 | template <HIDButton... T> | ||
| 89 | [[nodiscard]] bool IsAnyButtonPressed() { | ||
| 90 | return (IsButtonPressed(T) || ...); | ||
| 91 | } | ||
| 92 | |||
| 93 | /** | ||
| 94 | * The specified button is considered to be pressed once | ||
| 95 | * if it is currently pressed and not pressed previously. | ||
| 96 | * | ||
| 97 | * @param button The button to check. | ||
| 98 | * | ||
| 99 | * @returns True when the button is pressed once. | ||
| 100 | */ | ||
| 101 | [[nodiscard]] bool IsButtonPressedOnce(HIDButton button) const; | ||
| 102 | |||
| 103 | /** | ||
| 104 | * Checks whether any of the buttons in the parameter list is pressed once. | ||
| 105 | * | ||
| 106 | * @tparam T The buttons to check. | ||
| 107 | * | ||
| 108 | * @returns True when at least one of the buttons is pressed once. | ||
| 109 | */ | ||
| 110 | template <HIDButton... T> | ||
| 111 | [[nodiscard]] bool IsAnyButtonPressedOnce() const { | ||
| 112 | return (IsButtonPressedOnce(T) || ...); | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * The specified button is considered to be held down if it is pressed in all 9 button states. | ||
| 117 | * | ||
| 118 | * @param button The button to check. | ||
| 119 | * | ||
| 120 | * @returns True when the button is held down. | ||
| 121 | */ | ||
| 122 | [[nodiscard]] bool IsButtonHeld(HIDButton button) const; | ||
| 123 | |||
| 124 | /** | ||
| 125 | * Checks whether any of the buttons in the parameter list is held down. | ||
| 126 | * | ||
| 127 | * @tparam T The buttons to check. | ||
| 128 | * | ||
| 129 | * @returns True when at least one of the buttons is held down. | ||
| 130 | */ | ||
| 131 | template <HIDButton... T> | ||
| 132 | [[nodiscard]] bool IsAnyButtonHeld() const { | ||
| 133 | return (IsButtonHeld(T) || ...); | ||
| 134 | } | ||
| 135 | |||
| 136 | private: | ||
| 137 | Service::HID::Controller_NPad& npad; | ||
| 138 | |||
| 139 | /// Stores 9 consecutive button states polled from HID. | ||
| 140 | std::array<u32, 9> button_states{}; | ||
| 141 | |||
| 142 | std::size_t previous_index{}; | ||
| 143 | std::size_t current_index{}; | ||
| 144 | }; | ||