code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"

namespace Core {
class System;
}

namespace Core::HID {
struct FirmwareVersion;
struct VibrationDeviceHandle;
struct VibrationValue;
struct VibrationDeviceInfo;
} // namespace Core::HID

namespace Core::Timing {
struct EventType;
}

namespace Kernel {
class KEvent;
class KSharedMemory;
} // namespace Kernel

namespace Service::HID {
class AppletResource;
class CaptureButton;
class Controller_Stubbed;
class ConsoleSixAxis;
class DebugMouse;
class DebugPad;
class Digitizer;
class Gesture;
class HidFirmwareSettings;
class HomeButton;
class Keyboard;
class Mouse;
class NPad;
class Palma;
class SevenSixAxis;
class SixAxis;
class SleepButton;
class TouchScreen;
class TouchDriver;
class TouchResource;
class UniquePad;
class NpadVibrationBase;
class NpadN64VibrationDevice;
class NpadGcVibrationDevice;
class NpadVibrationDevice;
struct HandheldConfig;

class ResourceManager {

public:
    explicit ResourceManager(Core::System& system_, std::shared_ptr<HidFirmwareSettings> settings);
    ~ResourceManager();

    void Initialize();

    std::shared_ptr<AppletResource> GetAppletResource() const;
    std::shared_ptr<CaptureButton> GetCaptureButton() const;
    std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const;
    std::shared_ptr<DebugMouse> GetDebugMouse() const;
    std::shared_ptr<DebugPad> GetDebugPad() const;
    std::shared_ptr<Digitizer> GetDigitizer() const;
    std::shared_ptr<Gesture> GetGesture() const;
    std::shared_ptr<HomeButton> GetHomeButton() const;
    std::shared_ptr<Keyboard> GetKeyboard() const;
    std::shared_ptr<Mouse> GetMouse() const;
    std::shared_ptr<NPad> GetNpad() const;
    std::shared_ptr<Palma> GetPalma() const;
    std::shared_ptr<SevenSixAxis> GetSevenSixAxis() const;
    std::shared_ptr<SixAxis> GetSixAxis() const;
    std::shared_ptr<SleepButton> GetSleepButton() const;
    std::shared_ptr<TouchScreen> GetTouchScreen() const;
    std::shared_ptr<UniquePad> GetUniquePad() const;

    Result CreateAppletResource(u64 aruid);

    Result RegisterCoreAppletResource();
    Result UnregisterCoreAppletResource();
    Result RegisterAppletResourceUserId(u64 aruid, bool bool_value);
    void UnregisterAppletResourceUserId(u64 aruid);

    Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
    void FreeAppletResourceId(u64 aruid);

    void EnableInput(u64 aruid, bool is_enabled);
    void EnableSixAxisSensor(u64 aruid, bool is_enabled);
    void EnablePadInput(u64 aruid, bool is_enabled);
    void EnableTouchScreen(u64 aruid, bool is_enabled);

    NpadVibrationBase* GetVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
    NpadN64VibrationDevice* GetN64VibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
    NpadVibrationDevice* GetNSVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
    NpadGcVibrationDevice* GetGcVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
    Result SetAruidValidForVibration(u64 aruid, bool is_enabled);
    void SetForceHandheldStyleVibration(bool is_forced);
    Result IsVibrationAruidActive(u64 aruid, bool& is_active) const;
    Result GetVibrationDeviceInfo(Core::HID::VibrationDeviceInfo& device_info,
                                  const Core::HID::VibrationDeviceHandle& handle);
    Result SendVibrationValue(u64 aruid, const Core::HID::VibrationDeviceHandle& handle,
                              const Core::HID::VibrationValue& value);

    Result GetTouchScreenFirmwareVersion(Core::HID::FirmwareVersion& firmware) const;

    void UpdateControllers(std::chrono::nanoseconds ns_late);
    void UpdateNpad(std::chrono::nanoseconds ns_late);
    void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late);
    void UpdateMotion(std::chrono::nanoseconds ns_late);

private:
    Result CreateAppletResourceImpl(u64 aruid);
    void InitializeHandheldConfig();
    void InitializeHidCommonSampler();
    void InitializeTouchScreenSampler();
    void InitializeConsoleSixAxisSampler();
    void InitializeAHidSampler();

    bool is_initialized{false};

    mutable std::recursive_mutex shared_mutex;
    std::shared_ptr<AppletResource> applet_resource{nullptr};

    mutable std::mutex input_mutex;
    Kernel::KEvent* input_event{nullptr};

    std::shared_ptr<HandheldConfig> handheld_config{nullptr};
    std::shared_ptr<HidFirmwareSettings> firmware_settings{nullptr};

    std::shared_ptr<CaptureButton> capture_button{nullptr};
    std::shared_ptr<ConsoleSixAxis> console_six_axis{nullptr};
    std::shared_ptr<DebugMouse> debug_mouse{nullptr};
    std::shared_ptr<DebugPad> debug_pad{nullptr};
    std::shared_ptr<Digitizer> digitizer{nullptr};
    std::shared_ptr<HomeButton> home_button{nullptr};
    std::shared_ptr<Keyboard> keyboard{nullptr};
    std::shared_ptr<Mouse> mouse{nullptr};
    std::shared_ptr<NPad> npad{nullptr};
    std::shared_ptr<Palma> palma{nullptr};
    std::shared_ptr<SevenSixAxis> seven_six_axis{nullptr};
    std::shared_ptr<SixAxis> six_axis{nullptr};
    std::shared_ptr<SleepButton> sleep_button{nullptr};
    std::shared_ptr<UniquePad> unique_pad{nullptr};
    std::shared_ptr<Core::Timing::EventType> npad_update_event;
    std::shared_ptr<Core::Timing::EventType> default_update_event;
    std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
    std::shared_ptr<Core::Timing::EventType> motion_update_event;

    // TODO: Create these resources
    // std::shared_ptr<AudioControl> audio_control{nullptr};
    // std::shared_ptr<ButtonConfig> button_config{nullptr};
    // std::shared_ptr<Config> config{nullptr};
    // std::shared_ptr<Connection> connection{nullptr};
    // std::shared_ptr<CustomConfig> custom_config{nullptr};
    // std::shared_ptr<Digitizer> digitizer{nullptr};
    // std::shared_ptr<Hdls> hdls{nullptr};
    // std::shared_ptr<PlayReport> play_report{nullptr};
    // std::shared_ptr<Rail> rail{nullptr};

    // Touch Resources
    std::shared_ptr<Gesture> gesture{nullptr};
    std::shared_ptr<TouchScreen> touch_screen{nullptr};
    std::shared_ptr<TouchResource> touch_resource{nullptr};
    std::shared_ptr<TouchDriver> touch_driver{nullptr};
    std::shared_ptr<Core::Timing::EventType> touch_update_event{nullptr};

    Core::System& system;
    KernelHelpers::ServiceContext service_context;
};

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "core/core_timing.h"
#include "hid_core/hid_result.h"
#include "hid_core/hid_util.h"
#include "hid_core/resources/abstracted_pad/abstract_battery_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
#include "hid_core/resources/applet_resource.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/shared_memory_format.h"

namespace Service::HID {

NpadAbstractBatteryHandler::NpadAbstractBatteryHandler() {}

NpadAbstractBatteryHandler::~NpadAbstractBatteryHandler() = default;

void NpadAbstractBatteryHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
    abstract_pad_holder = holder;
}

void NpadAbstractBatteryHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
    applet_resource_holder = applet_resource;
}

void NpadAbstractBatteryHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
    properties_handler = handler;
}

Result NpadAbstractBatteryHandler::IncrementRefCounter() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }
    ref_counter++;
    return ResultSuccess;
}

Result NpadAbstractBatteryHandler::DecrementRefCounter() {
    if (ref_counter == 0) {
        return ResultNpadHandlerNotInitialized;
    }
    ref_counter--;
    return ResultSuccess;
}

Result NpadAbstractBatteryHandler::UpdateBatteryState(u64 aruid) {
    const auto npad_index = NpadIdTypeToIndex(properties_handler->GetNpadId());
    AruidData* aruid_data = applet_resource_holder->applet_resource->GetAruidData(aruid);
    if (aruid_data == nullptr) {
        return ResultSuccess;
    }

    auto& npad_internal_state =
        aruid_data->shared_memory_format->npad.npad_entry[npad_index].internal_state;
    auto& system_properties = npad_internal_state.system_properties;

    system_properties.is_charging_joy_dual.Assign(dual_battery.is_charging);
    system_properties.is_powered_joy_dual.Assign(dual_battery.is_powered);
    system_properties.is_charging_joy_left.Assign(left_battery.is_charging);
    system_properties.is_powered_joy_left.Assign(left_battery.is_powered);
    system_properties.is_charging_joy_right.Assign(right_battery.is_charging);
    system_properties.is_powered_joy_right.Assign(right_battery.is_powered);

    npad_internal_state.battery_level_dual = dual_battery.battery_level;
    npad_internal_state.battery_level_left = left_battery.battery_level;
    npad_internal_state.battery_level_right = right_battery.battery_level;

    return ResultSuccess;
}

void NpadAbstractBatteryHandler::UpdateBatteryState() {
    if (ref_counter == 0) {
        return;
    }
    has_new_battery_data = GetNewBatteryState();
}

bool NpadAbstractBatteryHandler::GetNewBatteryState() {
    bool has_changed = false;
    Core::HID::NpadPowerInfo new_dual_battery_state{};
    Core::HID::NpadPowerInfo new_left_battery_state{};
    Core::HID::NpadPowerInfo new_right_battery_state{};
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        const auto power_info = abstract_pad->power_info;
        if (power_info.battery_level > Core::HID::NpadBatteryLevel::Full) {
            // Abort
            continue;
        }

        const auto style = abstract_pad->assignment_style;

        if (style.is_external_assigned || style.is_handheld_assigned) {
            new_dual_battery_state = power_info;
        }
        if (style.is_external_left_assigned || style.is_handheld_left_assigned) {
            new_left_battery_state = power_info;
        }
        if (style.is_external_right_assigned || style.is_handheld_right_assigned) {
            new_right_battery_state = power_info;
        }

        if (abstract_pad->internal_flags.is_battery_low_ovln_required) {
            if (abstract_pad->interface_type == Core::HID::NpadInterfaceType::Rail) {
                // TODO
            }
            abstract_pad->internal_flags.is_battery_low_ovln_required.Assign(false);
        }
    }

    if (dual_battery.battery_level != new_dual_battery_state.battery_level ||
        dual_battery.is_charging != new_dual_battery_state.is_charging ||
        dual_battery.is_powered != new_dual_battery_state.is_powered) {
        has_changed = true;
        dual_battery = new_dual_battery_state;
    }

    if (left_battery.battery_level != new_left_battery_state.battery_level ||
        left_battery.is_charging != new_left_battery_state.is_charging ||
        left_battery.is_powered != new_left_battery_state.is_powered) {
        has_changed = true;
        left_battery = new_left_battery_state;
    }

    if (right_battery.battery_level != new_right_battery_state.battery_level ||
        right_battery.is_charging != new_right_battery_state.is_charging ||
        right_battery.is_powered != new_right_battery_state.is_powered) {
        has_changed = true;
        right_battery = new_right_battery_state;
    }

    return has_changed;
}

void NpadAbstractBatteryHandler::UpdateCoreBatteryState() {
    if (ref_counter == 0) {
        return;
    }
    if (!has_new_battery_data) {
        return;
    }

    UpdateBatteryState(0);
}

void NpadAbstractBatteryHandler::InitializeBatteryState(u64 aruid) {
    UpdateBatteryState(aruid);
}

bool NpadAbstractBatteryHandler::HasBattery() const {
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    for (std::size_t i = 0; i < count; i++) {
        const auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        return abstract_pad->disabled_feature_set.has_fullkey_battery ||
               abstract_pad->disabled_feature_set.has_left_right_joy_battery;
    }

    return false;
}

void NpadAbstractBatteryHandler::HasLeftRightBattery(bool& has_left, bool& has_right) const {
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    has_left = false;
    has_right = false;

    for (std::size_t i = 0; i < count; i++) {
        const auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        if (!abstract_pad->disabled_feature_set.has_fullkey_battery &&
            !abstract_pad->disabled_feature_set.has_left_right_joy_battery) {
            continue;
        }
        has_left = abstract_pad->assignment_style.is_external_left_assigned ||
                   abstract_pad->assignment_style.is_handheld_left_assigned;
        has_right = abstract_pad->assignment_style.is_external_right_assigned ||
                    abstract_pad->assignment_style.is_handheld_right_assigned;
    }
}

} // namespace Service::HID

repo_name: litucks/torzu

license: mit


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"

namespace Service::HID {
struct AppletResourceHolder;
class NpadAbstractedPadHolder;
class NpadAbstractPropertiesHandler;

/// Handles Npad request from HID interfaces
class NpadAbstractBatteryHandler final {
public:
    explicit NpadAbstractBatteryHandler();
    ~NpadAbstractBatteryHandler();

    void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
    void SetAppletResource(AppletResourceHolder* applet_resource);
    void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);

    Result IncrementRefCounter();
    Result DecrementRefCounter();

    Result UpdateBatteryState(u64 aruid);
    void UpdateBatteryState();
    bool GetNewBatteryState();
    void UpdateCoreBatteryState();
    void InitializeBatteryState(u64 aruid);

    bool HasBattery() const;
    void HasLeftRightBattery(bool& has_left, bool& has_right) const;

private:
    AppletResourceHolder* applet_resource_holder{nullptr};
    NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
    NpadAbstractPropertiesHandler* properties_handler{nullptr};

    s32 ref_counter{};
    Core::HID::NpadPowerInfo dual_battery{};
    Core::HID::NpadPowerInfo left_battery{};
    Core::HID::NpadPowerInfo right_battery{};
    bool has_new_battery_data{};
};

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "hid_core/hid_result.h"
#include "hid_core/hid_util.h"
#include "hid_core/resources/abstracted_pad/abstract_button_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
#include "hid_core/resources/applet_resource.h"
#include "hid_core/resources/npad/npad_resource.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/shared_memory_format.h"

namespace Service::HID {

NpadAbstractButtonHandler::NpadAbstractButtonHandler() {}

NpadAbstractButtonHandler::~NpadAbstractButtonHandler() = default;

void NpadAbstractButtonHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
    abstract_pad_holder = holder;
}

void NpadAbstractButtonHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
    applet_resource_holder = applet_resource;
}

void NpadAbstractButtonHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
    properties_handler = handler;
}

Result NpadAbstractButtonHandler::IncrementRefCounter() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }
    ref_counter++;
    return ResultSuccess;
}

Result NpadAbstractButtonHandler::DecrementRefCounter() {
    if (ref_counter == 0) {
        return ResultNpadHandlerNotInitialized;
    }
    ref_counter--;
    return ResultSuccess;
}

Result NpadAbstractButtonHandler::UpdateAllButtonWithHomeProtection(u64 aruid) {
    const Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
    auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid);

    if (data == nullptr) {
        return ResultSuccess;
    }

    auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
    UpdateButtonLifo(npad_entry, aruid);

    bool is_home_button_protection_enabled{};
    const auto result = applet_resource_holder->shared_npad_resource->GetHomeProtectionEnabled(
        is_home_button_protection_enabled, aruid, npad_id);

    if (result.IsError()) {
        return ResultSuccess;
    }

    npad_entry.internal_state.button_properties.is_home_button_protection_enabled.Assign(
        is_home_button_protection_enabled);

    return ResultSuccess;
}

void NpadAbstractButtonHandler::UpdateAllButtonLifo() {
    Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
    for (std::size_t i = 0; i < AruidIndexMax; i++) {
        auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
        auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
        UpdateButtonLifo(npad_entry, data->aruid);
    }
}

void NpadAbstractButtonHandler::UpdateCoreBatteryState() {
    Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
    for (std::size_t i = 0; i < AruidIndexMax; i++) {
        auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
        auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
        UpdateButtonLifo(npad_entry, data->aruid);
    }
}

void NpadAbstractButtonHandler::UpdateButtonState(u64 aruid) {
    Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
    auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid);
    if (data == nullptr) {
        return;
    }
    auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
    UpdateButtonLifo(npad_entry, aruid);
}

Result NpadAbstractButtonHandler::SetHomeProtection(bool is_enabled, u64 aruid) {
    const Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
    auto result = applet_resource_holder->shared_npad_resource->SetHomeProtectionEnabled(
        aruid, npad_id, is_enabled);
    if (result.IsError()) {
        return result;
    }

    auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid);
    if (data == nullptr) {
        return ResultSuccess;
    }

    bool is_home_protection_enabled{};
    result = applet_resource_holder->shared_npad_resource->GetHomeProtectionEnabled(
        is_home_protection_enabled, aruid, npad_id);
    if (result.IsError()) {
        return ResultSuccess;
    }

    auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
    npad_entry.internal_state.button_properties.is_home_button_protection_enabled.Assign(
        is_home_protection_enabled);
    return ResultSuccess;
}

bool NpadAbstractButtonHandler::IsButtonPressedOnConsoleMode() {
    return is_button_pressed_on_console_mode;
}

void NpadAbstractButtonHandler::EnableCenterClamp() {
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        abstract_pad->internal_flags.use_center_clamp.Assign(true);
    }
}

void NpadAbstractButtonHandler::UpdateButtonLifo(NpadSharedMemoryEntry& shared_memory, u64 aruid) {
    auto* npad_resource = applet_resource_holder->shared_npad_resource;
    Core::HID::NpadStyleTag style_tag = {properties_handler->GetStyleSet(aruid)};
    style_tag.system_ext.Assign(npad_resource->GetActiveData()->GetNpadSystemExtState());

    UpdateNpadFullkeyLifo(style_tag, 0, aruid, shared_memory);
    UpdateHandheldLifo(style_tag, 1, aruid, shared_memory);
    UpdateJoyconDualLifo(style_tag, 2, aruid, shared_memory);
    UpdateJoyconLeftLifo(style_tag, 3, aruid, shared_memory);
    UpdateJoyconRightLifo(style_tag, 4, aruid, shared_memory);
    UpdatePalmaLifo(style_tag, 5, aruid, shared_memory);
    UpdateSystemExtLifo(style_tag, 6, aruid, shared_memory);
}

void NpadAbstractButtonHandler::UpdateNpadFullkeyLifo(Core::HID::NpadStyleTag style_tag,
                                                      int style_index, u64 aruid,
                                                      NpadSharedMemoryEntry& shared_memory) {
    // TODO
}

void NpadAbstractButtonHandler::UpdateHandheldLifo(Core::HID::NpadStyleTag style_tag,
                                                   int style_index, u64 aruid,
                                                   NpadSharedMemoryEntry& shared_memory) {
    // TODO
}

void NpadAbstractButtonHandler::UpdateJoyconDualLifo(Core::HID::NpadStyleTag style_tag,
                                                     int style_index, u64 aruid,
                                                     NpadSharedMemoryEntry& shared_memory) {
    // TODO
}

void NpadAbstractButtonHandler::UpdateJoyconLeftLifo(Core::HID::NpadStyleTag style_tag,
                                                     int style_index, u64 aruid,
                                                     NpadSharedMemoryEntry& shared_memory) {
    // TODO
}

void NpadAbstractButtonHandler::UpdateJoyconRightLifo(Core::HID::NpadStyleTag style_tag,
                                                      int style_index, u64 aruid,
                                                      NpadSharedMemoryEntry& shared_memory) {
    // TODO
}

void NpadAbstractButtonHandler::UpdateSystemExtLifo(Core::HID::NpadStyleTag style_tag,
                                                    int style_index, u64 aruid,
                                                    NpadSharedMemoryEntry& shared_memory) {
    // TODO
}

void NpadAbstractButtonHandler::UpdatePalmaLifo(Core::HID::NpadStyleTag style_tag, int style_index,
                                                u64 aruid, NpadSharedMemoryEntry& shared_memory) {
    // TODO
}

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"

namespace Service::HID {
struct NpadSharedMemoryEntry;

struct AppletResourceHolder;
class NpadAbstractedPadHolder;
class NpadAbstractPropertiesHandler;

/// Handles Npad request from HID interfaces
class NpadAbstractButtonHandler final {
public:
    explicit NpadAbstractButtonHandler();
    ~NpadAbstractButtonHandler();

    void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
    void SetAppletResource(AppletResourceHolder* applet_resource);
    void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);

    Result IncrementRefCounter();
    Result DecrementRefCounter();

    Result UpdateAllButtonWithHomeProtection(u64 aruid);

    void UpdateAllButtonLifo();
    void UpdateCoreBatteryState();
    void UpdateButtonState(u64 aruid);

    Result SetHomeProtection(bool is_enabled, u64 aruid);
    bool IsButtonPressedOnConsoleMode();
    void EnableCenterClamp();

    void UpdateButtonLifo(NpadSharedMemoryEntry& shared_memory, u64 aruid);

    void UpdateNpadFullkeyLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
                               NpadSharedMemoryEntry& shared_memory);
    void UpdateHandheldLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
                            NpadSharedMemoryEntry& shared_memory);
    void UpdateJoyconDualLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
                              NpadSharedMemoryEntry& shared_memory);
    void UpdateJoyconLeftLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
                              NpadSharedMemoryEntry& shared_memory);
    void UpdateJoyconRightLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
                               NpadSharedMemoryEntry& shared_memory);
    void UpdateSystemExtLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
                             NpadSharedMemoryEntry& shared_memory);
    void UpdatePalmaLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
                         NpadSharedMemoryEntry& shared_memory);

private:
    struct GcTrigger {
        float left;
        float right;
    };

    AppletResourceHolder* applet_resource_holder{nullptr};
    NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
    NpadAbstractPropertiesHandler* properties_handler{nullptr};

    s32 ref_counter{};

    bool is_button_pressed_on_console_mode{};

    u64 gc_sampling_number{};
    GcTrigger gc_trigger_state{};
};

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "hid_core/hid_result.h"
#include "hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
#include "hid_core/resources/npad/npad_types.h"

namespace Service::HID {

NpadAbstractIrSensorHandler::NpadAbstractIrSensorHandler() {}

NpadAbstractIrSensorHandler::~NpadAbstractIrSensorHandler() = default;

void NpadAbstractIrSensorHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
    abstract_pad_holder = holder;
}

void NpadAbstractIrSensorHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
    properties_handler = handler;
}

Result NpadAbstractIrSensorHandler::IncrementRefCounter() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }
    ref_counter++;
    return ResultSuccess;
}

Result NpadAbstractIrSensorHandler::DecrementRefCounter() {
    if (ref_counter == 0) {
        return ResultNpadHandlerNotInitialized;
    }
    ref_counter--;
    return ResultSuccess;
}

void NpadAbstractIrSensorHandler::UpdateIrSensorState() {
    const auto previous_state = sensor_state;
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    if (count == 0) {
        sensor_state = NpadIrSensorState::Disabled;
        if (sensor_state == previous_state) {
            return;
        }
        ir_sensor_event->Signal();
        return;
    }

    bool is_found{};
    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        if (!abstract_pad->disabled_feature_set.has_bluetooth_address) {
            continue;
        }
        is_found = true;
        xcd_handle = abstract_pad->xcd_handle;
    }

    if (is_found) {
        if (sensor_state == NpadIrSensorState::Active) {
            return;
        }
        sensor_state = NpadIrSensorState::Available;
        if (sensor_state == previous_state) {
            return;
        }
        ir_sensor_event->Signal();
        return;
    }

    sensor_state = NpadIrSensorState::Unavailable;
    if (sensor_state == previous_state) {
        return;
    }

    ir_sensor_event->Signal();
    return;
}

Result NpadAbstractIrSensorHandler::ActivateIrSensor(bool is_enabled) {
    if (sensor_state == NpadIrSensorState::Unavailable) {
        return ResultIrSensorIsNotReady;
    }
    if (is_enabled && sensor_state == NpadIrSensorState::Available) {
        sensor_state = NpadIrSensorState::Active;
    } else {
        if (is_enabled) {
            return ResultSuccess;
        }
        if (sensor_state != NpadIrSensorState::Active) {
            return ResultSuccess;
        }
        sensor_state = NpadIrSensorState::Available;
    }
    ir_sensor_event->Signal();
    return ResultSuccess;
}

Result NpadAbstractIrSensorHandler::GetIrSensorEventHandle(Kernel::KReadableEvent** out_event) {
    *out_event = &ir_sensor_event->GetReadableEvent();
    return ResultSuccess;
}

Result NpadAbstractIrSensorHandler::GetXcdHandleForNpadWithIrSensor(u64& handle) const {
    if (sensor_state < NpadIrSensorState::Available) {
        return ResultIrSensorIsNotReady;
    }
    // handle = xcd_handle;
    return ResultSuccess;
}

NpadIrSensorState NpadAbstractIrSensorHandler::GetSensorState() const {
    return sensor_state;
}

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"

namespace Core::HID {
class EmulatedController;
}

namespace Kernel {
class KEvent;
class KReadableEvent;
} // namespace Kernel

enum class NpadIrSensorState : u32 {
    Disabled,
    Unavailable,
    Available,
    Active,
};

namespace Service::HID {
class NpadAbstractedPadHolder;
class NpadAbstractPropertiesHandler;

/// Handles Npad request from HID interfaces
class NpadAbstractIrSensorHandler final {
public:
    explicit NpadAbstractIrSensorHandler();
    ~NpadAbstractIrSensorHandler();

    void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
    void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);

    Result IncrementRefCounter();
    Result DecrementRefCounter();

    void UpdateIrSensorState();
    Result ActivateIrSensor(bool param_2);

    Result GetIrSensorEventHandle(Kernel::KReadableEvent** out_event);

    Result GetXcdHandleForNpadWithIrSensor(u64& handle) const;

    NpadIrSensorState GetSensorState() const;

private:
    NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
    NpadAbstractPropertiesHandler* properties_handler{nullptr};

    s32 ref_counter{};
    Kernel::KEvent* ir_sensor_event{nullptr};
    Core::HID::EmulatedController* xcd_handle{};
    NpadIrSensorState sensor_state{};
};
} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "core/core_timing.h"
#include "hid_core/hid_result.h"
#include "hid_core/hid_util.h"
#include "hid_core/resources/abstracted_pad/abstract_led_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
#include "hid_core/resources/applet_resource.h"
#include "hid_core/resources/npad/npad_types.h"

namespace Service::HID {

NpadAbstractLedHandler::NpadAbstractLedHandler() {}

NpadAbstractLedHandler::~NpadAbstractLedHandler() = default;

void NpadAbstractLedHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
    abstract_pad_holder = holder;
}

void NpadAbstractLedHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
    applet_resource_holder = applet_resource;
}

void NpadAbstractLedHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
    properties_handler = handler;
}

Result NpadAbstractLedHandler::IncrementRefCounter() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }
    ref_counter++;
    return ResultSuccess;
}

Result NpadAbstractLedHandler::DecrementRefCounter() {
    if (ref_counter == 0) {
        return ResultNpadHandlerNotInitialized;
    }
    ref_counter--;
    return ResultSuccess;
}

void NpadAbstractLedHandler::SetNpadLedHandlerLedPattern() {
    const auto npad_id = properties_handler->GetNpadId();

    switch (npad_id) {
    case Core::HID::NpadIdType::Player1:
        left_pattern = Core::HID::LedPattern{1, 0, 0, 0};
        break;
    case Core::HID::NpadIdType::Player2:
        left_pattern = Core::HID::LedPattern{1, 1, 0, 0};
        break;
    case Core::HID::NpadIdType::Player3:
        left_pattern = Core::HID::LedPattern{1, 1, 1, 0};
        break;
    case Core::HID::NpadIdType::Player4:
        left_pattern = Core::HID::LedPattern{1, 1, 1, 1};
        break;
    case Core::HID::NpadIdType::Player5:
        left_pattern = Core::HID::LedPattern{1, 0, 0, 1};
        break;
    case Core::HID::NpadIdType::Player6:
        left_pattern = Core::HID::LedPattern{1, 0, 1, 0};
        break;
    case Core::HID::NpadIdType::Player7:
        left_pattern = Core::HID::LedPattern{1, 0, 1, 1};
        break;
    case Core::HID::NpadIdType::Player8:
        left_pattern = Core::HID::LedPattern{0, 1, 1, 0};
        break;
    case Core::HID::NpadIdType::Other:
    case Core::HID::NpadIdType::Handheld:
        left_pattern = Core::HID::LedPattern{0, 0, 0, 0};
        break;
    default:
        ASSERT_MSG(false, "Invalid npad id type");
        break;
    }

    switch (npad_id) {
    case Core::HID::NpadIdType::Player1:
        right_pattern = Core::HID::LedPattern{0, 0, 0, 1};
        break;
    case Core::HID::NpadIdType::Player2:
        right_pattern = Core::HID::LedPattern{0, 1, 1, 1};
        break;
    case Core::HID::NpadIdType::Player3:
        right_pattern = Core::HID::LedPattern{0, 1, 1, 1};
        break;
    case Core::HID::NpadIdType::Player4:
        right_pattern = Core::HID::LedPattern{1, 1, 1, 1};
        break;
    case Core::HID::NpadIdType::Player5:
        right_pattern = Core::HID::LedPattern{1, 0, 0, 1};
        break;
    case Core::HID::NpadIdType::Player6:
        right_pattern = Core::HID::LedPattern{0, 1, 0, 1};
        break;
    case Core::HID::NpadIdType::Player7:
        right_pattern = Core::HID::LedPattern{1, 1, 0, 1};
        break;
    case Core::HID::NpadIdType::Player8:
        right_pattern = Core::HID::LedPattern{0, 1, 1, 0};
        break;
    case Core::HID::NpadIdType::Other:
    case Core::HID::NpadIdType::Handheld:
        right_pattern = Core::HID::LedPattern{0, 0, 0, 0};
        break;
    default:
        ASSERT_MSG(false, "Invalid npad id type");
        break;
    }
}

void NpadAbstractLedHandler::SetLedBlinkingDevice(Core::HID::LedPattern pattern) {
    led_blinking = pattern;
}

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"

namespace Service::HID {
struct AppletResourceHolder;
class NpadAbstractedPadHolder;
class NpadAbstractPropertiesHandler;

/// Handles Npad request from HID interfaces
class NpadAbstractLedHandler final {
public:
    explicit NpadAbstractLedHandler();
    ~NpadAbstractLedHandler();

    void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
    void SetAppletResource(AppletResourceHolder* applet_resource);
    void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);

    Result IncrementRefCounter();
    Result DecrementRefCounter();

    void SetNpadLedHandlerLedPattern();

    void SetLedBlinkingDevice(Core::HID::LedPattern pattern);

private:
    AppletResourceHolder* applet_resource_holder{nullptr};
    NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
    NpadAbstractPropertiesHandler* properties_handler{nullptr};

    s32 ref_counter{};
    Core::HID::LedPattern led_blinking{0, 0, 0, 0};
    Core::HID::LedPattern left_pattern{0, 0, 0, 0};
    Core::HID::LedPattern right_pattern{0, 0, 0, 0};
    u64 led_interval{};
};
} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "hid_core/hid_result.h"
#include "hid_core/resources/abstracted_pad/abstract_mcu_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
#include "hid_core/resources/npad/npad_types.h"

namespace Service::HID {

NpadAbstractMcuHandler::NpadAbstractMcuHandler() {}

NpadAbstractMcuHandler::~NpadAbstractMcuHandler() = default;

void NpadAbstractMcuHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
    abstract_pad_holder = holder;
}

void NpadAbstractMcuHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
    properties_handler = handler;
}

Result NpadAbstractMcuHandler::IncrementRefCounter() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }
    ref_counter++;
    return ResultSuccess;
}

Result NpadAbstractMcuHandler::DecrementRefCounter() {
    if (ref_counter == 0) {
        return ResultNpadHandlerNotInitialized;
    }
    ref_counter--;
    return ResultSuccess;
}

void NpadAbstractMcuHandler::UpdateMcuState() {
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = properties_handler->GetAbstractedPads(abstract_pads);

    if (count == 0) {
        mcu_holder = {};
        return;
    }

    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        if (!abstract_pad->disabled_feature_set.has_left_joy_rail_bus) {
            if (!abstract_pad->disabled_feature_set.has_left_joy_six_axis_sensor &&
                !abstract_pad->disabled_feature_set.has_right_joy_six_axis_sensor) {
                continue;
            }
            if (mcu_holder[1].state != NpadMcuState::Active) {
                mcu_holder[1].state = NpadMcuState::Available;
            }
            mcu_holder[1].abstracted_pad = abstract_pad;
            continue;
        }
        if (mcu_holder[0].state != NpadMcuState::Active) {
            mcu_holder[0].state = NpadMcuState::Available;
        }
        mcu_holder[0].abstracted_pad = abstract_pad;
    }
}

Result NpadAbstractMcuHandler::GetAbstractedPad(IAbstractedPad** data, u32 mcu_index) {
    if (mcu_holder[mcu_index].state == NpadMcuState::None ||
        mcu_holder[mcu_index].abstracted_pad == nullptr) {
        return ResultMcuIsNotReady;
    }
    *data = mcu_holder[mcu_index].abstracted_pad;
    return ResultSuccess;
}

NpadMcuState NpadAbstractMcuHandler::GetMcuState(u32 mcu_index) {
    return mcu_holder[mcu_index].state;
}

Result NpadAbstractMcuHandler::SetMcuState(bool is_enabled, u32 mcu_index) {
    NpadMcuState& state = mcu_holder[mcu_index].state;

    if (state == NpadMcuState::None) {
        return ResultMcuIsNotReady;
    }

    if ((is_enabled) && (state == NpadMcuState::Available)) {
        state = NpadMcuState::Active;
        return ResultSuccess;
    }

    if (is_enabled) {
        return ResultSuccess;
    }
    if (state != NpadMcuState::Active) {
        return ResultSuccess;
    }

    state = NpadMcuState::Available;
    return ResultSuccess;
}

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"

namespace Service::HID {
struct IAbstractedPad;
class NpadAbstractedPadHolder;
class NpadAbstractPropertiesHandler;

enum class NpadMcuState : u32 {
    None,
    Available,
    Active,
};

struct NpadMcuHolder {
    NpadMcuState state;
    INSERT_PADDING_BYTES(0x4);
    IAbstractedPad* abstracted_pad;
};
static_assert(sizeof(NpadMcuHolder) == 0x10, "NpadMcuHolder is an invalid size");

/// Handles Npad request from HID interfaces
class NpadAbstractMcuHandler final {
public:
    explicit NpadAbstractMcuHandler();
    ~NpadAbstractMcuHandler();

    void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
    void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);

    Result IncrementRefCounter();
    Result DecrementRefCounter();

    void UpdateMcuState();
    Result GetAbstractedPad(IAbstractedPad** data, u32 mcu_index);
    NpadMcuState GetMcuState(u32 mcu_index);
    Result SetMcuState(bool is_enabled, u32 mcu_index);

private:
    NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
    NpadAbstractPropertiesHandler* properties_handler{nullptr};

    s32 ref_counter{};
    std::array<NpadMcuHolder, 2> mcu_holder{};
};
} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "hid_core/hid_result.h"
#include "hid_core/resources/abstracted_pad/abstract_nfc_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
#include "hid_core/resources/npad/npad_types.h"

namespace Service::HID {

NpadAbstractNfcHandler::NpadAbstractNfcHandler() {}

NpadAbstractNfcHandler::~NpadAbstractNfcHandler() = default;

void NpadAbstractNfcHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
    abstract_pad_holder = holder;
}

void NpadAbstractNfcHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
    properties_handler = handler;
}

Result NpadAbstractNfcHandler::IncrementRefCounter() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }
    ref_counter++;
    return ResultSuccess;
}

Result NpadAbstractNfcHandler::DecrementRefCounter() {
    if (ref_counter == 0) {
        return ResultNpadHandlerNotInitialized;
    }
    ref_counter--;
    return ResultSuccess;
}

void NpadAbstractNfcHandler::UpdateNfcState() {
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = properties_handler->GetAbstractedPads(abstract_pads);

    if (count == 0) {
        if (sensor_state == NpadNfcState::Active) {
            nfc_activate_event->Signal();
        }
        if (sensor_state == NpadNfcState::Unavailable) {
            return;
        }
        sensor_state = NpadNfcState::Unavailable;
        input_event->Signal();
        return;
    }

    bool is_found{};
    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        if (!abstract_pad->disabled_feature_set.has_nfc) {
            continue;
        }
        is_found = true;
        xcd_handle = 0;
    }

    if (is_found) {
        if (sensor_state == NpadNfcState::Active) {
            return;
        }
        if (sensor_state == NpadNfcState::Available) {
            return;
        }
        sensor_state = NpadNfcState::Available;
        input_event->Signal();
        return;
    }

    if (sensor_state == NpadNfcState::Active) {
        nfc_activate_event->Signal();
    }
    if (sensor_state == NpadNfcState::Unavailable) {
        return;
    }
    sensor_state = NpadNfcState::Unavailable;
    input_event->Signal();
    return;
}

bool NpadAbstractNfcHandler::HasNfcSensor() {
    return sensor_state != NpadNfcState::Unavailable;
}

bool NpadAbstractNfcHandler::IsNfcActivated() {
    return sensor_state == NpadNfcState::Active;
}

Result NpadAbstractNfcHandler::GetAcquireNfcActivateEventHandle(
    Kernel::KReadableEvent** out_event) {
    *out_event = &nfc_activate_event->GetReadableEvent();
    return ResultSuccess;
}

void NpadAbstractNfcHandler::SetInputEvent(Kernel::KEvent* event) {
    input_event = event;
}

Result NpadAbstractNfcHandler::ActivateNfc(bool is_enabled) {
    if (sensor_state == NpadNfcState::Active) {
        return ResultNfcIsNotReady;
    }

    NpadNfcState new_state = NpadNfcState::Available;
    if (is_enabled) {
        new_state = NpadNfcState::Active;
    }
    if (sensor_state != new_state) {
        sensor_state = new_state;
        nfc_activate_event->Signal();
    }
    return ResultSuccess;
}

Result NpadAbstractNfcHandler::GetXcdHandleWithNfc(u64& out_xcd_handle) const {
    if (sensor_state == NpadNfcState::Unavailable) {
        return ResultNfcIsNotReady;
    }
    if (xcd_handle == 0) {
        return ResultNfcXcdHandleIsNotInitialized;
    }

    out_xcd_handle = xcd_handle;
    return ResultSuccess;
}

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"

namespace Kernel {
class KReadableEvent;
}

enum class NpadNfcState : u32 {
    Unavailable,
    Available,
    Active,
};

namespace Service::HID {
class NpadAbstractedPadHolder;
class NpadAbstractPropertiesHandler;

/// Handles Npad request from HID interfaces
class NpadAbstractNfcHandler final {
public:
    explicit NpadAbstractNfcHandler();
    ~NpadAbstractNfcHandler();

    void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
    void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);

    Result IncrementRefCounter();
    Result DecrementRefCounter();

    void UpdateNfcState();
    bool HasNfcSensor();
    bool IsNfcActivated();

    Result GetAcquireNfcActivateEventHandle(Kernel::KReadableEvent** out_event);
    void SetInputEvent(Kernel::KEvent* event);

    Result ActivateNfc(bool is_enabled);

    Result GetXcdHandleWithNfc(u64& out_xcd_handle) const;

private:
    NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
    NpadAbstractPropertiesHandler* properties_handler{nullptr};

    s32 ref_counter{};
    Kernel::KEvent* nfc_activate_event{nullptr};
    Kernel::KEvent* input_event{nullptr};
    u64 xcd_handle{};
    NpadNfcState sensor_state{NpadNfcState::Unavailable};
};
} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "hid_core/hid_core.h"
#include "hid_core/hid_result.h"
#include "hid_core/resources/abstracted_pad/abstract_pad.h"
#include "hid_core/resources/applet_resource.h"
#include "hid_core/resources/npad/npad_types.h"

namespace Service::HID {

AbstractPad::AbstractPad() {}

AbstractPad::~AbstractPad() = default;

void AbstractPad::SetExternals(AppletResourceHolder* applet_resource,
                               CaptureButtonResource* capture_button_resource,
                               HomeButtonResource* home_button_resource,
                               SixAxisResource* sixaxis_resource, PalmaResource* palma_resource,
                               NpadVibration* vibration, Core::HID::HIDCore* core) {
    applet_resource_holder = applet_resource;

    properties_handler.SetAppletResource(applet_resource_holder);
    properties_handler.SetAbstractPadHolder(&abstract_pad_holder);

    led_handler.SetAppletResource(applet_resource_holder);
    led_handler.SetAbstractPadHolder(&abstract_pad_holder);
    led_handler.SetPropertiesHandler(&properties_handler);

    ir_sensor_handler.SetAbstractPadHolder(&abstract_pad_holder);
    ir_sensor_handler.SetPropertiesHandler(&properties_handler);

    nfc_handler.SetAbstractPadHolder(&abstract_pad_holder);
    nfc_handler.SetPropertiesHandler(&properties_handler);

    mcu_handler.SetAbstractPadHolder(&abstract_pad_holder);
    mcu_handler.SetPropertiesHandler(&properties_handler);

    vibration_handler.SetAppletResource(applet_resource_holder);
    vibration_handler.SetAbstractPadHolder(&abstract_pad_holder);
    vibration_handler.SetPropertiesHandler(&properties_handler);
    vibration_handler.SetN64Vibration(&vibration_n64);
    vibration_handler.SetVibration(&vibration_left, &vibration_right);
    vibration_handler.SetGcVibration(&vibration_gc);
    vibration_handler.SetVibrationHandler(vibration);
    vibration_handler.SetHidCore(core);

    sixaxis_handler.SetAppletResource(applet_resource_holder);
    sixaxis_handler.SetAbstractPadHolder(&abstract_pad_holder);
    sixaxis_handler.SetPropertiesHandler(&properties_handler);
    sixaxis_handler.SetSixaxisResource(sixaxis_resource);

    button_handler.SetAppletResource(applet_resource_holder);
    button_handler.SetAbstractPadHolder(&abstract_pad_holder);
    button_handler.SetPropertiesHandler(&properties_handler);

    battery_handler.SetAppletResource(applet_resource_holder);
    battery_handler.SetAbstractPadHolder(&abstract_pad_holder);
    battery_handler.SetPropertiesHandler(&properties_handler);

    palma_handler.SetAbstractPadHolder(&abstract_pad_holder);
    palma_handler.SetPropertiesHandler(&properties_handler);
    palma_handler.SetPalmaResource(palma_resource);
}

void AbstractPad::SetNpadId(Core::HID::NpadIdType npad_id) {
    properties_handler.SetNpadId(npad_id);
}

Result AbstractPad::Activate() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }

    if (ref_counter != 0) {
        ref_counter++;
        return ResultSuccess;
    }

    std::size_t stage = 0;
    Result result = ResultSuccess;

    if (result.IsSuccess()) {
        stage++;
        result = properties_handler.IncrementRefCounter();
    }
    if (result.IsSuccess()) {
        stage++;
        result = led_handler.IncrementRefCounter();
    }
    if (result.IsSuccess()) {
        stage++;
        result = ir_sensor_handler.IncrementRefCounter();
    }
    if (result.IsSuccess()) {
        stage++;
        result = mcu_handler.IncrementRefCounter();
    }
    if (result.IsSuccess()) {
        stage++;
        result = nfc_handler.IncrementRefCounter();
    }
    if (result.IsSuccess()) {
        stage++;
        result = vibration_handler.IncrementRefCounter();
    }
    if (result.IsSuccess()) {
        stage++;
        result = sixaxis_handler.IncrementRefCounter();
    }
    if (result.IsSuccess()) {
        stage++;
        result = button_handler.IncrementRefCounter();
    }
    if (result.IsSuccess()) {
        stage++;
        result = battery_handler.IncrementRefCounter();
    }
    if (result.IsSuccess()) {
        stage++;
        result = palma_handler.IncrementRefCounter();
    }

    if (result.IsSuccess()) {
        ref_counter++;
        return result;
    }

    if (stage > 9) {
        battery_handler.DecrementRefCounter();
    }
    if (stage > 8) {
        button_handler.DecrementRefCounter();
    }
    if (stage > 7) {
        sixaxis_handler.DecrementRefCounter();
    }
    if (stage > 6) {
        vibration_handler.DecrementRefCounter();
    }
    if (stage > 5) {
        nfc_handler.DecrementRefCounter();
    }
    if (stage > 4) {
        mcu_handler.DecrementRefCounter();
    }
    if (stage > 3) {
        ir_sensor_handler.DecrementRefCounter();
    }
    if (stage > 2) {
        led_handler.DecrementRefCounter();
    }
    if (stage > 1) {
        properties_handler.DecrementRefCounter();
    }
    return result;
}

Result AbstractPad::Deactivate() {
    if (ref_counter == 0) {
        return ResultNpadResourceNotInitialized;
    }

    ref_counter--;
    battery_handler.DecrementRefCounter();
    button_handler.DecrementRefCounter();
    sixaxis_handler.DecrementRefCounter();
    vibration_handler.DecrementRefCounter();
    nfc_handler.DecrementRefCounter();
    ir_sensor_handler.DecrementRefCounter();
    mcu_handler.DecrementRefCounter();
    led_handler.DecrementRefCounter();
    properties_handler.DecrementRefCounter();
    palma_handler.DecrementRefCounter();

    return ResultSuccess;
}

Result AbstractPad::ActivateNpad(u64 aruid) {
    Result result = ResultSuccess;
    if (result.IsSuccess()) {
        result = properties_handler.ActivateNpadUnknown0x88(aruid);
    }
    if (result.IsSuccess()) {
        result = sixaxis_handler.UpdateSixAxisState2(aruid);
    }
    if (result.IsSuccess()) {
        result = battery_handler.UpdateBatteryState(aruid);
    }
    return result;
}

NpadAbstractedPadHolder* AbstractPad::GetAbstractedPadHolder() {
    return &abstract_pad_holder;
}

NpadAbstractPropertiesHandler* AbstractPad::GetAbstractPropertiesHandler() {
    return &properties_handler;
}

NpadAbstractLedHandler* AbstractPad::GetAbstractLedHandler() {
    return &led_handler;
}

NpadAbstractIrSensorHandler* AbstractPad::GetAbstractIrSensorHandler() {
    return &ir_sensor_handler;
}

NpadAbstractMcuHandler* AbstractPad::GetAbstractMcuHandler() {
    return &mcu_handler;
}

NpadAbstractNfcHandler* AbstractPad::GetAbstractNfcHandler() {
    return &nfc_handler;
}

NpadAbstractVibrationHandler* AbstractPad::GetAbstractVibrationHandler() {
    return &vibration_handler;
}

NpadAbstractSixAxisHandler* AbstractPad::GetAbstractSixAxisHandler() {
    return &sixaxis_handler;
}

NpadAbstractButtonHandler* AbstractPad::GetAbstractButtonHandler() {
    return &button_handler;
}

NpadAbstractBatteryHandler* AbstractPad::GetAbstractBatteryHandler() {
    return &battery_handler;
}

NpadN64VibrationDevice* AbstractPad::GetN64VibrationDevice() {
    return &vibration_n64;
}

NpadVibrationDevice* AbstractPad::GetVibrationDevice(Core::HID::DeviceIndex device_index) {
    if (device_index == Core::HID::DeviceIndex::Right) {
        return &vibration_right;
    }
    return &vibration_left;
}

NpadGcVibrationDevice* AbstractPad::GetGCVibrationDevice() {
    return &vibration_gc;
}

Core::HID::NpadIdType AbstractPad::GetLastActiveNpad() {
    return properties_handler.GetNpadId();
}

void AbstractPad::UpdateInterfaceType() {
    if (interface_type != properties_handler.GetInterfaceType()) {
        Update();
    }
    battery_handler.UpdateBatteryState();
}

void AbstractPad::Update() {
    properties_handler.UpdateDeviceType();
    led_handler.SetNpadLedHandlerLedPattern();
    vibration_handler.UpdateVibrationState();
    sixaxis_handler.UpdateSixAxisState();
    nfc_handler.UpdateNfcState();
    ir_sensor_handler.UpdateIrSensorState();
    mcu_handler.UpdateMcuState();
    palma_handler.UpdatePalmaState();
    battery_handler.UpdateBatteryState();
    button_handler.EnableCenterClamp();

    interface_type = properties_handler.GetInterfaceType();

    std::scoped_lock lock{*applet_resource_holder->shared_mutex};
    properties_handler.UpdateAllDeviceProperties();
    battery_handler.UpdateCoreBatteryState();
    button_handler.UpdateCoreBatteryState();
}

void AbstractPad::UpdatePadState() {
    button_handler.UpdateAllButtonLifo();
    sixaxis_handler.UpdateSixAxisState();
    battery_handler.UpdateCoreBatteryState();
}

void AbstractPad::EnableAppletToGetInput(u64 aruid) {
    button_handler.UpdateButtonState(aruid);
    sixaxis_handler.UpdateSixAxisState(aruid);
    battery_handler.UpdateBatteryState(aruid);
}

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <array>
#include <mutex>

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"
#include "hid_core/resources/applet_resource.h"
#include "hid_core/resources/npad/npad_types.h"

#include "hid_core/resources/abstracted_pad/abstract_battery_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_button_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_led_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_mcu_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_nfc_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/abstracted_pad/abstract_palma_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_vibration_handler.h"
#include "hid_core/resources/vibration/gc_vibration_device.h"
#include "hid_core/resources/vibration/n64_vibration_device.h"
#include "hid_core/resources/vibration/vibration_device.h"

namespace Service::HID {
class AppletResource;
class SixAxisResource;
class PalmaResource;
class NPadResource;
class NpadLastActiveHandler;
class NpadIrNfcHandler;
class UniquePads;
class NpadPalmaHandler;
class FirmwareResource;
class NpadVibration;
class NpadHighestBattery;
class NpadGcVibration;

class CaptureButtonResource;
class HomeButtonResource;

struct HandheldConfig;

/// Handles Npad request from HID interfaces
class AbstractPad final {
public:
    explicit AbstractPad();
    ~AbstractPad();

    void SetExternals(AppletResourceHolder* applet_resource,
                      CaptureButtonResource* capture_button_resource,
                      HomeButtonResource* home_button_resource, SixAxisResource* sixaxis_resource,
                      PalmaResource* palma_resource, NpadVibration* vibration,
                      Core::HID::HIDCore* core);
    void SetNpadId(Core::HID::NpadIdType npad_id);

    Result Activate();
    Result Deactivate();

    Result ActivateNpad(u64 aruid);

    NpadAbstractedPadHolder* GetAbstractedPadHolder();
    NpadAbstractPropertiesHandler* GetAbstractPropertiesHandler();
    NpadAbstractLedHandler* GetAbstractLedHandler();
    NpadAbstractIrSensorHandler* GetAbstractIrSensorHandler();
    NpadAbstractMcuHandler* GetAbstractMcuHandler();
    NpadAbstractNfcHandler* GetAbstractNfcHandler();
    NpadAbstractVibrationHandler* GetAbstractVibrationHandler();
    NpadAbstractSixAxisHandler* GetAbstractSixAxisHandler();
    NpadAbstractButtonHandler* GetAbstractButtonHandler();
    NpadAbstractBatteryHandler* GetAbstractBatteryHandler();

    NpadN64VibrationDevice* GetN64VibrationDevice();
    NpadVibrationDevice* GetVibrationDevice(Core::HID::DeviceIndex device_index);
    NpadGcVibrationDevice* GetGCVibrationDevice();

    Core::HID::NpadIdType GetLastActiveNpad();
    void UpdateInterfaceType();
    void Update();

    void UpdatePadState();
    void EnableAppletToGetInput(u64 aruid);

private:
    AppletResourceHolder* applet_resource_holder{nullptr};
    NpadAbstractedPadHolder abstract_pad_holder{};
    NpadAbstractPropertiesHandler properties_handler{};
    NpadAbstractLedHandler led_handler{};
    NpadAbstractIrSensorHandler ir_sensor_handler{};
    NpadAbstractNfcHandler nfc_handler{};
    NpadAbstractMcuHandler mcu_handler{};
    NpadAbstractVibrationHandler vibration_handler{};
    NpadAbstractSixAxisHandler sixaxis_handler{};
    NpadAbstractButtonHandler button_handler{};
    NpadAbstractBatteryHandler battery_handler{};
    NpadAbstractPalmaHandler palma_handler{};

    NpadN64VibrationDevice vibration_n64{};
    NpadVibrationDevice vibration_left{};
    NpadVibrationDevice vibration_right{};
    NpadGcVibrationDevice vibration_gc{};

    // SixAxisConfigHolder fullkey_config;
    // SixAxisConfigHolder handheld_config;
    // SixAxisConfigHolder dual_left_config;
    // SixAxisConfigHolder dual_right_config;
    // SixAxisConfigHolder left_config;
    // SixAxisConfigHolder right_config;

    s32 ref_counter{};
    Core::HID::NpadInterfaceType interface_type{Core::HID::NpadInterfaceType::None};
};

using FullAbstractPad = std::array<AbstractPad, MaxSupportedNpadIdTypes>;

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "hid_core/hid_result.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/npad/npad_types.h"

namespace Service::HID {

Result NpadAbstractedPadHolder::RegisterAbstractPad(IAbstractedPad* abstracted_pad) {
    if (list_size >= assignment_list.size()) {
        return ResultNpadIsNotProController;
    }

    for (std::size_t i = 0; i < list_size; i++) {
        if (assignment_list[i].device_type == abstracted_pad->device_type) {
            return ResultNpadIsNotProController;
        }
    }

    assignment_list[list_size] = {
        .abstracted_pad = abstracted_pad,
        .device_type = abstracted_pad->device_type,
        .interface_type = abstracted_pad->interface_type,
        .controller_id = abstracted_pad->controller_id,
    };

    list_size++;
    return ResultSuccess;
}

void NpadAbstractedPadHolder::RemoveAbstractPadByControllerId(u64 controller_id) {
    if (list_size == 0) {
        return;
    }
    if (controller_id == 0) {
        return;
    }
    for (std::size_t i = 0; i < list_size; i++) {
        if (assignment_list[i].controller_id != controller_id) {
            continue;
        }
        for (std::size_t e = i + 1; e < list_size; e++) {
            assignment_list[e - 1] = assignment_list[e];
        }
        list_size--;
        return;
    }
}

void NpadAbstractedPadHolder::DetachAbstractedPad() {
    while (list_size > 0) {
        for (std::size_t i = 1; i < list_size; i++) {
            assignment_list[i - 1] = assignment_list[i];
        }
        list_size--;
    }
}

u64 NpadAbstractedPadHolder::RemoveAbstractPadByAssignmentStyle(
    Service::HID::AssignmentStyle assignment_style) {
    for (std::size_t i = 0; i < list_size; i++) {
        if ((assignment_style.raw & assignment_list[i].abstracted_pad->assignment_style.raw) == 0) {
            continue;
        }
        for (std::size_t e = i + 1; e < list_size; e++) {
            assignment_list[e - 1] = assignment_list[e];
        }
        list_size--;
        return list_size;
    }
    return list_size;
}

u32 NpadAbstractedPadHolder::GetAbstractedPads(std::span<IAbstractedPad*> list) const {
    u32 num_elements = std::min(static_cast<u32>(list.size()), list_size);
    for (std::size_t i = 0; i < num_elements; i++) {
        list[i] = assignment_list[i].abstracted_pad;
    }
    return num_elements;
}

void NpadAbstractedPadHolder::SetAssignmentMode(const NpadJoyAssignmentMode& mode) {
    assignment_mode = mode;
}

NpadJoyAssignmentMode NpadAbstractedPadHolder::GetAssignmentMode() const {
    return assignment_mode;
}

std::size_t NpadAbstractedPadHolder::GetStyleIndexList(
    std::span<Core::HID::NpadStyleIndex> list) const {
    for (std::size_t i = 0; i < list_size; i++) {
        list[i] = assignment_list[i].device_type;
    }
    return list_size;
}

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <array>
#include <mutex>
#include <span>

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"
#include "hid_core/resources/npad/npad_types.h"

namespace Service::HID {
struct IAbstractedPad;

struct AbstractAssignmentHolder {
    IAbstractedPad* abstracted_pad;
    Core::HID::NpadStyleIndex device_type;
    Core::HID::NpadInterfaceType interface_type;
    INSERT_PADDING_BYTES(0x6);
    u64 controller_id;
};
static_assert(sizeof(AbstractAssignmentHolder) == 0x18,
              "AbstractAssignmentHolder  is an invalid size");

/// This is nn::hid::server::NpadAbstractedPadHolder
class NpadAbstractedPadHolder final {
public:
    Result RegisterAbstractPad(IAbstractedPad* abstracted_pad);
    void RemoveAbstractPadByControllerId(u64 controller_id);
    void DetachAbstractedPad();
    u64 RemoveAbstractPadByAssignmentStyle(Service::HID::AssignmentStyle assignment_style);
    u32 GetAbstractedPads(std::span<IAbstractedPad*> list) const;

    void SetAssignmentMode(const NpadJoyAssignmentMode& mode);
    NpadJoyAssignmentMode GetAssignmentMode() const;

    std::size_t GetStyleIndexList(std::span<Core::HID::NpadStyleIndex> list) const;

private:
    std::array<AbstractAssignmentHolder, 5> assignment_list{};
    u32 list_size{};
    NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
};
} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "hid_core/hid_result.h"
#include "hid_core/resources/abstracted_pad/abstract_palma_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"

namespace Service::HID {

NpadAbstractPalmaHandler::NpadAbstractPalmaHandler() {}

NpadAbstractPalmaHandler::~NpadAbstractPalmaHandler() = default;

void NpadAbstractPalmaHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
    abstract_pad_holder = holder;
}

void NpadAbstractPalmaHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
    properties_handler = handler;
    return;
}

void NpadAbstractPalmaHandler::SetPalmaResource(PalmaResource* resource) {
    palma_resource = resource;
}

Result NpadAbstractPalmaHandler::IncrementRefCounter() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }
    ref_counter++;
    return ResultSuccess;
}

Result NpadAbstractPalmaHandler::DecrementRefCounter() {
    if (ref_counter == 0) {
        return ResultNpadHandlerNotInitialized;
    }
    ref_counter--;
    return ResultSuccess;
}

void NpadAbstractPalmaHandler::UpdatePalmaState() {
    // TODO
}

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"

namespace Service::HID {
class NpadAbstractedPadHolder;
class NpadAbstractPropertiesHandler;
class PalmaResource;

class NpadAbstractPalmaHandler final {
public:
    explicit NpadAbstractPalmaHandler();
    ~NpadAbstractPalmaHandler();

    void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
    void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
    void SetPalmaResource(PalmaResource* resource);

    Result IncrementRefCounter();
    Result DecrementRefCounter();

    void UpdatePalmaState();

private:
    NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
    NpadAbstractPropertiesHandler* properties_handler{nullptr};
    PalmaResource* palma_resource{nullptr};

    s32 ref_counter{};
};

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "hid_core/hid_util.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
#include "hid_core/resources/applet_resource.h"
#include "hid_core/resources/npad/npad_resource.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/shared_memory_format.h"

namespace Service::HID {

NpadAbstractPropertiesHandler::NpadAbstractPropertiesHandler() {}

NpadAbstractPropertiesHandler::~NpadAbstractPropertiesHandler() = default;

void NpadAbstractPropertiesHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
    abstract_pad_holder = holder;
    return;
}

void NpadAbstractPropertiesHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
    applet_resource_holder = applet_resource;
    return;
}

void NpadAbstractPropertiesHandler::SetNpadId(Core::HID::NpadIdType npad_id) {
    if (!IsNpadIdValid(npad_id)) {
        ASSERT_MSG(false, "Invalid npad id");
    }

    npad_id_type = npad_id;
}

Core::HID::NpadIdType NpadAbstractPropertiesHandler::GetNpadId() const {
    return npad_id_type;
}

Result NpadAbstractPropertiesHandler::IncrementRefCounter() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }

    if (ref_counter != 0) {
        ref_counter++;
        return ResultSuccess;
    }

    const auto npad_index = NpadIdTypeToIndex(npad_id_type);
    for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
        auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index);
        auto& internal_state =
            data->shared_memory_format->npad.npad_entry[npad_index].internal_state;
        if (!data->flag.is_assigned) {
            continue;
        }
        internal_state.fullkey_lifo.buffer_count = 0;
        internal_state.handheld_lifo.buffer_count = 0;
        internal_state.joy_dual_lifo.buffer_count = 0;
        internal_state.joy_left_lifo.buffer_count = 0;
        internal_state.joy_right_lifo.buffer_count = 0;
        internal_state.palma_lifo.buffer_count = 0;
        internal_state.system_ext_lifo.buffer_count = 0;
        internal_state.gc_trigger_lifo.buffer_count = 0;
        internal_state.sixaxis_fullkey_lifo.lifo.buffer_count = 0;
        internal_state.sixaxis_handheld_lifo.lifo.buffer_count = 0;
        internal_state.sixaxis_dual_left_lifo.lifo.buffer_count = 0;
        internal_state.sixaxis_dual_right_lifo.lifo.buffer_count = 0;
        internal_state.sixaxis_left_lifo.lifo.buffer_count = 0;
        internal_state.sixaxis_right_lifo.lifo.buffer_count = 0;

        internal_state.style_tag = {Core::HID::NpadStyleSet::None};
        internal_state.assignment_mode = NpadJoyAssignmentMode::Dual;
        internal_state.joycon_color = {};
        internal_state.fullkey_color = {};

        internal_state.system_properties.raw = 0;
        internal_state.button_properties.raw = 0;
        internal_state.device_type.raw = 0;

        internal_state.battery_level_dual = Core::HID::NpadBatteryLevel::Empty;
        internal_state.battery_level_left = Core::HID::NpadBatteryLevel::Empty;
        internal_state.battery_level_right = Core::HID::NpadBatteryLevel::Empty;

        internal_state.applet_footer_type = AppletFooterUiType::None;
        internal_state.applet_footer_attributes = {};
        internal_state.lark_type_l_and_main = {};
        internal_state.lark_type_r = {};

        internal_state.sixaxis_fullkey_properties.is_newly_assigned.Assign(true);
        internal_state.sixaxis_handheld_properties.is_newly_assigned.Assign(true);
        internal_state.sixaxis_dual_left_properties.is_newly_assigned.Assign(true);
        internal_state.sixaxis_dual_right_properties.is_newly_assigned.Assign(true);
        internal_state.sixaxis_left_properties.is_newly_assigned.Assign(true);
        internal_state.sixaxis_right_properties.is_newly_assigned.Assign(true);
    }

    ref_counter++;
    return ResultSuccess;
}

Result NpadAbstractPropertiesHandler::DecrementRefCounter() {
    if (ref_counter == 0) {
        return ResultNpadHandlerNotInitialized;
    }
    ref_counter--;
    return ResultSuccess;
}

Result NpadAbstractPropertiesHandler::ActivateNpadUnknown0x88(u64 aruid) {
    const auto npad_index = NpadIdTypeToIndex(npad_id_type);
    for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
        auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index);
        if (!data->flag.is_assigned || data->aruid != aruid) {
            continue;
        }
        UpdateDeviceProperties(aruid, data->shared_memory_format->npad.npad_entry[npad_index]);
        return ResultSuccess;
    }
    return ResultSuccess;
}

void NpadAbstractPropertiesHandler::UpdateDeviceType() {
    // TODO
}

void NpadAbstractPropertiesHandler::UpdateDeviceColor() {
    // TODO
}

void NpadAbstractPropertiesHandler::UpdateFooterAttributes() {
    // TODO
}

void NpadAbstractPropertiesHandler::UpdateAllDeviceProperties() {
    const auto npad_index = NpadIdTypeToIndex(npad_id_type);
    for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
        auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index);
        if (data == nullptr || !data->flag.is_assigned) {
            continue;
        }
        auto& npad_entry = data->shared_memory_format->npad.npad_entry[npad_index];
        UpdateDeviceProperties(data->aruid, npad_entry);
    }
}

Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetFullkeyInterfaceType() {
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        if (abstract_pad->device_type != Core::HID::NpadStyleIndex::Fullkey) {
            continue;
        }
        if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) {
            // Abort
            continue;
        }
        return abstract_pad->interface_type;
    }

    return Core::HID::NpadInterfaceType::None;
}

Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetInterfaceType() {
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        if (!abstract_pad->disabled_feature_set.has_identification_code) {
            continue;
        }
        if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) {
            // Abort
            continue;
        }
        return abstract_pad->interface_type;
    }
    return Core::HID::NpadInterfaceType::None;
}

Core::HID::NpadStyleSet NpadAbstractPropertiesHandler::GetStyleSet(u64 aruid) {
    // TODO
    return Core::HID::NpadStyleSet::None;
}

std::size_t NpadAbstractPropertiesHandler::GetAbstractedPadsWithStyleTag(
    std::span<IAbstractedPad*> list, Core::HID::NpadStyleTag style) {
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    if (count == 0) {
        return count;
    }

    bool is_supported_style_set{};
    const auto result = applet_resource_holder->shared_npad_resource->IsSupportedNpadStyleSet(
        is_supported_style_set, applet_resource_holder->applet_resource->GetActiveAruid());

    if (!is_supported_style_set || result.IsError()) {
        for (std::size_t i = 0; i < count; i++) {
            // TODO
        }
        return count;
    }

    std::size_t filtered_count{};
    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        const bool is_enabled = true;
        if (is_enabled) {
            list[filtered_count] = abstract_pad;
            filtered_count++;
        }
    }

    return filtered_count;
}

std::size_t NpadAbstractPropertiesHandler::GetAbstractedPads(std::span<IAbstractedPad*> list) {
    Core::HID::NpadStyleTag style{
        GetStyleSet(applet_resource_holder->applet_resource->GetActiveAruid())};
    return GetAbstractedPadsWithStyleTag(list, style);
}

AppletFooterUiType NpadAbstractPropertiesHandler::GetAppletFooterUiType() {
    return applet_ui_type.footer;
}

AppletDetailedUiType NpadAbstractPropertiesHandler::GetAppletDetailedUiType() {
    return applet_ui_type;
}

void NpadAbstractPropertiesHandler::UpdateDeviceProperties(u64 aruid,
                                                           NpadSharedMemoryEntry& internal_state) {
    // TODO
}

Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetNpadInterfaceType() {
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) {
            // Abort
            continue;
        }
        return abstract_pad->interface_type;
    }

    return Core::HID::NpadInterfaceType::None;
}

Result NpadAbstractPropertiesHandler::GetNpadFullKeyGripColor(
    Core::HID::NpadColor& main_color, Core::HID::NpadColor& sub_color) const {
    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    if (applet_ui_type.footer != AppletFooterUiType::SwitchProController) {
        return ResultNpadIsNotProController;
    }

    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        return ResultSuccess;
    }

    return ResultNpadIsNotProController;
}

void NpadAbstractPropertiesHandler::GetNpadLeftRightInterfaceType(
    Core::HID::NpadInterfaceType& out_left_interface,
    Core::HID::NpadInterfaceType& out_right_interface) const {
    out_left_interface = Core::HID::NpadInterfaceType::None;
    out_right_interface = Core::HID::NpadInterfaceType::None;

    std::array<IAbstractedPad*, 5> abstract_pads{};
    const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);

    for (std::size_t i = 0; i < count; i++) {
        auto* abstract_pad = abstract_pads[i];
        if (!abstract_pad->internal_flags.is_connected) {
            continue;
        }
        if (abstract_pad->assignment_style.is_external_left_assigned &&
            abstract_pad->assignment_style.is_handheld_left_assigned) {
            if (abstract_pad->interface_type > Core::HID::NpadInterfaceType::Embedded) {
                // Abort
                continue;
            }
            out_left_interface = abstract_pad->interface_type;
            continue;
        }
        if (abstract_pad->assignment_style.is_external_right_assigned &&
            abstract_pad->assignment_style.is_handheld_right_assigned) {
            if (abstract_pad->interface_type > Core::HID::NpadInterfaceType::Embedded) {
                // Abort
                continue;
            }
            out_right_interface = abstract_pad->interface_type;
            continue;
        }
    }
}

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <span>

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"
#include "hid_core/resources/npad/npad_types.h"

namespace Service::HID {
struct NpadSharedMemoryEntry;

struct AppletResourceHolder;
class NpadAbstractedPadHolder;

struct ColorProperties {
    ColorAttribute attribute;
    Core::HID::NpadControllerColor color;
    INSERT_PADDING_BYTES(0x4);
};

/// Handles Npad request from HID interfaces
class NpadAbstractPropertiesHandler final {
public:
    explicit NpadAbstractPropertiesHandler();
    ~NpadAbstractPropertiesHandler();

    void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
    void SetAppletResource(AppletResourceHolder* applet_resource);
    void SetNpadId(Core::HID::NpadIdType npad_id);

    Core::HID::NpadIdType GetNpadId() const;

    Result IncrementRefCounter();
    Result DecrementRefCounter();

    Result ActivateNpadUnknown0x88(u64 aruid);

    void UpdateDeviceType();
    void UpdateDeviceColor();
    void UpdateFooterAttributes();
    void UpdateAllDeviceProperties();

    Core::HID::NpadInterfaceType GetFullkeyInterfaceType();
    Core::HID::NpadInterfaceType GetInterfaceType();

    Core::HID::NpadStyleSet GetStyleSet(u64 aruid);
    std::size_t GetAbstractedPadsWithStyleTag(std::span<IAbstractedPad*> list,
                                              Core::HID::NpadStyleTag style);
    std::size_t GetAbstractedPads(std::span<IAbstractedPad*> list);

    AppletFooterUiType GetAppletFooterUiType();

    AppletDetailedUiType GetAppletDetailedUiType();

    void UpdateDeviceProperties(u64 aruid, NpadSharedMemoryEntry& internal_state);

    Core::HID::NpadInterfaceType GetNpadInterfaceType();

    Result GetNpadFullKeyGripColor(Core::HID::NpadColor& main_color,
                                   Core::HID::NpadColor& sub_color) const;

    void GetNpadLeftRightInterfaceType(Core::HID::NpadInterfaceType& param_2,
                                       Core::HID::NpadInterfaceType& param_3) const;

private:
    AppletResourceHolder* applet_resource_holder{nullptr};
    NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
    Core::HID::NpadIdType npad_id_type{Core::HID::NpadIdType::Invalid};
    s32 ref_counter{};
    Core::HID::DeviceIndex device_type{};
    AppletDetailedUiType applet_ui_type{};
    AppletFooterUiAttributes applet_ui_attributes{};
    bool is_vertical{};
    bool is_horizontal{};
    bool use_plus{};
    bool use_minus{};
    bool has_directional_buttons{};
    ColorProperties fullkey_color{};
    ColorProperties left_color{};
    ColorProperties right_color{};
};
} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "hid_core/hid_result.h"
#include "hid_core/hid_util.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h"
#include "hid_core/resources/applet_resource.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/shared_memory_format.h"

namespace Service::HID {

NpadAbstractSixAxisHandler::NpadAbstractSixAxisHandler() {}

NpadAbstractSixAxisHandler::~NpadAbstractSixAxisHandler() = default;

void NpadAbstractSixAxisHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
    abstract_pad_holder = holder;
}

void NpadAbstractSixAxisHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
    applet_resource_holder = applet_resource;
}

void NpadAbstractSixAxisHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
    properties_handler = handler;
}

void NpadAbstractSixAxisHandler::SetSixaxisResource(SixAxisResource* resource) {
    six_axis_resource = resource;
}

Result NpadAbstractSixAxisHandler::IncrementRefCounter() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }
    ref_counter++;
    return ResultSuccess;
}

Result NpadAbstractSixAxisHandler::DecrementRefCounter() {
    if (ref_counter == 0) {
        return ResultNpadHandlerNotInitialized;
    }
    ref_counter--;
    return ResultSuccess;
}

u64 NpadAbstractSixAxisHandler::IsFirmwareUpdateAvailable() {
    // TODO
    return false;
}

Result NpadAbstractSixAxisHandler::UpdateSixAxisState() {
    Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
    for (std::size_t i = 0; i < AruidIndexMax; i++) {
        auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
        if (data == nullptr || !data->flag.is_assigned) {
            continue;
        }
        auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
        UpdateSixaxisInternalState(npad_entry, data->aruid,
                                   data->flag.enable_six_axis_sensor.As<bool>());
    }
    return ResultSuccess;
}

Result NpadAbstractSixAxisHandler::UpdateSixAxisState(u64 aruid) {
    Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
    auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid);
    if (data == nullptr) {
        return ResultSuccess;
    }
    auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
    UpdateSixaxisInternalState(npad_entry, data->aruid,
                               data->flag.enable_six_axis_sensor.As<bool>());
    return ResultSuccess;
}

Result NpadAbstractSixAxisHandler::UpdateSixAxisState2(u64 aruid) {
    const auto npad_index = NpadIdTypeToIndex(properties_handler->GetNpadId());
    AruidData* aruid_data = applet_resource_holder->applet_resource->GetAruidData(aruid);
    if (aruid_data == nullptr) {
        return ResultSuccess;
    }
    auto& npad_internal_state = aruid_data->shared_memory_format->npad.npad_entry[npad_index];
    UpdateSixaxisInternalState(npad_internal_state, aruid,
                               aruid_data->flag.enable_six_axis_sensor.As<bool>());
    return ResultSuccess;
}

void NpadAbstractSixAxisHandler::UpdateSixaxisInternalState(NpadSharedMemoryEntry& npad_entry,
                                                            u64 aruid, bool is_sensor_enabled) {
    const Core::HID::NpadStyleTag style_tag{properties_handler->GetStyleSet(aruid)};

    if (!style_tag.palma) {
        UpdateSixaxisFullkeyLifo(style_tag, npad_entry.internal_state.sixaxis_fullkey_lifo,
                                 is_sensor_enabled);
    } else {
        UpdateSixAxisPalmaLifo(style_tag, npad_entry.internal_state.sixaxis_fullkey_lifo,
                               is_sensor_enabled);
    }
    UpdateSixaxisHandheldLifo(style_tag, npad_entry.internal_state.sixaxis_handheld_lifo,
                              is_sensor_enabled);
    UpdateSixaxisDualLifo(style_tag, npad_entry.internal_state.sixaxis_dual_left_lifo,
                          is_sensor_enabled);
    UpdateSixaxisDualLifo(style_tag, npad_entry.internal_state.sixaxis_dual_right_lifo,
                          is_sensor_enabled);
    UpdateSixaxisLeftLifo(style_tag, npad_entry.internal_state.sixaxis_left_lifo,
                          is_sensor_enabled);
    UpdateSixaxisRightLifo(style_tag, npad_entry.internal_state.sixaxis_right_lifo,
                           is_sensor_enabled);
    // TODO: Set sixaxis properties
}

void NpadAbstractSixAxisHandler::UpdateSixaxisFullkeyLifo(Core::HID::NpadStyleTag style_tag,
                                                          NpadSixAxisSensorLifo& sensor_lifo,
                                                          bool is_sensor_enabled) {
    // TODO
}

void NpadAbstractSixAxisHandler::UpdateSixAxisPalmaLifo(Core::HID::NpadStyleTag style_tag,
                                                        NpadSixAxisSensorLifo& sensor_lifo,
                                                        bool is_sensor_enabled) {
    // TODO
}

void NpadAbstractSixAxisHandler::UpdateSixaxisHandheldLifo(Core::HID::NpadStyleTag style_tag,
                                                           NpadSixAxisSensorLifo& sensor_lifo,
                                                           bool is_sensor_enabled) {
    // TODO
}

void NpadAbstractSixAxisHandler::UpdateSixaxisDualLifo(Core::HID::NpadStyleTag style_tag,
                                                       NpadSixAxisSensorLifo& sensor_lifo,
                                                       bool is_sensor_enabled) {
    // TODO
}

void NpadAbstractSixAxisHandler::UpdateSixaxisLeftLifo(Core::HID::NpadStyleTag style_tag,
                                                       NpadSixAxisSensorLifo& sensor_lifo,
                                                       bool is_sensor_enabled) {
    // TODO
}

void NpadAbstractSixAxisHandler::UpdateSixaxisRightLifo(Core::HID::NpadStyleTag style_tag,
                                                        NpadSixAxisSensorLifo& sensor_lifo,
                                                        bool is_sensor_enabled) {
    // TODO
}

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"

namespace Service::HID {
class SixAxisResource;
struct AppletResourceHolder;
class NpadAbstractedPadHolder;
class NpadAbstractPropertiesHandler;
struct NpadSixAxisSensorLifo;

/// Handles Npad request from HID interfaces
class NpadAbstractSixAxisHandler final {
public:
    explicit NpadAbstractSixAxisHandler();
    ~NpadAbstractSixAxisHandler();

    void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
    void SetAppletResource(AppletResourceHolder* applet_resource);
    void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
    void SetSixaxisResource(SixAxisResource* resource);

    Result IncrementRefCounter();
    Result DecrementRefCounter();

    u64 IsFirmwareUpdateAvailable();

    Result UpdateSixAxisState();
    Result UpdateSixAxisState(u64 aruid);
    Result UpdateSixAxisState2(u64 aruid);

private:
    void UpdateSixaxisInternalState(NpadSharedMemoryEntry& npad_entry, u64 aruid,
                                    bool is_sensor_enabled);
    void UpdateSixaxisFullkeyLifo(Core::HID::NpadStyleTag style_tag,
                                  NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
    void UpdateSixAxisPalmaLifo(Core::HID::NpadStyleTag style_tag,
                                NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
    void UpdateSixaxisHandheldLifo(Core::HID::NpadStyleTag style_tag,
                                   NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
    void UpdateSixaxisDualLifo(Core::HID::NpadStyleTag style_tag,
                               NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
    void UpdateSixaxisLeftLifo(Core::HID::NpadStyleTag style_tag,
                               NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
    void UpdateSixaxisRightLifo(Core::HID::NpadStyleTag style_tag,
                                NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);

    AppletResourceHolder* applet_resource_holder{nullptr};
    NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
    NpadAbstractPropertiesHandler* properties_handler{nullptr};
    SixAxisResource* six_axis_resource{nullptr};

    s32 ref_counter{};
};

} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_result.h"
#include "hid_core/hid_util.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
#include "hid_core/resources/abstracted_pad/abstract_vibration_handler.h"
#include "hid_core/resources/applet_resource.h"
#include "hid_core/resources/npad/npad_vibration.h"
#include "hid_core/resources/vibration/gc_vibration_device.h"
#include "hid_core/resources/vibration/n64_vibration_device.h"
#include "hid_core/resources/vibration/vibration_device.h"

namespace Service::HID {

NpadAbstractVibrationHandler::NpadAbstractVibrationHandler() {}

NpadAbstractVibrationHandler::~NpadAbstractVibrationHandler() = default;

void NpadAbstractVibrationHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
    abstract_pad_holder = holder;
}

void NpadAbstractVibrationHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
    applet_resource_holder = applet_resource;
}

void NpadAbstractVibrationHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
    properties_handler = handler;
}

void NpadAbstractVibrationHandler::SetVibrationHandler(NpadVibration* handler) {
    vibration_handler = handler;
}

void NpadAbstractVibrationHandler::SetHidCore(Core::HID::HIDCore* core) {
    hid_core = core;
}

void NpadAbstractVibrationHandler::SetN64Vibration(NpadN64VibrationDevice* n64_device) {
    n64_vibration_device = n64_device;
}

void NpadAbstractVibrationHandler::SetVibration(NpadVibrationDevice* left_device,
                                                NpadVibrationDevice* right_device) {
    left_vibration_device = left_device;
    right_vibration_device = right_device;
}

void NpadAbstractVibrationHandler::SetGcVibration(NpadGcVibrationDevice* gc_device) {
    gc_vibration_device = gc_device;
}

Result NpadAbstractVibrationHandler::IncrementRefCounter() {
    if (ref_counter == std::numeric_limits<s32>::max() - 1) {
        return ResultNpadHandlerOverflow;
    }
    ref_counter++;
    return ResultSuccess;
}

Result NpadAbstractVibrationHandler::DecrementRefCounter() {
    if (ref_counter == 0) {
        return ResultNpadHandlerNotInitialized;
    }
    ref_counter--;
    return ResultSuccess;
}

void NpadAbstractVibrationHandler::UpdateVibrationState() {
    const bool is_handheld_hid_enabled =
        applet_resource_holder->handheld_config->is_handheld_hid_enabled;
    const bool is_force_handheld_style_vibration =
        applet_resource_holder->handheld_config->is_force_handheld_style_vibration;

    if (!is_handheld_hid_enabled && is_force_handheld_style_vibration) {
        // TODO
    }

    // TODO: This function isn't accurate. It's supposed to get 5 abstracted pads from the
    // NpadAbstractPropertiesHandler but this handler isn't fully implemented yet
    IAbstractedPad abstracted_pad{};
    const auto npad_id = properties_handler->GetNpadId();
    abstracted_pad.xcd_handle = hid_core->GetEmulatedController(npad_id);
    abstracted_pad.internal_flags.is_connected.Assign(abstracted_pad.xcd_handle->IsConnected());

    if (abstracted_pad.internal_flags.is_connected) {
        left_vibration_device->Mount(abstracted_pad, Core::HID::DeviceIndex::Left,
                                     vibration_handler);
        right_vibration_device->Mount(abstracted_pad, Core::HID::DeviceIndex::Right,
                                      vibration_handler);
        gc_vibration_device->Mount(abstracted_pad, 0, vibration_handler);
        gc_vibration_device->Mount(abstracted_pad, 0, vibration_handler);
        n64_vibration_device->Mount(abstracted_pad, vibration_handler);
        return;
    }

    left_vibration_device->Unmount();
    right_vibration_device->Unmount();
    gc_vibration_device->Unmount();
    gc_vibration_device->Unmount();
    n64_vibration_device->Unmount();
}
} // namespace Service::HID


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <span>

#include "common/common_types.h"
#include "core/hle/result.h"
#include "hid_core/hid_types.h"

namespace Core::HID {
class HIDCore;
}

namespace Service::HID {
struct AppletResourceHolder;
class NpadAbstractedPadHolder;
class NpadAbstractPropertiesHandler;
class NpadGcVibrationDevice;
class NpadVibrationDevice;
class NpadN64VibrationDevice;
class NpadVibration;

/// Keeps track of battery levels and updates npad battery shared memory values
class NpadAbstractVibrationHandler final {
public:
    explicit NpadAbstractVibrationHandler();
    ~NpadAbstractVibrationHandler();

    void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
    void SetAppletResource(AppletResourceHolder* applet_resource);
    void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
    void SetVibrationHandler(NpadVibration* handler);
    void SetHidCore(Core::HID::HIDCore* core);

    void SetN64Vibration(NpadN64VibrationDevice* n64_device);
    void SetVibration(NpadVibrationDevice* left_device, NpadVibrationDevice* right_device);
    void SetGcVibration(NpadGcVibrationDevice* gc_device);

    Result IncrementRefCounter();
    Result DecrementRefCounter();

    void UpdateVibrationState();

private:
    AppletResourceHolder* applet_resource_holder{nullptr};
    NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
    NpadAbstractPropertiesHandler* properties_handler{nullptr};
    Core::HID::HIDCore* hid_core{nullptr};

    NpadN64VibrationDevice* n64_vibration_device{nullptr};
    NpadVibrationDevice* left_vibration_device{};
    NpadVibrationDevice* right_vibration_device{};
    NpadGcVibrationDevice* gc_vibration_device{nullptr};
    NpadVibration* vibration_handler{nullptr};
    s32 ref_counter{};
};
} // namespace Service::HID