Added SDL_StartTextInputWithProperties()

This allows you to customize the text input so you can have numeric text entry, hidden passwords, etc.

Fixes https://github.com/libsdl-org/SDL/issues/7101
Fixes https://github.com/libsdl-org/SDL/issues/7965
Fixes https://github.com/libsdl-org/SDL/issues/9439
This commit is contained in:
Sam Lantinga 2024-08-02 06:56:51 -07:00
parent 5d51e3b4ab
commit 81f8e6aba6
36 changed files with 737 additions and 76 deletions

View File

@ -185,6 +185,7 @@
F3C17D3928E424B800E1A26D /* sample.wav in Resources */ = {isa = PBXBuildFile; fileRef = 00794E6209D20839003FC8A1 /* sample.wav */; };
F3C17D3B28E4252900E1A26D /* icon.bmp in Resources */ = {isa = PBXBuildFile; fileRef = 00794E5D09D20839003FC8A1 /* icon.bmp */; };
F3C2CAC62C5C8BD6004D7998 /* unifont-15.1.05.hex in Resources */ = {isa = PBXBuildFile; fileRef = F3C2CAC52C5C8BD6004D7998 /* unifont-15.1.05.hex */; };
F3C2CB072C5D3FB2004D7998 /* icon.bmp in Resources */ = {isa = PBXBuildFile; fileRef = 00794E5D09D20839003FC8A1 /* icon.bmp */; };
F3CB56892A7895F800766177 /* SDL3.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 003FA643093FFD41000C53B3 /* SDL3.framework */; };
F3CB568A2A7895F800766177 /* SDL3.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 003FA643093FFD41000C53B3 /* SDL3.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
F3CB568C2A7896BF00766177 /* SDL3.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 003FA643093FFD41000C53B3 /* SDL3.framework */; };
@ -3026,6 +3027,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F3C2CB072C5D3FB2004D7998 /* icon.bmp in Resources */,
F3C2CAC62C5C8BD6004D7998 /* unifont-15.1.05.hex in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -1375,9 +1375,11 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
*/
static final int HEIGHT_PADDING = 15;
public int input_type;
public int x, y, w, h;
public ShowTextInputTask(int x, int y, int w, int h) {
public ShowTextInputTask(int input_type, int x, int y, int w, int h) {
this.input_type = input_type;
this.x = x;
this.y = y;
this.w = w;
@ -1405,6 +1407,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
} else {
mTextEdit.setLayoutParams(params);
}
mTextEdit.setInputType(input_type);
mTextEdit.setVisibility(View.VISIBLE);
mTextEdit.requestFocus();
@ -1419,9 +1422,9 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
/**
* This method is called by SDL using JNI.
*/
public static boolean showTextInput(int x, int y, int w, int h) {
public static boolean showTextInput(int input_type, int x, int y, int w, int h) {
// Transfer the task to the main thread as a Runnable
return mSingleton.commandHandler.post(new ShowTextInputTask(x, y, w, h));
return mSingleton.commandHandler.post(new ShowTextInputTask(input_type, x, y, w, h));
}
public static boolean isTextInputEvent(KeyEvent event) {

View File

@ -12,6 +12,7 @@ import android.view.inputmethod.InputConnection;
public class SDLDummyEdit extends View implements View.OnKeyListener
{
InputConnection ic;
int input_type;
public SDLDummyEdit(Context context) {
super(context);
@ -20,6 +21,10 @@ public class SDLDummyEdit extends View implements View.OnKeyListener
setOnKeyListener(this);
}
public void setInputType(int input_type) {
this.input_type = input_type;
}
@Override
public boolean onCheckIsTextEditor() {
return true;
@ -51,8 +56,7 @@ public class SDLDummyEdit extends View implements View.OnKeyListener
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
ic = new SDLInputConnection(this, true);
outAttrs.inputType = InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_FLAG_MULTI_LINE;
outAttrs.inputType = input_type;
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI |
EditorInfo.IME_FLAG_NO_FULLSCREEN /* API 11 */;

View File

@ -2620,6 +2620,8 @@ extern "C" {
* A variable to control whether the return key on the soft keyboard should
* hide the soft keyboard on Android and iOS.
*
* This hint sets the default value of SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN.
*
* The variable can be set to the following values:
*
* - "0": The return key will be handled as a key event. (default)

View File

@ -367,11 +367,93 @@ extern SDL_DECLSPEC SDL_Keycode SDLCALL SDL_GetKeyFromName(const char *name);
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_SetTextInputArea
* \sa SDL_StartTextInputWithProperties
* \sa SDL_StopTextInput
* \sa SDL_TextInputActive
*/
extern SDL_DECLSPEC int SDLCALL SDL_StartTextInput(SDL_Window *window);
/**
* Text input type.
*
* These are the valid values for SDL_PROP_TEXTINPUT_TYPE_NUMBER. Not every value is valid on every platform, but where a value isn't supported, a reasonable fallback will be used.
*
* \since This enum is available since SDL 3.0.0.
*
* \sa SDL_StartTextInputWithProperties
*/
typedef enum SDL_TextInputType
{
SDL_TEXTINPUT_TYPE_TEXT, /**< The input is text */
SDL_TEXTINPUT_TYPE_TEXT_NAME, /**< The input is a person's name */
SDL_TEXTINPUT_TYPE_TEXT_EMAIL, /**< The input is an e-mail address */
SDL_TEXTINPUT_TYPE_TEXT_USERNAME, /**< The input is a username */
SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN, /**< The input is a secure password that is hidden */
SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE, /**< The input is a secure password that is visible */
SDL_TEXTINPUT_TYPE_NUMBER, /**< The input is a number */
SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN, /**< The input is a secure PIN that is hidden */
SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE /**< The input is a secure PIN that is visible */
} SDL_TextInputType;
/**
* Auto capitalization type.
*
* These are the valid values for SDL_PROP_TEXTINPUT_AUTOCAPITALIZATION_NUMBER. Not every value is valid on every platform, but where a value isn't supported, a reasonable fallback will be used.
*
* \since This enum is available since SDL 3.0.0.
*
* \sa SDL_StartTextInputWithProperties
*/
typedef enum SDL_Capitalization
{
SDL_CAPITALIZE_NONE, /**< No auto-capitalization will be done */
SDL_CAPITALIZE_SENTENCES, /**< The first letter of sentences will be capitalized */
SDL_CAPITALIZE_WORDS, /**< The first letter of words will be capitalized */
SDL_CAPITALIZE_LETTERS /**< All letters will be capitalized */
} SDL_Capitalization;
/**
* Start accepting Unicode text input events in a window, with properties describing the input.
*
* This function will enable text input (SDL_EVENT_TEXT_INPUT and
* SDL_EVENT_TEXT_EDITING events) in the specified window. Please use this
* function paired with SDL_StopTextInput().
*
* Text input events are not received by default.
*
* On some platforms using this function shows the screen keyboard.
*
* These are the supported properties:
*
* - `SDL_PROP_TEXTINPUT_TYPE_NUMBER` - an SDL_TextInputType value that describes text being input, defaults to SDL_TEXTINPUT_TYPE_TEXT.
* - `SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER` - an SDL_Capitalization value that describes how text should be capitalized, defaults to SDL_CAPITALIZE_NONE.
* - `SDL_PROP_TEXTINPUT_AUTOCORRECT_BOOLEAN` - true to enable auto completion and auto correction.
* - `SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN` - true if multiple lines of text are allowed. This defaults to true if SDL_HINT_RETURN_KEY_HIDES_IME is "0" or is not set, and defaults to false if SDL_HINT_RETURN_KEY_HIDES_IME is "1".
*
* On Android you can directly specify the input type:
*
* - `SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER` - the text input type to use, overriding other properties. This is documented at https://developer.android.com/reference/android/text/InputType
*
* \param window the window to enable text input.
* \param props the properties to use.
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_SetTextInputArea
* \sa SDL_StartTextInput
* \sa SDL_StopTextInput
* \sa SDL_TextInputActive
*/
extern SDL_DECLSPEC int SDLCALL SDL_StartTextInputWithProperties(SDL_Window *window, SDL_PropertiesID props);
#define SDL_PROP_TEXTINPUT_TYPE_NUMBER "SDL.textinput.type"
#define SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER "SDL.textinput.capitalization"
#define SDL_PROP_TEXTINPUT_AUTOCORRECT_BOOLEAN "SDL.textinput.autocorrect"
#define SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN "SDL.textinput.multiline"
#define SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER "SDL.textinput.android.inputtype"
/**
* Check whether or not Unicode text input events are enabled for a window.
*

View File

@ -645,7 +645,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
midSetSystemCursor = (*env)->GetStaticMethodID(env, mActivityClass, "setSystemCursor", "(I)Z");
midSetWindowStyle = (*env)->GetStaticMethodID(env, mActivityClass, "setWindowStyle", "(Z)V");
midShouldMinimizeOnFocusLoss = (*env)->GetStaticMethodID(env, mActivityClass, "shouldMinimizeOnFocusLoss", "()Z");
midShowTextInput = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIII)Z");
midShowTextInput = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIIII)Z");
midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
midOpenFileDescriptor = (*env)->GetStaticMethodID(env, mActivityClass, "openFileDescriptor", "(Ljava/lang/String;Ljava/lang/String;)I");
midShowFileDialog = (*env)->GetStaticMethodID(env, mActivityClass, "showFileDialog", "([Ljava/lang/String;ZZI)Z");
@ -2044,10 +2044,11 @@ int Android_JNI_SuspendScreenSaver(SDL_bool suspend)
return Android_JNI_SendMessage(COMMAND_SET_KEEP_SCREEN_ON, (suspend == SDL_FALSE) ? 0 : 1);
}
void Android_JNI_ShowScreenKeyboard(SDL_Rect *inputRect)
void Android_JNI_ShowScreenKeyboard(int input_type, SDL_Rect *inputRect)
{
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticBooleanMethod(env, mActivityClass, midShowTextInput,
input_type,
inputRect->x,
inputRect->y,
inputRect->w,

View File

@ -63,7 +63,7 @@ extern void Android_JNI_MinizeWindow(void);
extern SDL_bool Android_JNI_ShouldMinimizeOnFocusLoss(void);
extern SDL_bool Android_JNI_GetAccelerometerValues(float values[3]);
extern void Android_JNI_ShowScreenKeyboard(SDL_Rect *inputRect);
extern void Android_JNI_ShowScreenKeyboard(int input_type, SDL_Rect *inputRect);
extern void Android_JNI_HideScreenKeyboard(void);
extern SDL_bool Android_JNI_IsScreenKeyboardShown(void);
extern ANativeWindow *Android_JNI_GetNativeWindow(void);

View File

@ -816,6 +816,7 @@ SDL3_0.0.0 {
SDL_SignalCondition;
SDL_SignalSemaphore;
SDL_StartTextInput;
SDL_StartTextInputWithProperties;
SDL_StepUTF8;
SDL_StopHapticEffect;
SDL_StopHapticEffects;

View File

@ -841,6 +841,7 @@
#define SDL_SignalCondition SDL_SignalCondition_REAL
#define SDL_SignalSemaphore SDL_SignalSemaphore_REAL
#define SDL_StartTextInput SDL_StartTextInput_REAL
#define SDL_StartTextInputWithProperties SDL_StartTextInputWithProperties_REAL
#define SDL_StepUTF8 SDL_StepUTF8_REAL
#define SDL_StopHapticEffect SDL_StopHapticEffect_REAL
#define SDL_StopHapticEffects SDL_StopHapticEffects_REAL

View File

@ -851,6 +851,7 @@ SDL_DYNAPI_PROC(int,SDL_ShowWindowSystemMenu,(SDL_Window *a, int b, int c),(a,b,
SDL_DYNAPI_PROC(int,SDL_SignalCondition,(SDL_Condition *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SignalSemaphore,(SDL_Semaphore *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_StartTextInput,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_StartTextInputWithProperties,(SDL_Window *a, SDL_PropertiesID b),(a,b),return)
SDL_DYNAPI_PROC(Uint32,SDL_StepUTF8,(const char **a, size_t *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_StopHapticEffect,(SDL_Haptic *a, int b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_StopHapticEffects,(SDL_Haptic *a),(a),return)

View File

@ -327,7 +327,7 @@ int SDL_SetKeyboardFocus(SDL_Window *window)
if (SDL_TextInputActive(keyboard->focus)) {
if (video && video->StartTextInput) {
video->StartTextInput(video, keyboard->focus);
video->StartTextInput(video, keyboard->focus, keyboard->focus->text_input_props);
}
}
}

View File

@ -106,6 +106,7 @@ struct SDL_Window
int safe_inset_bottom;
SDL_Rect safe_rect;
SDL_PropertiesID text_input_props;
SDL_bool text_input_active;
SDL_Rect text_input_rect;
int text_input_cursor;
@ -331,14 +332,14 @@ struct SDL_VideoDevice
int (*SuspendScreenSaver)(SDL_VideoDevice *_this);
/* Text input */
int (*StartTextInput)(SDL_VideoDevice *_this, SDL_Window *window);
int (*StartTextInput)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
int (*StopTextInput)(SDL_VideoDevice *_this, SDL_Window *window);
int (*UpdateTextInputArea)(SDL_VideoDevice *_this, SDL_Window *window);
int (*ClearComposition)(SDL_VideoDevice *_this, SDL_Window *window);
/* Screen keyboard */
SDL_bool (*HasScreenKeyboardSupport)(SDL_VideoDevice *_this);
void (*ShowScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window);
void (*ShowScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
void (*HideScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window);
SDL_bool (*IsScreenKeyboardShown)(SDL_VideoDevice *_this, SDL_Window *window);
@ -565,4 +566,9 @@ extern SDL_bool SDL_ShouldAllowTopmost(void);
extern void SDL_ToggleDragAndDropSupport(void);
extern SDL_TextInputType SDL_GetTextInputType(SDL_PropertiesID props);
extern SDL_Capitalization SDL_GetTextInputCapitalization(SDL_PropertiesID props);
extern SDL_bool SDL_GetTextInputAutocorrect(SDL_PropertiesID props);
extern SDL_bool SDL_GetTextInputMultiline(SDL_PropertiesID props);
#endif /* SDL_sysvideo_h_ */

View File

@ -4011,6 +4011,7 @@ void SDL_DestroyWindow(SDL_Window *window)
SDL_HideWindow(window);
}
SDL_DestroyProperties(window->text_input_props);
SDL_DestroyProperties(window->props);
/* Clear the modal status, but don't unset the parent, as it may be
@ -5129,23 +5130,80 @@ void SDL_WM_SetIcon(SDL_Surface *icon, Uint8 *mask)
}
#endif
int SDL_StartTextInput(SDL_Window *window)
SDL_TextInputType SDL_GetTextInputType(SDL_PropertiesID props)
{
CHECK_WINDOW_MAGIC(window, -1);
return (SDL_TextInputType)SDL_GetNumberProperty(props, SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_TEXT);
}
/* Show the on-screen keyboard, if desired */
SDL_Capitalization SDL_GetTextInputCapitalization(SDL_PropertiesID props)
{
return (SDL_Capitalization)SDL_GetNumberProperty(props, SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER, SDL_CAPITALIZE_NONE);
}
SDL_bool SDL_GetTextInputAutocorrect(SDL_PropertiesID props)
{
return SDL_GetBooleanProperty(props, SDL_PROP_TEXTINPUT_AUTOCORRECT_BOOLEAN, SDL_FALSE);
}
SDL_bool SDL_GetTextInputMultiline(SDL_PropertiesID props)
{
if (SDL_HasProperty(props, SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN)) {
return SDL_GetBooleanProperty(props, SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN, SDL_FALSE);
}
if (SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, SDL_FALSE)) {
return SDL_FALSE;
} else {
return SDL_TRUE;
}
}
static SDL_bool AutoShowingScreenKeyboard(void)
{
const char *hint = SDL_GetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD);
if (((!hint || SDL_strcasecmp(hint, "auto") == 0) && !SDL_HasKeyboard()) ||
SDL_GetStringBoolean(hint, SDL_FALSE)) {
return SDL_TRUE;
} else {
return SDL_FALSE;
}
}
int SDL_StartTextInput(SDL_Window *window)
{
return SDL_StartTextInputWithProperties(window, 0);
}
int SDL_StartTextInputWithProperties(SDL_Window *window, SDL_PropertiesID props)
{
CHECK_WINDOW_MAGIC(window, -1);
if (window->text_input_props) {
SDL_DestroyProperties(window->text_input_props);
window->text_input_props = 0;
}
if (props) {
window->text_input_props = SDL_CreateProperties();
if (!window->text_input_props) {
return -1;
}
if (SDL_CopyProperties(props, window->text_input_props) < 0) {
return -1;
}
}
/* Show the on-screen keyboard, if desired */
if (AutoShowingScreenKeyboard() && !SDL_ScreenKeyboardShown(window)) {
if (_this->ShowScreenKeyboard) {
_this->ShowScreenKeyboard(_this, window);
_this->ShowScreenKeyboard(_this, window, props);
}
}
if (!window->text_input_active) {
/* Finally start the text input system */
if (_this->StartTextInput) {
if (_this->StartTextInput(_this, window) < 0) {
if (_this->StartTextInput(_this, window, props) < 0) {
return -1;
}
}
@ -5174,9 +5232,7 @@ int SDL_StopTextInput(SDL_Window *window)
}
/* Hide the on-screen keyboard, if desired */
const char *hint = SDL_GetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD);
if (((!hint || SDL_strcasecmp(hint, "auto") == 0) && !SDL_HasKeyboard()) ||
SDL_GetStringBoolean(hint, SDL_FALSE)) {
if (AutoShowingScreenKeyboard() && SDL_ScreenKeyboardShown(window)) {
if (_this->HideScreenKeyboard) {
_this->HideScreenKeyboard(_this, window);
}
@ -5239,7 +5295,9 @@ SDL_bool SDL_HasScreenKeyboardSupport(void)
SDL_bool SDL_ScreenKeyboardShown(SDL_Window *window)
{
if (window && _this && _this->IsScreenKeyboardShown) {
CHECK_WINDOW_MAGIC(window, SDL_FALSE);
if (_this->IsScreenKeyboardShown) {
return _this->IsScreenKeyboardShown(_this, window);
}
return SDL_FALSE;

View File

@ -30,6 +30,46 @@
#include "../../core/android/SDL_android.h"
#define TYPE_CLASS_TEXT 0x00000001
#define TYPE_CLASS_NUMBER 0x00000002
#define TYPE_CLASS_PHONE 0x00000003
#define TYPE_CLASS_DATETIME 0x00000004
#define TYPE_DATETIME_VARIATION_NORMAL 0x00000000
#define TYPE_DATETIME_VARIATION_DATE 0x00000010
#define TYPE_DATETIME_VARIATION_TIME 0x00000020
#define TYPE_NUMBER_VARIATION_NORMAL 0x00000000
#define TYPE_NUMBER_VARIATION_PASSWORD 0x00000010
#define TYPE_NUMBER_FLAG_SIGNED 0x00001000
#define TYPE_NUMBER_FLAG_DECIMAL 0x00002000
#define TYPE_TEXT_FLAG_CAP_CHARACTERS 0x00001000
#define TYPE_TEXT_FLAG_CAP_WORDS 0x00002000
#define TYPE_TEXT_FLAG_CAP_SENTENCES 0x00004000
#define TYPE_TEXT_FLAG_AUTO_CORRECT 0x00008000
#define TYPE_TEXT_FLAG_AUTO_COMPLETE 0x00010000
#define TYPE_TEXT_FLAG_MULTI_LINE 0x00020000
#define TYPE_TEXT_FLAG_IME_MULTI_LINE 0x00040000
#define TYPE_TEXT_FLAG_NO_SUGGESTIONS 0x00080000
#define TYPE_TEXT_VARIATION_NORMAL 0x00000000
#define TYPE_TEXT_VARIATION_URI 0x00000010
#define TYPE_TEXT_VARIATION_EMAIL_ADDRESS 0x00000020
#define TYPE_TEXT_VARIATION_EMAIL_SUBJECT 0x00000030
#define TYPE_TEXT_VARIATION_SHORT_MESSAGE 0x00000040
#define TYPE_TEXT_VARIATION_LONG_MESSAGE 0x00000050
#define TYPE_TEXT_VARIATION_PERSON_NAME 0x00000060
#define TYPE_TEXT_VARIATION_POSTAL_ADDRESS 0x00000070
#define TYPE_TEXT_VARIATION_PASSWORD 0x00000080
#define TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 0x00000090
#define TYPE_TEXT_VARIATION_WEB_EDIT_TEXT 0x000000a0
#define TYPE_TEXT_VARIATION_FILTER 0x000000b0
#define TYPE_TEXT_VARIATION_PHONETIC 0x000000c0
#define TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS 0x000000d0
#define TYPE_TEXT_VARIATION_WEB_PASSWORD 0x000000e0
static SDL_Scancode Android_Keycodes[] = {
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_UNKNOWN */
SDL_SCANCODE_SOFTLEFT, /* AKEYCODE_SOFT_LEFT */
@ -343,9 +383,67 @@ SDL_bool Android_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
return SDL_TRUE;
}
void Android_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
void Android_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
Android_JNI_ShowScreenKeyboard(&window->text_input_rect);
int input_type = 0;
if (SDL_HasProperty(props, SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER)) {
input_type = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER, 0);
} else {
switch (SDL_GetTextInputType(props)) {
default:
case SDL_TEXTINPUT_TYPE_TEXT:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_NORMAL);
break;
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PERSON_NAME);
break;
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
break;
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_NORMAL);
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
break;
case SDL_TEXTINPUT_TYPE_NUMBER:
input_type = (TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_NORMAL);
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
input_type = (TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_PASSWORD);
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
input_type = (TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_NORMAL);
break;
}
switch (SDL_GetTextInputCapitalization(props)) {
default:
case SDL_CAPITALIZE_NONE:
break;
case SDL_CAPITALIZE_LETTERS:
input_type |= TYPE_TEXT_FLAG_CAP_CHARACTERS;
break;
case SDL_CAPITALIZE_WORDS:
input_type |= TYPE_TEXT_FLAG_CAP_WORDS;
break;
case SDL_CAPITALIZE_SENTENCES:
input_type |= TYPE_TEXT_FLAG_CAP_SENTENCES;
break;
}
if (SDL_GetTextInputAutocorrect(props)) {
input_type |= (TYPE_TEXT_FLAG_AUTO_CORRECT | TYPE_TEXT_FLAG_AUTO_COMPLETE);
}
if (SDL_GetTextInputMultiline(props)) {
input_type |= TYPE_TEXT_FLAG_MULTI_LINE;
}
}
Android_JNI_ShowScreenKeyboard(input_type, &window->text_input_rect);
SDL_screen_keyboard_shown = SDL_TRUE;
}
@ -358,7 +456,7 @@ void Android_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
void Android_RestoreScreenKeyboardOnResume(SDL_VideoDevice *_this, SDL_Window *window)
{
if (SDL_screen_keyboard_shown) {
Android_ShowScreenKeyboard(_this, window);
Android_ShowScreenKeyboard(_this, window, window->text_input_props);
}
}

View File

@ -26,7 +26,7 @@ extern int Android_OnKeyDown(int keycode);
extern int Android_OnKeyUp(int keycode);
extern SDL_bool Android_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
extern void Android_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern void Android_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
extern void Android_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern void Android_RestoreScreenKeyboardOnResume(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_bool Android_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);

View File

@ -27,7 +27,7 @@ extern void Cocoa_InitKeyboard(SDL_VideoDevice *_this);
extern void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event);
extern void Cocoa_QuitKeyboard(SDL_VideoDevice *_this);
extern int Cocoa_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window);
extern int Cocoa_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
extern int Cocoa_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
extern int Cocoa_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);

View File

@ -381,7 +381,7 @@ void Cocoa_InitKeyboard(SDL_VideoDevice *_this)
SDL_ToggleModState(SDL_KMOD_CAPS, (data.modifierFlags & NSEventModifierFlagCapsLock) ? SDL_TRUE : SDL_FALSE);
}
int Cocoa_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window)
int Cocoa_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
@autoreleasepool {
NSView *parentView;

View File

@ -178,7 +178,7 @@ void GDK_EnsureHints(void)
}
}
int GDK_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window)
int GDK_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
/*
* Currently a stub, since all input is handled by the virtual keyboard,
@ -226,7 +226,7 @@ SDL_bool GDK_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
return SDL_TRUE;
}
void GDK_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
void GDK_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
/*
* There is XGameUiTextEntryOpen but it's only in online docs,
@ -253,6 +253,39 @@ void GDK_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
return;
}
XGameUiTextEntryInputScope scope;
switch (SDL_GetTextInputType(props)) {
default:
case SDL_TEXTINPUT_TYPE_TEXT:
scope = (XGameUiTextEntryInputScope)g_TextInputScope;
break;
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
scope = XGameUiTextEntryInputScope::Default;
break;
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
scope = XGameUiTextEntryInputScope::EmailSmtpAddress;
break;
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
scope = XGameUiTextEntryInputScope::Default;
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
scope = XGameUiTextEntryInputScope::Password;
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
scope = XGameUiTextEntryInputScope::Default;
break;
case SDL_TEXTINPUT_TYPE_NUMBER:
scope = XGameUiTextEntryInputScope::Number;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
// FIXME: Password or number scope?
scope = XGameUiTextEntryInputScope::Number;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
scope = XGameUiTextEntryInputScope::Number;
break;
}
g_TextBlock->queue = g_TextTaskQueue;
g_TextBlock->context = _this;
g_TextBlock->callback = GDK_InternalTextEntryCallback;
@ -261,7 +294,7 @@ void GDK_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
g_TitleText,
g_DescriptionText,
g_DefaultText,
(XGameUiTextEntryInputScope)g_TextInputScope,
scope,
(uint32_t)g_MaxTextLength))) {
SDL_free(g_TextBlock);
g_TextBlock = NULL;

View File

@ -32,13 +32,13 @@ extern "C" {
void GDK_EnsureHints(void);
int GDK_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window);
int GDK_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
int GDK_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
int GDK_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
int GDK_ClearComposition(SDL_VideoDevice *_this, SDL_Window *window);
SDL_bool GDK_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
void GDK_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
void GDK_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
void GDK_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
SDL_bool GDK_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);

View File

@ -50,7 +50,7 @@ SDL_bool N3DS_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
return SDL_TRUE;
}
int N3DS_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window)
int N3DS_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
char buffer[BUFFER_SIZE];
SwkbdButton button_pressed;

View File

@ -30,7 +30,7 @@ void N3DS_SwkbQuit();
SDL_bool N3DS_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
int N3DS_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window);
int N3DS_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
int N3DS_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
#endif /* SDL_n3dskeyboard_h_ */

View File

@ -249,7 +249,7 @@ SDL_bool PSP_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
return SDL_TRUE;
}
void PSP_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
void PSP_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
char list[0x20000] __attribute__((aligned(64))); // Needed for sceGuStart to work
int i;
@ -266,7 +266,36 @@ void PSP_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
data.language = PSP_UTILITY_OSK_LANGUAGE_DEFAULT;
data.lines = 1;
data.unk_24 = 1;
data.inputtype = PSP_UTILITY_OSK_INPUTTYPE_ALL;
switch (SDL_GetTextInputType(props)) {
default:
case SDL_TEXTINPUT_TYPE_TEXT:
data.inputtype = PSP_UTILITY_OSK_INPUTTYPE_ALL;
break;
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
data.inputtype = PSP_UTILITY_OSK_INPUTTYPE_ALL;
break;
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
data.inputtype = PSP_UTILITY_OSK_INPUTTYPE_ALL;
break;
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
data.inputtype = PSP_UTILITY_OSK_INPUTTYPE_ALL;
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
data.inputtype = PSP_UTILITY_OSK_INPUTTYPE_ALL;
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
data.inputtype = PSP_UTILITY_OSK_INPUTTYPE_ALL;
break;
case SDL_TEXTINPUT_TYPE_NUMBER:
data.inputtype = PSP_UTILITY_OSK_INPUTTYPE_LATIN_DIGIT;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
data.inputtype = PSP_UTILITY_OSK_INPUTTYPE_LATIN_DIGIT;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
data.inputtype = PSP_UTILITY_OSK_INPUTTYPE_LATIN_DIGIT;
break;
}
data.desc = NULL;
data.intext = NULL;
data.outtextlength = input_text_length;

View File

@ -74,7 +74,7 @@ int PSP_GL_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
/* PSP on screen keyboard */
SDL_bool PSP_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
void PSP_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
void PSP_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
void PSP_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
SDL_bool PSP_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);

View File

@ -88,7 +88,7 @@
#ifdef SDL_IPHONE_KEYBOARD
SDL_bool UIKit_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
void UIKit_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
void UIKit_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
void UIKit_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
SDL_bool UIKit_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
int UIKit_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);

View File

@ -278,15 +278,6 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
textField.text = obligateForBackspace;
committedText = textField.text;
/* set UITextInputTrait properties, mostly to defaults */
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.enablesReturnKeyAutomatically = NO;
textField.keyboardAppearance = UIKeyboardAppearanceDefault;
textField.keyboardType = UIKeyboardTypeDefault;
textField.returnKeyType = UIReturnKeyDefault;
textField.secureTextEntry = NO;
textField.hidden = YES;
keyboardVisible = NO;
@ -393,6 +384,103 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
object:nil];
}
- (void)setKeyboardProperties:(SDL_PropertiesID) props
{
textField.secureTextEntry = NO;
switch (SDL_GetTextInputType(props)) {
default:
case SDL_TEXTINPUT_TYPE_TEXT:
textField.keyboardType = UIKeyboardTypeDefault;
textField.textContentType = nil;
break;
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
textField.keyboardType = UIKeyboardTypeDefault;
textField.textContentType = UITextContentTypeName;
break;
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
textField.keyboardType = UIKeyboardTypeEmailAddress;
textField.textContentType = UITextContentTypeEmailAddress;
break;
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
textField.keyboardType = UIKeyboardTypeDefault;
if (@available(iOS 11.0, *)) {
textField.textContentType = UITextContentTypeUsername;
} else {
textField.textContentType = nil;
}
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
textField.keyboardType = UIKeyboardTypeDefault;
if (@available(iOS 11.0, *)) {
textField.textContentType = UITextContentTypePassword;
} else {
textField.textContentType = nil;
}
textField.secureTextEntry = YES;
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
textField.keyboardType = UIKeyboardTypeDefault;
if (@available(iOS 11.0, *)) {
textField.textContentType = UITextContentTypePassword;
} else {
textField.textContentType = nil;
}
break;
case SDL_TEXTINPUT_TYPE_NUMBER:
textField.keyboardType = UIKeyboardTypeNumberPad;
textField.textContentType = nil;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
textField.keyboardType = UIKeyboardTypeNumberPad;
if (@available(iOS 12.0, *)) {
textField.textContentType = UITextContentTypeOneTimeCode;
} else {
textField.textContentType = nil;
}
textField.secureTextEntry = YES;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
textField.keyboardType = UIKeyboardTypeNumberPad;
if (@available(iOS 12.0, *)) {
textField.textContentType = UITextContentTypeOneTimeCode;
} else {
textField.textContentType = nil;
}
break;
}
switch (SDL_GetTextInputCapitalization(props)) {
default:
case SDL_CAPITALIZE_NONE:
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
break;
case SDL_CAPITALIZE_LETTERS:
textField.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;
break;
case SDL_CAPITALIZE_WORDS:
textField.autocapitalizationType = UITextAutocapitalizationTypeWords;
break;
case SDL_CAPITALIZE_SENTENCES:
textField.autocapitalizationType = UITextAutocapitalizationTypeSentences;
break;
}
if (SDL_GetTextInputAutocorrect(props)) {
textField.autocorrectionType = UITextAutocorrectionTypeYes;
textField.spellCheckingType = UITextSpellCheckingTypeYes;
} else {
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.spellCheckingType = UITextSpellCheckingTypeNo;
}
if (SDL_GetTextInputMultiline(props)) {
textField.enablesReturnKeyAutomatically = YES;
} else {
textField.enablesReturnKeyAutomatically = NO;
}
}
/* reveal onscreen virtual keyboard */
- (void)showKeyboard
{
@ -596,10 +684,11 @@ SDL_bool UIKit_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
return SDL_TRUE;
}
void UIKit_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
void UIKit_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
@autoreleasepool {
SDL_uikitviewcontroller *vc = GetWindowViewController(window);
[vc setKeyboardProperties:props];
[vc showKeyboard];
}
}

View File

@ -411,7 +411,7 @@ void VITA_ImeEventHandler(void *arg, const SceImeEventData *e)
}
#endif
void VITA_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
void VITA_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
SDL_VideoData *videodata = _this->internal;
SceInt32 res;
@ -427,8 +427,46 @@ void VITA_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
param.supportedLanguages = SCE_IME_LANGUAGE_ENGLISH_US;
param.languagesForced = SCE_FALSE;
param.type = SCE_IME_TYPE_DEFAULT;
param.option = SCE_IME_OPTION_NO_ASSISTANCE;
switch (SDL_GetTextInputType(props)) {
default:
case SDL_TEXTINPUT_TYPE_TEXT:
param.type = SCE_IME_TYPE_DEFAULT;
break;
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
param.type = SCE_IME_TYPE_DEFAULT;
break;
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
param.type = SCE_IME_TYPE_MAIL;
break;
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
param.type = SCE_IME_TYPE_DEFAULT;
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
param.type = SCE_IME_TYPE_DEFAULT;
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
param.type = SCE_IME_TYPE_DEFAULT;
break;
case SDL_TEXTINPUT_TYPE_NUMBER:
param.type = SCE_IME_TYPE_NUMBER;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
param.type = SCE_IME_TYPE_NUMBER;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
param.type = SCE_IME_TYPE_NUMBER;
break;
}
param.option = 0;
if (SDL_GetTextInputCapitalization(props) != SDL_CAPITALIZE_SENTENCES) {
param.option |= SCE_IME_OPTION_NO_AUTO_CAPITALIZATION;
}
if (!SDL_GetTextInputAutocorrect(props)) {
param.option |= SCE_IME_OPTION_NO_ASSISTANCE;
}
if (SDL_GetTextInputMultiline(props)) {
param.option |= SCE_IME_OPTION_MULTILINE;
}
param.inputTextBuffer = libime_out;
param.maxTextLength = SCE_IME_MAX_TEXT_LENGTH;
param.handler = VITA_ImeEventHandler;

View File

@ -97,7 +97,7 @@ int VITA_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
/* VITA on screen keyboard */
SDL_bool VITA_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
void VITA_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
void VITA_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
void VITA_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
SDL_bool VITA_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);

View File

@ -51,7 +51,7 @@ void Wayland_QuitKeyboard(SDL_VideoDevice *_this)
#endif
}
int Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window)
int Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
SDL_VideoData *internal = _this->internal;
struct SDL_WaylandInput *input = internal->input;
@ -59,13 +59,71 @@ int Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window)
if (internal->text_input_manager) {
if (input && input->text_input) {
const SDL_Rect *rect = &input->text_input->cursor_rect;
enum zwp_text_input_v3_content_hint hint = ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE;
enum zwp_text_input_v3_content_purpose purpose;
switch (SDL_GetTextInputType(props)) {
default:
case SDL_TEXTINPUT_TYPE_TEXT:
purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL;
break;
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NAME;
break;
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_EMAIL;
break;
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL;
hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA;
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PASSWORD;
hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA);
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PASSWORD;
hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA;
break;
case SDL_TEXTINPUT_TYPE_NUMBER:
purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER;
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PIN;
hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA);
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PIN;
hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA;
break;
}
switch (SDL_GetTextInputCapitalization(props)) {
default:
case SDL_CAPITALIZE_NONE:
break;
case SDL_CAPITALIZE_LETTERS:
hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE;
break;
case SDL_CAPITALIZE_WORDS:
hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_TITLECASE;
break;
case SDL_CAPITALIZE_SENTENCES:
hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_AUTO_CAPITALIZATION;
break;
}
if (SDL_GetTextInputAutocorrect(props)) {
hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_COMPLETION | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SPELLCHECK);
}
if (SDL_GetTextInputMultiline(props)) {
hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_MULTILINE;
}
zwp_text_input_v3_enable(input->text_input->text_input);
/* Now that it's enabled, set the input properties */
zwp_text_input_v3_set_content_type(input->text_input->text_input,
ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,
ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL);
zwp_text_input_v3_set_content_type(input->text_input->text_input, hint, purpose);
if (!SDL_RectEmpty(rect)) {
/* This gets reset on enable so we have to cache it */
zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,

View File

@ -32,7 +32,7 @@ typedef struct SDL_WaylandTextInput
extern int Wayland_InitKeyboard(SDL_VideoDevice *_this);
extern void Wayland_QuitKeyboard(SDL_VideoDevice *_this);
extern int Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window);
extern int Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
extern int Wayland_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
extern int Wayland_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_bool Wayland_HasScreenKeyboardSupport(SDL_VideoDevice *_this);

View File

@ -196,7 +196,7 @@ void WIN_ResetDeadKeys(void)
}
}
int WIN_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window)
int WIN_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
WIN_ResetDeadKeys();

View File

@ -29,7 +29,7 @@ extern void WIN_QuitKeyboard(SDL_VideoDevice *_this);
extern void WIN_ResetDeadKeys(void);
extern int WIN_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
extern int WIN_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_ClearComposition(SDL_VideoDevice *_this, SDL_Window *window);

View File

@ -69,7 +69,7 @@ extern void WINRT_ProcessCharacterReceivedEvent(SDL_Window *window, Windows::UI:
#if NTDDI_VERSION >= NTDDI_WIN10
extern void WINTRT_InitialiseInputPaneEvents(SDL_VideoDevice *_this);
extern SDL_bool WINRT_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
extern void WINRT_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern void WINRT_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
extern void WINRT_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_bool WINRT_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
#endif // NTDDI_VERSION >= ...

View File

@ -148,7 +148,7 @@ SDL_bool WINRT_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
return SDL_TRUE;
}
void WINRT_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
void WINRT_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
using namespace Windows::UI::ViewManagement;
InputPane ^ inputPane = InputPane::GetForCurrentView();

View File

@ -421,7 +421,7 @@ static void X11_ResetXIM(SDL_VideoDevice *_this, SDL_Window *window)
#endif
}
int X11_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window)
int X11_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
X11_ResetXIM(_this, window);
@ -451,7 +451,7 @@ SDL_bool X11_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
return videodata->is_steam_deck;
}
void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
SDL_VideoData *videodata = _this->internal;
@ -459,10 +459,33 @@ void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
/* For more documentation of the URL parameters, see:
* https://partner.steamgames.com/doc/api/ISteamUtils#ShowFloatingGamepadTextInput
*/
const int k_EFloatingGamepadTextInputModeModeSingleLine = 0; // Enter dismisses the keyboard
const int k_EFloatingGamepadTextInputModeModeMultipleLines = 1; // User needs to explicitly dismiss the keyboard
const int k_EFloatingGamepadTextInputModeModeEmail = 2; // Keyboard is displayed in a special mode that makes it easier to enter emails
const int k_EFloatingGamepadTextInputModeModeNumeric = 3; // Numeric keypad is shown
char deeplink[128];
int mode;
switch (SDL_GetTextInputType(props)) {
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
mode = k_EFloatingGamepadTextInputModeModeEmail;
break;
case SDL_TEXTINPUT_TYPE_NUMBER:
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
mode = k_EFloatingGamepadTextInputModeModeNumeric;
break;
default:
if (SDL_GetTextInputMultiline(props)) {
mode = k_EFloatingGamepadTextInputModeModeMultipleLines;
} else {
mode = k_EFloatingGamepadTextInputModeModeSingleLine;
}
break;
}
(void)SDL_snprintf(deeplink, sizeof(deeplink),
"steam://open/keyboard?XPosition=0&YPosition=0&Width=0&Height=0&Mode=%d",
SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, SDL_FALSE) ? 0 : 1);
mode);
SDL_OpenURL(deeplink);
videodata->steam_keyboard_open = SDL_TRUE;
}

View File

@ -26,11 +26,11 @@
extern int X11_InitKeyboard(SDL_VideoDevice *_this);
extern void X11_UpdateKeymap(SDL_VideoDevice *_this, SDL_bool send_event);
extern void X11_QuitKeyboard(SDL_VideoDevice *_this);
extern int X11_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
extern int X11_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_bool X11_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
extern void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
extern void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_bool X11_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
extern KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode, unsigned char group, unsigned int mod_mask);

View File

@ -15,6 +15,7 @@
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3/SDL_test_font.h>
#ifdef HAVE_SDL_TTF
#include "SDL_ttf.h"
#endif
@ -40,6 +41,11 @@
#endif
#define MAX_TEXT_LENGTH 256
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
#define MARGIN 32.0f
#define LINE_HEIGHT (FONT_CHARACTER_SIZE + 4.0f)
#define CURSOR_BLINK_INTERVAL_MS 500
typedef struct
@ -47,6 +53,10 @@ typedef struct
SDL_Window *window;
SDL_Renderer *renderer;
int rendererID;
SDL_bool settings_visible;
SDL_Texture *settings_icon;
SDL_FRect settings_rect;
SDL_PropertiesID text_settings;
SDL_FRect textRect;
SDL_FRect markedRect;
char text[MAX_TEXT_LENGTH];
@ -68,6 +78,33 @@ static const SDL_Color backColor = { 255, 255, 255, 255 };
static const SDL_Color textColor = { 0, 0, 0, 255 };
static SDL_BlendMode highlight_mode;
static const struct
{
const char *label;
const char *setting;
int value;
} settings[] = {
{ "Text", SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_TEXT },
{ "Name", SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_TEXT_NAME },
{ "E-mail", SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_TEXT_EMAIL },
{ "Username", SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_TEXT_USERNAME },
{ "Password (hidden)", SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN },
{ "Password (visible)", SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE },
{ "Number", SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_NUMBER },
{ "Numeric PIN (hidden)", SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN },
{ "Numeric PIN (visible)", SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE },
{ "", NULL },
{ "No capitalization", SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER, SDL_CAPITALIZE_NONE },
{ "Capitalize sentences", SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER, SDL_CAPITALIZE_SENTENCES },
{ "Capitalize words", SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER, SDL_CAPITALIZE_WORDS },
{ "All caps", SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER, SDL_CAPITALIZE_LETTERS },
{ "", NULL },
{ "Auto-correct OFF", SDL_PROP_TEXTINPUT_AUTOCORRECT_BOOLEAN, SDL_FALSE },
{ "Auto-correct ON", SDL_PROP_TEXTINPUT_AUTOCORRECT_BOOLEAN, SDL_TRUE },
{ "Multiline OFF", SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN, SDL_FALSE },
{ "Multiline ON", SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN, SDL_TRUE }
};
#ifdef HAVE_SDL_TTF
static TTF_Font *font;
#else
@ -487,7 +524,9 @@ static void InitInput(WindowState *ctx)
ctx->textRect.h = 50.0f;
ctx->markedRect = ctx->textRect;
SDL_StartTextInput(ctx->window);
ctx->text_settings = SDL_CreateProperties();
SDL_StartTextInputWithProperties(ctx->window, ctx->text_settings);
}
@ -692,6 +731,7 @@ static void CleanupVideo(void)
SDL_StopTextInput(ctx->window);
ClearCandidates(ctx);
SDL_DestroyProperties(ctx->text_settings);
}
#ifdef HAVE_SDL_TTF
TTF_CloseFont(font);
@ -701,11 +741,85 @@ static void CleanupVideo(void)
#endif
}
static void DrawSettingsButton(WindowState *ctx)
{
SDL_Renderer *renderer = ctx->renderer;
SDL_RenderTexture(renderer, ctx->settings_icon, NULL, &ctx->settings_rect);
}
static void ToggleSettings(WindowState *ctx)
{
if (ctx->settings_visible) {
ctx->settings_visible = SDL_FALSE;
SDL_StartTextInputWithProperties(ctx->window, ctx->text_settings);
} else {
SDL_StopTextInput(ctx->window);
ctx->settings_visible = SDL_TRUE;
}
}
static void DrawSettings(WindowState *ctx)
{
SDL_Renderer *renderer = ctx->renderer;
SDL_FRect checkbox;
int i;
checkbox.x = MARGIN;
checkbox.y = MARGIN;
checkbox.w = (float)FONT_CHARACTER_SIZE;
checkbox.h = (float)FONT_CHARACTER_SIZE;
for (i = 0; i < SDL_arraysize(settings); ++i) {
if (settings[i].setting) {
int value = (int)SDL_GetNumberProperty(ctx->text_settings, settings[i].setting, 0);
if (value == settings[i].value) {
SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255);
SDL_RenderFillRect(renderer, &checkbox);
}
SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
SDL_RenderRect(renderer, &checkbox);
SDLTest_DrawString(renderer, checkbox.x + checkbox.w + 8.0f, checkbox.y, settings[i].label);
}
checkbox.y += LINE_HEIGHT;
}
}
static void ClickSettings(WindowState *ctx, float x, float y)
{
int setting = (int)SDL_floorf((y - MARGIN) / LINE_HEIGHT);
if (setting >= 0 && setting < SDL_arraysize(settings)) {
SDL_SetNumberProperty(ctx->text_settings, settings[setting].setting, settings[setting].value);
}
}
static void RedrawWindow(WindowState *ctx)
{
SDL_Renderer *renderer = ctx->renderer;
int rendererID = ctx->rendererID;
SDL_FRect drawnTextRect, cursorRect, underlineRect;
char text[MAX_TEXT_LENGTH];
DrawSettingsButton(ctx);
if (ctx->settings_visible) {
DrawSettings(ctx);
return;
}
/* Hide the text if it's a password */
switch ((SDL_TextInputType)SDL_GetNumberProperty(ctx->text_settings, SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_TEXT)) {
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN: {
size_t len = SDL_utf8strlen(ctx->text);
SDL_memset(text, '*', len);
text[len] = '\0';
break;
}
default:
SDL_strlcpy(text, ctx->text, sizeof(text));
break;
}
SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
SDL_RenderFillRect(renderer, &ctx->textRect);
@ -716,9 +830,9 @@ static void RedrawWindow(WindowState *ctx)
drawnTextRect.w = 0.0f;
drawnTextRect.h = UNIFONT_GLYPH_SIZE * UNIFONT_DRAW_SCALE;
if (ctx->text[0]) {
if (text[0]) {
#ifdef HAVE_SDL_TTF
SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, ctx->text, textColor);
SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, text, textColor);
SDL_Texture *texture;
/* Vertically center text */
@ -732,7 +846,7 @@ static void RedrawWindow(WindowState *ctx)
SDL_RenderTexture(renderer, texture, NULL, &drawnTextRect);
SDL_DestroyTexture(texture);
#else
char *utext = ctx->text;
char *utext = text;
Uint32 codepoint;
size_t len;
SDL_FRect dstrect;
@ -756,13 +870,6 @@ static void RedrawWindow(WindowState *ctx)
/* The marked text rectangle is the text area that hasn't been filled by committed text */
ctx->markedRect.x = ctx->textRect.x + drawnTextRect.w;
ctx->markedRect.w = ctx->textRect.w - drawnTextRect.w;
if (ctx->markedRect.w < 0) {
/* Stop text input because we cannot hold any more characters */
SDL_StopTextInput(ctx->window);
return;
} else {
SDL_StartTextInput(ctx->window);
}
/* Update the drawn text rectangle for composition text, after the committed text */
drawnTextRect.x += drawnTextRect.w;
@ -974,10 +1081,18 @@ int main(int argc, char *argv[])
WindowState *ctx = &windowstate[i];
SDL_Window *window = state->windows[i];
SDL_Renderer *renderer = state->renderers[i];
int icon_w = 0, icon_h = 0;
SDL_SetRenderLogicalPresentation(renderer, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_LOGICAL_PRESENTATION_LETTERBOX, SDL_SCALEMODE_LINEAR);
ctx->window = window;
ctx->renderer = renderer;
ctx->rendererID = i;
ctx->settings_icon = LoadTexture(renderer, "icon.bmp", SDL_TRUE, &icon_w, &icon_h);
ctx->settings_rect.x = (float)WINDOW_WIDTH - icon_w - MARGIN;
ctx->settings_rect.y = MARGIN;
ctx->settings_rect.w = (float)icon_w;
ctx->settings_rect.h = (float)icon_h;
InitInput(ctx);
@ -999,6 +1114,23 @@ int main(int argc, char *argv[])
while (SDL_PollEvent(&event)) {
SDLTest_CommonEvent(state, &event, &done);
switch (event.type) {
case SDL_EVENT_MOUSE_BUTTON_UP: {
SDL_FPoint point;
WindowState *ctx = GetWindowStateForWindowID(event.button.windowID);
if (!ctx) {
break;
}
SDL_ConvertEventToRenderCoordinates(ctx->renderer, &event);
point.x = event.button.x;
point.y = event.button.y;
if (SDL_PointInRectFloat(&point, &ctx->settings_rect)) {
ToggleSettings(ctx);
} else if (ctx->settings_visible) {
ClickSettings(ctx, point.x, point.y);
}
break;
}
case SDL_EVENT_KEY_DOWN: {
WindowState *ctx = GetWindowStateForWindowID(event.key.windowID);
if (!ctx) {