From 81f8e6aba6b3b73e44767a61f37e8f72b18ce3e4 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 2 Aug 2024 06:56:51 -0700
Subject: [PATCH] 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
---
.../SDLTest/SDLTest.xcodeproj/project.pbxproj | 2 +
.../main/java/org/libsdl/app/SDLActivity.java | 9 +-
.../java/org/libsdl/app/SDLDummyEdit.java | 8 +-
include/SDL3/SDL_hints.h | 2 +
include/SDL3/SDL_keyboard.h | 82 ++++++++++
src/core/android/SDL_android.c | 5 +-
src/core/android/SDL_android.h | 2 +-
src/dynapi/SDL_dynapi.sym | 1 +
src/dynapi/SDL_dynapi_overrides.h | 1 +
src/dynapi/SDL_dynapi_procs.h | 1 +
src/events/SDL_keyboard.c | 2 +-
src/video/SDL_sysvideo.h | 10 +-
src/video/SDL_video.c | 76 ++++++++-
src/video/android/SDL_androidkeyboard.c | 104 +++++++++++-
src/video/android/SDL_androidkeyboard.h | 2 +-
src/video/cocoa/SDL_cocoakeyboard.h | 2 +-
src/video/cocoa/SDL_cocoakeyboard.m | 2 +-
src/video/gdk/SDL_gdktextinput.cpp | 39 ++++-
src/video/gdk/SDL_gdktextinput.h | 4 +-
src/video/n3ds/SDL_n3dsswkb.c | 2 +-
src/video/n3ds/SDL_n3dsswkb.h | 2 +-
src/video/psp/SDL_pspvideo.c | 33 +++-
src/video/psp/SDL_pspvideo.h | 2 +-
src/video/uikit/SDL_uikitviewcontroller.h | 2 +-
src/video/uikit/SDL_uikitviewcontroller.m | 109 +++++++++++--
src/video/vita/SDL_vitavideo.c | 44 ++++-
src/video/vita/SDL_vitavideo.h | 2 +-
src/video/wayland/SDL_waylandkeyboard.c | 66 +++++++-
src/video/wayland/SDL_waylandkeyboard.h | 2 +-
src/video/windows/SDL_windowskeyboard.c | 2 +-
src/video/windows/SDL_windowskeyboard.h | 2 +-
src/video/winrt/SDL_winrtevents_c.h | 2 +-
src/video/winrt/SDL_winrtkeyboard.cpp | 2 +-
src/video/x11/SDL_x11keyboard.c | 29 +++-
src/video/x11/SDL_x11keyboard.h | 4 +-
test/testime.c | 154 ++++++++++++++++--
36 files changed, 737 insertions(+), 76 deletions(-)
diff --git a/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj b/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj
index 0d28405ff1966..a3b389edca9c0 100644
--- a/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj
+++ b/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj
@@ -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;
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
index 6cfbc904f9598..134a3dfdcf604 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
@@ -1375,9 +1375,11 @@ static class ShowTextInputTask implements Runnable {
*/
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 void run() {
} else {
mTextEdit.setLayoutParams(params);
}
+ mTextEdit.setInputType(input_type);
mTextEdit.setVisibility(View.VISIBLE);
mTextEdit.requestFocus();
@@ -1419,9 +1422,9 @@ public void run() {
/**
* 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) {
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLDummyEdit.java b/android-project/app/src/main/java/org/libsdl/app/SDLDummyEdit.java
index dca28145ec19c..40e556ff41066 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLDummyEdit.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLDummyEdit.java
@@ -12,6 +12,7 @@
public class SDLDummyEdit extends View implements View.OnKeyListener
{
InputConnection ic;
+ int input_type;
public SDLDummyEdit(Context context) {
super(context);
@@ -20,6 +21,10 @@ public SDLDummyEdit(Context context) {
setOnKeyListener(this);
}
+ public void setInputType(int input_type) {
+ this.input_type = input_type;
+ }
+
@Override
public boolean onCheckIsTextEditor() {
return true;
@@ -51,8 +56,7 @@ public boolean onKeyPreIme (int keyCode, KeyEvent event) {
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 */;
diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h
index eb14e7a2c6421..79aa0089e3788 100644
--- a/include/SDL3/SDL_hints.h
+++ b/include/SDL3/SDL_hints.h
@@ -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)
diff --git a/include/SDL3/SDL_keyboard.h b/include/SDL3/SDL_keyboard.h
index b5453a0a15408..67c4f5842e037 100644
--- a/include/SDL3/SDL_keyboard.h
+++ b/include/SDL3/SDL_keyboard.h
@@ -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.
*
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index c0c73bcf6ceb4..bf0f30b986114 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -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,
diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h
index ef0df18e30b19..6950ef2c76ebc 100644
--- a/src/core/android/SDL_android.h
+++ b/src/core/android/SDL_android.h
@@ -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);
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index bf7a2276b3153..38aad316a8e65 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -816,6 +816,7 @@ SDL3_0.0.0 {
SDL_SignalCondition;
SDL_SignalSemaphore;
SDL_StartTextInput;
+ SDL_StartTextInputWithProperties;
SDL_StepUTF8;
SDL_StopHapticEffect;
SDL_StopHapticEffects;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 96d40eaa36afc..004eee31cbb28 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -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
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 749af3ce25ff2..6cdf7ff094b65 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -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)
diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c
index 63c503d149c57..78abd861394b9 100644
--- a/src/events/SDL_keyboard.c
+++ b/src/events/SDL_keyboard.c
@@ -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);
}
}
}
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 2be73c9b5614f..6554191225eab 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -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_ */
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 484f84f13ef0f..fa6707f99e2da 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -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;
diff --git a/src/video/android/SDL_androidkeyboard.c b/src/video/android/SDL_androidkeyboard.c
index 85a124725ce67..84da48166f044 100644
--- a/src/video/android/SDL_androidkeyboard.c
+++ b/src/video/android/SDL_androidkeyboard.c
@@ -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);
}
}
diff --git a/src/video/android/SDL_androidkeyboard.h b/src/video/android/SDL_androidkeyboard.h
index bcbd948e1caa9..c7b70090b8b7e 100644
--- a/src/video/android/SDL_androidkeyboard.h
+++ b/src/video/android/SDL_androidkeyboard.h
@@ -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);
diff --git a/src/video/cocoa/SDL_cocoakeyboard.h b/src/video/cocoa/SDL_cocoakeyboard.h
index 85a409258a3a7..0103e1a8a336f 100644
--- a/src/video/cocoa/SDL_cocoakeyboard.h
+++ b/src/video/cocoa/SDL_cocoakeyboard.h
@@ -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);
diff --git a/src/video/cocoa/SDL_cocoakeyboard.m b/src/video/cocoa/SDL_cocoakeyboard.m
index 685d6752df7e7..1bc0664da7ed8 100644
--- a/src/video/cocoa/SDL_cocoakeyboard.m
+++ b/src/video/cocoa/SDL_cocoakeyboard.m
@@ -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;
diff --git a/src/video/gdk/SDL_gdktextinput.cpp b/src/video/gdk/SDL_gdktextinput.cpp
index 7af1b381a0409..0c6b1d30c10be 100644
--- a/src/video/gdk/SDL_gdktextinput.cpp
+++ b/src/video/gdk/SDL_gdktextinput.cpp
@@ -178,7 +178,7 @@ void GDK_EnsureHints(void)
}
}
-int GDK_StartTextInput(SDL_VideoD
(Patch may be truncated, please check the link at the top of this post.)