Controller Applet

From Nintendo Switch Brew
Revision as of 17:31, 16 December 2020 by Yellows8 (talk | contribs)
Jump to navigation Jump to search

This is the controller applet which can be launched by Home Menu. Official sw uses this under nn::hid, and nn::hid::system with the "ForSystem" funcs. See AM_services#Library_Applets.

Library Applet Versions

System Version Value
pre-1.0.0 <=0x2
[1.0.0+] 0x3
[3.0.0+] 0x4
[6.0.0+] 0x5
[8.0.0+] 0x7
[11.0.0+] 0x8


This is "nn::hid::system::ControllerSupportArgPrivate". This is a 0x14-byte struct pushed for input storage. The data here is setup by sdknso internally without exposing it to the user.

PlayStartupSound is set to (Flag1 != 0) & (Flag0 != 0). Flag0/Flag1 are always 0 except with *ForSystem funcs in sdknso.

Offset Size Description
0x0 0x4 Size of this ControllerSupportArgPrivate struct.
0x4 0x4 Size of the storage following this one (#ControllerSupportArg or #ControllerFirmwareUpdateArg). With ShowControllerKeyRemappingForSystem, this is the size of #ControllerSupportArg even though the actual storage is #ControllerKeyRemappingArg.
0x8 0x1 Flag0
0x9 0x1 Flag1
0xA 0x1 #ControllerSupportMode
0xB 0x1 #ControllerSupportCaller. Always zero except with ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem, which sets this to the input param.
0xC 0x4 Output from GetSupportedNpadStyleSet. With ShowControllerSupportForSystem on pre-3.0.0 this is value 0.
0x10 0x4 Output from GetNpadJoyHoldType. With ShowControllerSupportForSystem on pre-3.0.0 this is value 1.


This is "nn::hid::ControllerSupportArg". This is a 0x21C-byte (0x9C-byte with version <=0x2, 0x430-byte with version 0x7) struct pushed for input storage.

Offset Size Description
0x0 0x1 s8 playerCountMin (must be >=0 and <=max_supported_players). Older versions assert when invalid, newer versions clamp the used value to a valid range.
0x1 0x1 s8 playerCountMax (must be >=1 and <=max_supported_players). Older versions assert when invalid, newer versions clamp the used value to a valid range.
0x2 0x1 u8 enableTakeOverConnection. Disconnects the controllers when not enabled.
0x3 0x1 u8 enableLeftJustify.
0x4 0x1 u8 enablePermitJoyDual.
0x5 0x1 u8 enableSingleMode. Enables using a single player in handheld-mode, dual-mode, or single-mode (playerCount* are overridden). Using handheld-mode is not allowed if this is not enabled.
0x6 0x1 u8 enableIdentificationColor. Enables using the identificationColor array when non-zero.
0x7 4*max_supported_players u8 identificationColor[4]. Array of 4-byte entries for each player, see below for total entries (max controllers). This entry contains 4 u8s, for the RGBA8 color. This controls the color of the UI player box outline.
0x7 + 4*max_supported_players 0x1 u8 enableExplainText. Enables using the ExplainText data when non-zero.

With both versions, the rest of the struct is an array containing 0x81-byte (0x21-byte with version <=0x2) entries. With version pre-0x7 there's 4 entries allocated, starting with version 0x7 there's 8 entries allocated. This contains the ExplainText string which includes the NUL-terminator. Each entry corresponds to a controller NpadId, starting with NpadId/controller 0.

Regardless of version, the default data for this struct is setup by setting u32 +0 to 0x01010400, u8 +4 to 0x1, with the rest being cleared as needed. sdknso itself only calls the func for this from ShowControllerStrapGuide, since that's the only time sdknso itself writes to ControllerSupportArg besides ExplainText (and is also the only case where the ControllerSupportArg is not user-specified).


This is "nn::hid::ControllerFirmwareUpdateArg". This is a 4-byte struct pushed for the input storage. The default value of this entire struct is 0.

Offset Size Description
0x0 0x1 u8 enableForceUpdate, non-zero to enable. Default is 0. Forces a firmware update when enabled, without an UI option to skip it.
0x1 0x3 u8 padding[3].


This is "nn::hid::system::ControllerSupportMode".

Value Description
0 ShowControllerSupport
1 [3.0.0+] ShowControllerStrapGuide
2 [3.0.0+] ShowControllerFirmwareUpdate
4 [11.0.0+] ShowControllerKeyRemappingForSystem

In sdknso there's two funcs which expose ShowControllerSupport: one which has a param for the output #ControllerSupportResultInfo, and one that saves that to stack and ignores it.

ShowControllerSupportForSystem has equivalent funcs for the above two funcs, which are the same except Flag1 is set to 1 and Flag0 is set to the input bool.

ShowControllerFirmwareUpdateForSystem is the same as ShowControllerFirmwareUpdate, except Flag1 is set to 1 and ControllerSupportCaller is set to the input param.

ShowControllerSupportCore will assert if the mode is ShowControllerFirmwareUpdate, and ShowControllerFirmwareUpdateCore will assert if the mode is not ShowControllerFirmwareUpdate.

ShowControllerSupport seems to only display the applet UI when doing so is actually needed?(This doesn't apply to the ForSystem version)


This is "nn::hid::system::ControllerSupportCaller".

Value Description
0 Application
1 Skips the firmware-update confirmation dialog. This has the same affect as using the controller-update option from qlaunch System Settings.


This is "nn::hid::ControllerSupportResultInfo". This is a 8-byte struct.

Offset Size Description
0x0 0x1 s8 playerCount.
0x1 0x3 u8 padding[3].
0x4 0x4 u32 selectedId, NpadId.


This is "nn::hid::system::ControllerKeyRemappingArg". This is a 0x10-byte struct.

The defaults for this is all-zero for the first 0xC-bytes.

Offset Size Description
0x0 0x8
0x8 0x4
0xC 0x4 Padding


User-processes should push a common arguments struct, an #ControllerSupportArgPrivate, then #ControllerSupportArg / #ControllerFirmwareUpdateArg / #ControllerKeyRemappingArg.

On success, an output storage should be popped, with size 0xC being used to read from there (sdknso ignores the actual storage size). When #ControllerSupportArg was previously used, the first 8-bytes are copied to the output #ControllerSupportResultInfo (which the user can ignore), otherwise it's ignored. The remaining u32 determines the Result: