From 07f40d5cac635ff102aa6ce9c32572cc20d69959 Mon Sep 17 00:00:00 2001 From: xbzk Date: Fri, 18 Sep 2026 23:49:17 +0200 Subject: [PATCH] [npad,hid,am] npad WriteEmptyEntry fix, hid function 551 stub, and applet PopOutData rework (#4442) - [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions). - [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md) - [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability. ------------------- This was intended to fix Dave the Diver issue, but we found a real silly hid bug, then a maybe broader applet issue: By testing with John it was found out only the last controller connected worked, the others caused the game to freeze peacefully, no crashes, suggesting some loop or deadlock. After seeking that lead, it was found that the freeze was caused by a malformed HID history entry when the controller applet removed P2. Pressing P1 opens the controller applet, then Qt applet disconnects P2, which is expected. Upon seeking callstack and hid sync path, it was found out that NPad::WriteEmptyEntry: was using: ReadCurrentEntry().sampling_number + 1 instead of: ReadCurrentEntry().state.sampling_number + 1 (checked AtomicStorage in src\hid_core\resources\ring_lifo.h) Fixing that fixed the freeze, but killed the sound! Later handheld/docked was accidentally clicked and sound returned. Good lead. Then i just had to corner which part of the toggle was causing the refresh and do something similar at the controller applet return routine (PopOutData in library_applet_accessor.cpp). This part seems harmless, but i'm not clearly sure about how proper it is, since it was like a transplant and test operation. UPDATE: To try Diablo 3 on my machine it was needed to stub HID function 551. And to fix all abnormalies like multiple applet requests and crash the function PopOutData was reworked to ensurey idempotency among different applet focus conditions: focus state changed: updates state and signals if needed no state change, HLE application frontend: requests focus state changed notification already pending change message: flag remains true and no duplicate pushed to queue entry Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4442 Reviewed-by: MaranBr Reviewed-by: lizzie --- src/core/hle/service/am/lifecycle_manager.h | 7 +++++++ .../am/service/library_applet_accessor.cpp | 12 ++++++------ src/core/hle/service/hid/hid_system_server.cpp | 4 ++-- src/hid_core/resources/npad/npad.cpp | 16 ++++++++-------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/core/hle/service/am/lifecycle_manager.h b/src/core/hle/service/am/lifecycle_manager.h index ae041d3e29..15657a36d8 100644 --- a/src/core/hle/service/am/lifecycle_manager.h +++ b/src/core/hle/service/am/lifecycle_manager.h @@ -92,6 +92,13 @@ public: } } + void RequestFocusStateChangedNotification(Kernel::KernelCore& kernel) { + if (m_focus_state_changed_notification_enabled) { + m_has_focus_state_changed = true; + this->SignalSystemEventIfNeeded(kernel); + } + } + void OnOperationAndPerformanceModeChanged(Kernel::KernelCore& kernel); public: diff --git a/src/core/hle/service/am/service/library_applet_accessor.cpp b/src/core/hle/service/am/service/library_applet_accessor.cpp index c49b1f3f05..849e5794cf 100644 --- a/src/core/hle/service/am/service/library_applet_accessor.cpp +++ b/src/core/hle/service/am/service/library_applet_accessor.cpp @@ -164,15 +164,15 @@ Result ILibraryAppletAccessor::PushInData(SharedPointer storage) { Result ILibraryAppletAccessor::PopOutData(Out> out_storage) { LOG_DEBUG(Service_AM, "called"); + R_TRY(m_broker->GetOutData().Pop(system.Kernel(), out_storage.Get())); if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet) { - caller_applet->lifecycle_manager.GetSystemEvent().Signal(system.Kernel()); - caller_applet->lifecycle_manager.RequestResumeNotification(); - caller_applet->lifecycle_manager.GetSystemEvent().Clear(system.Kernel()); - caller_applet->lifecycle_manager.UpdateRequestedFocusState(); + std::scoped_lock lk{caller_applet->lock}; + const bool focus_state_changed = caller_applet->lifecycle_manager.UpdateRequestedFocusState(); + const bool is_front_app = m_applet->frontend && caller_applet->lifecycle_manager.IsApplication(); + if (focus_state_changed) caller_applet->lifecycle_manager.SignalSystemEventIfNeeded(system.Kernel()); + else if (is_front_app) caller_applet->lifecycle_manager.RequestFocusStateChangedNotification(system.Kernel()); } - R_TRY(m_broker->GetOutData().Pop(system.Kernel(), out_storage.Get())); - if (m_applet->applet_id == AppletId::ProfileSelect && *out_storage) { auto impl = (*out_storage)->GetImpl(); diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp index f3c01b5d89..e544adf03c 100644 --- a/src/core/hle/service/hid/hid_system_server.cpp +++ b/src/core/hle/service/hid/hid_system_server.cpp @@ -121,7 +121,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr data; diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index e7a1ee2bf3..c67f839df1 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp @@ -398,21 +398,21 @@ void NPad::InitNewlyAddedController(Kernel::KernelCore& kernel, u64 aruid, Core: void NPad::WriteEmptyEntry(NpadInternalState* npad) { NPadGenericState dummy_pad_state{}; NpadGcTriggerState dummy_gc_state{}; - dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1; + dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->fullkey_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->handheld_lifo.ReadCurrentEntry().sampling_number + 1; + dummy_pad_state.sampling_number = npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->handheld_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->joy_dual_lifo.ReadCurrentEntry().sampling_number + 1; + dummy_pad_state.sampling_number = npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->joy_dual_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->joy_left_lifo.ReadCurrentEntry().sampling_number + 1; + dummy_pad_state.sampling_number = npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->joy_left_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->joy_right_lifo.ReadCurrentEntry().sampling_number + 1; + dummy_pad_state.sampling_number = npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->joy_right_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->palma_lifo.ReadCurrentEntry().sampling_number + 1; + dummy_pad_state.sampling_number = npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->palma_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->system_ext_lifo.ReadCurrentEntry().sampling_number + 1; + dummy_pad_state.sampling_number = npad->system_ext_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->system_ext_lifo.WriteNextEntry(dummy_pad_state); - dummy_gc_state.sampling_number = npad->gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1; + dummy_gc_state.sampling_number = npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state); }