diff options
Diffstat (limited to 'src/core/hid')
| -rw-r--r-- | src/core/hid/input_interpreter.cpp | 62 | ||||
| -rw-r--r-- | src/core/hid/input_interpreter.h | 144 | 
2 files changed, 206 insertions, 0 deletions
diff --git a/src/core/hid/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp new file mode 100644 index 000000000..c33d8a11a --- /dev/null +++ b/src/core/hid/input_interpreter.cpp @@ -0,0 +1,62 @@ +// 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/hid/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/hid/input_interpreter.h b/src/core/hid/input_interpreter.h new file mode 100644 index 000000000..9495e3daf --- /dev/null +++ b/src/core/hid/input_interpreter.h @@ -0,0 +1,144 @@ +// 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{}; +};  | 
