mirror of
https://github.com/glfw/glfw
synced 2026-09-26 16:18:21 +03:00
Add text input focus API plumbing
Introduce glfwSetTextInputFocus(window, focused), internal state and a platform hook for explicit application text input focus. Track whether the application has explicitly called the API with textInputFocusInitialized, so existing applications keep legacy platform behavior until they opt into explicit text input focus. This follows the text input focus direction from the IME support discussions in clear-code/glfw#5 and clear-code/glfw#7, without changing platform behavior yet.
This commit is contained in:
parent
de0574f1ea
commit
571d06738d
19 changed files with 141 additions and 0 deletions
|
|
@ -276,6 +276,47 @@ In this case, the preedit callback also works on X11. However, on-the-spot styl
|
|||
X11 is unstable, so it is not recommended.
|
||||
|
||||
|
||||
@subsection input_text_focus Text input focus
|
||||
|
||||
Text input focus describes whether the application is currently in a text input
|
||||
context. Examples include a chat box, text field, search box, rename dialog or
|
||||
editor. This is distinct from native window focus.
|
||||
|
||||
This is useful for applications that render their own user interface inside a
|
||||
single native window, such as games and browsers. In these applications, the
|
||||
native window may remain focused while the application switches between
|
||||
gameplay, menus, chat input, search fields, editors and other UI elements. The
|
||||
application is the only component that reliably knows when text input is
|
||||
expected.
|
||||
|
||||
Use @ref glfwSetTextInputFocus to tell GLFW when the application enters or
|
||||
leaves a text input context:
|
||||
|
||||
@code
|
||||
glfwSetTextInputFocus(window, GLFW_TRUE); // Text field became active
|
||||
glfwSetTextInputFocus(window, GLFW_FALSE); // Text field lost focus
|
||||
@endcode
|
||||
|
||||
This function does not turn the IME on or off. It expresses whether GLFW should
|
||||
route text input through the platform text input or IME path for this window.
|
||||
It does not request an input language change, force a specific IME state or
|
||||
force a specific input source.
|
||||
|
||||
For compatibility, GLFW preserves the previous platform text input behavior for
|
||||
applications that never call @ref glfwSetTextInputFocus. Once an application
|
||||
calls it for a window, that window enters explicit text input focus management.
|
||||
The application is then responsible for calling it with `GLFW_TRUE` when text
|
||||
input begins and with `GLFW_FALSE` when text input ends.
|
||||
|
||||
Applications that opt into explicit text input focus management should set the
|
||||
initial state explicitly, usually to `GLFW_FALSE`, after window creation. They
|
||||
should then set it to `GLFW_TRUE` only while a text input widget is active.
|
||||
|
||||
Individual platforms map this abstraction to their native text input
|
||||
mechanisms. Some platforms may also cancel or clear active preedit text when
|
||||
text input focus is set to `GLFW_FALSE`.
|
||||
|
||||
|
||||
@subsection input_preedit Preedit input
|
||||
|
||||
When inputting text with IME, the text is temporarily inputted, then conversion
|
||||
|
|
@ -407,6 +448,16 @@ glfwSetInputMode(window, GLFW_IME, GLFW_TRUE);
|
|||
glfwSetInputMode(window, GLFW_IME, GLFW_FALSE);
|
||||
@endcode
|
||||
|
||||
This is related to but distinct from @ref glfwSetTextInputFocus. Text input
|
||||
focus describes application intent: the application has entered or left a text
|
||||
input context. `GLFW_IME` controls platform-specific IME state. Applications
|
||||
should normally prefer @ref glfwSetTextInputFocus unless they specifically need
|
||||
platform-dependent IME state control.
|
||||
|
||||
As a rule of thumb, if you think you need to enable or disable IME because a
|
||||
chat box, text field, search field, rename dialog or editor gained or lost
|
||||
focus, you probably want text input focus instead.
|
||||
|
||||
You can use the following function to clear the current preedit.
|
||||
|
||||
@code
|
||||
|
|
|
|||
|
|
@ -5310,6 +5310,43 @@ GLFWAPI void glfwSetPreeditCursorRectangle(GLFWwindow* window, int x, int y, int
|
|||
*/
|
||||
GLFWAPI void glfwResetPreeditText(GLFWwindow* window);
|
||||
|
||||
/*! @brief Sets whether the application is in a text input context.
|
||||
*
|
||||
* This function tells GLFW whether the specified window is currently handling
|
||||
* application text input, such as a chat box, text field, search box, rename
|
||||
* dialog or editor. Text input focus is separate from native window focus.
|
||||
*
|
||||
* Pass `GLFW_TRUE` when the application enters a text input context and
|
||||
* `GLFW_FALSE` when it leaves that context. This does not turn the IME on or
|
||||
* off, switch input languages or force a specific platform input source.
|
||||
*
|
||||
* For compatibility, applications that never call this function keep the same
|
||||
* platform text input behavior as before this API was introduced. Once this
|
||||
* function is called for a window, the application is responsible for
|
||||
* notifying GLFW when text input begins and ends.
|
||||
*
|
||||
* This function is related to but distinct from `GLFW_IME`. Applications
|
||||
* should normally prefer this function unless they specifically need
|
||||
* platform-dependent IME state control.
|
||||
*
|
||||
* @param[in] window The window whose text input focus state to set.
|
||||
* @param[in] focused `GLFW_TRUE` to enter text input focus, or `GLFW_FALSE`
|
||||
* to leave it.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref ime_support
|
||||
* @sa @ref glfwSetInputMode
|
||||
*
|
||||
* @since Added in GLFW 3.X.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI void glfwSetTextInputFocus(GLFWwindow* window, int focused);
|
||||
|
||||
/*! @brief Returns the preedit candidate.
|
||||
*
|
||||
* This function returns the text and the text-count of the preedit candidate.
|
||||
|
|
|
|||
|
|
@ -536,6 +536,7 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform)
|
|||
.getClipboardString = _glfwGetClipboardStringCocoa,
|
||||
.updatePreeditCursorRectangle = _glfwUpdatePreeditCursorRectangleCocoa,
|
||||
.resetPreeditText = _glfwResetPreeditTextCocoa,
|
||||
.setTextInputFocus = _glfwSetTextInputFocusCocoa,
|
||||
.setIMEStatus = _glfwSetIMEStatusCocoa,
|
||||
.getIMEStatus = _glfwGetIMEStatusCocoa,
|
||||
.initJoysticks = _glfwInitJoysticksCocoa,
|
||||
|
|
|
|||
|
|
@ -300,6 +300,7 @@ const char* _glfwGetClipboardStringCocoa(void);
|
|||
|
||||
void _glfwUpdatePreeditCursorRectangleCocoa(_GLFWwindow* window);
|
||||
void _glfwResetPreeditTextCocoa(_GLFWwindow* window);
|
||||
void _glfwSetTextInputFocusCocoa(_GLFWwindow* window, GLFWbool focused);
|
||||
void _glfwSetIMEStatusCocoa(_GLFWwindow* window, int active);
|
||||
int _glfwGetIMEStatusCocoa(_GLFWwindow* window);
|
||||
|
||||
|
|
|
|||
|
|
@ -2037,6 +2037,11 @@ void _glfwResetPreeditTextCocoa(_GLFWwindow* window)
|
|||
} // autoreleasepool
|
||||
}
|
||||
|
||||
void _glfwSetTextInputFocusCocoa(_GLFWwindow* window, GLFWbool focused)
|
||||
{
|
||||
// TODO: Add a safe NSTextInputContext mapping without changing TIS behavior.
|
||||
}
|
||||
|
||||
void _glfwSetIMEStatusCocoa(_GLFWwindow* window, int active)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
|
|
|||
13
src/input.c
13
src/input.c
|
|
@ -1040,6 +1040,19 @@ GLFWAPI void glfwResetPreeditText(GLFWwindow* handle)
|
|||
_glfw.platform.resetPreeditText(window);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetTextInputFocus(GLFWwindow* handle, int focused)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
focused = focused ? GLFW_TRUE : GLFW_FALSE;
|
||||
window->textInputFocusInitialized = GLFW_TRUE;
|
||||
window->textInputFocus = focused;
|
||||
_glfw.platform.setTextInputFocus(window, focused);
|
||||
}
|
||||
|
||||
GLFWAPI unsigned int* glfwGetPreeditCandidate(GLFWwindow* handle, int index, int* textCount)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
|
|
|
|||
|
|
@ -592,6 +592,12 @@ struct _GLFWwindow
|
|||
GLFWbool stickyMouseButtons;
|
||||
GLFWbool lockKeyMods;
|
||||
GLFWbool disableMouseButtonLimit;
|
||||
|
||||
// Preserve legacy text input behavior for backward compatibility until
|
||||
// glfwSetTextInputFocus is used for this window.
|
||||
GLFWbool textInputFocusInitialized;
|
||||
GLFWbool textInputFocus;
|
||||
|
||||
int cursorMode;
|
||||
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
|
||||
char keys[GLFW_KEY_LAST + 1];
|
||||
|
|
@ -744,6 +750,7 @@ struct _GLFWplatform
|
|||
const char* (*getClipboardString)(void);
|
||||
void (*updatePreeditCursorRectangle)(_GLFWwindow*);
|
||||
void (*resetPreeditText)(_GLFWwindow*);
|
||||
void (*setTextInputFocus)(_GLFWwindow*,GLFWbool);
|
||||
void (*setIMEStatus)(_GLFWwindow*,int);
|
||||
int (*getIMEStatus)(_GLFWwindow*);
|
||||
GLFWbool (*initJoysticks)(void);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform)
|
|||
.getClipboardString = _glfwGetClipboardStringNull,
|
||||
.updatePreeditCursorRectangle = _glfwUpdatePreeditCursorRectangleNull,
|
||||
.resetPreeditText = _glfwResetPreeditTextNull,
|
||||
.setTextInputFocus = _glfwSetTextInputFocusNull,
|
||||
.setIMEStatus = _glfwSetIMEStatusNull,
|
||||
.getIMEStatus = _glfwGetIMEStatusNull,
|
||||
.initJoysticks = _glfwInitJoysticksNull,
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ int _glfwGetKeyScancodeNull(int key);
|
|||
|
||||
void _glfwUpdatePreeditCursorRectangleNull(_GLFWwindow* window);
|
||||
void _glfwResetPreeditTextNull(_GLFWwindow* window);
|
||||
void _glfwSetTextInputFocusNull(_GLFWwindow* window, GLFWbool focused);
|
||||
void _glfwSetIMEStatusNull(_GLFWwindow* window, int active);
|
||||
int _glfwGetIMEStatusNull(_GLFWwindow* window);
|
||||
|
||||
|
|
|
|||
|
|
@ -559,6 +559,10 @@ void _glfwResetPreeditTextNull(_GLFWwindow* window)
|
|||
{
|
||||
}
|
||||
|
||||
void _glfwSetTextInputFocusNull(_GLFWwindow* window, GLFWbool focused)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwSetIMEStatusNull(_GLFWwindow* window, int active)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -621,6 +621,7 @@ GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform)
|
|||
.getClipboardString = _glfwGetClipboardStringWin32,
|
||||
.updatePreeditCursorRectangle = _glfwUpdatePreeditCursorRectangleWin32,
|
||||
.resetPreeditText = _glfwResetPreeditTextWin32,
|
||||
.setTextInputFocus = _glfwSetTextInputFocusWin32,
|
||||
.setIMEStatus = _glfwSetIMEStatusWin32,
|
||||
.getIMEStatus = _glfwGetIMEStatusWin32,
|
||||
.initJoysticks = _glfwInitJoysticksWin32,
|
||||
|
|
|
|||
|
|
@ -578,6 +578,7 @@ const char* _glfwGetClipboardStringWin32(void);
|
|||
|
||||
void _glfwUpdatePreeditCursorRectangleWin32(_GLFWwindow* window);
|
||||
void _glfwResetPreeditTextWin32(_GLFWwindow* window);
|
||||
void _glfwSetTextInputFocusWin32(_GLFWwindow* window, GLFWbool focused);
|
||||
void _glfwSetIMEStatusWin32(_GLFWwindow* window, int active);
|
||||
int _glfwGetIMEStatusWin32(_GLFWwindow* window);
|
||||
|
||||
|
|
|
|||
|
|
@ -2873,6 +2873,11 @@ void _glfwResetPreeditTextWin32(_GLFWwindow* window)
|
|||
ImmReleaseContext(hWnd, hIMC);
|
||||
}
|
||||
|
||||
void _glfwSetTextInputFocusWin32(_GLFWwindow* window, GLFWbool focused)
|
||||
{
|
||||
// TODO: Add safe IMM/TSF text input focus plumbing without changing IME status.
|
||||
}
|
||||
|
||||
void _glfwSetIMEStatusWin32(_GLFWwindow* window, int active)
|
||||
{
|
||||
HWND hWnd = window->win32.handle;
|
||||
|
|
|
|||
|
|
@ -468,6 +468,7 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
|
|||
.getClipboardString = _glfwGetClipboardStringWayland,
|
||||
.updatePreeditCursorRectangle = _glfwUpdatePreeditCursorRectangleWayland,
|
||||
.resetPreeditText = _glfwResetPreeditTextWayland,
|
||||
.setTextInputFocus = _glfwSetTextInputFocusWayland,
|
||||
.setIMEStatus = _glfwSetIMEStatusWayland,
|
||||
.getIMEStatus = _glfwGetIMEStatusWayland,
|
||||
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
|
||||
|
|
|
|||
|
|
@ -720,6 +720,7 @@ const char* _glfwGetClipboardStringWayland(void);
|
|||
|
||||
void _glfwUpdatePreeditCursorRectangleWayland(_GLFWwindow* window);
|
||||
void _glfwResetPreeditTextWayland(_GLFWwindow* window);
|
||||
void _glfwSetTextInputFocusWayland(_GLFWwindow* window, GLFWbool focused);
|
||||
void _glfwSetIMEStatusWayland(_GLFWwindow* window, int active);
|
||||
int _glfwGetIMEStatusWayland(_GLFWwindow* window);
|
||||
|
||||
|
|
|
|||
|
|
@ -3943,6 +3943,11 @@ void _glfwResetPreeditTextWayland(_GLFWwindow* window)
|
|||
{
|
||||
}
|
||||
|
||||
void _glfwSetTextInputFocusWayland(_GLFWwindow* window, GLFWbool focused)
|
||||
{
|
||||
// TODO: Wire this to text-input-v3 enable/disable or focus integration.
|
||||
}
|
||||
|
||||
void _glfwSetIMEStatusWayland(_GLFWwindow* window, int active)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1190,6 +1190,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
|
|||
.getClipboardString = _glfwGetClipboardStringX11,
|
||||
.updatePreeditCursorRectangle = _glfwUpdatePreeditCursorRectangleX11,
|
||||
.resetPreeditText = _glfwResetPreeditTextX11,
|
||||
.setTextInputFocus = _glfwSetTextInputFocusX11,
|
||||
.setIMEStatus = _glfwSetIMEStatusX11,
|
||||
.getIMEStatus = _glfwGetIMEStatusX11,
|
||||
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
|
||||
|
|
|
|||
|
|
@ -981,6 +981,7 @@ const char* _glfwGetClipboardStringX11(void);
|
|||
|
||||
void _glfwUpdatePreeditCursorRectangleX11(_GLFWwindow* window);
|
||||
void _glfwResetPreeditTextX11(_GLFWwindow* window);
|
||||
void _glfwSetTextInputFocusX11(_GLFWwindow* window, GLFWbool focused);
|
||||
void _glfwSetIMEStatusX11(_GLFWwindow* window, int active);
|
||||
int _glfwGetIMEStatusX11(_GLFWwindow* window);
|
||||
|
||||
|
|
|
|||
|
|
@ -3429,6 +3429,10 @@ void _glfwSetIMEStatusX11(_GLFWwindow* window, int active)
|
|||
XUnsetICFocus(ic);
|
||||
}
|
||||
|
||||
void _glfwSetTextInputFocusX11(_GLFWwindow* window, GLFWbool focused)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwGetIMEStatusX11(_GLFWwindow* window)
|
||||
{
|
||||
if (!window->x11.ic)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue