diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs index 3ff7e7338..a063b41fd 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs @@ -239,45 +239,51 @@ namespace Ryujinx.HLE.HOS.Services.Hid switch (type) { case ControllerType.ProController: - controller.StyleSet = NpadStyleTag.FullKey; - controller.DeviceType = DeviceType.FullKey; - controller.SystemProperties |= NpadSystemProperties.IsAbxyButtonOriented | - NpadSystemProperties.IsPlusAvailable | - NpadSystemProperties.IsMinusAvailable; + controller.StyleSet = NpadStyleTag.FullKey; + controller.DeviceType = DeviceType.FullKey; + controller.SystemProperties |= NpadSystemProperties.IsAbxyButtonOriented | + NpadSystemProperties.IsPlusAvailable | + NpadSystemProperties.IsMinusAvailable; + controller.AppletFooterUiType = AppletFooterUiType.SwitchProController; break; case ControllerType.Handheld: - controller.StyleSet = NpadStyleTag.Handheld; - controller.DeviceType = DeviceType.HandheldLeft | - DeviceType.HandheldRight; - controller.SystemProperties |= NpadSystemProperties.IsAbxyButtonOriented | - NpadSystemProperties.IsPlusAvailable | - NpadSystemProperties.IsMinusAvailable; + controller.StyleSet = NpadStyleTag.Handheld; + controller.DeviceType = DeviceType.HandheldLeft | + DeviceType.HandheldRight; + controller.SystemProperties |= NpadSystemProperties.IsAbxyButtonOriented | + NpadSystemProperties.IsPlusAvailable | + NpadSystemProperties.IsMinusAvailable; + controller.AppletFooterUiType = AppletFooterUiType.HandheldJoyConLeftJoyConRight; break; case ControllerType.JoyconPair: - controller.StyleSet = NpadStyleTag.JoyDual; - controller.DeviceType = DeviceType.JoyLeft | - DeviceType.JoyRight; - controller.SystemProperties |= NpadSystemProperties.IsAbxyButtonOriented | - NpadSystemProperties.IsPlusAvailable | - NpadSystemProperties.IsMinusAvailable; + controller.StyleSet = NpadStyleTag.JoyDual; + controller.DeviceType = DeviceType.JoyLeft | + DeviceType.JoyRight; + controller.SystemProperties |= NpadSystemProperties.IsAbxyButtonOriented | + NpadSystemProperties.IsPlusAvailable | + NpadSystemProperties.IsMinusAvailable; + controller.AppletFooterUiType = _device.System.State.DockedMode ? AppletFooterUiType.JoyDual : AppletFooterUiType.HandheldJoyConLeftJoyConRight; break; case ControllerType.JoyconLeft: - controller.StyleSet = NpadStyleTag.JoyLeft; - controller.JoyAssignmentMode = NpadJoyAssignmentMode.Single; - controller.DeviceType = DeviceType.JoyLeft; - controller.SystemProperties |= NpadSystemProperties.IsSlSrButtonOriented | - NpadSystemProperties.IsMinusAvailable; + controller.StyleSet = NpadStyleTag.JoyLeft; + controller.JoyAssignmentMode = NpadJoyAssignmentMode.Single; + controller.DeviceType = DeviceType.JoyLeft; + controller.SystemProperties |= NpadSystemProperties.IsSlSrButtonOriented | + NpadSystemProperties.IsMinusAvailable; + controller.AppletFooterUiType = _device.System.State.DockedMode ? AppletFooterUiType.JoyDualLeftOnly : AppletFooterUiType.HandheldJoyConLeftOnly; break; case ControllerType.JoyconRight: - controller.StyleSet = NpadStyleTag.JoyRight; - controller.JoyAssignmentMode = NpadJoyAssignmentMode.Single; - controller.DeviceType = DeviceType.JoyRight; - controller.SystemProperties |= NpadSystemProperties.IsSlSrButtonOriented | - NpadSystemProperties.IsPlusAvailable; + controller.StyleSet = NpadStyleTag.JoyRight; + controller.JoyAssignmentMode = NpadJoyAssignmentMode.Single; + controller.DeviceType = DeviceType.JoyRight; + controller.SystemProperties |= NpadSystemProperties.IsSlSrButtonOriented | + NpadSystemProperties.IsPlusAvailable; + controller.AppletFooterUiType = _device.System.State.DockedMode ? AppletFooterUiType.JoyDualRightOnly : AppletFooterUiType.HandheldJoyConRightOnly; break; case ControllerType.Pokeball: - controller.StyleSet = NpadStyleTag.Palma; - controller.DeviceType = DeviceType.Palma; + controller.StyleSet = NpadStyleTag.Palma; + controller.DeviceType = DeviceType.Palma; + controller.AppletFooterUiType = AppletFooterUiType.None; break; } diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs index 9db5b5181..c2cd84329 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs @@ -35,19 +35,5 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer PlayerIndex.Unknown => NpadIdType.Unknown, _ => throw new ArgumentOutOfRangeException(nameof(index)) }; - - public static long GetLedPatternFromNpadId(NpadIdType npadIdType) - => npadIdType switch - { - NpadIdType.Player1 => 0b0001, - NpadIdType.Player2 => 0b0011, - NpadIdType.Player3 => 0b0111, - NpadIdType.Player4 => 0b1111, - NpadIdType.Player5 => 0b1001, - NpadIdType.Player6 => 0b0101, - NpadIdType.Player7 => 0b1101, - NpadIdType.Player8 => 0b0110, - _ => 0b0000 - }; } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs index 0155fb1eb..3f2aae356 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -746,22 +746,33 @@ namespace Ryujinx.HLE.HOS.Services.Hid } [CommandHipc(108)] - // GetPlayerLedPattern(uint NpadId) -> ulong LedPattern + // GetPlayerLedPattern(u32 npad_id) -> u64 led_pattern public ResultCode GetPlayerLedPattern(ServiceCtx context) { - NpadIdType npadId = (NpadIdType)context.RequestData.ReadInt32(); + NpadIdType npadId = (NpadIdType)context.RequestData.ReadUInt32(); - long ledPattern = HidUtils.GetLedPatternFromNpadId(npadId); + ulong ledPattern = npadId switch + { + NpadIdType.Player1 => 0b0001, + NpadIdType.Player2 => 0b0011, + NpadIdType.Player3 => 0b0111, + NpadIdType.Player4 => 0b1111, + NpadIdType.Player5 => 0b1001, + NpadIdType.Player6 => 0b0101, + NpadIdType.Player7 => 0b1101, + NpadIdType.Player8 => 0b0110, + NpadIdType.Unknown => 0b0000, + NpadIdType.Handheld => 0b0000, + _ => throw new ArgumentOutOfRangeException(nameof(npadId)) + }; context.ResponseData.Write(ledPattern); - Logger.Stub?.PrintStub(LogClass.ServiceHid, new { npadId, ledPattern }); - return ResultCode.Success; } [CommandHipc(109)] // 5.0.0+ - // ActivateNpadWithRevision(nn::applet::AppletResourceUserId, int Unknown) + // ActivateNpadWithRevision(nn::applet::AppletResourceUserId, int revision) public ResultCode ActivateNpadWithRevision(ServiceCtx context) { int revision = context.RequestData.ReadInt32(); @@ -798,32 +809,46 @@ namespace Ryujinx.HLE.HOS.Services.Hid } [CommandHipc(120)] - // SetNpadJoyHoldType(nn::applet::AppletResourceUserId, long NpadJoyHoldType) + // SetNpadJoyHoldType(nn::applet::AppletResourceUserId, ulong NpadJoyHoldType) public ResultCode SetNpadJoyHoldType(ServiceCtx context) { long appletResourceUserId = context.RequestData.ReadInt64(); - context.Device.Hid.Npads.JoyHold = (NpadJoyHoldType)context.RequestData.ReadInt64(); - Logger.Stub?.PrintStub(LogClass.ServiceHid, new { - appletResourceUserId, - context.Device.Hid.Npads.JoyHold - }); + NpadJoyHoldType npadJoyHoldType = (NpadJoyHoldType)context.RequestData.ReadUInt64(); + + if (npadJoyHoldType > NpadJoyHoldType.Horizontal) + { + throw new ArgumentOutOfRangeException(nameof(npadJoyHoldType)); + } + + foreach (PlayerIndex playerIndex in context.Device.Hid.Npads.GetSupportedPlayers()) + { + if (HidUtils.GetNpadIdTypeFromIndex(playerIndex) > NpadIdType.Handheld) + { + return ResultCode.InvalidNpadIdType; + } + } + + context.Device.Hid.Npads.JoyHold = npadJoyHoldType; return ResultCode.Success; } [CommandHipc(121)] - // GetNpadJoyHoldType(nn::applet::AppletResourceUserId) -> long NpadJoyHoldType + // GetNpadJoyHoldType(nn::applet::AppletResourceUserId) -> ulong NpadJoyHoldType public ResultCode GetNpadJoyHoldType(ServiceCtx context) { long appletResourceUserId = context.RequestData.ReadInt64(); - context.ResponseData.Write((long)context.Device.Hid.Npads.JoyHold); + foreach (PlayerIndex playerIndex in context.Device.Hid.Npads.GetSupportedPlayers()) + { + if (HidUtils.GetNpadIdTypeFromIndex(playerIndex) > NpadIdType.Handheld) + { + return ResultCode.InvalidNpadIdType; + } + } - Logger.Stub?.PrintStub(LogClass.ServiceHid, new { - appletResourceUserId, - context.Device.Hid.Npads.JoyHold - }); + context.ResponseData.Write((ulong)context.Device.Hid.Npads.JoyHold); return ResultCode.Success; } @@ -1171,6 +1196,21 @@ namespace Ryujinx.HLE.HOS.Services.Hid return ResultCode.Success; } + [CommandHipc(211)] // 7.0.0+ + // IsVibrationDeviceMounted(nn::hid::VibrationDeviceHandle, nn::applet::AppletResourceUserId) + public ResultCode IsVibrationDeviceMounted(ServiceCtx context) + { + int vibrationDeviceHandle = context.RequestData.ReadInt32(); + long appletResourceUserId = context.RequestData.ReadInt64(); + + // NOTE: Service use vibrationDeviceHandle to get the PlayerIndex. + // And return false if (npadIdType >= (NpadIdType)8 && npadIdType != NpadIdType.Handheld && npadIdType != NpadIdType.Unknown) + + context.ResponseData.Write(true); + + return ResultCode.Success; + } + [CommandHipc(300)] // ActivateConsoleSixAxisSensor(nn::applet::AppletResourceUserId) public ResultCode ActivateConsoleSixAxisSensor(ServiceCtx context) diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidSystemServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidSystemServer.cs index 019e99544..ec8295e27 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/IHidSystemServer.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidSystemServer.cs @@ -1,8 +1,76 @@ -namespace Ryujinx.HLE.HOS.Services.Hid +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Hid.HidServer; +using Ryujinx.HLE.HOS.Services.Hid.Types; + +namespace Ryujinx.HLE.HOS.Services.Hid { [Service("hid:sys")] class IHidSystemServer : IpcService { public IHidSystemServer(ServiceCtx context) { } + + [CommandHipc(303)] + // ApplyNpadSystemCommonPolicy(u64) + public ResultCode ApplyNpadSystemCommonPolicy(ServiceCtx context) + { + ulong commonPolicy = context.RequestData.ReadUInt64(); + + Logger.Stub?.PrintStub(LogClass.ServiceHid, new { commonPolicy }); + + return ResultCode.Success; + } + + [CommandHipc(306)] + // GetLastActiveNpad(u32) -> u8, u8 + public ResultCode GetLastActiveNpad(ServiceCtx context) + { + // TODO: RequestData seems to have garbage data, reading an extra uint seems to fix the issue. + context.RequestData.ReadUInt32(); + + ResultCode resultCode = GetAppletFooterUiTypeImpl(context, out AppletFooterUiType appletFooterUiType); + + context.ResponseData.Write((byte)appletFooterUiType); + context.ResponseData.Write((byte)0); + + return resultCode; + } + + [CommandHipc(307)] + // GetNpadSystemExtStyle() -> u64 + public ResultCode GetNpadSystemExtStyle(ServiceCtx context) + { + foreach (PlayerIndex playerIndex in context.Device.Hid.Npads.GetSupportedPlayers()) + { + if (HidUtils.GetNpadIdTypeFromIndex(playerIndex) > NpadIdType.Handheld) + { + return ResultCode.InvalidNpadIdType; + } + } + + context.ResponseData.Write((ulong)context.Device.Hid.Npads.SupportedStyleSets); + + return ResultCode.Success; + } + + [CommandHipc(314)] // 9.0.0+ + // GetAppletFooterUiType(u32) -> u8 + public ResultCode GetAppletFooterUiType(ServiceCtx context) + { + ResultCode resultCode = GetAppletFooterUiTypeImpl(context, out AppletFooterUiType appletFooterUiType); + + context.ResponseData.Write((byte)appletFooterUiType); + + return resultCode; + } + + private ResultCode GetAppletFooterUiTypeImpl(ServiceCtx context, out AppletFooterUiType appletFooterUiType) + { + NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32(); + PlayerIndex playerIndex = HidUtils.GetIndexFromNpadIdType(npadIdType); + + appletFooterUiType = context.Device.Hid.SharedMemory.Npads[(int)playerIndex].InternalState.AppletFooterUiType; + + return ResultCode.Success; + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs new file mode 100644 index 000000000..9b829cc50 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + enum ResultCode + { + ModuleId = 202, + ErrorCodeShift = 9, + + Success = 0, + + InvalidNpadIdType = (710 << ErrorCodeShift) | ModuleId + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/AppletFooterUiType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/AppletFooterUiType.cs new file mode 100644 index 000000000..c4ff8d7ef --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/AppletFooterUiType.cs @@ -0,0 +1,30 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types +{ + [Flags] + enum AppletFooterUiType : byte + { + None, + HandheldNone, + HandheldJoyConLeftOnly, + HandheldJoyConRightOnly, + HandheldJoyConLeftJoyConRight, + JoyDual, + JoyDualLeftOnly, + JoyDualRightOnly, + JoyLeftHorizontal, + JoyLeftVertical, + JoyRightHorizontal, + JoyRightVertical, + SwitchProController, + CompatibleProController, + CompatibleJoyCon, + LarkHvc1, + LarkHvc2, + LarkNesLeft, + LarkNesRight, + Lucia, + Verification + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadInternalState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadInternalState.cs index f225ff677..5ef5f48df 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadInternalState.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadInternalState.cs @@ -29,7 +29,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad public NpadBatteryLevel BatteryLevelJoyLeft; public NpadBatteryLevel BatteryLevelJoyRight; public uint AppletFooterUiAttributes; - public byte AppletFooterUiType; + public AppletFooterUiType AppletFooterUiType; private unsafe fixed byte _reserved2[0x7B]; public RingLifo GcTrigger; public NpadLarkType LarkTypeLeftAndMain;