Difference between revisions of "Software Keyboard"

 
(23 intermediate revisions by 2 users not shown)
Line 3: Line 3:
 
The below is for normal swkbd usage, see the [[#InlineKeyboard]] section for InlineKeyboard.
 
The below is for normal swkbd usage, see the [[#InlineKeyboard]] section for InlineKeyboard.
  
== Library Applet Versions ==
+
With version 0x6000B+ after pushing all other storage: when [[#CustomizedDictionarySet]] was setup where buffer addr/size is set and total_entries is non-zero, [[Applet_Manager_services#CreateHandleStorage]] will be used to create TransferMemory storage which is then pushed.
 +
 
 +
= Library Applet Versions =
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 23: Line 25:
 
|-
 
|-
 
| [5.0.0+] || 0x50009
 
| [5.0.0+] || 0x50009
 +
|-
 +
| [6.0.0+] || 0x6000B
 +
|-
 +
| [8.0.0+] || 0x8000D
 
|}
 
|}
  
== KeyboardConfig ==
+
= KeyboardConfig =
 
 
 
The second IStorage passed to this applet should contain the configuration for the keyboard.
 
The second IStorage passed to this applet should contain the configuration for the keyboard.
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Offset || Size || Typical Value || Notes
+
! Offset || Size || Description
 
|-
 
|-
| 0x0 || 4 || || Type
+
| 0x0 || 0x4 || [[#KeyboardMode]]
 
|-
 
|-
| 0x4 || 18 || 0 || UTF-16 text displayed in the submit button
+
| 0x4 || 0x12 || OkText
 
|-
 
|-
| 0x16 || 2 || 0 || UTF-16 "left optional symbol key"
+
| 0x16 || 0x2 || LeftOptionalSymbolKey
 
|-
 
|-
| 0x18 || 2 || 0 || UTF-16 "right optional symbol key"
+
| 0x18 || 0x2 || RightOptionalSymbolKey
 
|-
 
|-
| 0x1A || 1 || 0 || Enables dictionary usage when non-zero (including the system dictionary).
+
| 0x1A || 0x1 || IsPredictionEnabled
 
|-
 
|-
| 0x1C || 4 || 0 || [[#Key Set Disable Bitmask]]
+
| 0x1C || 0x4 || [[#InvalidCharFlag]]
 
|-
 
|-
| 0x20 || 4 || 1 || Initial cursor position (0 = start of string, 1 = end of string)
+
| 0x20 || 0x4 || [[#InitialCursorPos]]
 
|-
 
|-
| 0x24 || 130 || u"" || UTF-16 header text
+
| 0x24 || 0x82 || HeaderText
 
|-
 
|-
| 0xA6 || 258 || u"" || UTF-16 sub text
+
| 0xA6 || 0x102 || SubText
 
|-
 
|-
| 0x1A8 || 514 || u"" || UTF-16 guide text
+
| 0x1A8 || 0x202 || GuideText
 
|-
 
|-
| 0x3AC || 4 || 0 || stringLenMax
+
| 0x3AC || 0x4 || TextMaxLength
 
|-
 
|-
| 0x3B0 || 4 || 0 || stringLenMaxExt. When non-zero, specifies the max string length. When the input is too long, swkbd will display an icon and disable the ok-button.
+
| 0x3B0 || 0x4 || TextMinLength
 
|-
 
|-
| 0x3B4 || 4 || 0 || Password flag (0 = not password, 1 = password)
+
| 0x3B4 || 0x4 || [[#PasswordMode]]
 
|-
 
|-
| 0x3B8 || 4 || 1 || textDrawType
+
| 0x3B8 || 0x4 || [[#InputFormMode]]
 
|-
 
|-
| 0x3BC || 2 || 1 || Return button flag (0 = disable, non-zero = enable)
+
| 0x3BC || 0x1 || IsUseNewLine
 
|-
 
|-
| 0x3BE || 1 || 1 || Blur background (0 = no, 1 = yes)
+
| 0x3BD || 0x1 || IsUseUtf8
 
|-
 
|-
| 0x3C0 || 4 || 20 || Offset of initial string in work buffer (or 0)
+
| 0x3BE || 0x1 || IsUseBlurBackground
 
|-
 
|-
| 0x3C4 || 4 || 0 || Size of initial string in work buffer (bytes)
+
| 0x3C0 || 0x4 || InitialStringOffset
 
|-
 
|-
| 0x3C8 || 4 || 2024 || Offset of user dictionary in work buffer (or 0)
+
| 0x3C4 || 0x4 || InitialStringLength
 
|-
 
|-
| 0x3CC || 4 || 0 || Length of user dictionary (number of entries)
+
| 0x3C8 || 0x4 || UserDictionaryOffset
 
|-
 
|-
| 0x3D0 || 1 || 0 || [[#Text check]] enable
+
| 0x3CC || 0x4 || UserDictionaryNum
 
|-
 
|-
| 0x3D8 || 8 || 0 || [[#Text check]] callback function address. Not sure why this is included here
+
| 0x3D0 || 0x1 || IsUseTextCheck
 
|-
 
|-
| 0x3E0 || 0x20 || -1 || When set and enabled via textDrawType, controls displayed text grouping (inserts spaces, without affecting output string). Used for DownloadCodes.
+
| 0x3D1 || 0x7 || Reserved
 +
|-
 +
| 0x3D8 || 0x8 || [[#TextCheckCallback]]
 +
|-
 +
| 0x3E0 || 0x20 || SeparateTextPos
 
|}
 
|}
  
This struct is 0x3E0-bytes with version 0x5. Starting with version 0x30007 this struct is 0x400-bytes.
+
Version 0x6000B+:
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description
 +
|-
 +
| 0x3D4 || 0x20 || SeparateTextPos
 +
|-
 +
| 0x3F4 || 0xC0 || [[#CustomizedDictionarySet|CustomizedDicInfoList]]
 +
|-
 +
| 0x4B4 || 0x1 || CustomizedDicCount
 +
|-
 +
| 0x4B5 || 0x1 || [8.0.0+] IsCancelButtonDisabled
 +
|-
 +
| 0x4B6 || 0xD || Reserved
 +
|-
 +
| 0x4C3 || 0x1 || [8.0.0+] Trigger
 +
|-
 +
| 0x4C4 || 0x4 || Reserved
 +
|}
  
The 0x20-bytes at offset 0x3E0 is -1 normally, except for DownloadCodes.
+
Struct sizes:
 +
* Initial version: 0x3E0-bytes.
 +
* Version 0x30007+: 0x400-bytes.
 +
* Version 0x6000B+: 0x4C8-bytes.
  
 
Each entry in the user dictionary is 100 bytes long.
 
Each entry in the user dictionary is 100 bytes long.
  
stringLenMax: When the input is too long, swkbd will stop accepting more input until text is deleted via the B button (Backspace).
+
TextMaxLength: When the input is too long, swkbd will stop accepting more input until text is deleted via the B button (Backspace).
 
 
=== Type ===
 
* 0: Normal keyboard.
 
* 1: Number pad. The buttons at the bottom left/right are only available when the characters at offset 0x16/0x18 are set.
 
* 2: QWERTY (and variants) keyboard only.
 
 
 
=== textDrawType ===
 
If the length limit (stringLenMax) is 1..32, the type specified by textDrawType will be used. Otherwise, type1 will be used.
 
 
 
* 0: The text will be displayed on a line. Also enables displaying the Header and Sub text.
 
* 1: The text will be displayed in a box.
 
* 2: Used for DownloadCodes on 5.0.0+. Enables using the data starting at offset 0x3E0.
 
 
 
=== Key Set Disable Bitmask ===
 
Various bits in this u32 field disable certain keys on the keyboard.
 
 
 
<pre>
 
0x02: disable ' '
 
0x04: disable '@'
 
0x08: disable '%'
 
0x10: disable '/'
 
0x20: disable '\'
 
0x40: disable numbers
 
0x80: Used for DownloadCodes.
 
0x100: Used for UserNames. Disables '@', '%', and '\'.
 
</pre>
 
 
 
== Work Buffer ==
 
  
 +
= WorkBuffer =
 
This is the third IStorage passed to this applet. It is a transfer memory storage. The transfer memory should have size 0x1000 (0xd000 in certain cases) and permissions 0.
 
This is the third IStorage passed to this applet. It is a transfer memory storage. The transfer memory should have size 0x1000 (0xd000 in certain cases) and permissions 0.
  
 
The layout of the work buffer doesn't seem to matter as long as the offsets in the [[#KeyboardConfig]] are adjusted, but official code lays it out like this.
 
The layout of the work buffer doesn't seem to matter as long as the offsets in the [[#KeyboardConfig]] are adjusted, but official code lays it out like this.
  
Prior to version 0x5, offset 0x0 size 0x14(20) is a header (size 0x10 for version <=0x2).
+
Prior to version 0x5, offset 0x0 size 0x14 is a header (size 0x10 for version <=0x2).
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Offset || Size || Notes
+
! Offset || Size || Description
 
|-
 
|-
| 20 (decimal) || Unknown || UTF-16 initial string
+
| 0x14 || Unknown || UTF-16 initial string
 
|-
 
|-
| 2024 (decimal) || Unknown || User dictionary
+
| 0x7E8 || Unknown || User dictionary
 
|}
 
|}
  
== Text Check ==
+
= TextCheckCallback =
 
 
 
If text checking is enabled in [[#KeyboardConfig]], text will be checked when the submit button is pressed. First, swkbd sends the text via PushInteractiveOutData. Normally size 0x7D4 is allocated for the string.
 
If text checking is enabled in [[#KeyboardConfig]], text will be checked when the submit button is pressed. First, swkbd sends the text via PushInteractiveOutData. Normally size 0x7D4 is allocated for the string.
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Offset || Size || Notes
+
! Offset || Size || Description
 
|-
 
|-
 
| 0x0 || 0x8 || Buffer size
 
| 0x0 || 0x8 || Buffer size
 
|-
 
|-
 
| 0x8 || Variable || UTF-16 text
 
| 0x8 || Variable || UTF-16 text
|-
 
 
|}
 
|}
  
Line 149: Line 150:
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Offset || Size || Notes
+
! Offset || Size || Description
 
|-
 
|-
| 0x0 || 0x4 || TextCheckResult
+
| 0x0 || 0x4 || [[#TextCheckResult]]
 
|-
 
|-
 
| 0x4 || Variable || UTF-16 error message (shown in a dialog box)
 
| 0x4 || Variable || UTF-16 error message (shown in a dialog box)
|-
 
 
|}
 
|}
  
TextCheckResult:
+
= Output =
* 0: Success, valid string.
 
* 1: Failure, invalid string. Error message is displayed in a message-box, pressing OK will return to swkbd again.
 
* 2: Failure, invalid string. Error message is displayed in a message-box, pressing Cancel will return to swkbd again, while pressing OK will continue as if the text was valid.
 
* 3: Failure, invalid string. With value 3 and above, swkbd will silently not accept the string, without displaying any error.
 
 
 
== Output ==
 
 
 
 
When either the submit button is pressed and input has been validated, or the user cancels the text entry, swkbd will push its response and exit. The response IStorage has the following format. This storage is 0x7D8-bytes.
 
When either the submit button is pressed and input has been validated, or the user cancels the text entry, swkbd will push its response and exit. The response IStorage has the following format. This storage is 0x7D8-bytes.
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Offset || Size || Notes
+
! Offset || Size || Description
 
|-
 
|-
 
| 0x0 || 0x4 || Result code (0 = OK, 1 = Cancel)
 
| 0x0 || 0x4 || Result code (0 = OK, 1 = Cancel)
 
|-
 
|-
 
| 0x4 || Variable || UTF-16 text
 
| 0x4 || Variable || UTF-16 text
|-
 
 
|}
 
|}
  
== InlineKeyboard ==
+
= InlineKeyboard =
 
This doesn't run in the foreground and has completely different input/output [[AM_services#IStorage|IStorage]]s. This is essentially an asynchronous version of the regular swkbd. Whether it displays on the screen is controlled by the user-process. The user-process can also get the gfx data via [[Display_services]]. InlineKeyboard was added with 2.0.0, however it wasn't added to sdk-nso until the version corresponding to sysver 3.x (even though 2.0.0 system titles use it).
 
This doesn't run in the foreground and has completely different input/output [[AM_services#IStorage|IStorage]]s. This is essentially an asynchronous version of the regular swkbd. Whether it displays on the screen is controlled by the user-process. The user-process can also get the gfx data via [[Display_services]]. InlineKeyboard was added with 2.0.0, however it wasn't added to sdk-nso until the version corresponding to sysver 3.x (even though 2.0.0 system titles use it).
  
=== InitializeArg ===
+
== InitializeArg ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Offset || Size || Notes
+
! Offset || Size || Description
 
|-
 
|-
 
| 0x0 || 0x4 || Unknown, normally 0.
 
| 0x0 || 0x4 || Unknown, normally 0.
Line 194: Line 186:
 
|}
 
|}
  
=== AppearArg ===
+
== AppearArg ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Offset || Size || Notes
+
! Offset || Size || Description
 +
|-
 +
| 0x0 || 0x4 || [[#KeyboardMode]]
 +
|-
 +
| 0x4 || 0x12 || OkText
 +
|-
 +
| 0x16 || 2 || LeftOptionalSymbolKey
 
|-
 
|-
| 0x0 || 0x4 || Initialized to value 0x2.
+
| 0x18 || 2 || RightOptionalSymbolKey
 
|-
 
|-
| 0x4 || 0x12 || UTF-16 string okButtonText
+
| 0x1A || 0x1 || IsPredictionEnabled
 
|-
 
|-
| 0x16 || 2 || UTF-16 "left optional symbol key"
+
| 0x1B || 0x1 || IsCancelButtonDisabled
 
|-
 
|-
| 0x18 || 2 || UTF-16 "right optional symbol key"
+
| 0x1C || 0x4 || [[#InvalidCharFlag]]
 
|-
 
|-
| 0x1A || 0x1 || Enables dictionary usage when non-zero (including the system dictionary).
+
| 0x20 || 0x4 || TextMaxLength
 
|-
 
|-
| 0x1B || 0x1 ||  
+
| 0x24 || 0x4 || TextMinLength
 
|-
 
|-
| 0x1C || 0x4 || [[#Key Set Disable Bitmask]]
+
| 0x28 || 0x1 || IsUseNewLine
 
|-
 
|-
| 0x20 || 0x4 || s32, Unknown. Initialized to value -1.
+
| 0x29 || 0x1 || [10.0.0+] [[#MiniaturizationMode]]
 
|-
 
|-
| 0x24 || 0x4 || s32, Unknown. Initialized to value -1.
+
| 0x2A || 0x1 || Reserved
 
|-
 
|-
| 0x28 || 0x1 || Return button flag (0 = disable, non-zero = enable)
+
| 0x2B || 0x1 || Reserved
 
|-
 
|-
| 0x29 || 0x2 ||  
+
| 0x2C || 0x4 || [4.0.0+] [[#InvalidButtonFlag]]
 
|-
 
|-
| 0x2B || 0x1 ||  
+
| 0x30 || 0x1 || IsUseSaveData
 
|-
 
|-
| 0x2C || 0x4 ||  
+
| 0x31 || 0x7 || Reserved
 
|-
 
|-
| 0x30 || 0x1 || Initialized to value 1.
+
| 0x38 || 0x10 || [[Account_services#Uid|Uid]]
 
|-
 
|-
| 0x31 || 0x17 ||  
+
| 0x48 || 0x8 || StartSamplingNumber
 +
|-
 +
| 0x50 || 0x20 || Reserved
 
|}
 
|}
  
 
The above struct is cleared to 0 during initialization, besides the fields specified otherwise.
 
The above struct is cleared to 0 during initialization, besides the fields specified otherwise.
  
=== CalcArg ===
+
[6.0.0+] Flags bitmask 0x10000 is set when [[#CalcArg]] trigger is set.
 +
 
 +
== CalcArg ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Offset || Size || Flags bitmask || Notes
+
! Offset || Size || Flags bitmask || Description
 
|-
 
|-
 
| 0x0 || 0x4 || || Set to 0x30000.
 
| 0x0 || 0x4 || || Set to 0x30000.
Line 269: Line 271:
 
| 0x463 || 0x1 || 0x100 || footerScalable
 
| 0x463 || 0x1 || 0x100 || footerScalable
 
|-
 
|-
| 0x464 || 0x1 || 0x200 || alphaEnabledInInputMode
+
| 0x464 || 0x1 || 0x100 || alphaEnabledInInputMode
 
|-
 
|-
 
| 0x465 || 0x1 || 0x100 || inputModeFadeType
 
| 0x465 || 0x1 || 0x100 || inputModeFadeType
Line 275: Line 277:
 
| 0x466 || 0x1 || 0x200 || disableTouch
 
| 0x466 || 0x1 || 0x200 || disableTouch
 
|-
 
|-
| 0x467 || 0x1 || 0x800 || disableUSBKeyboard
+
| 0x467 || 0x1 || 0x800 || disableHardwareKeyboard ([1.0.0-9.2.0] disableUSBKeyboard)
 
|-
 
|-
 
| 0x468 || 0x5 || || Unknown
 
| 0x468 || 0x5 || || Unknown
Line 293: Line 295:
 
| 0x480 || 0x4 || 0x100 || float keytopBgAlpha
 
| 0x480 || 0x4 || 0x100 || float keytopBgAlpha
 
|-
 
|-
| 0x484 || 0x4 || || float, unknown
+
| 0x484 || 0x4 || 0x100 || float footerBgAlpha
 
|-
 
|-
 
| 0x488 || 0x4 || 0x200 || float balloonScale
 
| 0x488 || 0x4 || 0x200 || float balloonScale
Line 299: Line 301:
 
| 0x48C || 0x4 || || float, unknown
 
| 0x48C || 0x4 || || float, unknown
 
|-
 
|-
| 0x490 || 0x10 || ||  
+
| 0x490 || 0xC || ||  
 +
|-
 +
| 0x49C || 0x1 || Enable=0x2000, disable=0x4000. || [5.0.0+] SeGroup (sound effect)
 +
|-
 +
| 0x49D || 0x1 || || [6.0.0+] u8 triggerFlag, for [[#AppearArg]]. Enables using the trigger field when set, this is only set when trigger is non-zero.
 +
|-
 +
| 0x49E || 0x2 || || [6.0.0+] u8 trigger, for [[#AppearArg]]. Official sw currently only uses value 0.
 +
|-
 +
| 0x49F || 0x1 || || Padding
 
|-
 
|-
 
|}
 
|}
Line 309: Line 319:
 
The applet-specific IStorage for data input is the [[#InitializeArg]] within this struct.
 
The applet-specific IStorage for data input is the [[#InitializeArg]] within this struct.
  
=== Runtime ===
+
disableHardwareKeyboard: On [10.0.0+] there's sdknso user-facing funcs for both Hardware/USB, which call the same Impl func that has Hardware in the name.
 +
 
 +
== Runtime ==
 
Once the applet is running, official sw can call a func which does the following:
 
Once the applet is running, official sw can call a func which does the following:
 
* Checks whether the applet exited via an event, then handles exit if so and returns.
 
* Checks whether the applet exited via an event, then handles exit if so and returns.
Line 317: Line 329:
 
** The u32 from offset 0x0 from the last processed storage is then returned as the retval.
 
** The u32 from offset 0x0 from the last processed storage is then returned as the retval.
  
=== Request ===
+
== Request ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! RequestCommand || Data Size || Name || Notes
+
! RequestCommand || Data size || Description
 +
|-
 +
| 0x4 || 0x0 || Finalize
 +
|-
 +
| 0x6 || Varies || SetUserWordInfo
 +
|-
 +
| 0x7 || 0x70 || SetCustomizeDic
 +
|-
 +
| 0xA || 0x4A0 || Calc (data is [[#CalcArg]])
 +
|-
 +
| 0xB || 0xD0 || SetCustomizedDictionaries (data is [[#CustomizedDictionarySet]] with an additional 2-bytes of padding
 
|-
 
|-
| 0x4 || 0x0 || Finalize ||
+
| 0xC || 0x0 || UnsetCustomizedDictionaries
 
|-
 
|-
| 0x7 || 0x70 || SetCustomizeDic ||  
+
| 0xD || 0x1 || [8.0.0+] Takes an input u8 bool which controls whether ChangedString*V2 or ChangedString* replies should be used.
 
|-
 
|-
| 0xA || 0x4A0 || Calc || Data is [[#CalcArg]].
+
| 0xE || 0x1 || [8.0.0+] Takes an input u8 bool which controls whether MovedCursor*V2 or MovedCursor* replies should be used.
 
|}
 
|}
  
 
Requests are sent via an applet Interactive input IStorage: the u32 at offset 0x0 is the RequestCommand, and the rest of the storage is the request-specific data. While swkbd supports other requests, official sw only uses requests 0x4, 0x7, and 0xA.
 
Requests are sent via an applet Interactive input IStorage: the u32 at offset 0x0 is the RequestCommand, and the rest of the storage is the request-specific data. While swkbd supports other requests, official sw only uses requests 0x4, 0x7, and 0xA.
  
=== Reply ===
+
== Reply ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! ReplyType || Data size || Description
 +
|-
 +
| 0x0 || 0x1 || FinishedInitialize (reply data is ignored by the user-process)
 +
|-
 +
| 0x1 (default) || 0x0 || Official sw has no handling for this besides just closing the storage.
 +
|-
 +
| 0x2 || 0x3FC || ChangedString
 +
|-
 +
| 0x3 || 0x3F4 || MovedCursor
 +
|-
 +
| 0x4 || 0x3F4 || MovedTab
 +
|-
 +
| 0x5 || 0x3F0 || DecidedEnter
 +
|-
 +
| 0x6 || 0x0 || DecidedCancel
 +
|-
 +
| 0x7 || 0x7E4 || ChangedStringUtf8
 +
|-
 +
| 0x8 || 0x7DC || MovedCursorUtf8
 +
|-
 +
| 0x9 || 0x7D8 || DecidedEnterUtf8
 +
|-
 +
| 0xA || 0x0 || UnsetCustomizeDic (official sw clears a flag related to CustomizeDic, then runs the same handling code as 0x1/default)
 +
|-
 +
| 0xB || 0x0 || ReleasedUserWordInfo
 +
|-
 +
| 0xC || 0x0 || [6.0.0+] UnsetCustomizedDictionaries (official sw handles this the same as UnsetCustomizeDic)
 +
|-
 +
| 0xD || 0x3FC + 0x1 || [8.0.0+] ChangedStringV2
 +
|-
 +
| 0xE || 0x3F4 + 0x1 || [8.0.0+] MovedCursorV2
 +
|-
 +
| 0xF || 0x7E4 + 0x1 || [8.0.0+] ChangedStringUtf8V2
 +
|-
 +
| 0x10 || 0x7DC + 0x1 || [8.0.0+] MovedCursorUtf8V2
 +
|}
 +
 
 +
See [[#Runtime]]. In the storage, the first u32 is the State, while the second u32 is the ReplyType. The rest is the reply-specific data.
 +
 
 +
The replies with name "*Utf8" contain an UTF-8 string in the reply data, while the other replies contain an UTF-16 string. These are identical besides the string encoding.
 +
 
 +
Reply data format:
 +
* ChangedString*: +0 = string. Last 0x10-bytes: 4 u32s, where the first one is the length of the string in characters, without NUL-terminator. The last u32 is cursorPos. The other 2 fields are s32s.
 +
* MovedCursor*: +0 = string. Last 0x8-bytes: 2 u32s, where the first one is the stringLen, and the second one is cursorPos.
 +
* DecidedEnter*: +0 = string. The last u32 is the stringLen.
 +
* *V2: See above. Last byte: u8 bool, passed to the callback as <code>flag==0</code>.
 +
 
 +
= CustomizedDictionarySet =
 +
This is "nn::swkbd::CustomizedDictionarySet". This struct is 0xCE-bytes.
 +
 
 +
This was added with [6.0.0+].
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description
 +
|-
 +
| 0x0 || 0x8 || Dictionaries (0x1000-byte aligned buffer address)
 +
|-
 +
| 0x8 || 0x4 || DictionariesSize (0x1000-byte aligned buffer size)
 +
|-
 +
| 0xC || 0xC0 (0x18*4) || DicInfoList (array of 0x18 entries, where each entry is a [[#DictionaryInfo]]).
 +
|-
 +
| 0xCC || 0x2 || Count
 +
|}
 +
 
 +
= DictionaryInfo =
 +
This is "nn::swkbd::DictionaryInfo".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description
 +
|-
 +
| 0x0 || 0x4 || Offset
 +
|-
 +
| 0x4 || 0x2 || Size
 +
|-
 +
| 0x6 || 0x2 || [[#DictionaryLang]]
 +
|}
 +
 
 +
= DictionaryLang =
 +
This is "nn::swkbd::DictionaryLang".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Description
 +
|-
 +
| 0 || Japanese
 +
|-
 +
| 1 || AmericanEnglish
 +
|-
 +
| 2 || CanadianFrench
 +
|-
 +
| 3 || LatinAmericanSpanish
 +
|-
 +
| 4 || Reserved1
 +
|-
 +
| 5 || BritishEnglish
 +
|-
 +
| 6 || French
 +
|-
 +
| 7 || German
 +
|-
 +
| 8 || Spanish
 +
|-
 +
| 9 || Italian
 +
|-
 +
| 10 || Dutch
 +
|-
 +
| 11 || Portuguese
 +
|-
 +
| 12 || Russian
 +
|-
 +
| 13 || Reserved2
 +
|-
 +
| 14 || SimplifiedChinesePinyin
 +
|-
 +
| 15 || TraditionalChineseCangjie
 +
|-
 +
| 16 || TraditionalChineseSimplifiedCangjie
 +
|-
 +
| 17 || TraditionalChineseZhuyin
 +
|-
 +
| 18 || Korean
 +
|}
 +
 
 +
= KeyboardMode =
 +
This is "nn::swkbd::KeyboardMode".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Description
 +
|-
 +
| 0 || Full
 +
|-
 +
| 1 || Numeric
 +
|-
 +
| 2 || ASCII
 +
|-
 +
| 3 || FullLatin
 +
|-
 +
| 4 || Alphabet
 +
|-
 +
| 5 || SimplifiedChinese
 +
|-
 +
| 6 || TraditionalChinese
 +
|-
 +
| 7 || Korean
 +
|-
 +
| 8 || LanguageSet2
 +
|-
 +
| 9 || LanguageSet2Latin
 +
|}
 +
 
 +
= State =
 +
This is "nn::swkbd::State".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Description
 +
|-
 +
| 0 || None
 +
|-
 +
| 1 || Disappear
 +
|-
 +
| 2 || InAppear
 +
|-
 +
| 3 || Appear
 +
|-
 +
| 4 || InDisappear
 +
|-
 +
| 5 || SelectKeyTop
 +
|-
 +
| 6 || Miniaturized
 +
|}
 +
 
 +
= CloseResult =
 +
This is "nn::swkbd::CloseResult".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Description
 +
|-
 +
| 0 || Enter
 +
|-
 +
| 1 || Cancel
 +
|}
 +
 
 +
= PasswordMode =
 +
This is "nn::swkbd::PasswordMode".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Description
 +
|-
 +
| 0 || Show
 +
|-
 +
| 1 || Hide
 +
|}
 +
 
 +
= InitialCursorPos =
 +
This is "nn::swkbd::InitialCursorPos".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Description
 +
|-
 +
| 0 || First
 +
|-
 +
| 1 || Last
 +
|}
 +
 
 +
= InputFormMode =
 +
This is "nn::swkbd::InputFormMode".
 +
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! ReplyType || Data Size || Name || Notes
+
! Value || Description
 +
|-
 +
| 0 || OneLine
 +
|-
 +
| 1 || MultiLine
 
|-
 
|-
 +
| 2 || Separate
 
|}
 
|}
  
See [[#Runtime]]. In the storage, the first u32 is the retval, while the second u32 is the ReplyType. The rest is the reply-specific data.
+
= TextCheckResult =
 +
This is "nn::swkbd::TextCheckResult".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Description
 +
|-
 +
| 0 || Success
 +
|-
 +
| 1 || ShowFailureDialog
 +
|-
 +
| 2 || ShowConfirmDialog
 +
|}
 +
 
 +
= Preset =
 +
This is "nn::swkbd::Preset".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Description
 +
|-
 +
| 0 || Default
 +
|-
 +
| 1 || Password
 +
|-
 +
| 2 || UserName
 +
|-
 +
| 3 || DownloadCode
 +
|}
 +
 
 +
= MiniaturizationMode =
 +
This is "nn::swkbd::MiniaturizationMode".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Description
 +
|-
 +
| 0 || None
 +
|-
 +
| 1 || Auto
 +
|-
 +
| 2 || Forced
 +
|}
 +
 
 +
= InvalidCharFlag =
 +
This is "nn::swkbd::InvalidCharFlag".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Bits || Description
 +
|-
 +
| 1 || Space
 +
|-
 +
| 2 || AtMark
 +
|-
 +
| 3 || Percent
 +
|-
 +
| 4 || Slash
 +
|-
 +
| 5 || BackSlash
 +
|-
 +
| 6 || Numeric
 +
|-
 +
| 7 || OutsideOfDownloadCode
 +
|-
 +
| 8 || OutsideOfMiiNickName
 +
|}
 +
 
 +
= InvalidButtonFlag =
 +
This is "nn::swkbd::InvalidButtonFlag".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Bits || Description
 +
|-
 +
| 1 || AnalogStickL
 +
|-
 +
| 2 || AnalogStickR
 +
|-
 +
| 3 || ZL
 +
|-
 +
| 4 || ZR
 +
|}
 +
 
 +
= UserWord =
 +
This is "nn::swkbd::UserWord".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description
 +
|-
 +
| 0x0 || 0x32 || Reading
 +
|-
 +
| 0x32 || 0x32 || Word
 +
|}
 +
 
 +
= Rect =
 +
This is "nn::swkbd::Rect". This is a 0x8-byte struct.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description
 +
|-
 +
| 0x0 || 0x2 || (s16) Left
 +
|-
 +
| 0x2 || 0x2 || (s16) Top
 +
|-
 +
| 0x4 || 0x2 || (s16) Width
 +
|-
 +
| 0x6 || 0x2 || (s16) Height
 +
|}
  
 
[[Category:Library Applets]]
 
[[Category:Library Applets]]

Latest revision as of 17:45, 9 May 2021

The software keyboard (swkbd) expects to be passed three IStorages. See also AM_services#Library_Applets.

The below is for normal swkbd usage, see the #InlineKeyboard section for InlineKeyboard.

With version 0x6000B+ after pushing all other storage: when #CustomizedDictionarySet was setup where buffer addr/size is set and total_entries is non-zero, Applet_Manager_services#CreateHandleStorage will be used to create TransferMemory storage which is then pushed.

Library Applet Versions

System Version Value
0x0..0x1
0x2
0x3..4
[1.0.0+] 0x5
[2.0.0+] 0x10006
[3.0.0+] 0x30007
[4.0.0+] 0x40008
[5.0.0+] 0x50009
[6.0.0+] 0x6000B
[8.0.0+] 0x8000D

KeyboardConfig

The second IStorage passed to this applet should contain the configuration for the keyboard.

Offset Size Description
0x0 0x4 #KeyboardMode
0x4 0x12 OkText
0x16 0x2 LeftOptionalSymbolKey
0x18 0x2 RightOptionalSymbolKey
0x1A 0x1 IsPredictionEnabled
0x1C 0x4 #InvalidCharFlag
0x20 0x4 #InitialCursorPos
0x24 0x82 HeaderText
0xA6 0x102 SubText
0x1A8 0x202 GuideText
0x3AC 0x4 TextMaxLength
0x3B0 0x4 TextMinLength
0x3B4 0x4 #PasswordMode
0x3B8 0x4 #InputFormMode
0x3BC 0x1 IsUseNewLine
0x3BD 0x1 IsUseUtf8
0x3BE 0x1 IsUseBlurBackground
0x3C0 0x4 InitialStringOffset
0x3C4 0x4 InitialStringLength
0x3C8 0x4 UserDictionaryOffset
0x3CC 0x4 UserDictionaryNum
0x3D0 0x1 IsUseTextCheck
0x3D1 0x7 Reserved
0x3D8 0x8 #TextCheckCallback
0x3E0 0x20 SeparateTextPos

Version 0x6000B+:

Offset Size Description
0x3D4 0x20 SeparateTextPos
0x3F4 0xC0 CustomizedDicInfoList
0x4B4 0x1 CustomizedDicCount
0x4B5 0x1 [8.0.0+] IsCancelButtonDisabled
0x4B6 0xD Reserved
0x4C3 0x1 [8.0.0+] Trigger
0x4C4 0x4 Reserved

Struct sizes:

  • Initial version: 0x3E0-bytes.
  • Version 0x30007+: 0x400-bytes.
  • Version 0x6000B+: 0x4C8-bytes.

Each entry in the user dictionary is 100 bytes long.

TextMaxLength: When the input is too long, swkbd will stop accepting more input until text is deleted via the B button (Backspace).

WorkBuffer

This is the third IStorage passed to this applet. It is a transfer memory storage. The transfer memory should have size 0x1000 (0xd000 in certain cases) and permissions 0.

The layout of the work buffer doesn't seem to matter as long as the offsets in the #KeyboardConfig are adjusted, but official code lays it out like this.

Prior to version 0x5, offset 0x0 size 0x14 is a header (size 0x10 for version <=0x2).

Offset Size Description
0x14 Unknown UTF-16 initial string
0x7E8 Unknown User dictionary

TextCheckCallback

If text checking is enabled in #KeyboardConfig, text will be checked when the submit button is pressed. First, swkbd sends the text via PushInteractiveOutData. Normally size 0x7D4 is allocated for the string.

Offset Size Description
0x0 0x8 Buffer size
0x8 Variable UTF-16 text

The application then has an opportunity to validate or reject the text. It creates a new IStorage, writes the response to it, and sends it via PushInteractiveInData. This storage is 0x7D8-bytes.

Offset Size Description
0x0 0x4 #TextCheckResult
0x4 Variable UTF-16 error message (shown in a dialog box)

Output

When either the submit button is pressed and input has been validated, or the user cancels the text entry, swkbd will push its response and exit. The response IStorage has the following format. This storage is 0x7D8-bytes.

Offset Size Description
0x0 0x4 Result code (0 = OK, 1 = Cancel)
0x4 Variable UTF-16 text

InlineKeyboard

This doesn't run in the foreground and has completely different input/output IStorages. This is essentially an asynchronous version of the regular swkbd. Whether it displays on the screen is controlled by the user-process. The user-process can also get the gfx data via Display_services. InlineKeyboard was added with 2.0.0, however it wasn't added to sdk-nso until the version corresponding to sysver 3.x (even though 2.0.0 system titles use it).

InitializeArg

Offset Size Description
0x0 0x4 Unknown, normally 0.
0x4 0x1 Controls the LibraryAppletMode when launching the applet. Non-zero indicates LibraryAppletMode=0x1, otherwise LibraryAppletMode=0x3.
0x5 0x1 Set to 0x1 with [5.0.0+] in a separate init func by official sw, originally set to value 0.
0x6 0x2 Padding

AppearArg

Offset Size Description
0x0 0x4 #KeyboardMode
0x4 0x12 OkText
0x16 2 LeftOptionalSymbolKey
0x18 2 RightOptionalSymbolKey
0x1A 0x1 IsPredictionEnabled
0x1B 0x1 IsCancelButtonDisabled
0x1C 0x4 #InvalidCharFlag
0x20 0x4 TextMaxLength
0x24 0x4 TextMinLength
0x28 0x1 IsUseNewLine
0x29 0x1 [10.0.0+] #MiniaturizationMode
0x2A 0x1 Reserved
0x2B 0x1 Reserved
0x2C 0x4 [4.0.0+] #InvalidButtonFlag
0x30 0x1 IsUseSaveData
0x31 0x7 Reserved
0x38 0x10 Uid
0x48 0x8 StartSamplingNumber
0x50 0x20 Reserved

The above struct is cleared to 0 during initialization, besides the fields specified otherwise.

[6.0.0+] Flags bitmask 0x10000 is set when #CalcArg trigger is set.

CalcArg

Offset Size Flags bitmask Description
0x0 0x4 Set to 0x30000.
0x4 0x2 Size of this struct.
0x6 0x1 Unknown, set to value 0x1.
0x7 0x1 Unknown, set to value 0x1.
0x8 0x8 Flags
0x10 0x8 0x1 #InitializeArg
0x18 0x4 0x2 float volume
0x1C 0x4 0x10 s32 cursorPos
0x20 0x48 #AppearArg
0x68 0x3F4 0x8 InputText UTF-16 string
0x45C 0x1 0x20 utf8Mode
0x45D 0x1 Unknown
0x45E 0x1 0x8000 [5.0.0+] enableBackspace
0x45F 0x3 Unknown
0x462 0x1 0x200 keytopAsFloating
0x463 0x1 0x100 footerScalable
0x464 0x1 0x100 alphaEnabledInInputMode
0x465 0x1 0x100 inputModeFadeType
0x466 0x1 0x200 disableTouch
0x467 0x1 0x800 disableHardwareKeyboard ([1.0.0-9.2.0] disableUSBKeyboard)
0x468 0x5 Unknown
0x46D 0x2
0x46F 0x1
0x470 0x4 0x200 float keytopScale0
0x474 0x4 0x200 float keytopScale1
0x478 0x4 0x200 float keytopTranslate0
0x47C 0x4 0x200 float keytopTranslate1
0x480 0x4 0x100 float keytopBgAlpha
0x484 0x4 0x100 float footerBgAlpha
0x488 0x4 0x200 float balloonScale
0x48C 0x4 float, unknown
0x490 0xC
0x49C 0x1 Enable=0x2000, disable=0x4000. [5.0.0+] SeGroup (sound effect)
0x49D 0x1 [6.0.0+] u8 triggerFlag, for #AppearArg. Enables using the trigger field when set, this is only set when trigger is non-zero.
0x49E 0x2 [6.0.0+] u8 trigger, for #AppearArg. Official sw currently only uses value 0.
0x49F 0x1 Padding

This is 0x4A0-bytes.

All floats except for keytopTranslate0/keytopTranslate1 are initialized to value 1.0f.

The applet-specific IStorage for data input is the #InitializeArg within this struct.

disableHardwareKeyboard: On [10.0.0+] there's sdknso user-facing funcs for both Hardware/USB, which call the same Impl func that has Hardware in the name.

Runtime

Once the applet is running, official sw can call a func which does the following:

  • Checks whether the applet exited via an event, then handles exit if so and returns.
  • Otherwise:
    • If the Flags field in the #CalcArg state is non-zero, sends a Calc #Request then clears the Flags field.
    • Enters a loop which pops each applet Interactive output IStorage, reads 2 u32s from the #Reply storage and processes the reply.
    • The u32 from offset 0x0 from the last processed storage is then returned as the retval.

Request

RequestCommand Data size Description
0x4 0x0 Finalize
0x6 Varies SetUserWordInfo
0x7 0x70 SetCustomizeDic
0xA 0x4A0 Calc (data is #CalcArg)
0xB 0xD0 SetCustomizedDictionaries (data is #CustomizedDictionarySet with an additional 2-bytes of padding
0xC 0x0 UnsetCustomizedDictionaries
0xD 0x1 [8.0.0+] Takes an input u8 bool which controls whether ChangedString*V2 or ChangedString* replies should be used.
0xE 0x1 [8.0.0+] Takes an input u8 bool which controls whether MovedCursor*V2 or MovedCursor* replies should be used.

Requests are sent via an applet Interactive input IStorage: the u32 at offset 0x0 is the RequestCommand, and the rest of the storage is the request-specific data. While swkbd supports other requests, official sw only uses requests 0x4, 0x7, and 0xA.

Reply

ReplyType Data size Description
0x0 0x1 FinishedInitialize (reply data is ignored by the user-process)
0x1 (default) 0x0 Official sw has no handling for this besides just closing the storage.
0x2 0x3FC ChangedString
0x3 0x3F4 MovedCursor
0x4 0x3F4 MovedTab
0x5 0x3F0 DecidedEnter
0x6 0x0 DecidedCancel
0x7 0x7E4 ChangedStringUtf8
0x8 0x7DC MovedCursorUtf8
0x9 0x7D8 DecidedEnterUtf8
0xA 0x0 UnsetCustomizeDic (official sw clears a flag related to CustomizeDic, then runs the same handling code as 0x1/default)
0xB 0x0 ReleasedUserWordInfo
0xC 0x0 [6.0.0+] UnsetCustomizedDictionaries (official sw handles this the same as UnsetCustomizeDic)
0xD 0x3FC + 0x1 [8.0.0+] ChangedStringV2
0xE 0x3F4 + 0x1 [8.0.0+] MovedCursorV2
0xF 0x7E4 + 0x1 [8.0.0+] ChangedStringUtf8V2
0x10 0x7DC + 0x1 [8.0.0+] MovedCursorUtf8V2

See #Runtime. In the storage, the first u32 is the State, while the second u32 is the ReplyType. The rest is the reply-specific data.

The replies with name "*Utf8" contain an UTF-8 string in the reply data, while the other replies contain an UTF-16 string. These are identical besides the string encoding.

Reply data format:

  • ChangedString*: +0 = string. Last 0x10-bytes: 4 u32s, where the first one is the length of the string in characters, without NUL-terminator. The last u32 is cursorPos. The other 2 fields are s32s.
  • MovedCursor*: +0 = string. Last 0x8-bytes: 2 u32s, where the first one is the stringLen, and the second one is cursorPos.
  • DecidedEnter*: +0 = string. The last u32 is the stringLen.
  • *V2: See above. Last byte: u8 bool, passed to the callback as flag==0.

CustomizedDictionarySet

This is "nn::swkbd::CustomizedDictionarySet". This struct is 0xCE-bytes.

This was added with [6.0.0+].

Offset Size Description
0x0 0x8 Dictionaries (0x1000-byte aligned buffer address)
0x8 0x4 DictionariesSize (0x1000-byte aligned buffer size)
0xC 0xC0 (0x18*4) DicInfoList (array of 0x18 entries, where each entry is a #DictionaryInfo).
0xCC 0x2 Count

DictionaryInfo

This is "nn::swkbd::DictionaryInfo".

Offset Size Description
0x0 0x4 Offset
0x4 0x2 Size
0x6 0x2 #DictionaryLang

DictionaryLang

This is "nn::swkbd::DictionaryLang".

Value Description
0 Japanese
1 AmericanEnglish
2 CanadianFrench
3 LatinAmericanSpanish
4 Reserved1
5 BritishEnglish
6 French
7 German
8 Spanish
9 Italian
10 Dutch
11 Portuguese
12 Russian
13 Reserved2
14 SimplifiedChinesePinyin
15 TraditionalChineseCangjie
16 TraditionalChineseSimplifiedCangjie
17 TraditionalChineseZhuyin
18 Korean

KeyboardMode

This is "nn::swkbd::KeyboardMode".

Value Description
0 Full
1 Numeric
2 ASCII
3 FullLatin
4 Alphabet
5 SimplifiedChinese
6 TraditionalChinese
7 Korean
8 LanguageSet2
9 LanguageSet2Latin

State

This is "nn::swkbd::State".

Value Description
0 None
1 Disappear
2 InAppear
3 Appear
4 InDisappear
5 SelectKeyTop
6 Miniaturized

CloseResult

This is "nn::swkbd::CloseResult".

Value Description
0 Enter
1 Cancel

PasswordMode

This is "nn::swkbd::PasswordMode".

Value Description
0 Show
1 Hide

InitialCursorPos

This is "nn::swkbd::InitialCursorPos".

Value Description
0 First
1 Last

InputFormMode

This is "nn::swkbd::InputFormMode".

Value Description
0 OneLine
1 MultiLine
2 Separate

TextCheckResult

This is "nn::swkbd::TextCheckResult".

Value Description
0 Success
1 ShowFailureDialog
2 ShowConfirmDialog

Preset

This is "nn::swkbd::Preset".

Value Description
0 Default
1 Password
2 UserName
3 DownloadCode

MiniaturizationMode

This is "nn::swkbd::MiniaturizationMode".

Value Description
0 None
1 Auto
2 Forced

InvalidCharFlag

This is "nn::swkbd::InvalidCharFlag".

Bits Description
1 Space
2 AtMark
3 Percent
4 Slash
5 BackSlash
6 Numeric
7 OutsideOfDownloadCode
8 OutsideOfMiiNickName

InvalidButtonFlag

This is "nn::swkbd::InvalidButtonFlag".

Bits Description
1 AnalogStickL
2 AnalogStickR
3 ZL
4 ZR

UserWord

This is "nn::swkbd::UserWord".

Offset Size Description
0x0 0x32 Reading
0x32 0x32 Word

Rect

This is "nn::swkbd::Rect". This is a 0x8-byte struct.

Offset Size Description
0x0 0x2 (s16) Left
0x2 0x2 (s16) Top
0x4 0x2 (s16) Width
0x6 0x2 (s16) Height