summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar liamwhite2024-01-20 13:34:54 -0500
committerGravatar GitHub2024-01-20 13:34:54 -0500
commit5838779162897606a3525eb619379a56b2eec027 (patch)
tree3c3530e2f955545968fcc605122aa7565f4b5f1a /src
parentMerge pull request #12701 from liamwhite/flinger-layer-issues (diff)
parentservice: hid: Fully implement abstract vibration (diff)
downloadyuzu-5838779162897606a3525eb619379a56b2eec027.tar.gz
yuzu-5838779162897606a3525eb619379a56b2eec027.tar.xz
yuzu-5838779162897606a3525eb619379a56b2eec027.zip
Merge pull request #12660 from german77/better-vibration
service: hid: Fully implement abstract vibration
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/hid/hid.cpp1
-rw-r--r--src/core/hle/service/hid/hid_server.cpp334
-rw-r--r--src/core/hle/service/hid/hid_server.h1
-rw-r--r--src/core/hle/service/hid/hid_system_server.cpp98
-rw-r--r--src/core/hle/service/hid/hid_system_server.h6
-rw-r--r--src/hid_core/frontend/emulated_controller.cpp40
-rw-r--r--src/hid_core/frontend/emulated_controller.h20
-rw-r--r--src/hid_core/resource_manager.cpp123
-rw-r--r--src/hid_core/resource_manager.h25
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp2
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h6
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_pad.cpp13
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_pad.h6
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp42
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h12
-rw-r--r--src/hid_core/resources/applet_resource.cpp19
-rw-r--r--src/hid_core/resources/applet_resource.h1
-rw-r--r--src/hid_core/resources/npad/npad.cpp292
-rw-r--r--src/hid_core/resources/npad/npad.h59
-rw-r--r--src/hid_core/resources/npad/npad_types.h6
-rw-r--r--src/hid_core/resources/npad/npad_vibration.cpp4
-rw-r--r--src/hid_core/resources/npad/npad_vibration.h2
-rw-r--r--src/hid_core/resources/vibration/gc_vibration_device.cpp56
-rw-r--r--src/hid_core/resources/vibration/gc_vibration_device.h10
-rw-r--r--src/hid_core/resources/vibration/n64_vibration_device.cpp57
-rw-r--r--src/hid_core/resources/vibration/n64_vibration_device.h8
-rw-r--r--src/hid_core/resources/vibration/vibration_base.cpp4
-rw-r--r--src/hid_core/resources/vibration/vibration_base.h10
-rw-r--r--src/hid_core/resources/vibration/vibration_device.cpp72
-rw-r--r--src/hid_core/resources/vibration/vibration_device.h16
-rw-r--r--src/yuzu/configuration/configure_vibration.cpp8
31 files changed, 905 insertions, 448 deletions
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 03ebdc137..595a3372e 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -26,6 +26,7 @@ void LoopProcess(Core::System& system) {
26 resource_manager->Initialize(); 26 resource_manager->Initialize();
27 resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(), 27 resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(),
28 true); 28 true);
29 resource_manager->SetAruidValidForVibration(system.ApplicationProcess()->GetProcessId(), true);
29 30
30 server_manager->RegisterNamedService( 31 server_manager->RegisterNamedService(
31 "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); 32 "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index 1951da33b..30afed812 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -22,12 +22,16 @@
22#include "hid_core/resources/mouse/mouse.h" 22#include "hid_core/resources/mouse/mouse.h"
23#include "hid_core/resources/npad/npad.h" 23#include "hid_core/resources/npad/npad.h"
24#include "hid_core/resources/npad/npad_types.h" 24#include "hid_core/resources/npad/npad_types.h"
25#include "hid_core/resources/npad/npad_vibration.h"
25#include "hid_core/resources/palma/palma.h" 26#include "hid_core/resources/palma/palma.h"
26#include "hid_core/resources/six_axis/console_six_axis.h" 27#include "hid_core/resources/six_axis/console_six_axis.h"
27#include "hid_core/resources/six_axis/seven_six_axis.h" 28#include "hid_core/resources/six_axis/seven_six_axis.h"
28#include "hid_core/resources/six_axis/six_axis.h" 29#include "hid_core/resources/six_axis/six_axis.h"
29#include "hid_core/resources/touch_screen/gesture.h" 30#include "hid_core/resources/touch_screen/gesture.h"
30#include "hid_core/resources/touch_screen/touch_screen.h" 31#include "hid_core/resources/touch_screen/touch_screen.h"
32#include "hid_core/resources/vibration/gc_vibration_device.h"
33#include "hid_core/resources/vibration/n64_vibration_device.h"
34#include "hid_core/resources/vibration/vibration_device.h"
31 35
32namespace Service::HID { 36namespace Service::HID {
33 37
@@ -38,7 +42,7 @@ public:
38 : ServiceFramework{system_, "IActiveVibrationDeviceList"}, resource_manager(resource) { 42 : ServiceFramework{system_, "IActiveVibrationDeviceList"}, resource_manager(resource) {
39 // clang-format off 43 // clang-format off
40 static const FunctionInfo functions[] = { 44 static const FunctionInfo functions[] = {
41 {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"}, 45 {0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"},
42 }; 46 };
43 // clang-format on 47 // clang-format on
44 48
@@ -46,22 +50,49 @@ public:
46 } 50 }
47 51
48private: 52private:
49 void InitializeVibrationDevice(HLERequestContext& ctx) { 53 void ActivateVibrationDevice(HLERequestContext& ctx) {
50 IPC::RequestParser rp{ctx}; 54 IPC::RequestParser rp{ctx};
51 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; 55 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
52 56
53 if (resource_manager != nullptr && resource_manager->GetNpad()) {
54 resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle);
55 }
56
57 LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}", 57 LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
58 vibration_device_handle.npad_type, vibration_device_handle.npad_id, 58 vibration_device_handle.npad_type, vibration_device_handle.npad_id,
59 vibration_device_handle.device_index); 59 vibration_device_handle.device_index);
60 60
61 const auto result = ActivateVibrationDeviceImpl(vibration_device_handle);
62
61 IPC::ResponseBuilder rb{ctx, 2}; 63 IPC::ResponseBuilder rb{ctx, 2};
62 rb.Push(ResultSuccess); 64 rb.Push(result);
63 } 65 }
64 66
67 Result ActivateVibrationDeviceImpl(const Core::HID::VibrationDeviceHandle& handle) {
68 std::scoped_lock lock{mutex};
69
70 const Result is_valid = IsVibrationHandleValid(handle);
71 if (is_valid.IsError()) {
72 return is_valid;
73 }
74
75 for (std::size_t i = 0; i < list_size; i++) {
76 if (handle.device_index == vibration_device_list[i].device_index &&
77 handle.npad_id == vibration_device_list[i].npad_id &&
78 handle.npad_type == vibration_device_list[i].npad_type) {
79 return ResultSuccess;
80 }
81 }
82 if (list_size == vibration_device_list.size()) {
83 return ResultVibrationDeviceIndexOutOfRange;
84 }
85 const Result result = resource_manager->GetVibrationDevice(handle)->Activate();
86 if (result.IsError()) {
87 return result;
88 }
89 vibration_device_list[list_size++] = handle;
90 return ResultSuccess;
91 }
92
93 mutable std::mutex mutex;
94 std::size_t list_size{};
95 std::array<Core::HID::VibrationDeviceHandle, 0x100> vibration_device_list{};
65 std::shared_ptr<ResourceManager> resource_manager; 96 std::shared_ptr<ResourceManager> resource_manager;
66}; 97};
67 98
@@ -153,7 +184,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
153 {209, &IHidServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, 184 {209, &IHidServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
154 {210, &IHidServer::EndPermitVibrationSession, "EndPermitVibrationSession"}, 185 {210, &IHidServer::EndPermitVibrationSession, "EndPermitVibrationSession"},
155 {211, &IHidServer::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"}, 186 {211, &IHidServer::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
156 {212, nullptr, "SendVibrationValueInBool"}, 187 {212, &IHidServer::SendVibrationValueInBool, "SendVibrationValueInBool"},
157 {300, &IHidServer::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, 188 {300, &IHidServer::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
158 {301, &IHidServer::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, 189 {301, &IHidServer::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
159 {302, &IHidServer::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, 190 {302, &IHidServer::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
@@ -1492,59 +1523,13 @@ void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
1492void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { 1523void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {
1493 IPC::RequestParser rp{ctx}; 1524 IPC::RequestParser rp{ctx};
1494 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; 1525 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
1495 const auto controller = GetResourceManager()->GetNpad();
1496
1497 Core::HID::VibrationDeviceInfo vibration_device_info;
1498 bool check_device_index = false;
1499
1500 switch (vibration_device_handle.npad_type) {
1501 case Core::HID::NpadStyleIndex::Fullkey:
1502 case Core::HID::NpadStyleIndex::Handheld:
1503 case Core::HID::NpadStyleIndex::JoyconDual:
1504 case Core::HID::NpadStyleIndex::JoyconLeft:
1505 case Core::HID::NpadStyleIndex::JoyconRight:
1506 vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
1507 check_device_index = true;
1508 break;
1509 case Core::HID::NpadStyleIndex::GameCube:
1510 vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
1511 break;
1512 case Core::HID::NpadStyleIndex::N64:
1513 vibration_device_info.type = Core::HID::VibrationDeviceType::N64;
1514 break;
1515 default:
1516 vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
1517 break;
1518 }
1519
1520 vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
1521 if (check_device_index) {
1522 switch (vibration_device_handle.device_index) {
1523 case Core::HID::DeviceIndex::Left:
1524 vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
1525 break;
1526 case Core::HID::DeviceIndex::Right:
1527 vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
1528 break;
1529 case Core::HID::DeviceIndex::None:
1530 default:
1531 ASSERT_MSG(false, "DeviceIndex should never be None!");
1532 break;
1533 }
1534 }
1535 1526
1536 LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}", 1527 Core::HID::VibrationDeviceInfo vibration_device_info{};
1537 vibration_device_info.type, vibration_device_info.position); 1528 const auto result = GetResourceManager()->GetVibrationDeviceInfo(vibration_device_info,
1538 1529 vibration_device_handle);
1539 const auto result = IsVibrationHandleValid(vibration_device_handle);
1540 if (result.IsError()) {
1541 IPC::ResponseBuilder rb{ctx, 2};
1542 rb.Push(result);
1543 return;
1544 }
1545 1530
1546 IPC::ResponseBuilder rb{ctx, 4}; 1531 IPC::ResponseBuilder rb{ctx, 4};
1547 rb.Push(ResultSuccess); 1532 rb.Push(result);
1548 rb.PushRaw(vibration_device_info); 1533 rb.PushRaw(vibration_device_info);
1549} 1534}
1550 1535
@@ -1560,16 +1545,16 @@ void IHidServer::SendVibrationValue(HLERequestContext& ctx) {
1560 1545
1561 const auto parameters{rp.PopRaw<Parameters>()}; 1546 const auto parameters{rp.PopRaw<Parameters>()};
1562 1547
1563 GetResourceManager()->GetNpad()->VibrateController(parameters.applet_resource_user_id,
1564 parameters.vibration_device_handle,
1565 parameters.vibration_value);
1566
1567 LOG_DEBUG(Service_HID, 1548 LOG_DEBUG(Service_HID,
1568 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 1549 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1569 parameters.vibration_device_handle.npad_type, 1550 parameters.vibration_device_handle.npad_type,
1570 parameters.vibration_device_handle.npad_id, 1551 parameters.vibration_device_handle.npad_id,
1571 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); 1552 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1572 1553
1554 GetResourceManager()->SendVibrationValue(parameters.applet_resource_user_id,
1555 parameters.vibration_device_handle,
1556 parameters.vibration_value);
1557
1573 IPC::ResponseBuilder rb{ctx, 2}; 1558 IPC::ResponseBuilder rb{ctx, 2};
1574 rb.Push(ResultSuccess); 1559 rb.Push(ResultSuccess);
1575} 1560}
@@ -1591,10 +1576,28 @@ void IHidServer::GetActualVibrationValue(HLERequestContext& ctx) {
1591 parameters.vibration_device_handle.npad_id, 1576 parameters.vibration_device_handle.npad_id,
1592 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); 1577 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1593 1578
1579 bool has_active_aruid{};
1580 NpadVibrationDevice* device{nullptr};
1581 Core::HID::VibrationValue vibration_value{};
1582 Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id,
1583 has_active_aruid);
1584
1585 if (result.IsSuccess() && has_active_aruid) {
1586 result = IsVibrationHandleValid(parameters.vibration_device_handle);
1587 }
1588 if (result.IsSuccess() && has_active_aruid) {
1589 device = GetResourceManager()->GetNSVibrationDevice(parameters.vibration_device_handle);
1590 }
1591 if (device != nullptr) {
1592 result = device->GetActualVibrationValue(vibration_value);
1593 }
1594 if (result.IsError()) {
1595 vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE;
1596 }
1597
1594 IPC::ResponseBuilder rb{ctx, 6}; 1598 IPC::ResponseBuilder rb{ctx, 6};
1595 rb.Push(ResultSuccess); 1599 rb.Push(ResultSuccess);
1596 rb.PushRaw(GetResourceManager()->GetNpad()->GetLastVibration( 1600 rb.PushRaw(vibration_value);
1597 parameters.applet_resource_user_id, parameters.vibration_device_handle));
1598} 1601}
1599 1602
1600void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) { 1603void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) {
@@ -1609,25 +1612,27 @@ void IHidServer::PermitVibration(HLERequestContext& ctx) {
1609 IPC::RequestParser rp{ctx}; 1612 IPC::RequestParser rp{ctx};
1610 const auto can_vibrate{rp.Pop<bool>()}; 1613 const auto can_vibrate{rp.Pop<bool>()};
1611 1614
1612 // nnSDK saves this value as a float. Since it can only be 1.0f or 0.0f we simplify this value
1613 // by converting it to a bool
1614 Settings::values.vibration_enabled.SetValue(can_vibrate);
1615
1616 LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); 1615 LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
1617 1616
1617 const auto result =
1618 GetResourceManager()->GetNpad()->GetVibrationHandler()->SetVibrationMasterVolume(
1619 can_vibrate ? 1.0f : 0.0f);
1620
1618 IPC::ResponseBuilder rb{ctx, 2}; 1621 IPC::ResponseBuilder rb{ctx, 2};
1619 rb.Push(ResultSuccess); 1622 rb.Push(result);
1620} 1623}
1621 1624
1622void IHidServer::IsVibrationPermitted(HLERequestContext& ctx) { 1625void IHidServer::IsVibrationPermitted(HLERequestContext& ctx) {
1623 LOG_DEBUG(Service_HID, "called"); 1626 LOG_DEBUG(Service_HID, "called");
1624 1627
1625 // nnSDK checks if a float is greater than zero. We return the bool we stored earlier 1628 f32 master_volume{};
1626 const auto is_enabled = Settings::values.vibration_enabled.GetValue(); 1629 const auto result =
1630 GetResourceManager()->GetNpad()->GetVibrationHandler()->GetVibrationMasterVolume(
1631 master_volume);
1627 1632
1628 IPC::ResponseBuilder rb{ctx, 3}; 1633 IPC::ResponseBuilder rb{ctx, 3};
1629 rb.Push(ResultSuccess); 1634 rb.Push(result);
1630 rb.Push(is_enabled); 1635 rb.Push(master_volume > 0.0f);
1631} 1636}
1632 1637
1633void IHidServer::SendVibrationValues(HLERequestContext& ctx) { 1638void IHidServer::SendVibrationValues(HLERequestContext& ctx) {
@@ -1645,13 +1650,22 @@ void IHidServer::SendVibrationValues(HLERequestContext& ctx) {
1645 auto vibration_values = std::span( 1650 auto vibration_values = std::span(
1646 reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count); 1651 reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
1647 1652
1648 GetResourceManager()->GetNpad()->VibrateControllers(applet_resource_user_id,
1649 vibration_device_handles, vibration_values);
1650
1651 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1653 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1652 1654
1655 Result result = ResultSuccess;
1656 if (handle_count != vibration_count) {
1657 result = ResultVibrationArraySizeMismatch;
1658 }
1659
1660 for (std::size_t i = 0; i < handle_count; i++) {
1661 if (result.IsSuccess()) {
1662 result = GetResourceManager()->SendVibrationValue(
1663 applet_resource_user_id, vibration_device_handles[i], vibration_values[i]);
1664 }
1665 }
1666
1653 IPC::ResponseBuilder rb{ctx, 2}; 1667 IPC::ResponseBuilder rb{ctx, 2};
1654 rb.Push(ResultSuccess); 1668 rb.Push(result);
1655} 1669}
1656 1670
1657void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) { 1671void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) {
@@ -1666,43 +1680,6 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) {
1666 1680
1667 const auto parameters{rp.PopRaw<Parameters>()}; 1681 const auto parameters{rp.PopRaw<Parameters>()};
1668 1682
1669 /**
1670 * Note: This uses yuzu-specific behavior such that the StopHard command produces
1671 * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined below,
1672 * in order to differentiate between Stop and StopHard commands.
1673 * This is done to reuse the controller vibration functions made for regular controllers.
1674 */
1675 const auto vibration_value = [parameters] {
1676 switch (parameters.gc_erm_command) {
1677 case Core::HID::VibrationGcErmCommand::Stop:
1678 return Core::HID::VibrationValue{
1679 .low_amplitude = 0.0f,
1680 .low_frequency = 160.0f,
1681 .high_amplitude = 0.0f,
1682 .high_frequency = 320.0f,
1683 };
1684 case Core::HID::VibrationGcErmCommand::Start:
1685 return Core::HID::VibrationValue{
1686 .low_amplitude = 1.0f,
1687 .low_frequency = 160.0f,
1688 .high_amplitude = 1.0f,
1689 .high_frequency = 320.0f,
1690 };
1691 case Core::HID::VibrationGcErmCommand::StopHard:
1692 return Core::HID::VibrationValue{
1693 .low_amplitude = 0.0f,
1694 .low_frequency = 0.0f,
1695 .high_amplitude = 0.0f,
1696 .high_frequency = 0.0f,
1697 };
1698 default:
1699 return Core::HID::DEFAULT_VIBRATION_VALUE;
1700 }
1701 }();
1702
1703 GetResourceManager()->GetNpad()->VibrateController(
1704 parameters.applet_resource_user_id, parameters.vibration_device_handle, vibration_value);
1705
1706 LOG_DEBUG(Service_HID, 1683 LOG_DEBUG(Service_HID,
1707 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, " 1684 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
1708 "gc_erm_command={}", 1685 "gc_erm_command={}",
@@ -1711,8 +1688,23 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) {
1711 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id, 1688 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id,
1712 parameters.gc_erm_command); 1689 parameters.gc_erm_command);
1713 1690
1691 bool has_active_aruid{};
1692 NpadGcVibrationDevice* gc_device{nullptr};
1693 Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id,
1694 has_active_aruid);
1695
1696 if (result.IsSuccess() && has_active_aruid) {
1697 result = IsVibrationHandleValid(parameters.vibration_device_handle);
1698 }
1699 if (result.IsSuccess() && has_active_aruid) {
1700 gc_device = GetResourceManager()->GetGcVibrationDevice(parameters.vibration_device_handle);
1701 }
1702 if (gc_device != nullptr) {
1703 result = gc_device->SendVibrationGcErmCommand(parameters.gc_erm_command);
1704 }
1705
1714 IPC::ResponseBuilder rb{ctx, 2}; 1706 IPC::ResponseBuilder rb{ctx, 2};
1715 rb.Push(ResultSuccess); 1707 rb.Push(result);
1716} 1708}
1717 1709
1718void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) { 1710void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) {
@@ -1725,33 +1717,31 @@ void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) {
1725 1717
1726 const auto parameters{rp.PopRaw<Parameters>()}; 1718 const auto parameters{rp.PopRaw<Parameters>()};
1727 1719
1728 const auto last_vibration = GetResourceManager()->GetNpad()->GetLastVibration(
1729 parameters.applet_resource_user_id, parameters.vibration_device_handle);
1730
1731 const auto gc_erm_command = [last_vibration] {
1732 if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) {
1733 return Core::HID::VibrationGcErmCommand::Start;
1734 }
1735
1736 /**
1737 * Note: This uses yuzu-specific behavior such that the StopHard command produces
1738 * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined in the HID function
1739 * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands.
1740 * This is done to reuse the controller vibration functions made for regular controllers.
1741 */
1742 if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) {
1743 return Core::HID::VibrationGcErmCommand::StopHard;
1744 }
1745
1746 return Core::HID::VibrationGcErmCommand::Stop;
1747 }();
1748
1749 LOG_DEBUG(Service_HID, 1720 LOG_DEBUG(Service_HID,
1750 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 1721 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1751 parameters.vibration_device_handle.npad_type, 1722 parameters.vibration_device_handle.npad_type,
1752 parameters.vibration_device_handle.npad_id, 1723 parameters.vibration_device_handle.npad_id,
1753 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); 1724 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1754 1725
1726 bool has_active_aruid{};
1727 NpadGcVibrationDevice* gc_device{nullptr};
1728 Core::HID::VibrationGcErmCommand gc_erm_command{};
1729 Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id,
1730 has_active_aruid);
1731
1732 if (result.IsSuccess() && has_active_aruid) {
1733 result = IsVibrationHandleValid(parameters.vibration_device_handle);
1734 }
1735 if (result.IsSuccess() && has_active_aruid) {
1736 gc_device = GetResourceManager()->GetGcVibrationDevice(parameters.vibration_device_handle);
1737 }
1738 if (gc_device != nullptr) {
1739 result = gc_device->GetActualVibrationGcErmCommand(gc_erm_command);
1740 }
1741 if (result.IsError()) {
1742 gc_erm_command = Core::HID::VibrationGcErmCommand::Stop;
1743 }
1744
1755 IPC::ResponseBuilder rb{ctx, 4}; 1745 IPC::ResponseBuilder rb{ctx, 4};
1756 rb.Push(ResultSuccess); 1746 rb.Push(ResultSuccess);
1757 rb.PushEnum(gc_erm_command); 1747 rb.PushEnum(gc_erm_command);
@@ -1761,21 +1751,24 @@ void IHidServer::BeginPermitVibrationSession(HLERequestContext& ctx) {
1761 IPC::RequestParser rp{ctx}; 1751 IPC::RequestParser rp{ctx};
1762 const auto applet_resource_user_id{rp.Pop<u64>()}; 1752 const auto applet_resource_user_id{rp.Pop<u64>()};
1763 1753
1764 GetResourceManager()->GetNpad()->SetPermitVibrationSession(true);
1765
1766 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1754 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1767 1755
1756 const auto result =
1757 GetResourceManager()->GetNpad()->GetVibrationHandler()->BeginPermitVibrationSession(
1758 applet_resource_user_id);
1759
1768 IPC::ResponseBuilder rb{ctx, 2}; 1760 IPC::ResponseBuilder rb{ctx, 2};
1769 rb.Push(ResultSuccess); 1761 rb.Push(result);
1770} 1762}
1771 1763
1772void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) { 1764void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) {
1773 GetResourceManager()->GetNpad()->SetPermitVibrationSession(false);
1774
1775 LOG_DEBUG(Service_HID, "called"); 1765 LOG_DEBUG(Service_HID, "called");
1776 1766
1767 const auto result =
1768 GetResourceManager()->GetNpad()->GetVibrationHandler()->EndPermitVibrationSession();
1769
1777 IPC::ResponseBuilder rb{ctx, 2}; 1770 IPC::ResponseBuilder rb{ctx, 2};
1778 rb.Push(ResultSuccess); 1771 rb.Push(result);
1779} 1772}
1780 1773
1781void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) { 1774void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) {
@@ -1795,10 +1788,61 @@ void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) {
1795 parameters.vibration_device_handle.npad_id, 1788 parameters.vibration_device_handle.npad_id,
1796 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); 1789 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1797 1790
1791 bool is_mounted{};
1792 NpadVibrationBase* device{nullptr};
1793 Result result = IsVibrationHandleValid(parameters.vibration_device_handle);
1794
1795 if (result.IsSuccess()) {
1796 device = GetResourceManager()->GetVibrationDevice(parameters.vibration_device_handle);
1797 }
1798
1799 if (device != nullptr) {
1800 is_mounted = device->IsVibrationMounted();
1801 }
1802
1798 IPC::ResponseBuilder rb{ctx, 3}; 1803 IPC::ResponseBuilder rb{ctx, 3};
1799 rb.Push(ResultSuccess); 1804 rb.Push(result);
1800 rb.Push(GetResourceManager()->GetNpad()->IsVibrationDeviceMounted( 1805 rb.Push(is_mounted);
1801 parameters.applet_resource_user_id, parameters.vibration_device_handle)); 1806}
1807
1808void IHidServer::SendVibrationValueInBool(HLERequestContext& ctx) {
1809 IPC::RequestParser rp{ctx};
1810 struct Parameters {
1811 Core::HID::VibrationDeviceHandle vibration_device_handle;
1812 INSERT_PADDING_WORDS_NOINIT(1);
1813 u64 applet_resource_user_id;
1814 bool is_vibrating;
1815 };
1816 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1817
1818 const auto parameters{rp.PopRaw<Parameters>()};
1819
1820 LOG_DEBUG(Service_HID,
1821 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
1822 "is_vibrating={}",
1823 parameters.vibration_device_handle.npad_type,
1824 parameters.vibration_device_handle.npad_id,
1825 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id,
1826 parameters.is_vibrating);
1827
1828 bool has_active_aruid{};
1829 NpadN64VibrationDevice* n64_device{nullptr};
1830 Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id,
1831 has_active_aruid);
1832
1833 if (result.IsSuccess() && has_active_aruid) {
1834 result = IsVibrationHandleValid(parameters.vibration_device_handle);
1835 }
1836 if (result.IsSuccess() && has_active_aruid) {
1837 n64_device =
1838 GetResourceManager()->GetN64VibrationDevice(parameters.vibration_device_handle);
1839 }
1840 if (n64_device != nullptr) {
1841 result = n64_device->SendValueInBool(parameters.is_vibrating);
1842 }
1843
1844 IPC::ResponseBuilder rb{ctx, 2};
1845 rb.Push(result);
1802} 1846}
1803 1847
1804void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) { 1848void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/hid/hid_server.h b/src/core/hle/service/hid/hid_server.h
index cc7c4ebdd..3a2e0a230 100644
--- a/src/core/hle/service/hid/hid_server.h
+++ b/src/core/hle/service/hid/hid_server.h
@@ -97,6 +97,7 @@ private:
97 void BeginPermitVibrationSession(HLERequestContext& ctx); 97 void BeginPermitVibrationSession(HLERequestContext& ctx);
98 void EndPermitVibrationSession(HLERequestContext& ctx); 98 void EndPermitVibrationSession(HLERequestContext& ctx);
99 void IsVibrationDeviceMounted(HLERequestContext& ctx); 99 void IsVibrationDeviceMounted(HLERequestContext& ctx);
100 void SendVibrationValueInBool(HLERequestContext& ctx);
100 void ActivateConsoleSixAxisSensor(HLERequestContext& ctx); 101 void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
101 void StartConsoleSixAxisSensor(HLERequestContext& ctx); 102 void StartConsoleSixAxisSensor(HLERequestContext& ctx);
102 void StopConsoleSixAxisSensor(HLERequestContext& ctx); 103 void StopConsoleSixAxisSensor(HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp
index 3a0cb3cb1..4466a189b 100644
--- a/src/core/hle/service/hid/hid_system_server.cpp
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -7,6 +7,7 @@
7#include "hid_core/resource_manager.h" 7#include "hid_core/resource_manager.h"
8#include "hid_core/resources/npad/npad.h" 8#include "hid_core/resources/npad/npad.h"
9#include "hid_core/resources/npad/npad_types.h" 9#include "hid_core/resources/npad/npad_types.h"
10#include "hid_core/resources/npad/npad_vibration.h"
10#include "hid_core/resources/palma/palma.h" 11#include "hid_core/resources/palma/palma.h"
11#include "hid_core/resources/touch_screen/touch_screen.h" 12#include "hid_core/resources/touch_screen/touch_screen.h"
12 13
@@ -67,14 +68,14 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
67 {501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"}, 68 {501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"},
68 {502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"}, 69 {502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"},
69 {503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"}, 70 {503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"},
70 {504, nullptr, "SetAruidValidForVibration"}, 71 {504, &IHidSystemServer::SetAruidValidForVibration, "SetAruidValidForVibration"},
71 {505, &IHidSystemServer::EnableAppletToGetSixAxisSensor, "EnableAppletToGetSixAxisSensor"}, 72 {505, &IHidSystemServer::EnableAppletToGetSixAxisSensor, "EnableAppletToGetSixAxisSensor"},
72 {506, &IHidSystemServer::EnableAppletToGetPadInput, "EnableAppletToGetPadInput"}, 73 {506, &IHidSystemServer::EnableAppletToGetPadInput, "EnableAppletToGetPadInput"},
73 {507, &IHidSystemServer::EnableAppletToGetTouchScreen, "EnableAppletToGetTouchScreen"}, 74 {507, &IHidSystemServer::EnableAppletToGetTouchScreen, "EnableAppletToGetTouchScreen"},
74 {510, nullptr, "SetVibrationMasterVolume"}, 75 {510, &IHidSystemServer::SetVibrationMasterVolume, "SetVibrationMasterVolume"},
75 {511, nullptr, "GetVibrationMasterVolume"}, 76 {511, &IHidSystemServer::GetVibrationMasterVolume, "GetVibrationMasterVolume"},
76 {512, nullptr, "BeginPermitVibrationSession"}, 77 {512, &IHidSystemServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
77 {513, nullptr, "EndPermitVibrationSession"}, 78 {513, &IHidSystemServer::EndPermitVibrationSession, "EndPermitVibrationSession"},
78 {514, nullptr, "Unknown514"}, 79 {514, nullptr, "Unknown514"},
79 {520, nullptr, "EnableHandheldHids"}, 80 {520, nullptr, "EnableHandheldHids"},
80 {521, nullptr, "DisableHandheldHids"}, 81 {521, nullptr, "DisableHandheldHids"},
@@ -156,7 +157,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
156 {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, 157 {1152, nullptr, "SetTouchScreenDefaultConfiguration"},
157 {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"}, 158 {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
158 {1154, nullptr, "IsFirmwareAvailableForNotification"}, 159 {1154, nullptr, "IsFirmwareAvailableForNotification"},
159 {1155, nullptr, "SetForceHandheldStyleVibration"}, 160 {1155, &IHidSystemServer::SetForceHandheldStyleVibration, "SetForceHandheldStyleVibration"},
160 {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"}, 161 {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
161 {1157, nullptr, "CancelConnectionTrigger"}, 162 {1157, nullptr, "CancelConnectionTrigger"},
162 {1200, nullptr, "IsButtonConfigSupported"}, 163 {1200, nullptr, "IsButtonConfigSupported"},
@@ -538,6 +539,27 @@ void IHidSystemServer::EnableAppletToGetInput(HLERequestContext& ctx) {
538 rb.Push(ResultSuccess); 539 rb.Push(ResultSuccess);
539} 540}
540 541
542void IHidSystemServer::SetAruidValidForVibration(HLERequestContext& ctx) {
543 IPC::RequestParser rp{ctx};
544 struct Parameters {
545 bool is_enabled;
546 INSERT_PADDING_WORDS_NOINIT(1);
547 u64 applet_resource_user_id;
548 };
549 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
550
551 const auto parameters{rp.PopRaw<Parameters>()};
552
553 LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
554 parameters.is_enabled, parameters.applet_resource_user_id);
555
556 GetResourceManager()->SetAruidValidForVibration(parameters.applet_resource_user_id,
557 parameters.is_enabled);
558
559 IPC::ResponseBuilder rb{ctx, 2};
560 rb.Push(ResultSuccess);
561}
562
541void IHidSystemServer::EnableAppletToGetSixAxisSensor(HLERequestContext& ctx) { 563void IHidSystemServer::EnableAppletToGetSixAxisSensor(HLERequestContext& ctx) {
542 IPC::RequestParser rp{ctx}; 564 IPC::RequestParser rp{ctx};
543 struct Parameters { 565 struct Parameters {
@@ -601,6 +623,57 @@ void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) {
601 rb.Push(ResultSuccess); 623 rb.Push(ResultSuccess);
602} 624}
603 625
626void IHidSystemServer::SetVibrationMasterVolume(HLERequestContext& ctx) {
627 IPC::RequestParser rp{ctx};
628 const auto master_volume{rp.Pop<f32>()};
629
630 LOG_INFO(Service_HID, "called, volume={}", master_volume);
631
632 const auto result =
633 GetResourceManager()->GetNpad()->GetVibrationHandler()->SetVibrationMasterVolume(
634 master_volume);
635
636 IPC::ResponseBuilder rb{ctx, 2};
637 rb.Push(result);
638}
639
640void IHidSystemServer::GetVibrationMasterVolume(HLERequestContext& ctx) {
641 f32 master_volume{};
642 const auto result =
643 GetResourceManager()->GetNpad()->GetVibrationHandler()->GetVibrationMasterVolume(
644 master_volume);
645
646 LOG_INFO(Service_HID, "called, volume={}", master_volume);
647
648 IPC::ResponseBuilder rb{ctx, 3};
649 rb.Push(result);
650 rb.Push(master_volume);
651}
652
653void IHidSystemServer::BeginPermitVibrationSession(HLERequestContext& ctx) {
654 IPC::RequestParser rp{ctx};
655 const auto applet_resource_user_id{rp.Pop<u64>()};
656
657 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
658
659 const auto result =
660 GetResourceManager()->GetNpad()->GetVibrationHandler()->BeginPermitVibrationSession(
661 applet_resource_user_id);
662
663 IPC::ResponseBuilder rb{ctx, 2};
664 rb.Push(result);
665}
666
667void IHidSystemServer::EndPermitVibrationSession(HLERequestContext& ctx) {
668 LOG_INFO(Service_HID, "called");
669
670 const auto result =
671 GetResourceManager()->GetNpad()->GetVibrationHandler()->EndPermitVibrationSession();
672
673 IPC::ResponseBuilder rb{ctx, 2};
674 rb.Push(result);
675}
676
604void IHidSystemServer::IsJoyConAttachedOnAllRail(HLERequestContext& ctx) { 677void IHidSystemServer::IsJoyConAttachedOnAllRail(HLERequestContext& ctx) {
605 const bool is_attached = true; 678 const bool is_attached = true;
606 679
@@ -749,6 +822,19 @@ void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx
749 rb.PushRaw(touchscreen_config); 822 rb.PushRaw(touchscreen_config);
750} 823}
751 824
825void IHidSystemServer::SetForceHandheldStyleVibration(HLERequestContext& ctx) {
826 IPC::RequestParser rp{ctx};
827 const auto is_forced{rp.Pop<bool>()};
828
829 LOG_INFO(Service_HID, "called, is_forced={}", is_forced);
830
831 GetResourceManager()->SetForceHandheldStyleVibration(is_forced);
832 GetResourceManager()->GetNpad()->UpdateHandheldAbstractState();
833
834 IPC::ResponseBuilder rb{ctx, 2};
835 rb.Push(ResultSuccess);
836}
837
752void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) { 838void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) {
753 const bool is_enabled = false; 839 const bool is_enabled = false;
754 840
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h
index 0c2634e3f..90a719f02 100644
--- a/src/core/hle/service/hid/hid_system_server.h
+++ b/src/core/hle/service/hid/hid_system_server.h
@@ -42,9 +42,14 @@ private:
42 void RegisterAppletResourceUserId(HLERequestContext& ctx); 42 void RegisterAppletResourceUserId(HLERequestContext& ctx);
43 void UnregisterAppletResourceUserId(HLERequestContext& ctx); 43 void UnregisterAppletResourceUserId(HLERequestContext& ctx);
44 void EnableAppletToGetInput(HLERequestContext& ctx); 44 void EnableAppletToGetInput(HLERequestContext& ctx);
45 void SetAruidValidForVibration(HLERequestContext& ctx);
45 void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx); 46 void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx);
46 void EnableAppletToGetPadInput(HLERequestContext& ctx); 47 void EnableAppletToGetPadInput(HLERequestContext& ctx);
47 void EnableAppletToGetTouchScreen(HLERequestContext& ctx); 48 void EnableAppletToGetTouchScreen(HLERequestContext& ctx);
49 void SetVibrationMasterVolume(HLERequestContext& ctx);
50 void GetVibrationMasterVolume(HLERequestContext& ctx);
51 void BeginPermitVibrationSession(HLERequestContext& ctx);
52 void EndPermitVibrationSession(HLERequestContext& ctx);
48 void IsJoyConAttachedOnAllRail(HLERequestContext& ctx); 53 void IsJoyConAttachedOnAllRail(HLERequestContext& ctx);
49 void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); 54 void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx);
50 void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); 55 void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx);
@@ -61,6 +66,7 @@ private:
61 void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx); 66 void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx);
62 void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx); 67 void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx);
63 void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); 68 void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
69 void SetForceHandheldStyleVibration(HLERequestContext& ctx);
64 void IsUsingCustomButtonConfig(HLERequestContext& ctx); 70 void IsUsingCustomButtonConfig(HLERequestContext& ctx);
65 71
66 std::shared_ptr<ResourceManager> GetResourceManager(); 72 std::shared_ptr<ResourceManager> GetResourceManager();
diff --git a/src/hid_core/frontend/emulated_controller.cpp b/src/hid_core/frontend/emulated_controller.cpp
index b001cf2fd..f2499502d 100644
--- a/src/hid_core/frontend/emulated_controller.cpp
+++ b/src/hid_core/frontend/emulated_controller.cpp
@@ -145,8 +145,8 @@ void EmulatedController::ReloadColorsFromSettings() {
145 145
146void EmulatedController::LoadDevices() { 146void EmulatedController::LoadDevices() {
147 // TODO(german77): Use more buttons to detect the correct device 147 // TODO(german77): Use more buttons to detect the correct device
148 const auto left_joycon = button_params[Settings::NativeButton::DRight]; 148 const auto& left_joycon = button_params[Settings::NativeButton::DRight];
149 const auto right_joycon = button_params[Settings::NativeButton::A]; 149 const auto& right_joycon = button_params[Settings::NativeButton::A];
150 150
151 // Triggers for GC controllers 151 // Triggers for GC controllers
152 trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL]; 152 trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL];
@@ -1209,20 +1209,43 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
1209 controller.nfc_state = controller.nfc_values; 1209 controller.nfc_state = controller.nfc_values;
1210} 1210}
1211 1211
1212bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { 1212bool EmulatedController::SetVibration(bool should_vibrate) {
1213 VibrationValue vibration_value = DEFAULT_VIBRATION_VALUE;
1214 if (should_vibrate) {
1215 vibration_value.high_amplitude = 1.0f;
1216 vibration_value.low_amplitude = 1.0f;
1217 }
1218
1219 return SetVibration(DeviceIndex::Left, vibration_value);
1220}
1221
1222bool EmulatedController::SetVibration(u32 slot, Core::HID::VibrationGcErmCommand erm_command) {
1223 VibrationValue vibration_value = DEFAULT_VIBRATION_VALUE;
1224 if (erm_command == Core::HID::VibrationGcErmCommand::Start) {
1225 vibration_value.high_amplitude = 1.0f;
1226 vibration_value.low_amplitude = 1.0f;
1227 }
1228
1229 return SetVibration(DeviceIndex::Left, vibration_value);
1230}
1231
1232bool EmulatedController::SetVibration(DeviceIndex device_index, const VibrationValue& vibration) {
1213 if (!is_initialized) { 1233 if (!is_initialized) {
1214 return false; 1234 return false;
1215 } 1235 }
1216 if (device_index >= output_devices.size()) { 1236 if (device_index >= DeviceIndex::MaxDeviceIndex) {
1217 return false; 1237 return false;
1218 } 1238 }
1219 if (!output_devices[device_index]) { 1239 const std::size_t index = static_cast<std::size_t>(device_index);
1240 if (!output_devices[index]) {
1220 return false; 1241 return false;
1221 } 1242 }
1222 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); 1243 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
1223 const auto& player = Settings::values.players.GetValue()[player_index]; 1244 const auto& player = Settings::values.players.GetValue()[player_index];
1224 const f32 strength = static_cast<f32>(player.vibration_strength) / 100.0f; 1245 const f32 strength = static_cast<f32>(player.vibration_strength) / 100.0f;
1225 1246
1247 last_vibration_value = vibration;
1248
1226 if (!player.vibration_enabled) { 1249 if (!player.vibration_enabled) {
1227 return false; 1250 return false;
1228 } 1251 }
@@ -1240,8 +1263,11 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v
1240 .high_frequency = vibration.high_frequency, 1263 .high_frequency = vibration.high_frequency,
1241 .type = type, 1264 .type = type,
1242 }; 1265 };
1243 return output_devices[device_index]->SetVibration(status) == 1266 return output_devices[index]->SetVibration(status) == Common::Input::DriverResult::Success;
1244 Common::Input::DriverResult::Success; 1267}
1268
1269VibrationValue EmulatedController::GetActualVibrationValue(DeviceIndex device_index) const {
1270 return last_vibration_value;
1245} 1271}
1246 1272
1247bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { 1273bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {
diff --git a/src/hid_core/frontend/emulated_controller.h b/src/hid_core/frontend/emulated_controller.h
index 90e536e07..168abe089 100644
--- a/src/hid_core/frontend/emulated_controller.h
+++ b/src/hid_core/frontend/emulated_controller.h
@@ -356,10 +356,27 @@ public:
356 const NfcState& GetNfc() const; 356 const NfcState& GetNfc() const;
357 357
358 /** 358 /**
359 * Sends an on/off vibration to the left device
360 * @return true if vibration had no errors
361 */
362 bool SetVibration(bool should_vibrate);
363
364 /**
365 * Sends an GC vibration to the left device
366 * @return true if vibration had no errors
367 */
368 bool SetVibration(u32 slot, Core::HID::VibrationGcErmCommand erm_command);
369
370 /**
359 * Sends a specific vibration to the output device 371 * Sends a specific vibration to the output device
360 * @return true if vibration had no errors 372 * @return true if vibration had no errors
361 */ 373 */
362 bool SetVibration(std::size_t device_index, VibrationValue vibration); 374 bool SetVibration(DeviceIndex device_index, const VibrationValue& vibration);
375
376 /**
377 * @return The last sent vibration
378 */
379 VibrationValue GetActualVibrationValue(DeviceIndex device_index) const;
363 380
364 /** 381 /**
365 * Sends a small vibration to the output device 382 * Sends a small vibration to the output device
@@ -564,6 +581,7 @@ private:
564 f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; 581 f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
565 u32 turbo_button_state{0}; 582 u32 turbo_button_state{0};
566 std::size_t nfc_handles{0}; 583 std::size_t nfc_handles{0};
584 VibrationValue last_vibration_value{DEFAULT_VIBRATION_VALUE};
567 585
568 // Temporary values to avoid doing changes while the controller is in configuring mode 586 // Temporary values to avoid doing changes while the controller is in configuring mode
569 NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; 587 NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp
index 2c5fe6d51..ca824b4a3 100644
--- a/src/hid_core/resource_manager.cpp
+++ b/src/hid_core/resource_manager.cpp
@@ -7,6 +7,7 @@
7#include "core/hle/kernel/k_shared_memory.h" 7#include "core/hle/kernel/k_shared_memory.h"
8#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
9#include "hid_core/hid_core.h" 9#include "hid_core/hid_core.h"
10#include "hid_core/hid_util.h"
10#include "hid_core/resource_manager.h" 11#include "hid_core/resource_manager.h"
11 12
12#include "hid_core/resources/applet_resource.h" 13#include "hid_core/resources/applet_resource.h"
@@ -27,6 +28,10 @@
27#include "hid_core/resources/touch_screen/gesture.h" 28#include "hid_core/resources/touch_screen/gesture.h"
28#include "hid_core/resources/touch_screen/touch_screen.h" 29#include "hid_core/resources/touch_screen/touch_screen.h"
29#include "hid_core/resources/unique_pad/unique_pad.h" 30#include "hid_core/resources/unique_pad/unique_pad.h"
31#include "hid_core/resources/vibration/gc_vibration_device.h"
32#include "hid_core/resources/vibration/n64_vibration_device.h"
33#include "hid_core/resources/vibration/vibration_base.h"
34#include "hid_core/resources/vibration/vibration_device.h"
30 35
31namespace Service::HID { 36namespace Service::HID {
32 37
@@ -52,6 +57,7 @@ void ResourceManager::Initialize() {
52 57
53 system.HIDCore().ReloadInputDevices(); 58 system.HIDCore().ReloadInputDevices();
54 59
60 handheld_config = std::make_shared<HandheldConfig>();
55 InitializeHidCommonSampler(); 61 InitializeHidCommonSampler();
56 InitializeTouchScreenSampler(); 62 InitializeTouchScreenSampler();
57 InitializeConsoleSixAxisSampler(); 63 InitializeConsoleSixAxisSampler();
@@ -174,7 +180,7 @@ void ResourceManager::InitializeHidCommonSampler() {
174 debug_pad->SetAppletResource(applet_resource, &shared_mutex); 180 debug_pad->SetAppletResource(applet_resource, &shared_mutex);
175 digitizer->SetAppletResource(applet_resource, &shared_mutex); 181 digitizer->SetAppletResource(applet_resource, &shared_mutex);
176 keyboard->SetAppletResource(applet_resource, &shared_mutex); 182 keyboard->SetAppletResource(applet_resource, &shared_mutex);
177 npad->SetNpadExternals(applet_resource, &shared_mutex); 183 npad->SetNpadExternals(applet_resource, &shared_mutex, handheld_config);
178 six_axis->SetAppletResource(applet_resource, &shared_mutex); 184 six_axis->SetAppletResource(applet_resource, &shared_mutex);
179 mouse->SetAppletResource(applet_resource, &shared_mutex); 185 mouse->SetAppletResource(applet_resource, &shared_mutex);
180 debug_mouse->SetAppletResource(applet_resource, &shared_mutex); 186 debug_mouse->SetAppletResource(applet_resource, &shared_mutex);
@@ -257,6 +263,121 @@ void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) {
257 applet_resource->EnableTouchScreen(aruid, is_enabled); 263 applet_resource->EnableTouchScreen(aruid, is_enabled);
258} 264}
259 265
266NpadVibrationBase* ResourceManager::GetVibrationDevice(
267 const Core::HID::VibrationDeviceHandle& handle) {
268 return npad->GetVibrationDevice(handle);
269}
270
271NpadN64VibrationDevice* ResourceManager::GetN64VibrationDevice(
272 const Core::HID::VibrationDeviceHandle& handle) {
273 return npad->GetN64VibrationDevice(handle);
274}
275
276NpadVibrationDevice* ResourceManager::GetNSVibrationDevice(
277 const Core::HID::VibrationDeviceHandle& handle) {
278 return npad->GetNSVibrationDevice(handle);
279}
280
281NpadGcVibrationDevice* ResourceManager::GetGcVibrationDevice(
282 const Core::HID::VibrationDeviceHandle& handle) {
283 return npad->GetGcVibrationDevice(handle);
284}
285
286Result ResourceManager::SetAruidValidForVibration(u64 aruid, bool is_enabled) {
287 std::scoped_lock lock{shared_mutex};
288 const bool has_changed = applet_resource->SetAruidValidForVibration(aruid, is_enabled);
289
290 if (has_changed) {
291 auto devices = npad->GetAllVibrationDevices();
292 for ([[maybe_unused]] auto* device : devices) {
293 // TODO
294 }
295 }
296
297 auto* vibration_handler = npad->GetVibrationHandler();
298 if (aruid != vibration_handler->GetSessionAruid()) {
299 vibration_handler->EndPermitVibrationSession();
300 }
301
302 return ResultSuccess;
303}
304
305void ResourceManager::SetForceHandheldStyleVibration(bool is_forced) {
306 handheld_config->is_force_handheld_style_vibration = is_forced;
307}
308
309Result ResourceManager::IsVibrationAruidActive(u64 aruid, bool& is_active) const {
310 std::scoped_lock lock{shared_mutex};
311 is_active = applet_resource->IsVibrationAruidActive(aruid);
312 return ResultSuccess;
313}
314
315Result ResourceManager::GetVibrationDeviceInfo(Core::HID::VibrationDeviceInfo& device_info,
316 const Core::HID::VibrationDeviceHandle& handle) {
317 bool check_device_index = false;
318
319 const Result is_valid = IsVibrationHandleValid(handle);
320 if (is_valid.IsError()) {
321 return is_valid;
322 }
323
324 switch (handle.npad_type) {
325 case Core::HID::NpadStyleIndex::Fullkey:
326 case Core::HID::NpadStyleIndex::Handheld:
327 case Core::HID::NpadStyleIndex::JoyconDual:
328 case Core::HID::NpadStyleIndex::JoyconLeft:
329 case Core::HID::NpadStyleIndex::JoyconRight:
330 device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
331 check_device_index = true;
332 break;
333 case Core::HID::NpadStyleIndex::GameCube:
334 device_info.type = Core::HID::VibrationDeviceType::GcErm;
335 break;
336 case Core::HID::NpadStyleIndex::N64:
337 device_info.type = Core::HID::VibrationDeviceType::N64;
338 break;
339 default:
340 device_info.type = Core::HID::VibrationDeviceType::Unknown;
341 break;
342 }
343
344 device_info.position = Core::HID::VibrationDevicePosition::None;
345 if (check_device_index) {
346 switch (handle.device_index) {
347 case Core::HID::DeviceIndex::Left:
348 device_info.position = Core::HID::VibrationDevicePosition::Left;
349 break;
350 case Core::HID::DeviceIndex::Right:
351 device_info.position = Core::HID::VibrationDevicePosition::Right;
352 break;
353 case Core::HID::DeviceIndex::None:
354 default:
355 ASSERT_MSG(false, "DeviceIndex should never be None!");
356 break;
357 }
358 }
359 return ResultSuccess;
360}
361
362Result ResourceManager::SendVibrationValue(u64 aruid,
363 const Core::HID::VibrationDeviceHandle& handle,
364 const Core::HID::VibrationValue& value) {
365 bool has_active_aruid{};
366 NpadVibrationDevice* device{nullptr};
367 Result result = IsVibrationAruidActive(aruid, has_active_aruid);
368
369 if (result.IsSuccess() && has_active_aruid) {
370 result = IsVibrationHandleValid(handle);
371 }
372 if (result.IsSuccess() && has_active_aruid) {
373 device = GetNSVibrationDevice(handle);
374 }
375 if (device != nullptr) {
376 result = device->SendVibrationValue(value);
377 }
378 return result;
379}
380
260void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) { 381void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) {
261 auto& core_timing = system.CoreTiming(); 382 auto& core_timing = system.CoreTiming();
262 debug_pad->OnUpdate(core_timing); 383 debug_pad->OnUpdate(core_timing);
diff --git a/src/hid_core/resource_manager.h b/src/hid_core/resource_manager.h
index 7a21d8eb8..128e00125 100644
--- a/src/hid_core/resource_manager.h
+++ b/src/hid_core/resource_manager.h
@@ -10,6 +10,12 @@ namespace Core {
10class System; 10class System;
11} 11}
12 12
13namespace Core::HID {
14struct VibrationDeviceHandle;
15struct VibrationValue;
16struct VibrationDeviceInfo;
17} // namespace Core::HID
18
13namespace Core::Timing { 19namespace Core::Timing {
14struct EventType; 20struct EventType;
15} 21}
@@ -37,6 +43,11 @@ class SixAxis;
37class SleepButton; 43class SleepButton;
38class TouchScreen; 44class TouchScreen;
39class UniquePad; 45class UniquePad;
46class NpadVibrationBase;
47class NpadN64VibrationDevice;
48class NpadGcVibrationDevice;
49class NpadVibrationDevice;
50struct HandheldConfig;
40 51
41class ResourceManager { 52class ResourceManager {
42 53
@@ -79,6 +90,18 @@ public:
79 void EnablePadInput(u64 aruid, bool is_enabled); 90 void EnablePadInput(u64 aruid, bool is_enabled);
80 void EnableTouchScreen(u64 aruid, bool is_enabled); 91 void EnableTouchScreen(u64 aruid, bool is_enabled);
81 92
93 NpadVibrationBase* GetVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
94 NpadN64VibrationDevice* GetN64VibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
95 NpadVibrationDevice* GetNSVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
96 NpadGcVibrationDevice* GetGcVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
97 Result SetAruidValidForVibration(u64 aruid, bool is_enabled);
98 void SetForceHandheldStyleVibration(bool is_forced);
99 Result IsVibrationAruidActive(u64 aruid, bool& is_active) const;
100 Result GetVibrationDeviceInfo(Core::HID::VibrationDeviceInfo& device_info,
101 const Core::HID::VibrationDeviceHandle& handle);
102 Result SendVibrationValue(u64 aruid, const Core::HID::VibrationDeviceHandle& handle,
103 const Core::HID::VibrationValue& value);
104
82 void UpdateControllers(std::chrono::nanoseconds ns_late); 105 void UpdateControllers(std::chrono::nanoseconds ns_late);
83 void UpdateNpad(std::chrono::nanoseconds ns_late); 106 void UpdateNpad(std::chrono::nanoseconds ns_late);
84 void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late); 107 void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late);
@@ -113,6 +136,8 @@ private:
113 std::shared_ptr<TouchScreen> touch_screen = nullptr; 136 std::shared_ptr<TouchScreen> touch_screen = nullptr;
114 std::shared_ptr<UniquePad> unique_pad = nullptr; 137 std::shared_ptr<UniquePad> unique_pad = nullptr;
115 138
139 std::shared_ptr<HandheldConfig> handheld_config = nullptr;
140
116 // TODO: Create these resources 141 // TODO: Create these resources
117 // std::shared_ptr<AudioControl> audio_control = nullptr; 142 // std::shared_ptr<AudioControl> audio_control = nullptr;
118 // std::shared_ptr<ButtonConfig> button_config = nullptr; 143 // std::shared_ptr<ButtonConfig> button_config = nullptr;
diff --git a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp
index d4e4181bf..e399edfd7 100644
--- a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp
+++ b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp
@@ -115,7 +115,7 @@ Result NpadAbstractIrSensorHandler::GetXcdHandleForNpadWithIrSensor(u64& handle)
115 if (sensor_state < NpadIrSensorState::Available) { 115 if (sensor_state < NpadIrSensorState::Available) {
116 return ResultIrSensorIsNotReady; 116 return ResultIrSensorIsNotReady;
117 } 117 }
118 handle = xcd_handle; 118 // handle = xcd_handle;
119 return ResultSuccess; 119 return ResultSuccess;
120} 120}
121 121
diff --git a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h
index fe8e005af..997811511 100644
--- a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h
+++ b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h
@@ -7,6 +7,10 @@
7#include "core/hle/result.h" 7#include "core/hle/result.h"
8#include "hid_core/hid_types.h" 8#include "hid_core/hid_types.h"
9 9
10namespace Core::HID {
11class EmulatedController;
12}
13
10namespace Kernel { 14namespace Kernel {
11class KEvent; 15class KEvent;
12class KReadableEvent; 16class KReadableEvent;
@@ -50,7 +54,7 @@ private:
50 54
51 s32 ref_counter{}; 55 s32 ref_counter{};
52 Kernel::KEvent* ir_sensor_event{nullptr}; 56 Kernel::KEvent* ir_sensor_event{nullptr};
53 u64 xcd_handle{}; 57 Core::HID::EmulatedController* xcd_handle{};
54 NpadIrSensorState sensor_state{}; 58 NpadIrSensorState sensor_state{};
55}; 59};
56} // namespace Service::HID 60} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.cpp b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp
index 2c7691d7c..435b095f0 100644
--- a/src/hid_core/resources/abstracted_pad/abstract_pad.cpp
+++ b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include "hid_core/hid_core.h"
4#include "hid_core/hid_result.h" 5#include "hid_core/hid_result.h"
5#include "hid_core/resources/abstracted_pad/abstract_pad.h" 6#include "hid_core/resources/abstracted_pad/abstract_pad.h"
6#include "hid_core/resources/applet_resource.h" 7#include "hid_core/resources/applet_resource.h"
@@ -16,7 +17,7 @@ void AbstractPad::SetExternals(AppletResourceHolder* applet_resource,
16 CaptureButtonResource* capture_button_resource, 17 CaptureButtonResource* capture_button_resource,
17 HomeButtonResource* home_button_resource, 18 HomeButtonResource* home_button_resource,
18 SixAxisResource* sixaxis_resource, PalmaResource* palma_resource, 19 SixAxisResource* sixaxis_resource, PalmaResource* palma_resource,
19 VibrationHandler* vibration) { 20 NpadVibration* vibration, Core::HID::HIDCore* core) {
20 applet_resource_holder = applet_resource; 21 applet_resource_holder = applet_resource;
21 22
22 properties_handler.SetAppletResource(applet_resource_holder); 23 properties_handler.SetAppletResource(applet_resource_holder);
@@ -35,13 +36,14 @@ void AbstractPad::SetExternals(AppletResourceHolder* applet_resource,
35 mcu_handler.SetAbstractPadHolder(&abstract_pad_holder); 36 mcu_handler.SetAbstractPadHolder(&abstract_pad_holder);
36 mcu_handler.SetPropertiesHandler(&properties_handler); 37 mcu_handler.SetPropertiesHandler(&properties_handler);
37 38
38 std::array<NpadVibrationDevice*, 2> vibration_devices{&vibration_left, &vibration_right};
39 vibration_handler.SetAppletResource(applet_resource_holder); 39 vibration_handler.SetAppletResource(applet_resource_holder);
40 vibration_handler.SetAbstractPadHolder(&abstract_pad_holder); 40 vibration_handler.SetAbstractPadHolder(&abstract_pad_holder);
41 vibration_handler.SetPropertiesHandler(&properties_handler); 41 vibration_handler.SetPropertiesHandler(&properties_handler);
42 vibration_handler.SetN64Vibration(&vibration_n64); 42 vibration_handler.SetN64Vibration(&vibration_n64);
43 vibration_handler.SetVibration(vibration_devices); 43 vibration_handler.SetVibration(&vibration_left, &vibration_right);
44 vibration_handler.SetGcVibration(&vibration_gc); 44 vibration_handler.SetGcVibration(&vibration_gc);
45 vibration_handler.SetVibrationHandler(vibration);
46 vibration_handler.SetHidCore(core);
45 47
46 sixaxis_handler.SetAppletResource(applet_resource_holder); 48 sixaxis_handler.SetAppletResource(applet_resource_holder);
47 sixaxis_handler.SetAbstractPadHolder(&abstract_pad_holder); 49 sixaxis_handler.SetAbstractPadHolder(&abstract_pad_holder);
@@ -239,11 +241,6 @@ NpadVibrationDevice* AbstractPad::GetVibrationDevice(Core::HID::DeviceIndex devi
239 return &vibration_left; 241 return &vibration_left;
240} 242}
241 243
242void AbstractPad::GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list) {
243 list.emplace_back(&vibration_left);
244 list.emplace_back(&vibration_right);
245}
246
247NpadGcVibrationDevice* AbstractPad::GetGCVibrationDevice() { 244NpadGcVibrationDevice* AbstractPad::GetGCVibrationDevice() {
248 return &vibration_gc; 245 return &vibration_gc;
249} 246}
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.h b/src/hid_core/resources/abstracted_pad/abstract_pad.h
index cbdf84af7..329792457 100644
--- a/src/hid_core/resources/abstracted_pad/abstract_pad.h
+++ b/src/hid_core/resources/abstracted_pad/abstract_pad.h
@@ -32,7 +32,6 @@ class AppletResource;
32class SixAxisResource; 32class SixAxisResource;
33class PalmaResource; 33class PalmaResource;
34class NPadResource; 34class NPadResource;
35class AbstractPad;
36class NpadLastActiveHandler; 35class NpadLastActiveHandler;
37class NpadIrNfcHandler; 36class NpadIrNfcHandler;
38class UniquePads; 37class UniquePads;
@@ -44,7 +43,6 @@ class NpadGcVibration;
44 43
45class CaptureButtonResource; 44class CaptureButtonResource;
46class HomeButtonResource; 45class HomeButtonResource;
47class VibrationHandler;
48 46
49struct HandheldConfig; 47struct HandheldConfig;
50 48
@@ -57,7 +55,8 @@ public:
57 void SetExternals(AppletResourceHolder* applet_resource, 55 void SetExternals(AppletResourceHolder* applet_resource,
58 CaptureButtonResource* capture_button_resource, 56 CaptureButtonResource* capture_button_resource,
59 HomeButtonResource* home_button_resource, SixAxisResource* sixaxis_resource, 57 HomeButtonResource* home_button_resource, SixAxisResource* sixaxis_resource,
60 PalmaResource* palma_resource, VibrationHandler* vibration); 58 PalmaResource* palma_resource, NpadVibration* vibration,
59 Core::HID::HIDCore* core);
61 void SetNpadId(Core::HID::NpadIdType npad_id); 60 void SetNpadId(Core::HID::NpadIdType npad_id);
62 61
63 Result Activate(); 62 Result Activate();
@@ -78,7 +77,6 @@ public:
78 77
79 NpadN64VibrationDevice* GetN64VibrationDevice(); 78 NpadN64VibrationDevice* GetN64VibrationDevice();
80 NpadVibrationDevice* GetVibrationDevice(Core::HID::DeviceIndex device_index); 79 NpadVibrationDevice* GetVibrationDevice(Core::HID::DeviceIndex device_index);
81 void GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list);
82 NpadGcVibrationDevice* GetGCVibrationDevice(); 80 NpadGcVibrationDevice* GetGCVibrationDevice();
83 81
84 Core::HID::NpadIdType GetLastActiveNpad(); 82 Core::HID::NpadIdType GetLastActiveNpad();
diff --git a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp
index a00d6c9de..ca64b0a43 100644
--- a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp
+++ b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp
@@ -1,6 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include "hid_core/frontend/emulated_controller.h"
5#include "hid_core/hid_core.h"
4#include "hid_core/hid_result.h" 6#include "hid_core/hid_result.h"
5#include "hid_core/hid_util.h" 7#include "hid_core/hid_util.h"
6#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" 8#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
@@ -30,14 +32,22 @@ void NpadAbstractVibrationHandler::SetPropertiesHandler(NpadAbstractPropertiesHa
30 properties_handler = handler; 32 properties_handler = handler;
31} 33}
32 34
35void NpadAbstractVibrationHandler::SetVibrationHandler(NpadVibration* handler) {
36 vibration_handler = handler;
37}
38
39void NpadAbstractVibrationHandler::SetHidCore(Core::HID::HIDCore* core) {
40 hid_core = core;
41}
42
33void NpadAbstractVibrationHandler::SetN64Vibration(NpadN64VibrationDevice* n64_device) { 43void NpadAbstractVibrationHandler::SetN64Vibration(NpadN64VibrationDevice* n64_device) {
34 n64_vibration_device = n64_device; 44 n64_vibration_device = n64_device;
35} 45}
36 46
37void NpadAbstractVibrationHandler::SetVibration(std::span<NpadVibrationDevice*> device) { 47void NpadAbstractVibrationHandler::SetVibration(NpadVibrationDevice* left_device,
38 for (std::size_t i = 0; i < device.size() && i < vibration_device.size(); i++) { 48 NpadVibrationDevice* right_device) {
39 vibration_device[i] = device[i]; 49 left_vibration_device = left_device;
40 } 50 right_vibration_device = right_device;
41} 51}
42 52
43void NpadAbstractVibrationHandler::SetGcVibration(NpadGcVibrationDevice* gc_device) { 53void NpadAbstractVibrationHandler::SetGcVibration(NpadGcVibrationDevice* gc_device) {
@@ -69,5 +79,29 @@ void NpadAbstractVibrationHandler::UpdateVibrationState() {
69 if (!is_handheld_hid_enabled && is_force_handheld_style_vibration) { 79 if (!is_handheld_hid_enabled && is_force_handheld_style_vibration) {
70 // TODO 80 // TODO
71 } 81 }
82
83 // TODO: This function isn't accurate. It's supposed to get 5 abstracted pads from the
84 // NpadAbstractPropertiesHandler but this handler isn't fully implemented yet
85 IAbstractedPad abstracted_pad{};
86 const auto npad_id = properties_handler->GetNpadId();
87 abstracted_pad.xcd_handle = hid_core->GetEmulatedController(npad_id);
88 abstracted_pad.internal_flags.is_connected.Assign(abstracted_pad.xcd_handle->IsConnected());
89
90 if (abstracted_pad.internal_flags.is_connected) {
91 left_vibration_device->Mount(abstracted_pad, Core::HID::DeviceIndex::Left,
92 vibration_handler);
93 right_vibration_device->Mount(abstracted_pad, Core::HID::DeviceIndex::Right,
94 vibration_handler);
95 gc_vibration_device->Mount(abstracted_pad, 0, vibration_handler);
96 gc_vibration_device->Mount(abstracted_pad, 0, vibration_handler);
97 n64_vibration_device->Mount(abstracted_pad, vibration_handler);
98 return;
99 }
100
101 left_vibration_device->Unmount();
102 right_vibration_device->Unmount();
103 gc_vibration_device->Unmount();
104 gc_vibration_device->Unmount();
105 n64_vibration_device->Unmount();
72} 106}
73} // namespace Service::HID 107} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h
index aeb07ce86..8bc8129c2 100644
--- a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h
+++ b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h
@@ -9,6 +9,10 @@
9#include "core/hle/result.h" 9#include "core/hle/result.h"
10#include "hid_core/hid_types.h" 10#include "hid_core/hid_types.h"
11 11
12namespace Core::HID {
13class HIDCore;
14}
15
12namespace Service::HID { 16namespace Service::HID {
13struct AppletResourceHolder; 17struct AppletResourceHolder;
14class NpadAbstractedPadHolder; 18class NpadAbstractedPadHolder;
@@ -27,9 +31,11 @@ public:
27 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); 31 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
28 void SetAppletResource(AppletResourceHolder* applet_resource); 32 void SetAppletResource(AppletResourceHolder* applet_resource);
29 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); 33 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
34 void SetVibrationHandler(NpadVibration* handler);
35 void SetHidCore(Core::HID::HIDCore* core);
30 36
31 void SetN64Vibration(NpadN64VibrationDevice* n64_device); 37 void SetN64Vibration(NpadN64VibrationDevice* n64_device);
32 void SetVibration(std::span<NpadVibrationDevice*> device); 38 void SetVibration(NpadVibrationDevice* left_device, NpadVibrationDevice* right_device);
33 void SetGcVibration(NpadGcVibrationDevice* gc_device); 39 void SetGcVibration(NpadGcVibrationDevice* gc_device);
34 40
35 Result IncrementRefCounter(); 41 Result IncrementRefCounter();
@@ -41,9 +47,11 @@ private:
41 AppletResourceHolder* applet_resource_holder{nullptr}; 47 AppletResourceHolder* applet_resource_holder{nullptr};
42 NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; 48 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
43 NpadAbstractPropertiesHandler* properties_handler{nullptr}; 49 NpadAbstractPropertiesHandler* properties_handler{nullptr};
50 Core::HID::HIDCore* hid_core{nullptr};
44 51
45 NpadN64VibrationDevice* n64_vibration_device{nullptr}; 52 NpadN64VibrationDevice* n64_vibration_device{nullptr};
46 std::array<NpadVibrationDevice*, 2> vibration_device{}; 53 NpadVibrationDevice* left_vibration_device{};
54 NpadVibrationDevice* right_vibration_device{};
47 NpadGcVibrationDevice* gc_vibration_device{nullptr}; 55 NpadGcVibrationDevice* gc_vibration_device{nullptr};
48 NpadVibration* vibration_handler{nullptr}; 56 NpadVibration* vibration_handler{nullptr};
49 s32 ref_counter{}; 57 s32 ref_counter{};
diff --git a/src/hid_core/resources/applet_resource.cpp b/src/hid_core/resources/applet_resource.cpp
index a84826050..db4134037 100644
--- a/src/hid_core/resources/applet_resource.cpp
+++ b/src/hid_core/resources/applet_resource.cpp
@@ -200,6 +200,25 @@ void AppletResource::EnableInput(u64 aruid, bool is_enabled) {
200 data[index].flag.enable_touchscreen.Assign(is_enabled); 200 data[index].flag.enable_touchscreen.Assign(is_enabled);
201} 201}
202 202
203bool AppletResource::SetAruidValidForVibration(u64 aruid, bool is_enabled) {
204 const u64 index = GetIndexFromAruid(aruid);
205 if (index >= AruidIndexMax) {
206 return false;
207 }
208
209 if (!is_enabled && aruid == active_vibration_aruid) {
210 active_vibration_aruid = SystemAruid;
211 return true;
212 }
213
214 if (is_enabled && aruid != active_vibration_aruid) {
215 active_vibration_aruid = aruid;
216 return true;
217 }
218
219 return false;
220}
221
203void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) { 222void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) {
204 const u64 index = GetIndexFromAruid(aruid); 223 const u64 index = GetIndexFromAruid(aruid);
205 if (index >= AruidIndexMax) { 224 if (index >= AruidIndexMax) {
diff --git a/src/hid_core/resources/applet_resource.h b/src/hid_core/resources/applet_resource.h
index f3f32bac1..e9710d306 100644
--- a/src/hid_core/resources/applet_resource.h
+++ b/src/hid_core/resources/applet_resource.h
@@ -101,6 +101,7 @@ public:
101 Result DestroySevenSixAxisTransferMemory(); 101 Result DestroySevenSixAxisTransferMemory();
102 102
103 void EnableInput(u64 aruid, bool is_enabled); 103 void EnableInput(u64 aruid, bool is_enabled);
104 bool SetAruidValidForVibration(u64 aruid, bool is_enabled);
104 void EnableSixAxisSensor(u64 aruid, bool is_enabled); 105 void EnableSixAxisSensor(u64 aruid, bool is_enabled);
105 void EnablePadInput(u64 aruid, bool is_enabled); 106 void EnablePadInput(u64 aruid, bool is_enabled);
106 void EnableTouchScreen(u64 aruid, bool is_enabled); 107 void EnableTouchScreen(u64 aruid, bool is_enabled);
diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp
index de0f9cbb9..212f01429 100644
--- a/src/hid_core/resources/npad/npad.cpp
+++ b/src/hid_core/resources/npad/npad.cpp
@@ -21,6 +21,7 @@
21#include "hid_core/hid_util.h" 21#include "hid_core/hid_util.h"
22#include "hid_core/resources/applet_resource.h" 22#include "hid_core/resources/applet_resource.h"
23#include "hid_core/resources/npad/npad.h" 23#include "hid_core/resources/npad/npad.h"
24#include "hid_core/resources/npad/npad_vibration.h"
24#include "hid_core/resources/shared_memory_format.h" 25#include "hid_core/resources/shared_memory_format.h"
25 26
26namespace Service::HID { 27namespace Service::HID {
@@ -31,10 +32,6 @@ NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service
31 for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) { 32 for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) {
32 auto& controller = controller_data[aruid_index][i]; 33 auto& controller = controller_data[aruid_index][i];
33 controller.device = hid_core.GetEmulatedControllerByIndex(i); 34 controller.device = hid_core.GetEmulatedControllerByIndex(i);
34 controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
35 Core::HID::DEFAULT_VIBRATION_VALUE;
36 controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex]
37 .latest_vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE;
38 Core::HID::ControllerUpdateCallback engine_callback{ 35 Core::HID::ControllerUpdateCallback engine_callback{
39 .on_change = 36 .on_change =
40 [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, 37 [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); },
@@ -43,6 +40,10 @@ NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service
43 controller.callback_key = controller.device->SetCallback(engine_callback); 40 controller.callback_key = controller.device->SetCallback(engine_callback);
44 } 41 }
45 } 42 }
43 for (std::size_t i = 0; i < abstracted_pads.size(); ++i) {
44 abstracted_pads[i] = AbstractPad{};
45 abstracted_pads[i].SetNpadId(IndexToNpadIdType(i));
46 }
46} 47}
47 48
48NPad::~NPad() { 49NPad::~NPad() {
@@ -359,6 +360,7 @@ void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) {
359 npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id); 360 npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id);
360 WriteEmptyEntry(controller.shared_memory); 361 WriteEmptyEntry(controller.shared_memory);
361 hid_core.SetLastActiveController(npad_id); 362 hid_core.SetLastActiveController(npad_id);
363 abstracted_pads[NpadIdTypeToIndex(npad_id)].Update();
362} 364}
363 365
364void NPad::WriteEmptyEntry(NpadInternalState* npad) { 366void NPad::WriteEmptyEntry(NpadInternalState* npad) {
@@ -740,171 +742,6 @@ bool NPad::SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID:
740 return true; 742 return true;
741} 743}
742 744
743bool NPad::VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
744 std::size_t device_index,
745 const Core::HID::VibrationValue& vibration_value) {
746 auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
747 if (!controller.device->IsConnected()) {
748 return false;
749 }
750
751 if (!controller.device->IsVibrationEnabled(device_index)) {
752 if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f ||
753 controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) {
754 // Send an empty vibration to stop any vibrations.
755 Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f};
756 controller.device->SetVibration(device_index, vibration);
757 // Then reset the vibration value to its default value.
758 controller.vibration[device_index].latest_vibration_value =
759 Core::HID::DEFAULT_VIBRATION_VALUE;
760 }
761
762 return false;
763 }
764
765 if (!Settings::values.enable_accurate_vibrations.GetValue()) {
766 using std::chrono::duration_cast;
767 using std::chrono::milliseconds;
768 using std::chrono::steady_clock;
769
770 const auto now = steady_clock::now();
771
772 // Filter out non-zero vibrations that are within 15ms of each other.
773 if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) &&
774 duration_cast<milliseconds>(
775 now - controller.vibration[device_index].last_vibration_timepoint) <
776 milliseconds(15)) {
777 return false;
778 }
779
780 controller.vibration[device_index].last_vibration_timepoint = now;
781 }
782
783 Core::HID::VibrationValue vibration{
784 vibration_value.low_amplitude, vibration_value.low_frequency,
785 vibration_value.high_amplitude, vibration_value.high_frequency};
786 return controller.device->SetVibration(device_index, vibration);
787}
788
789void NPad::VibrateController(u64 aruid,
790 const Core::HID::VibrationDeviceHandle& vibration_device_handle,
791 const Core::HID::VibrationValue& vibration_value) {
792 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
793 return;
794 }
795
796 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
797 return;
798 }
799
800 auto& controller = GetControllerFromHandle(aruid, vibration_device_handle);
801 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
802
803 if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) {
804 return;
805 }
806
807 if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) {
808 ASSERT_MSG(false, "DeviceIndex should never be None!");
809 return;
810 }
811
812 // Some games try to send mismatched parameters in the device handle, block these.
813 if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft &&
814 (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight ||
815 vibration_device_handle.device_index == Core::HID::DeviceIndex::Right)) ||
816 (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight &&
817 (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft ||
818 vibration_device_handle.device_index == Core::HID::DeviceIndex::Left))) {
819 return;
820 }
821
822 // Filter out vibrations with equivalent values to reduce unnecessary state changes.
823 if (vibration_value.low_amplitude ==
824 controller.vibration[device_index].latest_vibration_value.low_amplitude &&
825 vibration_value.high_amplitude ==
826 controller.vibration[device_index].latest_vibration_value.high_amplitude) {
827 return;
828 }
829
830 if (VibrateControllerAtIndex(aruid, controller.device->GetNpadIdType(), device_index,
831 vibration_value)) {
832 controller.vibration[device_index].latest_vibration_value = vibration_value;
833 }
834}
835
836void NPad::VibrateControllers(
837 u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
838 std::span<const Core::HID::VibrationValue> vibration_values) {
839 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
840 return;
841 }
842
843 ASSERT_OR_EXECUTE_MSG(
844 vibration_device_handles.size() == vibration_values.size(), { return; },
845 "The amount of device handles does not match with the amount of vibration values,"
846 "this is undefined behavior!");
847
848 for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) {
849 VibrateController(aruid, vibration_device_handles[i], vibration_values[i]);
850 }
851}
852
853Core::HID::VibrationValue NPad::GetLastVibration(
854 u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
855 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
856 return {};
857 }
858
859 const auto& controller = GetControllerFromHandle(aruid, vibration_device_handle);
860 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
861 return controller.vibration[device_index].latest_vibration_value;
862}
863
864void NPad::InitializeVibrationDevice(
865 const Core::HID::VibrationDeviceHandle& vibration_device_handle) {
866 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
867 return;
868 }
869
870 const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid();
871 const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id);
872 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
873
874 if (aruid == 0) {
875 return;
876 }
877
878 InitializeVibrationDeviceAtIndex(aruid, npad_index, device_index);
879}
880
881void NPad::InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
882 std::size_t device_index) {
883 auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
884 if (!Settings::values.vibration_enabled.GetValue()) {
885 controller.vibration[device_index].device_mounted = false;
886 return;
887 }
888
889 controller.vibration[device_index].device_mounted =
890 controller.device->IsVibrationEnabled(device_index);
891}
892
893void NPad::SetPermitVibrationSession(bool permit_vibration_session) {
894 permit_vibration_session_enabled = permit_vibration_session;
895}
896
897bool NPad::IsVibrationDeviceMounted(
898 u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
899 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
900 return false;
901 }
902
903 const auto& controller = GetControllerFromHandle(aruid, vibration_device_handle);
904 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
905 return controller.vibration[device_index].device_mounted;
906}
907
908Result NPad::AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event, 745Result NPad::AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event,
909 Core::HID::NpadIdType npad_id) { 746 Core::HID::NpadIdType npad_id) {
910 std::scoped_lock lock{mutex}; 747 std::scoped_lock lock{mutex};
@@ -936,11 +773,6 @@ Result NPad::DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id) {
936 773
937 LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); 774 LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id);
938 auto& controller = GetControllerFromNpadIdType(aruid, npad_id); 775 auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
939 for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) {
940 // Send an empty vibration to stop any vibrations.
941 VibrateControllerAtIndex(aruid, npad_id, device_idx, {});
942 controller.vibration[device_idx].device_mounted = false;
943 }
944 776
945 auto* shared_memory = controller.shared_memory; 777 auto* shared_memory = controller.shared_memory;
946 // Don't reset shared_memory->assignment_mode this value is persistent 778 // Don't reset shared_memory->assignment_mode this value is persistent
@@ -1243,22 +1075,17 @@ void NPad::UnregisterAppletResourceUserId(u64 aruid) {
1243} 1075}
1244 1076
1245void NPad::SetNpadExternals(std::shared_ptr<AppletResource> resource, 1077void NPad::SetNpadExternals(std::shared_ptr<AppletResource> resource,
1246 std::recursive_mutex* shared_mutex) { 1078 std::recursive_mutex* shared_mutex,
1079 std::shared_ptr<HandheldConfig> handheld_config) {
1247 applet_resource_holder.applet_resource = resource; 1080 applet_resource_holder.applet_resource = resource;
1248 applet_resource_holder.shared_mutex = shared_mutex; 1081 applet_resource_holder.shared_mutex = shared_mutex;
1249 applet_resource_holder.shared_npad_resource = &npad_resource; 1082 applet_resource_holder.shared_npad_resource = &npad_resource;
1250} 1083 applet_resource_holder.handheld_config = handheld_config;
1251 1084
1252NPad::NpadControllerData& NPad::GetControllerFromHandle( 1085 for (auto& abstract_pad : abstracted_pads) {
1253 u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) { 1086 abstract_pad.SetExternals(&applet_resource_holder, nullptr, nullptr, nullptr, nullptr,
1254 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); 1087 &vibration_handler, &hid_core);
1255 return GetControllerFromNpadIdType(aruid, npad_id); 1088 }
1256}
1257
1258const NPad::NpadControllerData& NPad::GetControllerFromHandle(
1259 u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const {
1260 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
1261 return GetControllerFromNpadIdType(aruid, npad_id);
1262} 1089}
1263 1090
1264NPad::NpadControllerData& NPad::GetControllerFromHandle( 1091NPad::NpadControllerData& NPad::GetControllerFromHandle(
@@ -1396,4 +1223,97 @@ Result NPad::GetLastActiveNpad(Core::HID::NpadIdType& out_npad_id) const {
1396 return ResultSuccess; 1223 return ResultSuccess;
1397} 1224}
1398 1225
1226NpadVibration* NPad::GetVibrationHandler() {
1227 return &vibration_handler;
1228}
1229
1230std::vector<NpadVibrationBase*> NPad::GetAllVibrationDevices() {
1231 std::vector<NpadVibrationBase*> vibration_devices;
1232
1233 for (auto& abstract_pad : abstracted_pads) {
1234 auto* left_device = abstract_pad.GetVibrationDevice(Core::HID::DeviceIndex::Left);
1235 auto* right_device = abstract_pad.GetVibrationDevice(Core::HID::DeviceIndex::Right);
1236 auto* n64_device = abstract_pad.GetGCVibrationDevice();
1237 auto* gc_device = abstract_pad.GetGCVibrationDevice();
1238
1239 if (left_device != nullptr) {
1240 vibration_devices.emplace_back(left_device);
1241 }
1242 if (right_device != nullptr) {
1243 vibration_devices.emplace_back(right_device);
1244 }
1245 if (n64_device != nullptr) {
1246 vibration_devices.emplace_back(n64_device);
1247 }
1248 if (gc_device != nullptr) {
1249 vibration_devices.emplace_back(gc_device);
1250 }
1251 }
1252
1253 return vibration_devices;
1254}
1255
1256NpadVibrationBase* NPad::GetVibrationDevice(const Core::HID::VibrationDeviceHandle& handle) {
1257 if (IsVibrationHandleValid(handle).IsError()) {
1258 return nullptr;
1259 }
1260
1261 const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id));
1262 const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type);
1263 if (style_inde == Core::HID::NpadStyleIndex::GameCube) {
1264 return abstracted_pads[npad_index].GetGCVibrationDevice();
1265 }
1266 if (style_inde == Core::HID::NpadStyleIndex::N64) {
1267 return abstracted_pads[npad_index].GetN64VibrationDevice();
1268 }
1269 return abstracted_pads[npad_index].GetVibrationDevice(handle.device_index);
1270}
1271
1272NpadN64VibrationDevice* NPad::GetN64VibrationDevice(
1273 const Core::HID::VibrationDeviceHandle& handle) {
1274 if (IsVibrationHandleValid(handle).IsError()) {
1275 return nullptr;
1276 }
1277
1278 const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id));
1279 const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type);
1280 if (style_inde != Core::HID::NpadStyleIndex::N64) {
1281 return nullptr;
1282 }
1283 return abstracted_pads[npad_index].GetN64VibrationDevice();
1284}
1285
1286NpadVibrationDevice* NPad::GetNSVibrationDevice(const Core::HID::VibrationDeviceHandle& handle) {
1287 if (IsVibrationHandleValid(handle).IsError()) {
1288 return nullptr;
1289 }
1290
1291 const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id));
1292 const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type);
1293 if (style_inde == Core::HID::NpadStyleIndex::GameCube ||
1294 style_inde == Core::HID::NpadStyleIndex::N64) {
1295 return nullptr;
1296 }
1297
1298 return abstracted_pads[npad_index].GetVibrationDevice(handle.device_index);
1299}
1300
1301NpadGcVibrationDevice* NPad::GetGcVibrationDevice(const Core::HID::VibrationDeviceHandle& handle) {
1302 if (IsVibrationHandleValid(handle).IsError()) {
1303 return nullptr;
1304 }
1305
1306 const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id));
1307 const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type);
1308 if (style_inde != Core::HID::NpadStyleIndex::GameCube) {
1309 return nullptr;
1310 }
1311 return abstracted_pads[npad_index].GetGCVibrationDevice();
1312}
1313
1314void NPad::UpdateHandheldAbstractState() {
1315 std::scoped_lock lock{mutex};
1316 abstracted_pads[NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld)].Update();
1317}
1318
1399} // namespace Service::HID 1319} // namespace Service::HID
diff --git a/src/hid_core/resources/npad/npad.h b/src/hid_core/resources/npad/npad.h
index 01f3dabb1..18b25c688 100644
--- a/src/hid_core/resources/npad/npad.h
+++ b/src/hid_core/resources/npad/npad.h
@@ -10,9 +10,15 @@
10 10
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "hid_core/hid_types.h" 12#include "hid_core/hid_types.h"
13#include "hid_core/resources/abstracted_pad/abstract_pad.h"
13#include "hid_core/resources/controller_base.h" 14#include "hid_core/resources/controller_base.h"
14#include "hid_core/resources/npad/npad_resource.h" 15#include "hid_core/resources/npad/npad_resource.h"
15#include "hid_core/resources/npad/npad_types.h" 16#include "hid_core/resources/npad/npad_types.h"
17#include "hid_core/resources/npad/npad_vibration.h"
18#include "hid_core/resources/vibration/gc_vibration_device.h"
19#include "hid_core/resources/vibration/n64_vibration_device.h"
20#include "hid_core/resources/vibration/vibration_base.h"
21#include "hid_core/resources/vibration/vibration_device.h"
16 22
17namespace Core::HID { 23namespace Core::HID {
18class EmulatedController; 24class EmulatedController;
@@ -32,6 +38,7 @@ union Result;
32 38
33namespace Service::HID { 39namespace Service::HID {
34class AppletResource; 40class AppletResource;
41struct HandheldConfig;
35struct NpadInternalState; 42struct NpadInternalState;
36struct NpadSixAxisSensorLifo; 43struct NpadSixAxisSensorLifo;
37struct NpadSharedMemoryFormat; 44struct NpadSharedMemoryFormat;
@@ -68,31 +75,6 @@ public:
68 bool SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, 75 bool SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
69 NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode); 76 NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode);
70 77
71 bool VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
72 std::size_t device_index,
73 const Core::HID::VibrationValue& vibration_value);
74
75 void VibrateController(u64 aruid,
76 const Core::HID::VibrationDeviceHandle& vibration_device_handle,
77 const Core::HID::VibrationValue& vibration_value);
78
79 void VibrateControllers(
80 u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
81 std::span<const Core::HID::VibrationValue> vibration_values);
82
83 Core::HID::VibrationValue GetLastVibration(
84 u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
85
86 void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle);
87
88 void InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
89 std::size_t device_index);
90
91 void SetPermitVibrationSession(bool permit_vibration_session);
92
93 bool IsVibrationDeviceMounted(
94 u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
95
96 Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event, 78 Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event,
97 Core::HID::NpadIdType npad_id); 79 Core::HID::NpadIdType npad_id);
98 80
@@ -145,7 +127,8 @@ public:
145 Result RegisterAppletResourceUserId(u64 aruid); 127 Result RegisterAppletResourceUserId(u64 aruid);
146 void UnregisterAppletResourceUserId(u64 aruid); 128 void UnregisterAppletResourceUserId(u64 aruid);
147 void SetNpadExternals(std::shared_ptr<AppletResource> resource, 129 void SetNpadExternals(std::shared_ptr<AppletResource> resource,
148 std::recursive_mutex* shared_mutex); 130 std::recursive_mutex* shared_mutex,
131 std::shared_ptr<HandheldConfig> handheld_config);
149 132
150 AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); 133 AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
151 134
@@ -161,18 +144,20 @@ public:
161 144
162 Result GetLastActiveNpad(Core::HID::NpadIdType& out_npad_id) const; 145 Result GetLastActiveNpad(Core::HID::NpadIdType& out_npad_id) const;
163 146
164private: 147 NpadVibration* GetVibrationHandler();
165 struct VibrationData { 148 std::vector<NpadVibrationBase*> GetAllVibrationDevices();
166 bool device_mounted{}; 149 NpadVibrationBase* GetVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
167 Core::HID::VibrationValue latest_vibration_value{}; 150 NpadN64VibrationDevice* GetN64VibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
168 std::chrono::steady_clock::time_point last_vibration_timepoint{}; 151 NpadVibrationDevice* GetNSVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
169 }; 152 NpadGcVibrationDevice* GetGcVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
170 153
154 void UpdateHandheldAbstractState();
155
156private:
171 struct NpadControllerData { 157 struct NpadControllerData {
172 NpadInternalState* shared_memory = nullptr; 158 NpadInternalState* shared_memory = nullptr;
173 Core::HID::EmulatedController* device = nullptr; 159 Core::HID::EmulatedController* device = nullptr;
174 160
175 std::array<VibrationData, 2> vibration{};
176 bool is_connected{}; 161 bool is_connected{};
177 162
178 // Dual joycons can have only one side connected 163 // Dual joycons can have only one side connected
@@ -192,10 +177,6 @@ private:
192 void WriteEmptyEntry(NpadInternalState* npad); 177 void WriteEmptyEntry(NpadInternalState* npad);
193 178
194 NpadControllerData& GetControllerFromHandle( 179 NpadControllerData& GetControllerFromHandle(
195 u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle);
196 const NpadControllerData& GetControllerFromHandle(
197 u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const;
198 NpadControllerData& GetControllerFromHandle(
199 u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle); 180 u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle);
200 const NpadControllerData& GetControllerFromHandle( 181 const NpadControllerData& GetControllerFromHandle(
201 u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const; 182 u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const;
@@ -215,11 +196,13 @@ private:
215 mutable std::mutex mutex; 196 mutable std::mutex mutex;
216 NPadResource npad_resource; 197 NPadResource npad_resource;
217 AppletResourceHolder applet_resource_holder{}; 198 AppletResourceHolder applet_resource_holder{};
199 std::array<AbstractPad, MaxSupportedNpadIdTypes> abstracted_pads;
200 NpadVibration vibration_handler{};
201
218 Kernel::KEvent* input_event{nullptr}; 202 Kernel::KEvent* input_event{nullptr};
219 std::mutex* input_mutex{nullptr}; 203 std::mutex* input_mutex{nullptr};
220 204
221 std::atomic<u64> press_state{}; 205 std::atomic<u64> press_state{};
222 bool permit_vibration_session_enabled;
223 std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax> 206 std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax>
224 controller_data{}; 207 controller_data{};
225}; 208};
diff --git a/src/hid_core/resources/npad/npad_types.h b/src/hid_core/resources/npad/npad_types.h
index fd86c8e40..92700d69a 100644
--- a/src/hid_core/resources/npad/npad_types.h
+++ b/src/hid_core/resources/npad/npad_types.h
@@ -8,6 +8,10 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "hid_core/hid_types.h" 9#include "hid_core/hid_types.h"
10 10
11namespace Core::HID {
12class EmulatedController;
13}
14
11namespace Service::HID { 15namespace Service::HID {
12static constexpr std::size_t MaxSupportedNpadIdTypes = 10; 16static constexpr std::size_t MaxSupportedNpadIdTypes = 10;
13static constexpr std::size_t StyleIndexCount = 7; 17static constexpr std::size_t StyleIndexCount = 7;
@@ -348,7 +352,7 @@ struct IAbstractedPad {
348 u8 indicator; 352 u8 indicator;
349 std::vector<f32> virtual_six_axis_sensor_acceleration; 353 std::vector<f32> virtual_six_axis_sensor_acceleration;
350 std::vector<f32> virtual_six_axis_sensor_angle; 354 std::vector<f32> virtual_six_axis_sensor_angle;
351 u64 xcd_handle; 355 Core::HID::EmulatedController* xcd_handle;
352 u64 color; 356 u64 color;
353}; 357};
354} // namespace Service::HID 358} // namespace Service::HID
diff --git a/src/hid_core/resources/npad/npad_vibration.cpp b/src/hid_core/resources/npad/npad_vibration.cpp
index 7056e8eab..05aad4c54 100644
--- a/src/hid_core/resources/npad/npad_vibration.cpp
+++ b/src/hid_core/resources/npad/npad_vibration.cpp
@@ -77,4 +77,8 @@ Result NpadVibration::EndPermitVibrationSession() {
77 return ResultSuccess; 77 return ResultSuccess;
78} 78}
79 79
80u64 NpadVibration::GetSessionAruid() const {
81 return session_aruid;
82}
83
80} // namespace Service::HID 84} // namespace Service::HID
diff --git a/src/hid_core/resources/npad/npad_vibration.h b/src/hid_core/resources/npad/npad_vibration.h
index 0748aeffc..d5a95f2a0 100644
--- a/src/hid_core/resources/npad/npad_vibration.h
+++ b/src/hid_core/resources/npad/npad_vibration.h
@@ -25,6 +25,8 @@ public:
25 Result BeginPermitVibrationSession(u64 aruid); 25 Result BeginPermitVibrationSession(u64 aruid);
26 Result EndPermitVibrationSession(); 26 Result EndPermitVibrationSession();
27 27
28 u64 GetSessionAruid() const;
29
28private: 30private:
29 f32 volume{}; 31 f32 volume{};
30 u64 session_aruid{}; 32 u64 session_aruid{};
diff --git a/src/hid_core/resources/vibration/gc_vibration_device.cpp b/src/hid_core/resources/vibration/gc_vibration_device.cpp
index f01f81b9a..ad42b9d66 100644
--- a/src/hid_core/resources/vibration/gc_vibration_device.cpp
+++ b/src/hid_core/resources/vibration/gc_vibration_device.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include "hid_core/frontend/emulated_controller.h"
4#include "hid_core/hid_result.h" 5#include "hid_core/hid_result.h"
5#include "hid_core/resources/npad/npad_types.h" 6#include "hid_core/resources/npad/npad_types.h"
6#include "hid_core/resources/npad/npad_vibration.h" 7#include "hid_core/resources/npad/npad_vibration.h"
@@ -10,24 +11,25 @@ namespace Service::HID {
10 11
11NpadGcVibrationDevice::NpadGcVibrationDevice() {} 12NpadGcVibrationDevice::NpadGcVibrationDevice() {}
12 13
13Result NpadGcVibrationDevice::IncrementRefCounter() { 14Result NpadGcVibrationDevice::Activate() {
14 if (ref_counter == 0 && is_mounted) { 15 if (ref_counter == 0 && is_mounted) {
15 f32 volume = 1.0f; 16 f32 volume = 1.0f;
16 const auto result = vibration_handler->GetVibrationVolume(volume); 17 const auto result = vibration_handler->GetVibrationVolume(volume);
17 if (result.IsSuccess()) { 18 if (result.IsSuccess()) {
18 // TODO: SendVibrationGcErmCommand 19 xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop);
19 } 20 }
20 } 21 }
22
21 ref_counter++; 23 ref_counter++;
22 return ResultSuccess; 24 return ResultSuccess;
23} 25}
24 26
25Result NpadGcVibrationDevice::DecrementRefCounter() { 27Result NpadGcVibrationDevice::Deactivate() {
26 if (ref_counter == 1 && !is_mounted) { 28 if (ref_counter == 1 && is_mounted) {
27 f32 volume = 1.0f; 29 f32 volume = 1.0f;
28 const auto result = vibration_handler->GetVibrationVolume(volume); 30 const auto result = vibration_handler->GetVibrationVolume(volume);
29 if (result.IsSuccess()) { 31 if (result.IsSuccess()) {
30 // TODO: SendVibrationGcErmCommand 32 xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop);
31 } 33 }
32 } 34 }
33 35
@@ -38,6 +40,48 @@ Result NpadGcVibrationDevice::DecrementRefCounter() {
38 return ResultSuccess; 40 return ResultSuccess;
39} 41}
40 42
43Result NpadGcVibrationDevice::Mount(IAbstractedPad& abstracted_pad, u32 slot,
44 NpadVibration* handler) {
45 if (!abstracted_pad.internal_flags.is_connected) {
46 return ResultSuccess;
47 }
48
49 // TODO: This device doesn't use a xcd handle instead has an GC adapter handle. This is just to
50 // keep compatibility with the front end.
51 xcd_handle = abstracted_pad.xcd_handle;
52 adapter_slot = slot;
53 vibration_handler = handler;
54 is_mounted = true;
55
56 if (ref_counter == 0) {
57 return ResultSuccess;
58 }
59
60 f32 volume{1.0f};
61 const auto result = vibration_handler->GetVibrationVolume(volume);
62 if (result.IsSuccess()) {
63 xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop);
64 }
65
66 return ResultSuccess;
67}
68
69Result NpadGcVibrationDevice::Unmount() {
70 if (ref_counter == 0 || !is_mounted) {
71 is_mounted = false;
72 return ResultSuccess;
73 }
74
75 f32 volume{1.0f};
76 const auto result = vibration_handler->GetVibrationVolume(volume);
77 if (result.IsSuccess()) {
78 xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop);
79 }
80
81 is_mounted = false;
82 return ResultSuccess;
83}
84
41Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command) { 85Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command) {
42 if (!is_mounted) { 86 if (!is_mounted) {
43 return ResultSuccess; 87 return ResultSuccess;
@@ -55,7 +99,7 @@ Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcEr
55 return ResultSuccess; 99 return ResultSuccess;
56 } 100 }
57 } 101 }
58 // TODO: SendVibrationGcErmCommand 102 xcd_handle->SetVibration(adapter_slot, command);
59 return ResultSuccess; 103 return ResultSuccess;
60} 104}
61 105
diff --git a/src/hid_core/resources/vibration/gc_vibration_device.h b/src/hid_core/resources/vibration/gc_vibration_device.h
index 87abca57d..c624cbb28 100644
--- a/src/hid_core/resources/vibration/gc_vibration_device.h
+++ b/src/hid_core/resources/vibration/gc_vibration_device.h
@@ -20,12 +20,18 @@ class NpadGcVibrationDevice final : public NpadVibrationBase {
20public: 20public:
21 explicit NpadGcVibrationDevice(); 21 explicit NpadGcVibrationDevice();
22 22
23 Result IncrementRefCounter() override; 23 Result Activate() override;
24 Result DecrementRefCounter() override; 24 Result Deactivate() override;
25
26 Result Mount(IAbstractedPad& abstracted_pad, u32 slot, NpadVibration* handler);
27 Result Unmount();
25 28
26 Result SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command); 29 Result SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command);
27 30
28 Result GetActualVibrationGcErmCommand(Core::HID::VibrationGcErmCommand& out_command); 31 Result GetActualVibrationGcErmCommand(Core::HID::VibrationGcErmCommand& out_command);
29 Result SendVibrationNotificationPattern(Core::HID::VibrationGcErmCommand command); 32 Result SendVibrationNotificationPattern(Core::HID::VibrationGcErmCommand command);
33
34private:
35 u32 adapter_slot;
30}; 36};
31} // namespace Service::HID 37} // namespace Service::HID
diff --git a/src/hid_core/resources/vibration/n64_vibration_device.cpp b/src/hid_core/resources/vibration/n64_vibration_device.cpp
index 639f87abf..94ad37c8f 100644
--- a/src/hid_core/resources/vibration/n64_vibration_device.cpp
+++ b/src/hid_core/resources/vibration/n64_vibration_device.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include "hid_core/frontend/emulated_controller.h"
4#include "hid_core/hid_result.h" 5#include "hid_core/hid_result.h"
5#include "hid_core/resources/npad/npad_types.h" 6#include "hid_core/resources/npad/npad_types.h"
6#include "hid_core/resources/npad/npad_vibration.h" 7#include "hid_core/resources/npad/npad_vibration.h"
@@ -10,12 +11,12 @@ namespace Service::HID {
10 11
11NpadN64VibrationDevice::NpadN64VibrationDevice() {} 12NpadN64VibrationDevice::NpadN64VibrationDevice() {}
12 13
13Result NpadN64VibrationDevice::IncrementRefCounter() { 14Result NpadN64VibrationDevice::Activate() {
14 if (ref_counter == 0 && is_mounted) { 15 if (ref_counter == 0 && is_mounted) {
15 f32 volume = 1.0f; 16 f32 volume = 1.0f;
16 const auto result = vibration_handler->GetVibrationVolume(volume); 17 const auto result = vibration_handler->GetVibrationVolume(volume);
17 if (result.IsSuccess()) { 18 if (result.IsSuccess()) {
18 // TODO: SendVibrationInBool 19 xcd_handle->SetVibration(false);
19 } 20 }
20 } 21 }
21 22
@@ -23,19 +24,12 @@ Result NpadN64VibrationDevice::IncrementRefCounter() {
23 return ResultSuccess; 24 return ResultSuccess;
24} 25}
25 26
26Result NpadN64VibrationDevice::DecrementRefCounter() { 27Result NpadN64VibrationDevice::Deactivate() {
27 if (ref_counter == 1) { 28 if (ref_counter == 1 && is_mounted) {
28 if (!is_mounted) {
29 ref_counter = 0;
30 if (is_mounted != false) {
31 // TODO: SendVibrationInBool
32 }
33 return ResultSuccess;
34 }
35 f32 volume = 1.0f; 29 f32 volume = 1.0f;
36 const auto result = vibration_handler->GetVibrationVolume(volume); 30 const auto result = vibration_handler->GetVibrationVolume(volume);
37 if (result.IsSuccess()) { 31 if (result.IsSuccess()) {
38 // TODO 32 xcd_handle->SetVibration(false);
39 } 33 }
40 } 34 }
41 35
@@ -46,6 +40,43 @@ Result NpadN64VibrationDevice::DecrementRefCounter() {
46 return ResultSuccess; 40 return ResultSuccess;
47} 41}
48 42
43Result NpadN64VibrationDevice::Mount(IAbstractedPad& abstracted_pad, NpadVibration* handler) {
44 if (!abstracted_pad.internal_flags.is_connected) {
45 return ResultSuccess;
46 }
47 xcd_handle = abstracted_pad.xcd_handle;
48 vibration_handler = handler;
49 is_mounted = true;
50
51 if (ref_counter == 0) {
52 return ResultSuccess;
53 }
54
55 f32 volume{1.0f};
56 const auto result = vibration_handler->GetVibrationVolume(volume);
57 if (result.IsSuccess()) {
58 xcd_handle->SetVibration(false);
59 }
60
61 return ResultSuccess;
62}
63
64Result NpadN64VibrationDevice::Unmount() {
65 if (ref_counter == 0 || !is_mounted) {
66 is_mounted = false;
67 return ResultSuccess;
68 }
69
70 f32 volume{1.0f};
71 const auto result = vibration_handler->GetVibrationVolume(volume);
72 if (result.IsSuccess()) {
73 xcd_handle->SetVibration(false);
74 }
75
76 is_mounted = false;
77 return ResultSuccess;
78}
79
49Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) { 80Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) {
50 if (ref_counter < 1) { 81 if (ref_counter < 1) {
51 return ResultVibrationNotInitialized; 82 return ResultVibrationNotInitialized;
@@ -56,7 +87,7 @@ Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) {
56 if (result.IsError()) { 87 if (result.IsError()) {
57 return result; 88 return result;
58 } 89 }
59 // TODO: SendVibrationInBool 90 xcd_handle->SetVibration(false);
60 } 91 }
61 return ResultSuccess; 92 return ResultSuccess;
62} 93}
diff --git a/src/hid_core/resources/vibration/n64_vibration_device.h b/src/hid_core/resources/vibration/n64_vibration_device.h
index 54e6efc1a..09de7701c 100644
--- a/src/hid_core/resources/vibration/n64_vibration_device.h
+++ b/src/hid_core/resources/vibration/n64_vibration_device.h
@@ -14,14 +14,18 @@
14 14
15namespace Service::HID { 15namespace Service::HID {
16class NpadVibration; 16class NpadVibration;
17struct IAbstractedPad;
17 18
18/// Handles Npad request from HID interfaces 19/// Handles Npad request from HID interfaces
19class NpadN64VibrationDevice final : public NpadVibrationBase { 20class NpadN64VibrationDevice final : public NpadVibrationBase {
20public: 21public:
21 explicit NpadN64VibrationDevice(); 22 explicit NpadN64VibrationDevice();
22 23
23 Result IncrementRefCounter() override; 24 Result Activate() override;
24 Result DecrementRefCounter() override; 25 Result Deactivate() override;
26
27 Result Mount(IAbstractedPad& abstracted_pad, NpadVibration* handler);
28 Result Unmount();
25 29
26 Result SendValueInBool(bool is_vibrating); 30 Result SendValueInBool(bool is_vibrating);
27 Result SendVibrationNotificationPattern(u32 pattern); 31 Result SendVibrationNotificationPattern(u32 pattern);
diff --git a/src/hid_core/resources/vibration/vibration_base.cpp b/src/hid_core/resources/vibration/vibration_base.cpp
index 350f349c2..f28d30406 100644
--- a/src/hid_core/resources/vibration/vibration_base.cpp
+++ b/src/hid_core/resources/vibration/vibration_base.cpp
@@ -10,12 +10,12 @@ namespace Service::HID {
10 10
11NpadVibrationBase::NpadVibrationBase() {} 11NpadVibrationBase::NpadVibrationBase() {}
12 12
13Result NpadVibrationBase::IncrementRefCounter() { 13Result NpadVibrationBase::Activate() {
14 ref_counter++; 14 ref_counter++;
15 return ResultSuccess; 15 return ResultSuccess;
16} 16}
17 17
18Result NpadVibrationBase::DecrementRefCounter() { 18Result NpadVibrationBase::Deactivate() {
19 if (ref_counter > 0) { 19 if (ref_counter > 0) {
20 ref_counter--; 20 ref_counter--;
21 } 21 }
diff --git a/src/hid_core/resources/vibration/vibration_base.h b/src/hid_core/resources/vibration/vibration_base.h
index c6c5fc4d9..69c26e669 100644
--- a/src/hid_core/resources/vibration/vibration_base.h
+++ b/src/hid_core/resources/vibration/vibration_base.h
@@ -6,6 +6,10 @@
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/hle/result.h" 7#include "core/hle/result.h"
8 8
9namespace Core::HID {
10class EmulatedController;
11}
12
9namespace Service::HID { 13namespace Service::HID {
10class NpadVibration; 14class NpadVibration;
11 15
@@ -14,13 +18,13 @@ class NpadVibrationBase {
14public: 18public:
15 explicit NpadVibrationBase(); 19 explicit NpadVibrationBase();
16 20
17 virtual Result IncrementRefCounter(); 21 virtual Result Activate();
18 virtual Result DecrementRefCounter(); 22 virtual Result Deactivate();
19 23
20 bool IsVibrationMounted() const; 24 bool IsVibrationMounted() const;
21 25
22protected: 26protected:
23 u64 xcd_handle{}; 27 Core::HID::EmulatedController* xcd_handle{nullptr};
24 s32 ref_counter{}; 28 s32 ref_counter{};
25 bool is_mounted{}; 29 bool is_mounted{};
26 NpadVibration* vibration_handler{nullptr}; 30 NpadVibration* vibration_handler{nullptr};
diff --git a/src/hid_core/resources/vibration/vibration_device.cpp b/src/hid_core/resources/vibration/vibration_device.cpp
index 888c3a7ed..08b14591f 100644
--- a/src/hid_core/resources/vibration/vibration_device.cpp
+++ b/src/hid_core/resources/vibration/vibration_device.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include "hid_core/frontend/emulated_controller.h"
4#include "hid_core/hid_result.h" 5#include "hid_core/hid_result.h"
5#include "hid_core/resources/npad/npad_types.h" 6#include "hid_core/resources/npad/npad_types.h"
6#include "hid_core/resources/npad/npad_vibration.h" 7#include "hid_core/resources/npad/npad_vibration.h"
@@ -10,12 +11,30 @@ namespace Service::HID {
10 11
11NpadVibrationDevice::NpadVibrationDevice() {} 12NpadVibrationDevice::NpadVibrationDevice() {}
12 13
13Result NpadVibrationDevice::IncrementRefCounter() { 14Result NpadVibrationDevice::Activate() {
15 if (ref_counter == 0 && is_mounted) {
16 f32 volume = 1.0f;
17 const auto result = vibration_handler->GetVibrationVolume(volume);
18 if (result.IsSuccess()) {
19 xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE);
20 // TODO: SendNotificationPattern;
21 }
22 }
23
14 ref_counter++; 24 ref_counter++;
15 return ResultSuccess; 25 return ResultSuccess;
16} 26}
17 27
18Result NpadVibrationDevice::DecrementRefCounter() { 28Result NpadVibrationDevice::Deactivate() {
29 if (ref_counter == 1 && is_mounted) {
30 f32 volume = 1.0f;
31 const auto result = vibration_handler->GetVibrationVolume(volume);
32 if (result.IsSuccess()) {
33 xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE);
34 // TODO: SendNotificationPattern;
35 }
36 }
37
19 if (ref_counter > 0) { 38 if (ref_counter > 0) {
20 ref_counter--; 39 ref_counter--;
21 } 40 }
@@ -23,6 +42,45 @@ Result NpadVibrationDevice::DecrementRefCounter() {
23 return ResultSuccess; 42 return ResultSuccess;
24} 43}
25 44
45Result NpadVibrationDevice::Mount(IAbstractedPad& abstracted_pad, Core::HID::DeviceIndex index,
46 NpadVibration* handler) {
47 if (!abstracted_pad.internal_flags.is_connected) {
48 return ResultSuccess;
49 }
50 xcd_handle = abstracted_pad.xcd_handle;
51 device_index = index;
52 vibration_handler = handler;
53 is_mounted = true;
54
55 if (ref_counter == 0) {
56 return ResultSuccess;
57 }
58
59 f32 volume{1.0f};
60 const auto result = vibration_handler->GetVibrationVolume(volume);
61 if (result.IsSuccess()) {
62 xcd_handle->SetVibration(false);
63 }
64
65 return ResultSuccess;
66}
67
68Result NpadVibrationDevice::Unmount() {
69 if (ref_counter == 0 || !is_mounted) {
70 is_mounted = false;
71 return ResultSuccess;
72 }
73
74 f32 volume{1.0f};
75 const auto result = vibration_handler->GetVibrationVolume(volume);
76 if (result.IsSuccess()) {
77 xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE);
78 }
79
80 is_mounted = false;
81 return ResultSuccess;
82}
83
26Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue& value) { 84Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue& value) {
27 if (ref_counter == 0) { 85 if (ref_counter == 0) {
28 return ResultVibrationNotInitialized; 86 return ResultVibrationNotInitialized;
@@ -37,7 +95,7 @@ Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue&
37 return result; 95 return result;
38 } 96 }
39 if (volume <= 0.0f) { 97 if (volume <= 0.0f) {
40 // TODO: SendVibrationValue 98 xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE);
41 return ResultSuccess; 99 return ResultSuccess;
42 } 100 }
43 101
@@ -45,7 +103,7 @@ Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue&
45 vibration_value.high_amplitude *= volume; 103 vibration_value.high_amplitude *= volume;
46 vibration_value.low_amplitude *= volume; 104 vibration_value.low_amplitude *= volume;
47 105
48 // TODO: SendVibrationValue 106 xcd_handle->SetVibration(device_index, vibration_value);
49 return ResultSuccess; 107 return ResultSuccess;
50} 108}
51 109
@@ -63,11 +121,11 @@ Result NpadVibrationDevice::SendVibrationNotificationPattern([[maybe_unused]] u3
63 pattern = 0; 121 pattern = 0;
64 } 122 }
65 123
66 // return xcd_handle->SendVibrationNotificationPattern(pattern); 124 // TODO: SendVibrationNotificationPattern;
67 return ResultSuccess; 125 return ResultSuccess;
68} 126}
69 127
70Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& out_value) { 128Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& out_value) const {
71 if (ref_counter < 1) { 129 if (ref_counter < 1) {
72 return ResultVibrationNotInitialized; 130 return ResultVibrationNotInitialized;
73 } 131 }
@@ -77,7 +135,7 @@ Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& o
77 return ResultSuccess; 135 return ResultSuccess;
78 } 136 }
79 137
80 // TODO: SendVibrationValue 138 out_value = xcd_handle->GetActualVibrationValue(device_index);
81 return ResultSuccess; 139 return ResultSuccess;
82} 140}
83 141
diff --git a/src/hid_core/resources/vibration/vibration_device.h b/src/hid_core/resources/vibration/vibration_device.h
index 3574ad60b..c2f9891d3 100644
--- a/src/hid_core/resources/vibration/vibration_device.h
+++ b/src/hid_core/resources/vibration/vibration_device.h
@@ -12,6 +12,10 @@
12#include "hid_core/resources/npad/npad_types.h" 12#include "hid_core/resources/npad/npad_types.h"
13#include "hid_core/resources/vibration/vibration_base.h" 13#include "hid_core/resources/vibration/vibration_base.h"
14 14
15namespace Core::HID {
16enum class DeviceIndex : u8;
17}
18
15namespace Service::HID { 19namespace Service::HID {
16class NpadVibration; 20class NpadVibration;
17 21
@@ -20,16 +24,20 @@ class NpadVibrationDevice final : public NpadVibrationBase {
20public: 24public:
21 explicit NpadVibrationDevice(); 25 explicit NpadVibrationDevice();
22 26
23 Result IncrementRefCounter(); 27 Result Activate();
24 Result DecrementRefCounter(); 28 Result Deactivate();
29
30 Result Mount(IAbstractedPad& abstracted_pad, Core::HID::DeviceIndex index,
31 NpadVibration* handler);
32 Result Unmount();
25 33
26 Result SendVibrationValue(const Core::HID::VibrationValue& value); 34 Result SendVibrationValue(const Core::HID::VibrationValue& value);
27 Result SendVibrationNotificationPattern(u32 pattern); 35 Result SendVibrationNotificationPattern(u32 pattern);
28 36
29 Result GetActualVibrationValue(Core::HID::VibrationValue& out_value); 37 Result GetActualVibrationValue(Core::HID::VibrationValue& out_value) const;
30 38
31private: 39private:
32 u32 device_index{}; 40 Core::HID::DeviceIndex device_index{};
33}; 41};
34 42
35} // namespace Service::HID 43} // namespace Service::HID
diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp
index d898d8acc..6b1f4527b 100644
--- a/src/yuzu/configuration/configure_vibration.cpp
+++ b/src/yuzu/configuration/configure_vibration.cpp
@@ -116,8 +116,8 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
116 .high_amplitude = 1.0f, 116 .high_amplitude = 1.0f,
117 .high_frequency = 320.0f, 117 .high_frequency = 320.0f,
118 }; 118 };
119 controller->SetVibration(0, vibration); 119 controller->SetVibration(Core::HID::DeviceIndex::Left, vibration);
120 controller->SetVibration(1, vibration); 120 controller->SetVibration(Core::HID::DeviceIndex::Right, vibration);
121 121
122 // Restore previous values 122 // Restore previous values
123 player.vibration_enabled = old_vibration_enabled; 123 player.vibration_enabled = old_vibration_enabled;
@@ -127,7 +127,7 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
127void ConfigureVibration::StopVibrations() { 127void ConfigureVibration::StopVibrations() {
128 for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { 128 for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
129 auto controller = hid_core.GetEmulatedControllerByIndex(i); 129 auto controller = hid_core.GetEmulatedControllerByIndex(i);
130 controller->SetVibration(0, Core::HID::DEFAULT_VIBRATION_VALUE); 130 controller->SetVibration(Core::HID::DeviceIndex::Left, Core::HID::DEFAULT_VIBRATION_VALUE);
131 controller->SetVibration(1, Core::HID::DEFAULT_VIBRATION_VALUE); 131 controller->SetVibration(Core::HID::DeviceIndex::Right, Core::HID::DEFAULT_VIBRATION_VALUE);
132 } 132 }
133} 133}