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 @@  #include "common/assert.h"  #include "common/logging/log.h"  #include "core/frontend/applets/controller.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/hid.h" -#include "core/hle/service/sm/sm.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h"  namespace Core::Frontend {  ControllerApplet::~ControllerApplet() = default; -DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_) -    : service_manager{service_manager_} {} +DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_core{hid_core_} {}  DefaultControllerApplet::~DefaultControllerApplet() = default; @@ -22,24 +21,20 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb                                                       const ControllerParameters& parameters) const {      LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); -    auto& npad = -        service_manager.GetService<Service::HID::Hid>("hid") -            ->GetAppletResource() -            ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); - -    auto& players = Settings::values.players.GetValue(); -      const std::size_t min_supported_players =          parameters.enable_single_mode ? 1 : parameters.min_players;      // Disconnect Handheld first. -    npad.DisconnectNpadAtIndex(8); +    auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); +    handheld->Disconnect();      // Deduce the best configuration based on the input parameters. -    for (std::size_t index = 0; index < players.size() - 2; ++index) { +    for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) { +        auto* controller = hid_core.GetEmulatedControllerByIndex(index); +          // First, disconnect all controllers regardless of the value of keep_controllers_connected.          // This makes it easy to connect the desired controllers. -        npad.DisconnectNpadAtIndex(index); +        controller->Disconnect();          // Only connect the minimum number of required players.          if (index >= min_supported_players) { @@ -49,27 +44,27 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb          // Connect controllers based on the following priority list from highest to lowest priority:          // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld          if (parameters.allow_pro_controller) { -            npad.AddNewControllerAt( -                npad.MapSettingsTypeToNPad(Settings::ControllerType::ProController), index); +            controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); +            controller->Connect();          } else if (parameters.allow_dual_joycons) { -            npad.AddNewControllerAt( -                npad.MapSettingsTypeToNPad(Settings::ControllerType::DualJoyconDetached), index); +            controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); +            controller->Connect();          } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {              // Assign left joycons to even player indices and right joycons to odd player indices.              // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and              // a right Joycon for Player 2 in 2 Player Assist mode.              if (index % 2 == 0) { -                npad.AddNewControllerAt( -                    npad.MapSettingsTypeToNPad(Settings::ControllerType::LeftJoycon), index); +                controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft); +                controller->Connect();              } else { -                npad.AddNewControllerAt( -                    npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index); +                controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight); +                controller->Connect();              }          } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&                     !Settings::values.use_docked_mode.GetValue()) {              // We should *never* reach here under any normal circumstances. -            npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld), -                                    index); +            controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); +            controller->Connect();          } else {              UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!");          } 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 @@  #include "common/common_types.h" -namespace Service::SM { -class ServiceManager; +namespace Core::HID { +class HIDCore;  }  namespace Core::Frontend { @@ -44,14 +44,14 @@ public:  class DefaultControllerApplet final : public ControllerApplet {  public: -    explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_); +    explicit DefaultControllerApplet(HID::HIDCore& hid_core_);      ~DefaultControllerApplet() override;      void ReconfigureControllers(std::function<void()> callback,                                  const ControllerParameters& parameters) const override;  private: -    Service::SM::ServiceManager& service_manager; +    HID::HIDCore& hid_core;  };  } // 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 @@  // Refer to the license.txt file included.  #include <mutex> -#include "common/settings.h"  #include "core/frontend/emu_window.h" -#include "core/frontend/input.h"  namespace Core::Frontend {  GraphicsContext::~GraphicsContext() = default; -class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>, -                              public std::enable_shared_from_this<TouchState> { -public: -    std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage&) override { -        return std::make_unique<Device>(shared_from_this()); -    } - -    std::mutex mutex; - -    Input::TouchStatus status; - -private: -    class Device : public Input::TouchDevice { -    public: -        explicit Device(std::weak_ptr<TouchState>&& touch_state_) : touch_state(touch_state_) {} -        Input::TouchStatus GetStatus() const override { -            if (auto state = touch_state.lock()) { -                std::lock_guard guard{state->mutex}; -                return state->status; -            } -            return {}; -        } - -    private: -        std::weak_ptr<TouchState> touch_state; -    }; -}; -  EmuWindow::EmuWindow() {      // TODO: Find a better place to set this.      config.min_client_area_size =          std::make_pair(Layout::MinimumSize::Width, Layout::MinimumSize::Height);      active_config = config; -    touch_state = std::make_shared<TouchState>(); -    Input::RegisterFactory<Input::TouchDevice>("emu_window", touch_state); -} - -EmuWindow::~EmuWindow() { -    Input::UnregisterFactory<Input::TouchDevice>("emu_window"); -} - -/** - * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout - * @param layout FramebufferLayout object describing the framebuffer size and screen positions - * @param framebuffer_x Framebuffer x-coordinate to check - * @param framebuffer_y Framebuffer y-coordinate to check - * @return True if the coordinates are within the touchpad, otherwise false - */ -static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, u32 framebuffer_x, -                                u32 framebuffer_y) { -    return (framebuffer_y >= layout.screen.top && framebuffer_y < layout.screen.bottom && -            framebuffer_x >= layout.screen.left && framebuffer_x < layout.screen.right); -} - -std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const { -    new_x = std::max(new_x, framebuffer_layout.screen.left); -    new_x = std::min(new_x, framebuffer_layout.screen.right - 1); - -    new_y = std::max(new_y, framebuffer_layout.screen.top); -    new_y = std::min(new_y, framebuffer_layout.screen.bottom - 1); - -    return std::make_pair(new_x, new_y);  } -void EmuWindow::TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id) { -    if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { -        return; -    } -    if (id >= touch_state->status.size()) { -        return; -    } +EmuWindow::~EmuWindow() {} -    std::lock_guard guard{touch_state->mutex}; +std::pair<f32, f32> EmuWindow::MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const { +    std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);      const float x =          static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /          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) {          static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /          static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); -    touch_state->status[id] = std::make_tuple(x, y, true); -} - -void EmuWindow::TouchReleased(size_t id) { -    if (id >= touch_state->status.size()) { -        return; -    } -    std::lock_guard guard{touch_state->mutex}; -    touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false); +    return std::make_pair(x, y);  } -void EmuWindow::TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id) { -    if (id >= touch_state->status.size()) { -        return; -    } - -    if (!std::get<2>(touch_state->status[id])) { -        return; -    } +std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const { +    new_x = std::max(new_x, framebuffer_layout.screen.left); +    new_x = std::min(new_x, framebuffer_layout.screen.right - 1); -    if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { -        std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); -    } +    new_y = std::max(new_y, framebuffer_layout.screen.top); +    new_y = std::min(new_y, framebuffer_layout.screen.bottom - 1); -    TouchPressed(framebuffer_x, framebuffer_y, id); +    return std::make_pair(new_x, new_y);  }  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:      virtual bool IsShown() const = 0;      /** -     * Signal that a touch pressed event has occurred (e.g. mouse click pressed) -     * @param framebuffer_x Framebuffer x-coordinate that was pressed -     * @param framebuffer_y Framebuffer y-coordinate that was pressed -     * @param id Touch event ID -     */ -    void TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id); - -    /** -     * Signal that a touch released event has occurred (e.g. mouse click released) -     * @param id Touch event ID -     */ -    void TouchReleased(size_t id); - -    /** -     * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) -     * @param framebuffer_x Framebuffer x-coordinate -     * @param framebuffer_y Framebuffer y-coordinate -     * @param id Touch event ID -     */ -    void TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id); - -    /**       * Returns currently active configuration.       * @note Accesses to the returned object need not be consistent because it may be modified in       * another thread @@ -212,6 +190,11 @@ protected:          client_area_height = size.second;      } +    /** +     * Converts a screen postion into the equivalent touchscreen position. +     */ +    std::pair<f32, f32> MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const; +      WindowSystemInfo window_info;  private: @@ -237,9 +220,6 @@ private:      WindowConfig config;        ///< Internal configuration (changes pending for being applied in                                  /// ProcessConfigurationChanges)      WindowConfig active_config; ///< Internal active configuration - -    class TouchState; -    std::shared_ptr<TouchState> touch_state;  };  } // 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) {      ASSERT(height > 0);      // The drawing code needs at least somewhat valid values for both screens      // so just calculate them both even if the other isn't showing. -    FramebufferLayout res{width, height, false, {}}; +    FramebufferLayout res{ +        .width = width, +        .height = height, +        .screen = {}, +        .is_srgb = false, +    };      const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width);      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 {  struct FramebufferLayout {      u32 width{ScreenUndocked::Width};      u32 height{ScreenUndocked::Height}; -    bool is_srgb{}; -      Common::Rectangle<u32> screen; - -    /** -     * Returns the ration of pixel size of the screen, compared to the native size of the undocked -     * Switch screen. -     */ -    float GetScalingRatio() const { -        return static_cast<float>(screen.GetWidth()) / ScreenUndocked::Width; -    } +    bool is_srgb{};  };  /** 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 @@ -// 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 <tuple> -#include <unordered_map> -#include <utility> -#include "common/logging/log.h" -#include "common/param_package.h" -#include "common/quaternion.h" -#include "common/vector_math.h" - -namespace Input { - -enum class AnalogDirection : u8 { -    RIGHT, -    LEFT, -    UP, -    DOWN, -}; -struct AnalogProperties { -    float deadzone; -    float range; -    float threshold; -}; -template <typename StatusType> -struct InputCallback { -    std::function<void(StatusType)> on_change; -}; - -/// An abstract class template for an input device (a button, an analog input, etc.). -template <typename StatusType> -class InputDevice { -public: -    virtual ~InputDevice() = default; -    virtual StatusType GetStatus() const { -        return {}; -    } -    virtual StatusType GetRawStatus() const { -        return GetStatus(); -    } -    virtual AnalogProperties GetAnalogProperties() const { -        return {}; -    } -    virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const { -        return {}; -    } -    virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low, -                               [[maybe_unused]] f32 amp_high, -                               [[maybe_unused]] f32 freq_high) const { -        return {}; -    } -    void SetCallback(InputCallback<StatusType> callback_) { -        callback = std::move(callback_); -    } -    void TriggerOnChange() { -        if (callback.on_change) { -            callback.on_change(GetStatus()); -        } -    } - -private: -    InputCallback<StatusType> callback; -}; - -/// 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 contains all parameters for creating the device - */ -template <typename InputDeviceType> -std::unique_ptr<InputDeviceType> CreateDevice(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); -} - -/** - * A button device is an input device that returns bool as status. - * true for pressed; false for released. - */ -using ButtonDevice = InputDevice<bool>; - -/** - * An analog device is an input device that returns a tuple of x and y coordinates as status. The - * coordinates are within the unit circle. x+ is defined as right direction, and y+ is defined as up - * direction - */ -using AnalogDevice = InputDevice<std::tuple<float, float>>; - -/** - * A vibration device is an input device that returns an unsigned byte as status. - * It represents whether the vibration device supports vibration or not. - * If the status returns 1, it supports vibration. Otherwise, it does not support vibration. - */ -using VibrationDevice = InputDevice<u8>; - -/** - * A motion status is an object that returns a tuple of accelerometer state vector, - * gyroscope state vector, rotation state vector, orientation state matrix and quaterion state - * vector. - * - * For both 3D vectors: - *   x+ is the same direction as RIGHT on D-pad. - *   y+ is normal to the touch screen, pointing outward. - *   z+ is the same direction as UP on D-pad. - * - * For accelerometer state vector - *   Units: g (gravitational acceleration) - * - * For gyroscope state vector: - *   Orientation is determined by right-hand rule. - *   Units: deg/sec - * - * For rotation state vector - *   Units: rotations - * - * For orientation state matrix - *   x vector - *   y vector - *   z vector - * - * For quaternion state vector - *   xyz vector - *   w float - */ -using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>, -                                std::array<Common::Vec3f, 3>, Common::Quaternion<f32>>; - -/** - * A motion device is an input device that returns a motion status object - */ -using MotionDevice = InputDevice<MotionStatus>; - -/** - * A touch status is an object that returns an array of 16 tuple elements of two floats and a bool. - * The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is - * pressed. - */ -using TouchStatus = std::array<std::tuple<float, float, bool>, 16>; - -/** - * A touch device is an input device that returns a touch status object - */ -using TouchDevice = InputDevice<TouchStatus>; - -/** - * A mouse device is an input device that returns a tuple of two floats and four ints. - * The first two floats are X and Y device coordinates of the mouse (from 0-1). - * The s32s are the mouse wheel. - */ -using MouseDevice = InputDevice<std::tuple<float, float, s32, s32>>; - -} // 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 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/core.h" -#include "core/frontend/input_interpreter.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/hid.h" -#include "core/hle/service/sm/sm.h" - -InputInterpreter::InputInterpreter(Core::System& system) -    : npad{system.ServiceManager() -               .GetService<Service::HID::Hid>("hid") -               ->GetAppletResource() -               ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} { -    ResetButtonStates(); -} - -InputInterpreter::~InputInterpreter() = default; - -void InputInterpreter::PollInput() { -    const u32 button_state = npad.GetAndResetPressState(); - -    previous_index = current_index; -    current_index = (current_index + 1) % button_states.size(); - -    button_states[current_index] = button_state; -} - -void InputInterpreter::ResetButtonStates() { -    previous_index = 0; -    current_index = 0; - -    button_states[0] = 0xFFFFFFFF; - -    for (std::size_t i = 1; i < button_states.size(); ++i) { -        button_states[i] = 0; -    } -} - -bool InputInterpreter::IsButtonPressed(HIDButton button) const { -    return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; -} - -bool InputInterpreter::IsButtonPressedOnce(HIDButton button) const { -    const bool current_press = -        (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; -    const bool previous_press = -        (button_states[previous_index] & (1U << static_cast<u8>(button))) != 0; - -    return current_press && !previous_press; -} - -bool InputInterpreter::IsButtonHeld(HIDButton button) const { -    u32 held_buttons{button_states[0]}; - -    for (std::size_t i = 1; i < button_states.size(); ++i) { -        held_buttons &= button_states[i]; -    } - -    return (held_buttons & (1U << static_cast<u8>(button))) != 0; -} 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 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> - -#include "common/common_types.h" - -namespace Core { -class System; -} - -namespace Service::HID { -class Controller_NPad; -} - -enum class HIDButton : u8 { -    A, -    B, -    X, -    Y, -    LStick, -    RStick, -    L, -    R, -    ZL, -    ZR, -    Plus, -    Minus, - -    DLeft, -    DUp, -    DRight, -    DDown, - -    LStickLeft, -    LStickUp, -    LStickRight, -    LStickDown, - -    RStickLeft, -    RStickUp, -    RStickRight, -    RStickDown, - -    LeftSL, -    LeftSR, - -    RightSL, -    RightSR, -}; - -/** - * The InputInterpreter class interfaces with HID to retrieve button press states. - * Input is intended to be polled every 50ms so that a button is considered to be - * held down after 400ms has elapsed since the initial button press and subsequent - * repeated presses occur every 50ms. - */ -class InputInterpreter { -public: -    explicit InputInterpreter(Core::System& system); -    virtual ~InputInterpreter(); - -    /// Gets a button state from HID and inserts it into the array of button states. -    void PollInput(); - -    /// Resets all the button states to their defaults. -    void ResetButtonStates(); - -    /** -     * Checks whether the button is pressed. -     * -     * @param button The button to check. -     * -     * @returns True when the button is pressed. -     */ -    [[nodiscard]] bool IsButtonPressed(HIDButton button) const; - -    /** -     * Checks whether any of the buttons in the parameter list is pressed. -     * -     * @tparam HIDButton The buttons to check. -     * -     * @returns True when at least one of the buttons is pressed. -     */ -    template <HIDButton... T> -    [[nodiscard]] bool IsAnyButtonPressed() { -        return (IsButtonPressed(T) || ...); -    } - -    /** -     * The specified button is considered to be pressed once -     * if it is currently pressed and not pressed previously. -     * -     * @param button The button to check. -     * -     * @returns True when the button is pressed once. -     */ -    [[nodiscard]] bool IsButtonPressedOnce(HIDButton button) const; - -    /** -     * Checks whether any of the buttons in the parameter list is pressed once. -     * -     * @tparam T The buttons to check. -     * -     * @returns True when at least one of the buttons is pressed once. -     */ -    template <HIDButton... T> -    [[nodiscard]] bool IsAnyButtonPressedOnce() const { -        return (IsButtonPressedOnce(T) || ...); -    } - -    /** -     * The specified button is considered to be held down if it is pressed in all 9 button states. -     * -     * @param button The button to check. -     * -     * @returns True when the button is held down. -     */ -    [[nodiscard]] bool IsButtonHeld(HIDButton button) const; - -    /** -     * Checks whether any of the buttons in the parameter list is held down. -     * -     * @tparam T The buttons to check. -     * -     * @returns True when at least one of the buttons is held down. -     */ -    template <HIDButton... T> -    [[nodiscard]] bool IsAnyButtonHeld() const { -        return (IsButtonHeld(T) || ...); -    } - -private: -    Service::HID::Controller_NPad& npad; - -    /// Stores 9 consecutive button states polled from HID. -    std::array<u32, 9> button_states{}; - -    std::size_t previous_index{}; -    std::size_t current_index{}; -}; | 
