From 0e92352e72f1d561e682c7845416927fba476da7 Mon Sep 17 00:00:00 2001 From: Shyanne Date: Tue, 25 Nov 2025 21:31:34 -0500 Subject: [PATCH] HLE: Implement IHidServer IsSixAxisSensorAtRest Fixes the actually insane amount of log spam in games that check for this, such as Luigi's Mansion 3. Values in HidDevices.NpadDevices.isAtRest may need to be tuned to a better range for resting detection. I originally set them to 0, and my controller rests at definitely NOT 0. Will need to be revisited when implementing functionality for the global SixAxisActive bool, IHidServer.StartSixAxisTracking, and IHidServer.StopSixAxisTracking. --- .../Services/Hid/HidDevices/NpadDevices.cs | 18 +++++++ .../HOS/Services/Hid/IHidServer.cs | 47 ++++++++++++++++--- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs b/src/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs index b9235b033..8fe9d3e62 100644 --- a/src/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs +++ b/src/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs @@ -56,6 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid _activeCount = 0; JoyHold = NpadJoyHoldType.Vertical; + SixAxisActive = false; } internal ref KEvent GetStyleSetUpdateEvent(PlayerIndex player) @@ -580,6 +581,23 @@ namespace Ryujinx.HLE.HOS.Services.Hid return needUpdateRight; } + + public bool isAtRest(int playerNumber) + { + + ref NpadInternalState currentNpad = ref _device.Hid.SharedMemory.Npads[playerNumber].InternalState; + ref SixAxisSensorState storage = ref GetSixAxisSensorLifo(ref currentNpad, false).GetCurrentEntryRef(); + + float acceleration = Math.Abs(storage.Acceleration.X) + + Math.Abs(storage.Acceleration.Y) + + Math.Abs(storage.Acceleration.Z); + + float angularVelocity = Math.Abs(storage.AngularVelocity.X) + + Math.Abs(storage.AngularVelocity.Y) + + Math.Abs(storage.AngularVelocity.Z); + + return ((acceleration <= 1.5F) && (angularVelocity <= 1.1F)); + } private void UpdateDisconnectedInputSixAxis(PlayerIndex index) { diff --git a/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs index 0d2fcaa2a..b11ecbf77 100644 --- a/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs +++ b/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -602,19 +602,52 @@ namespace Ryujinx.HLE.HOS.Services.Hid } [CommandCmif(82)] - // IsSixAxisSensorAtRest(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> bool IsAsRest + // IsSixAxisSensorAtRest(nn::hid::SixAxisSensorHandle, nn::applet::AppletResourceUserId) -> bool IsAtRest public ResultCode IsSixAxisSensorAtRest(ServiceCtx context) { int sixAxisSensorHandle = context.RequestData.ReadInt32(); + + // 4 byte struct w/ 4-byte alignment + // 0x0 0x4 TypeValue + // 0x0 0x1 NpadStyleIndex + // 0x1 0x1 PlayerNumber + // 0x2 0x1 DeviceIdx + + // uint typeValue = (uint) sixAxisSensorHandle; + // uint npadStyleIndex = (uint) sixAxisSensorHandle & 0xff; + int playerNumber = (sixAxisSensorHandle << 8) & 0xff; + // uint deviceIdx= ((uint) sixAxisSensorHandle << 16) & 0xff; + // uint unknown = ((uint) sixAxisSensorHandle << 24) & 0xff; + + // 32bit sign extension padding + // if = 0, + offset, else - offset + // npadStyleIndex = ((npadStyleIndex & 0x8000) == 0) ? npadStyleIndex | 0xFFFF0000 : npadStyleIndex & 0xFFFF0000; + // playerNumber = ((playerNumber & 0x8000) == 0) ? playerNumber | 0xFFFF0000 : playerNumber & 0xFFFF0000; + // deviceIdx = ((deviceIdx & 0x8000) == 0) ? deviceIdx | 0xFFFF0000 : deviceIdx & 0xFFFF0000; + // unknown = ((unknown & 0x8000) == 0) ? unknown | 0xFFFF0000 : unknown & 0xFFFF0000; + context.RequestData.BaseStream.Position += 4; // Padding long appletResourceUserId = context.RequestData.ReadInt64(); - bool isAtRest = true; - + bool isAtRest; + + // TODO: link to context.Device.Hid.Npads.SixAxisActive when properly implemented + // We currently do not support stopping or starting SixAxisTracking. + // It is just always tracking, the bool is unused. + // See Ryujinx.HLE.HOS.Services.Hid.NpadDevices + + // common cases: if + // controller is keyboard (keyboards don't have gyroscopes, silly goose!) + // controller has no gyroscope + // SixAxisActive == false + // SixAxisTracking == false + // then isAtRest = true + // else check gyroscopic activity + + // check gyroscopic activity + isAtRest = context.Device.Hid.Npads.isAtRest(playerNumber); + context.ResponseData.Write(isAtRest); - - Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, isAtRest }); - return ResultCode.Success; } @@ -629,7 +662,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid context.ResponseData.Write(_isFirmwareUpdateAvailableForSixAxisSensor); Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _isFirmwareUpdateAvailableForSixAxisSensor }); - + return ResultCode.Success; }