From a91f60b6addb2c96a53c0474af492f5b6bf38228 Mon Sep 17 00:00:00 2001 From: sh0inx 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 | 43 ++++++++++++++++--- 2 files changed, 55 insertions(+), 6 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..a79360b91 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) @@ -581,6 +582,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) { ref NpadInternalState currentNpad = ref _device.Hid.SharedMemory.Npads[(int)index].InternalState; diff --git a/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs index 66f6d8648..9578f68ea 100644 --- a/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs +++ b/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -582,19 +582,50 @@ 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; + // 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 + bool isAtRest = context.Device.Hid.Npads.isAtRest(playerNumber); context.ResponseData.Write(isAtRest); - - Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, isAtRest }); - return ResultCode.Success; } @@ -609,7 +640,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid context.ResponseData.Write(_isFirmwareUpdateAvailableForSixAxisSensor); Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _isFirmwareUpdateAvailableForSixAxisSensor }); - + return ResultCode.Success; }