mirror of
https://github.com/devkitPro/wut.git
synced 2026-06-22 12:30:29 -05:00
639 lines
16 KiB
C++
639 lines
16 KiB
C++
#pragma once
|
|
#include <wut.h>
|
|
#include <coreinit/filesystem.h>
|
|
#include <nn/result.h>
|
|
#include <padscore/kpad.h>
|
|
#include <vpad/input.h>
|
|
#include <string.h>
|
|
|
|
/**
|
|
* \defgroup nn_swkbd_swkbd Software Keyboard
|
|
* \ingroup nn_swkbd
|
|
* See \link nn::swkbd \endlink.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
|
|
namespace nn
|
|
{
|
|
|
|
/**
|
|
* Graphical software keyboard, supporting several languages and configurations.
|
|
* Applications should first call \link Create \endlink to initialise the
|
|
* library, followed by \link AppearInputForm \endlink to show a text area and
|
|
* virtual keyboard. Input should be forwarded to the keyboard via
|
|
* \link Calc \endlink, along with calls to \link CalcSubThreadFont \endlink and
|
|
* \link CalcSubThreadPredict \endlink. Finally, the keyboard can be rendered
|
|
* with \link DrawTV \endlink and \link DrawDRC \endlink. The user's interaction
|
|
* with the keyboard can be tracked with \link GetInputFormString \endlink,
|
|
* \link IsDecideOkButton \endlink and \link IsDecideCancelButton \endlink; and
|
|
* once satisfied the application can dismiss the keyboard with
|
|
* \link DisappearInputForm \endlink. Don't forget \link Destroy \endlink!
|
|
*/
|
|
namespace swkbd
|
|
{
|
|
|
|
enum class ControllerType
|
|
{
|
|
WiiRemote0 = 0,
|
|
WiiRemote1 = 1,
|
|
WiiRemote2 = 2,
|
|
WiiRemote3 = 3,
|
|
DrcGamepad = 4,
|
|
};
|
|
|
|
enum class LanguageType
|
|
{
|
|
Japanese = 0,
|
|
English = 1,
|
|
//! TODO: find more language types
|
|
};
|
|
|
|
enum class RegionType
|
|
{
|
|
Japan = 0,
|
|
USA = 1,
|
|
Europe = 2,
|
|
//! TODO: find more region types
|
|
};
|
|
|
|
enum class State
|
|
{
|
|
//! The input form / keyboard is completely hidden.
|
|
Hidden = 0,
|
|
//! The input form / keyboard is drawing the fade in animation.
|
|
FadeIn = 1,
|
|
//! The input form / keyboard is done drawing the fade in animation and completely visible.
|
|
Visible = 2,
|
|
//! The input form / keyboard is drawing the fade out animation.
|
|
FadeOut = 3,
|
|
};
|
|
|
|
enum class InputFormType
|
|
{
|
|
//! Input form seen when adding an NNID on Friends List or creating a folder on the System Menu. (Individual square design with up to 40 characters)
|
|
InputForm0 = 0,
|
|
//! The default input layout that is usually used (Page design)
|
|
Default = 1,
|
|
};
|
|
|
|
enum class KeyboardMode
|
|
{
|
|
//! The one that fully allows utf-16LE(char16_t) charaters
|
|
Full = 0,
|
|
//! Numpad used for entering for example a DNS address
|
|
Numpad = 1,
|
|
//! ascii, possibly used for passwords ?
|
|
Utf8 = 2,
|
|
//! the one thats used for registering an nnid full alphabet, numbers, '_' and '-'
|
|
NNID = 3,
|
|
};
|
|
|
|
enum class PasswordMode
|
|
{
|
|
//! Show clear text
|
|
Clear = 0,
|
|
//! Hides the text
|
|
Hide = 1,
|
|
//! Hides the charater after a few seconds
|
|
Fade = 2,
|
|
};
|
|
|
|
//! Configuration options for the virtual keyboard.
|
|
struct ConfigArg
|
|
{
|
|
ConfigArg()
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
languageType = LanguageType::English;
|
|
controllerType = ControllerType::DrcGamepad;
|
|
keyboardMode = KeyboardMode::Full;
|
|
accessFlags = 0x7FFFF;
|
|
unk_0x10 = 19;
|
|
unk_0x14 = -1;
|
|
unk_0x9C = 1;
|
|
unk_0xA4 = -1;
|
|
}
|
|
|
|
//! The language to use for input
|
|
LanguageType languageType;
|
|
ControllerType controllerType;
|
|
KeyboardMode keyboardMode;
|
|
//! TODO: find all bit flags
|
|
uint32_t accessFlags; // Bitmasked!
|
|
uint32_t unk_0x10;
|
|
int32_t unk_0x14;
|
|
bool unk_0x18;
|
|
//! Text that's displayed on the "OK" button
|
|
const char16_t *okString;
|
|
//! The left side button exclusive to the numpad keyboard mode
|
|
char16_t numpadCharLeft;
|
|
//! The right side button exclusive to the numpad keyboard mode
|
|
char16_t numpadCharRight;
|
|
//! Bool to either enable or disable word suggestions
|
|
bool showWordSuggestions;
|
|
WUT_PADDING_BYTES(3);
|
|
uint8_t unk_0x28;
|
|
uint8_t unk_0x29;
|
|
uint8_t unk_0x2A;
|
|
//! If true it'll disable the new Line character on the keyboard
|
|
bool disableNewLine;
|
|
WUT_UNKNOWN_BYTES(0x9C - 0x2C);
|
|
uint32_t unk_0x9C;
|
|
//! Draws the system Wii remote pointer.
|
|
bool drawSysWiiPointer;
|
|
int32_t unk_0xA4;
|
|
};
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x00, languageType);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x04, controllerType);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x08, keyboardMode);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x0C, accessFlags);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x10, unk_0x10);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x14, unk_0x14);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x18, unk_0x18);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x1C, okString);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x20, numpadCharLeft);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x22, numpadCharRight);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x24, showWordSuggestions);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x28, unk_0x28);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x29, unk_0x29);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x2A, unk_0x2A);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x2B, disableNewLine);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0x9C, unk_0x9C);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0xA0, drawSysWiiPointer);
|
|
WUT_CHECK_OFFSET(ConfigArg, 0xA4, unk_0xA4);
|
|
WUT_CHECK_SIZE(ConfigArg, 0xA8);
|
|
|
|
struct ReceiverArg
|
|
{
|
|
uint32_t unk_0x00 = 0;
|
|
uint32_t unk_0x04 = 0;
|
|
uint32_t unk_0x08 = 0;
|
|
int32_t unk_0x0C = -1;
|
|
uint32_t unk_0x10 = 0;
|
|
int32_t unk_0x14 = -1;
|
|
};
|
|
WUT_CHECK_OFFSET(ReceiverArg, 0x00, unk_0x00);
|
|
WUT_CHECK_OFFSET(ReceiverArg, 0x04, unk_0x04);
|
|
WUT_CHECK_OFFSET(ReceiverArg, 0x08, unk_0x08);
|
|
WUT_CHECK_OFFSET(ReceiverArg, 0x0C, unk_0x0C);
|
|
WUT_CHECK_OFFSET(ReceiverArg, 0x10, unk_0x10);
|
|
WUT_CHECK_OFFSET(ReceiverArg, 0x14, unk_0x14);
|
|
WUT_CHECK_SIZE(ReceiverArg, 0x18);
|
|
|
|
//! Arguments for the swkbd keyboard
|
|
struct KeyboardArg
|
|
{
|
|
//! Configuration for the keyboard itself
|
|
ConfigArg configArg;
|
|
ReceiverArg receiverArg;
|
|
};
|
|
WUT_CHECK_SIZE(KeyboardArg, 0xC0);
|
|
|
|
//! Arguments for swkbd the input form (text area).
|
|
struct InputFormArg
|
|
{
|
|
//! The type of input form
|
|
InputFormType type = InputFormType::Default;
|
|
int32_t unk_0x04 = -1;
|
|
//! Initial string to open the keyboard with
|
|
const char16_t *initialText = nullptr;
|
|
//! Hint string
|
|
const char16_t *hintText = nullptr;
|
|
//! The maximum number of characters that can be entered, -1 for unlimited.
|
|
int32_t maxTextLength = -1;
|
|
//! Which password inputting preset to use
|
|
nn::swkbd::PasswordMode passwordMode = nn::swkbd::PasswordMode::Clear;
|
|
uint32_t unk_0x18 = 0;
|
|
//! Whether or not to draw a cursor. Exclusive to the inputform0 input form type.
|
|
bool drawInput0Cursor = false;
|
|
//! Whether or not to highlight the initial string. Exclusive to the Default input form type.
|
|
bool higlightInitialText = false;
|
|
//! Whether or not to show a copy and a paste button.
|
|
bool showCopyPasteButtons = false;
|
|
WUT_PADDING_BYTES(1);
|
|
};
|
|
WUT_CHECK_OFFSET(InputFormArg, 0x00, type);
|
|
WUT_CHECK_OFFSET(InputFormArg, 0x04, unk_0x04);
|
|
WUT_CHECK_OFFSET(InputFormArg, 0x08, initialText);
|
|
WUT_CHECK_OFFSET(InputFormArg, 0x0C, hintText);
|
|
WUT_CHECK_OFFSET(InputFormArg, 0x10, maxTextLength);
|
|
WUT_CHECK_OFFSET(InputFormArg, 0x14, passwordMode);
|
|
WUT_CHECK_OFFSET(InputFormArg, 0x18, unk_0x18);
|
|
WUT_CHECK_OFFSET(InputFormArg, 0x1C, drawInput0Cursor);
|
|
WUT_CHECK_OFFSET(InputFormArg, 0x1D, higlightInitialText);
|
|
WUT_CHECK_OFFSET(InputFormArg, 0x1E, showCopyPasteButtons);
|
|
WUT_CHECK_SIZE(InputFormArg, 0x20);
|
|
|
|
//! Arguments for the swkbd input form and keyboard.
|
|
struct AppearArg
|
|
{
|
|
//! Arguments for the virtual keyboard
|
|
KeyboardArg keyboardArg;
|
|
//! Arguments for the input form (text area)
|
|
InputFormArg inputFormArg;
|
|
};
|
|
WUT_CHECK_SIZE(AppearArg, 0xE0);
|
|
|
|
//!The arguments used to initialise swkbd and pass in its required resources.
|
|
struct CreateArg
|
|
{
|
|
//! A pointer to a work memory buffer; see \link GetWorkMemorySize \endlink.
|
|
void *workMemory = nullptr;
|
|
//! The swkbd region to use.
|
|
RegionType regionType = RegionType::Europe;
|
|
uint32_t unk_0x08 = 0;
|
|
//! An FSClient for swkbd to use while loading resources.
|
|
FSClient *fsClient = nullptr;
|
|
};
|
|
WUT_CHECK_OFFSET(CreateArg, 0x00, workMemory);
|
|
WUT_CHECK_OFFSET(CreateArg, 0x04, regionType);
|
|
WUT_CHECK_OFFSET(CreateArg, 0x08, unk_0x08);
|
|
WUT_CHECK_OFFSET(CreateArg, 0x0C, fsClient);
|
|
WUT_CHECK_SIZE(CreateArg, 0x10);
|
|
|
|
//! Input and controller information for swkbd.
|
|
struct ControllerInfo
|
|
{
|
|
//! DRC input information, see \link VPADRead \endlink.
|
|
VPADStatus *vpad = nullptr;
|
|
//! Wiimote and extension controller inputs, see \link KPADRead \endlink.
|
|
KPADStatus *kpad[4] = { nullptr, nullptr, nullptr, nullptr };
|
|
};
|
|
WUT_CHECK_OFFSET(ControllerInfo, 0x00, vpad);
|
|
WUT_CHECK_OFFSET(ControllerInfo, 0x04, kpad);
|
|
WUT_CHECK_SIZE(ControllerInfo, 0x14);
|
|
|
|
struct DrawStringInfo
|
|
{
|
|
DrawStringInfo()
|
|
{
|
|
memset(this, 0, sizeof(*this));
|
|
}
|
|
|
|
WUT_UNKNOWN_BYTES(0x1C);
|
|
};
|
|
WUT_CHECK_SIZE(DrawStringInfo, 0x1C);
|
|
|
|
struct KeyboardCondition
|
|
{
|
|
//! Selected Language
|
|
uint32_t unk_0x00 = 0;
|
|
//! Selected Character menu
|
|
uint32_t unk_0x04 = 0;
|
|
};
|
|
WUT_CHECK_OFFSET(KeyboardCondition, 0x00, unk_0x00);
|
|
WUT_CHECK_OFFSET(KeyboardCondition, 0x04, unk_0x04);
|
|
WUT_CHECK_SIZE(KeyboardCondition, 0x8);
|
|
|
|
struct IEventReceiver;
|
|
struct IControllerEventObj;
|
|
struct ISoundObj;
|
|
|
|
/**
|
|
* Show an input form (keyboard with text area) with the given configuration.
|
|
*
|
|
* \param args
|
|
* An \link nn::swkbd::AppearArg AppearArg \endlink struct with the desired
|
|
* configuration for the keyboard and input form.
|
|
*
|
|
* \return
|
|
* \c true on success, or \c false on error.
|
|
*
|
|
* \sa
|
|
* - \link DisappearInputForm \endlink
|
|
* - \link GetInputFormString \endlink
|
|
* - \link IsDecideOkButton \endlink
|
|
* - \link IsDecideCancelButton \endlink
|
|
*/
|
|
bool
|
|
AppearInputForm(const AppearArg& args);
|
|
|
|
/**
|
|
* Show a keyboard with the given configuration.
|
|
*
|
|
* \param args
|
|
* An \link nn::swkbd::KeyboardArg KeyboardArg \endlink struct with the desired
|
|
* configuration for the keyboard.
|
|
*
|
|
* \return
|
|
* \c true on success, or \c false on error.
|
|
*
|
|
* \sa
|
|
* - \link DisappearKeyboard \endlink
|
|
* - \link IsDecideOkButton \endlink
|
|
* - \link IsDecideCancelButton \endlink
|
|
*/
|
|
bool
|
|
AppearKeyboard(const KeyboardArg& args);
|
|
|
|
/**
|
|
* Calculate font data. Call in response to
|
|
* \link IsNeedCalcSubThreadFont \endlink.
|
|
*
|
|
* \sa
|
|
* - \link CalcSubThreadPredict \endlink
|
|
* - \link Calc \endlink
|
|
*/
|
|
void
|
|
CalcSubThreadFont();
|
|
|
|
/**
|
|
* Calculate word prediction data. Call in response to
|
|
* \link IsNeedCalcSubThreadPredict \endlink.
|
|
*
|
|
* \sa
|
|
* - \link CalcSubThreadFont \endlink
|
|
* - \link Calc \endlink
|
|
*/
|
|
void
|
|
CalcSubThreadPredict();
|
|
|
|
/**
|
|
* Respond to user inputs and calculate the state of input buffers and graphics.
|
|
*
|
|
* \param controllerInfo
|
|
* A \link nn::swkbd::ControllerInfo ControllerInfo \endlink structure
|
|
* containing fresh data from the controllers (see \link VPADRead \endlink
|
|
* and \link KPADRead \endlink). Each controller can also be \c nullptr if data
|
|
* is not available.
|
|
*
|
|
* \sa
|
|
* - \link CalcSubThreadFont \endlink
|
|
* - \link CalcSubThreadPredict \endlink
|
|
*/
|
|
void
|
|
Calc(const ControllerInfo &controllerInfo);
|
|
|
|
void
|
|
ConfirmUnfixAll();
|
|
|
|
/**
|
|
* Initialise the swkbd library and create the keyboard and input form.
|
|
*
|
|
* \param args
|
|
* A \link nn::swkbd::CreateArg CreateArg \endlink structure containing the
|
|
* desired keyboard region, a pointer to work memory, and an
|
|
* \link FSClient \endlink. See \link nn::swkbd::CreateArg CreateArg\endlink.
|
|
*
|
|
* \return
|
|
* \c true on success, \c false otherwise.
|
|
*
|
|
* \sa
|
|
* - \link Destroy \endlink
|
|
* - \link GetWorkMemorySize \endlink
|
|
*/
|
|
bool
|
|
Create(const CreateArg &args);
|
|
|
|
/**
|
|
* Clean up and shut down the swkbd library.
|
|
*
|
|
* \note
|
|
* Resources passed into \link Create \endlink (work memory, filesystem client)
|
|
* must be manually freed by the application <em>after</em> calling this
|
|
* function.
|
|
*
|
|
* \sa
|
|
* - \link Create \endlink
|
|
*/
|
|
void
|
|
Destroy();
|
|
|
|
/**
|
|
* Hide a previously shown input form.
|
|
*
|
|
* \return
|
|
* \c true on success, \c false otherwise.
|
|
*
|
|
* \sa
|
|
* - \link AppearInputForm \endlink
|
|
* - \link GetInputFormString \endlink
|
|
*/
|
|
bool
|
|
DisappearInputForm();
|
|
|
|
/**
|
|
* Hide a previously shown keyboard.
|
|
*
|
|
* \return
|
|
* \c true on success, \c false otherwise.
|
|
*
|
|
* \sa
|
|
* - \link AppearKeyboard \endlink
|
|
*/
|
|
bool
|
|
DisappearKeyboard();
|
|
|
|
/**
|
|
* Draw the keyboard to the DRC. Must be called inside a valid GX2 rendering
|
|
* context, after rendering all other DRC graphics (to appear under the
|
|
* keyboard)
|
|
*/
|
|
void
|
|
DrawDRC();
|
|
|
|
/**
|
|
* Draw the keyboard to the TV. Must be called inside a valid GX2 rendering
|
|
* context, after rendering all other TV graphics (to appear under the
|
|
* keyboard)
|
|
*/
|
|
void
|
|
DrawTV();
|
|
|
|
void
|
|
GetDrawStringInfo(DrawStringInfo *drawStringInfo);
|
|
|
|
/**
|
|
* Get the string the user typed into the input form.
|
|
*
|
|
* \returns
|
|
* The user's text, as a null-terminated UTF-16 string.
|
|
*
|
|
* \sa
|
|
* - \link SetInputFormString \endlink
|
|
*/
|
|
const char16_t *
|
|
GetInputFormString();
|
|
|
|
void
|
|
GetKeyboardCondition(KeyboardCondition *keyboardCondition);
|
|
|
|
/**
|
|
* Get the current state of the input form.
|
|
*
|
|
* \returns
|
|
* The current \link nn::swkbd::State State \endlink of the input form.
|
|
*/
|
|
State
|
|
GetStateInputForm();
|
|
|
|
State
|
|
GetStateKeyboard();
|
|
|
|
/**
|
|
* Get the required size for swkbd's work memory buffer. The application must
|
|
* allocate a buffer of this size and pass it into \link Create \endlink.
|
|
*
|
|
* \param unk
|
|
* Unknown. A value of 0 seems to work.
|
|
*
|
|
* \return
|
|
* The required size of the work buffer, in bytes.
|
|
*
|
|
* \sa
|
|
* - \link Create \endlink
|
|
*/
|
|
uint32_t
|
|
GetWorkMemorySize(uint32_t unk);
|
|
|
|
void
|
|
InactivateSelectCursor();
|
|
|
|
bool
|
|
InitLearnDic(void *dictionary);
|
|
|
|
bool
|
|
IsCoveredWithSubWindow();
|
|
|
|
/**
|
|
* Gets the current status of the Cancel button on the keyboard.
|
|
*
|
|
* \param outIsSelected
|
|
* Pointer to a boolean to write the button status to, or \c nullptr if the
|
|
* return value is enough.
|
|
*
|
|
* \return
|
|
* \c true if the Cancel button has been pressed, or \c false otherwise.
|
|
*
|
|
* \sa
|
|
* - \link IsDecideOkButton \endlink
|
|
*/
|
|
bool
|
|
IsDecideCancelButton(bool *outIsSelected);
|
|
|
|
/**
|
|
* Gets the current status of the OK button on the keyboard.
|
|
*
|
|
* \param outIsSelected
|
|
* Pointer to a boolean to write the button status to, or \c nullptr if the
|
|
* return value is enough.
|
|
*
|
|
* \return
|
|
* \c true if the OK button has been pressed, or \c false otherwise.
|
|
*
|
|
* \sa
|
|
* - \link IsDecideCancelButton \endlink
|
|
*/
|
|
bool
|
|
IsDecideOkButton(bool *outIsSelected);
|
|
|
|
bool
|
|
IsKeyboardTarget(IEventReceiver *eventReceiver);
|
|
|
|
/**
|
|
* Determines whether the font data needs calculating. If it does, a call to
|
|
* \link CalcSubThreadFont \endlink is required.
|
|
*
|
|
* \return
|
|
* \c true if the font data needs calculating, \c false otherwise.
|
|
*
|
|
* \sa
|
|
* - \link IsNeedCalcSubThreadPredict \endlink
|
|
*/
|
|
bool
|
|
IsNeedCalcSubThreadFont();
|
|
|
|
/**
|
|
* Determines whether the prediction data needs calculating. If it does, a call
|
|
* to \link CalcSubThreadPredict \endlink is required.
|
|
*
|
|
* \return
|
|
* \c true if the prediction data needs calculating, \c false otherwise.
|
|
*
|
|
* \sa
|
|
* - \link IsNeedCalcSubThreadFont \endlink
|
|
*/
|
|
bool
|
|
IsNeedCalcSubThreadPredict();
|
|
|
|
/**
|
|
* Determines whether the selection cursor is active.
|
|
*
|
|
* \return
|
|
* \c true if the selection cursor is active, \c false otherwise.
|
|
*/
|
|
bool
|
|
IsSelectCursorActive();
|
|
|
|
/**
|
|
* Mutes or unmutes the sounds generated by the keyboard.
|
|
* Must be called inside a valid AX sound context, after AXInit and before AXQuit.
|
|
*
|
|
* \param muted
|
|
* \c true to disable all sounds, or \c false to enable them.
|
|
*/
|
|
void
|
|
MuteAllSound(bool muted);
|
|
|
|
void
|
|
SetControllerRemo(ControllerType type);
|
|
|
|
/**
|
|
* Set the character at which the cursor is positioned.
|
|
*
|
|
* \param pos
|
|
* The position at which to move the cursor, with 0 corresponding to the start
|
|
* of the string (before the first character).
|
|
*
|
|
* <!--
|
|
* TODO: check factual accuracy?
|
|
* Does one need to account for multiword UTF-16 characters?
|
|
* -->
|
|
*/
|
|
void
|
|
SetCursorPos(int pos);
|
|
|
|
/**
|
|
* Enables and disables the OK button on the keyboard. When disabled, the button
|
|
* cannot be pressed.
|
|
*
|
|
* \param enable
|
|
* \c true to enable the button, or \c false to disable it.
|
|
*/
|
|
void
|
|
SetEnableOkButton(bool enable);
|
|
|
|
/**
|
|
* Sets the text in the input form.
|
|
*
|
|
* \param str
|
|
* The UTF-16 string to set the input form to.
|
|
*
|
|
* \sa
|
|
* - \link GetInputFormString \endlink
|
|
*/
|
|
void
|
|
SetInputFormString(const char16_t *str);
|
|
|
|
void
|
|
SetReceiver(const ReceiverArg &receiver);
|
|
|
|
void
|
|
SetSelectFrom(int);
|
|
|
|
void
|
|
SetUserControllerEventObj(IControllerEventObj *controllerEventObj);
|
|
|
|
void
|
|
SetUserSoundObj(ISoundObj *soundObj);
|
|
|
|
} // namespace swkbd
|
|
} // namespace nn
|
|
|
|
#endif // ifdef __cplusplus
|
|
|
|
/** @} */
|