summaryrefslogtreecommitdiffstats
path: root/src/core/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/frontend')
-rw-r--r--src/core/frontend/applets/controller.cpp45
-rw-r--r--src/core/frontend/applets/controller.h8
-rw-r--r--src/core/frontend/emu_window.cpp98
-rw-r--r--src/core/frontend/emu_window.h30
-rw-r--r--src/core/frontend/input.h217
-rw-r--r--src/core/frontend/input_interpreter.cpp62
-rw-r--r--src/core/frontend/input_interpreter.h144
7 files changed, 39 insertions, 565 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/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{};
-};