Skip to content

Conversation

dkosmari
Copy link

@dkosmari dkosmari commented May 22, 2025

Description

This adds support for the built-in software keyboard API.

By default, the application will get a working swkbd when calling SDL_StartTextInput(), with reasonable defaults.

Platform-specific functions were added to SDL_system.h:

  • SDL_WiiUSetSWKBDEnabled(): allow the application to disable the swkbd. This can be called before initializing the video driver, which changes SDL's behavior (it will call SDL_StartTextInput() during driver initialization, so the application ALWAYS receives text input events from the USB keyboard.) It can be called at any point later too, to disable or re-enable the swkbd. Disabling it will free up all memory allocated by the swkbd backend.

  • SDL_WiiUSetSWKBDCreateArg() and SDL_WiiUSetSWKBDAppearArg() allow the application to directly control the CreateArg and AppearArg arguments to customize the swkbd. When either is set to NULL, SDL will use its own internal CreateArg and AppearArg objects, providing the customization functions below.

  • SDL_WiiUSetSWKBDLocale(): allows the application to override the swkbd region/language. By default, the system region/language (from the system settings) will be used. The argument is a unix-style locale string ("en", "en_US", "ja", "en_GB", "ja_JP" etc).

Customization functions:

  • SDL_WiiUSetSWKBDHighlightInitialText()
  • SDL_WiiUSetSWKBDHintText()
  • SDL_WiiUSetSWKBDInitialText()
  • SDL_WiiUSetSWKBDKeyboardMode()
  • SDL_WiiUSetSWKBDOKLabel()
  • SDL_WiiUSetSWKBDPasswordMode()
  • SDL_WiiUSetSWKBDShowCopyPasteButtons()
  • SDL_WiiUSetSWKBDShowWordSuggestions()

These set the various fields of the internal AppearArg object. They're reset to their default values (documented in SDL_system.h) after the swkbd is shown.

I'm open to suggestions, about changing this behavior, so all customization persists between keyboard appearances.

Manual input:

  • SDL_WiiUSetSWKBDVPAD()
  • SDL_WiiUSetSWKBDKPAD()

This is necessary when the application is not using the SDL joystick/gamecontroller subsystem, and calling VPADRead() or KPADRead() directly.

New events

There are optional SDL_SYSWMEVENT messages generated by the swkbd when it closes. The event.syswm.msg->wiiu.event field will be one of:

  • SDL_WIIU_SYSWM_SWKBD_OK_START_EVENT: sent when the "OK" button is pressed, before any text input event.
  • SDL_WIIU_SYSWM_SWKBD_OK_FINISH_EVENT: sent after all text input events (corresponding to the swkbd's text) are sent.
  • SDL_WIIU_SYSWM_SWKBD_CANCEL_EVENT: sent when the "Cancel" button is pressed.

To receive any SDL_SYSWMEVENT the application needs to call:

SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);

Justification: we cannot distinguish whether the text input event is coming from a hardware keyboard or the software keyboard. In a typical UI, hwkbd input will be inserted/deleted/replaced using a "current cursor position." But the swkbd has its own input form, with its own cursor and text selection handling; it produces the final string the UI text input widget should contain.

That means a text input event should either:

  • hwkbd: insert the new text input event at the UI cursor position.
  • swkbd: clear the text in the UI, and start appending all text input events.

I do not know how to distinguish between both cases, on the application/UI code, other than making wild assumptions about the timing of the events. This more of a SDL design limitation, because the drag/drop events do have a begin/complete delimiters, to help combining multiple related events.

Limitations

This makes SDL depend on libstdc++, since the nn::swkbd is a C++-only API. This dependency can be dropped when WUT gets a C API for nn::swkbd.
It no longer depends on libstdc++, as of 64ad1d7.

Daniel K. O. (dkosmari) added 7 commits April 6, 2025 10:48
- No more replacement of global new/delete operators; use strings with custom allocators
  instead.
- Don't rely on C locale API, let the user control the locale explicitly.
- A few more customization functions.
- Properly documented all functions.
- Added enums.
- Input feeding from VPAD and KPAD is now public.
- Added function to manually disable the swkbd.
- Added missing include `<new>`.
- Don't copy the user-supplied `nn::swkbd::AppearArg`.
@dkosmari
Copy link
Author

Here's a sample program using this PR: https://github.com/dkosmari/devkitpro-autoconf/tree/main/examples/wiiu/sdl2-swkbd

Here's an imgui fork using this PR: https://github.com/dkosmari/imgui

@dkosmari dkosmari changed the title Add support for swkbd. Wii U: Add support for swkbd. May 23, 2025
@dkosmari
Copy link
Author

Now it no longer depends on libstdc++.

@gradylink
Copy link

Any plan to merge this soon.

Copy link

@GaryOderNichts GaryOderNichts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. Can you rename SDL_wiiu_swkbd.cpp to SDL_wiiuswkbd.cpp to match the other files?


if (WIIU_SWKBD_IsScreenKeyboardShown(NULL, renderer->window)) {
GX2SetContextState(NULL);
#ifdef WIIU_FIX_SWKBD_GAMMA

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm really not a fan of this workaround. I wonder if there's some option that needs to be set in swkbd for this to behave correctly. I'll take a look once I have some spare time.

Comment on lines +636 to +670
/**
* Sets a `nn::swkbd::CreateArg` object that will be used to create the swkbd.
*
* You don't need to set `arg->fsClient` nor `arg->workMemory`, these will be
* allocated if they are `NULL`, when the swkbd is first shown.
*
* \param arg Pointer to a persistent `nn::swkbd::CreateArg` object, or `NULL` to use the
* default.
*
* \note
* The swkbd will be re-initialized after calling this function.
*/
extern DECLSPEC void SDLCALL SDL_WiiUSetSWKBDCreateArg(void * arg);

/**
* Sets a `nn::swkbd::AppearArg` object that will be used every time the swkbd is shown.
* You don't have to call this function again if you update the argument's content.
*
* \param arg Pointer to a persistent `nn::swkbd::AppearArg` object, or `NULL` to use the
* default.
*
* \note
* When a `nn::swkbd::AppearArg` argument is used, all related customization options
* are ignored.
*
* \sa SDL_WiiUSetSWKBDHighlightInitialText
* \sa SDL_WiiUSetSWKBDHintText
* \sa SDL_WiiUSetSWKBDInitialText
* \sa SDL_WiiUSetSWKBDKeyboardMode
* \sa SDL_WiiUSetSWKBDOKLabel
* \sa SDL_WiiUSetSWKBDPasswordMode
* \sa SDL_WiiUSetSWKBDShowCopyPasteButtons
* \sa SDL_WiiUSetSWKBDShowWordSuggestions
*/
extern DECLSPEC void SDLCALL SDL_WiiUSetSWKBDAppearArg(const void * arg);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this really be exposed? I'd prefer just having the helper functions below.

Comment on lines +681 to +688

/*
* Local Variables:
* indent-tabs-mode: t
* tab-width: 8
* c-basic-offset: 8
* End:
*/

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove these emacs variables from the files you didn't create?

Comment on lines +172 to +173
// TODO: control disabled inputs, needs to fix nn::swkbd::ConfigArg
// input form options

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you PR this fix to wut?

detail::create::created = true;
}

__attribute__((__destructor__)) void WIIU_SWKBD_Finalize(void)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer calling this in WIIU_VideoQuit instead of using __attribute__((__destructor__)).

arg.keyboardArg.configArg.languageType = detail::get_language_from_system();

// set keyboard layout according to language
// TODO: fix wut: it's the unk_0x10 field

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you PR this to wut?

@gradylink
Copy link

Thanks for the PR. Can you rename SDL_wiiu_swkbd.cpp to SDL_wiiuswkbd.cpp to match the other files?

Shouldn't it be SDL_wiiuswkb.cpp (without the d) to match Switch and 3DS?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants