Skip to content

Commit

Permalink
Win32: Support preedit candidate feature
Browse files Browse the repository at this point in the history
You can use this feature when you need to manage the drawing of
the preedit candidates on the application side.
  • Loading branch information
daipom authored and ashie committed Apr 1, 2024
1 parent 79fe47e commit 4a2883b
Show file tree
Hide file tree
Showing 11 changed files with 503 additions and 46 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,17 @@ information on what to include when reporting a bug.
area (#2130)
- Added `glfwResetPreeditText` function to reset preedit of input method
(#2130)
- Added `glfwSetPreeditCandidateCallback` function and
`GLFWpreeditcandidatefun` type for preedit candidates (#2130)
- Added `glfwGetPreeditCandidate` function to get a preeidt candidate text
(#2130)
- Added `GLFW_IME` input mode for `glfwGetInputMode` and `glfwSetInputMode`
(#2130)
- Added `GLFW_X11_ONTHESPOT` init hint for using on-the-spot input method
style on X11 (#2130)
- Added `GLFW_MANAGE_PREEDIT_CANDIDATE` init hint for displaying preedit
candidates on the application side (supported only on Windows currently)
(#2130)


## Contact
Expand Down
74 changes: 74 additions & 0 deletions docs/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,80 @@ glfwResetPreeditText(window);
@endcode
@subsection manage_preedit_candidate Manage preedit candidate
By default, the IME manages the drawing of the preedit candidates, but
sometimes you need to do that on the application side for some reason. In such
a case, you can use
[GLFW_MANAGE_PREEDIT_CANDIDATE](@ref GLFW_MANAGE_PREEDIT_CANDIDATE_hint) init hint.
By setting this to `GLFW_TRUE`, the IME stops managing the drawing of the
candidates and the application needs to manage it by using the following
functions.
@note
@win32 Only the OS currently supports this hint.
You can register the candidate callback as follows.
@code
glfwSetPreeditCandidateCallback(window, candidate_callback);
@endcode
The callback receives the following information.
@code
void candidate_callback(GLFWwindow* window,
int candidates_count,
int selected_index,
int page_start,
int page_size)
{
}
@endcode
`candidates_count` is the number of total candidates. `selected_index` is the
index of the currently selected candidate. Normally all candidates should not
be displayed at once, but divided into pages. You can use `page_start` and
`page_size` to manage the pages. `page_start` is the index of the first
candidate on the current page. `page_size` is the number of the candidates on
the current page.
You can get the text of the candidate on the specific index as follows. Each
character of the returned text is a native endian UTF-32.
@code
int text_count;
unsigned int* text = glfwGetPreeditCandidate(window, index, &text_count);
@endcode
A sample code to get all candidate texts on the current page is as follows.
@code
void candidate_callback(GLFWwindow* window, int candidates_count,
int selected_index, int page_start, int page_size)
{
int i, j;
for (i = 0; i < page_size; ++i)
{
int index = i + page_start;
int text_count;
unsigned int* text = glfwGetPreeditCandidate(window, index, &text_count);
if (index == selected_index)
printf("> ");
for (j = 0; j < text_count; ++j)
{
char encoded[5] = "";
encode_utf8(encoded, text[j]); // Some kind of encoding process
printf("%s", encoded);
}
printf("\n");
}
}
glfwSetPreeditCandidateCallback(window, candidate_callback);
@endcode
## Mouse input {#input_mouse}
Mouse input comes in many forms, including mouse motion, button presses and
Expand Down
31 changes: 21 additions & 10 deletions docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ The ANGLE platform type is specified via the `EGL_ANGLE_platform_angle`
extension. This extension is not used if this hint is
`GLFW_ANGLE_PLATFORM_TYPE_NONE`, which is the default value.
@anchor GLFW_MANAGE_PREEDIT_CANDIDATE_hint
__GLFW_MANAGE_PREEDIT_CANDIDATE__ specifies whether to manage the preedit
candidates on the application side. Possible values are `GLFW_TRUE` and
`GLFW_FALSE`. The default is `GLFW_FALSE` and there is no need to manage
the candidates on the application side. When you need to do that on the
application side for some reason, you can enable this hint. Please see
@ref ime_support for more information about IME support.
@win32 Only the OS currently supports this hint.
#### macOS specific init hints {#init_hints_osx}
Expand Down Expand Up @@ -164,16 +174,17 @@ it is recommended not to use this hint in normal cases. Possible values are
#### Supported and default values {#init_hints_values}
Initialization hint | Default value | Supported values
-------------------------------- | ------------------------------- | ----------------
@ref GLFW_PLATFORM | `GLFW_ANY_PLATFORM` | `GLFW_ANY_PLATFORM`, `GLFW_PLATFORM_WIN32`, `GLFW_PLATFORM_COCOA`, `GLFW_PLATFORM_WAYLAND`, `GLFW_PLATFORM_X11` or `GLFW_PLATFORM_NULL`
@ref GLFW_JOYSTICK_HAT_BUTTONS | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_ANGLE_PLATFORM_TYPE | `GLFW_ANGLE_PLATFORM_TYPE_NONE` | `GLFW_ANGLE_PLATFORM_TYPE_NONE`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGL`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGLES`, `GLFW_ANGLE_PLATFORM_TYPE_D3D9`, `GLFW_ANGLE_PLATFORM_TYPE_D3D11`, `GLFW_ANGLE_PLATFORM_TYPE_VULKAN` or `GLFW_ANGLE_PLATFORM_TYPE_METAL`
@ref GLFW_COCOA_CHDIR_RESOURCES | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_COCOA_MENUBAR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_WAYLAND_LIBDECOR | `GLFW_WAYLAND_PREFER_LIBDECOR` | `GLFW_WAYLAND_PREFER_LIBDECOR` or `GLFW_WAYLAND_DISABLE_LIBDECOR`
@ref GLFW_X11_XCB_VULKAN_SURFACE | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_X11_ONTHESPOT | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
Initialization hint | Default value | Supported values
---------------------------------- | ------------------------------- | ----------------
@ref GLFW_PLATFORM | `GLFW_ANY_PLATFORM` | `GLFW_ANY_PLATFORM`, `GLFW_PLATFORM_WIN32`, `GLFW_PLATFORM_COCOA`, `GLFW_PLATFORM_WAYLAND`, `GLFW_PLATFORM_X11` or `GLFW_PLATFORM_NULL`
@ref GLFW_JOYSTICK_HAT_BUTTONS | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_ANGLE_PLATFORM_TYPE | `GLFW_ANGLE_PLATFORM_TYPE_NONE` | `GLFW_ANGLE_PLATFORM_TYPE_NONE`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGL`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGLES`, `GLFW_ANGLE_PLATFORM_TYPE_D3D9`, `GLFW_ANGLE_PLATFORM_TYPE_D3D11`, `GLFW_ANGLE_PLATFORM_TYPE_VULKAN` or `GLFW_ANGLE_PLATFORM_TYPE_METAL`
@ref GLFW_MANAGE_PREEDIT_CANDIDATE | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_COCOA_CHDIR_RESOURCES | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_COCOA_MENUBAR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_WAYLAND_LIBDECOR | `GLFW_WAYLAND_PREFER_LIBDECOR` | `GLFW_WAYLAND_PREFER_LIBDECOR` or `GLFW_WAYLAND_DISABLE_LIBDECOR`
@ref GLFW_X11_XCB_VULKAN_SURFACE | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_X11_ONTHESPOT | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
### Runtime platform selection {#platform}
Expand Down
101 changes: 101 additions & 0 deletions include/GLFW/glfw3.h
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,11 @@ extern "C" {
* Platform selection [init hint](@ref GLFW_PLATFORM).
*/
#define GLFW_PLATFORM 0x00050003
/*! @brief Preedit candidate init hint.
*
* Preedit candidate [init hint](@ref GLFW_MANAGE_PREEDIT_CANDIDATE_hint).
*/
#define GLFW_MANAGE_PREEDIT_CANDIDATE 0x00050004
/*! @brief macOS specific init hint.
*
* macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint).
Expand Down Expand Up @@ -1989,6 +1994,29 @@ typedef void (* GLFWpreeditfun)(GLFWwindow* window,
*/
typedef void (* GLFWimestatusfun)(GLFWwindow* window);

/*! @brief The function pointer type for preedit candidate callbacks.
*
* This is the function pointer type for preedit candidate callback functions.
* Use @ref glfwGetPreeditCandidate to get the candidate text for a specific index.
*
* @param[in] window The window that received the event.
* @param[in] candidates_count Candidates count.
* @param[in] selected_index.Index of selected candidate.
* @param[in] page_start Start index of candidate currently displayed.
* @param[in] page_size Count of candidates currently displayed.
*
* @sa @ref ime_support
* @sa @ref glfwSetPreeditCandidateCallback
* @sa @ref glfwGetPreeditCandidate
*
* @ingroup input
*/
typedef void (* GLFWpreeditcandidatefun)(GLFWwindow* window,
int candidates_count,
int selected_index,
int page_start,
int page_size);

/*! @brief The function pointer type for path drop callbacks.
*
* This is the function pointer type for path drop callbacks. A path drop
Expand Down Expand Up @@ -5270,6 +5298,34 @@ GLFWAPI void glfwSetPreeditCursorRectangle(GLFWwindow* window, int x, int y, int
*/
GLFWAPI void glfwResetPreeditText(GLFWwindow* window);

/*! @brief Returns the preedit candidate.
*
* This function returns the text and the text-count of the preedit candidate.
*
* By default, the IME manages the preedit candidates, so there is no need to
* use this function. See @ref glfwSetPreeditCandidateCallback and
* [GLFW_MANAGE_PREEDIT_CANDIDATE](@ref GLFW_MANAGE_PREEDIT_CANDIDATE_hint) for details.
*
* @param[in] window The window.
* @param[in] index The index of the candidate.
* @param[out] textCount The text-count of the candidate.
* @return The text of the candidate as Unicode code points.
*
* @remark @macos @x11 @wayland Don't support this function.
*
* @par Thread Safety
* This function may only be called from the main thread.
*
* @sa @ref ime_support
* @sa @ref glfwSetPreeditCandidateCallback
* @sa [GLFW_MANAGE_PREEDIT_CANDIDATE](@ref GLFW_MANAGE_PREEDIT_CANDIDATE_hint)
*
* @since Added in GLFW 3.X.
*
* @ingroup input
*/
GLFWAPI unsigned int* glfwGetPreeditCandidate(GLFWwindow* window, int index, int* textCount);

/*! @brief Sets the key callback.
*
* This function sets the key callback of the specified window, which is called
Expand Down Expand Up @@ -5478,6 +5534,51 @@ GLFWAPI GLFWpreeditfun glfwSetPreeditCallback(GLFWwindow* window, GLFWpreeditfun
*/
GLFWAPI GLFWimestatusfun glfwSetIMEStatusCallback(GLFWwindow* window, GLFWimestatusfun cbfun);

/*! @brief Sets the preedit candidate change callback.
*
* This function sets the preedit candidate callback of the specified
* window, which is called when the candidates are updated and can be used
* to display them by the application side.
*
* By default, this callback is not called because the IME displays the
* candidates and there is nothing to do on the application side. Only when
* the application side needs to use this to manage the displaying of
* IME candidates, you can set
* [GLFW_MANAGE_PREEDIT_CANDIDATE](@ref GLFW_MANAGE_PREEDIT_CANDIDATE_hint) init hint
* and stop the IME from managing it.
*
* @param[in] window The window whose callback to set.
* @param[in] cbfun The new callback, or `NULL` to remove the currently set
* callback.
* @return The previously set callback, or `NULL` if no callback was set or an
* error occurred.
*
* @callback_signature
* @code
* void function_name(GLFWwindow* window,
int candidates_count,
int selected_index,
int page_start,
int page_size)
* @endcode
* For more information about the callback parameters, see the
* [function pointer type](@ref GLFWpreeditcandidatefun).
*
* @remark @macos @x11 @wayland Don't support this function. The callback is
* not called.
*
* @par Thread Safety
* This function may only be called from the main thread.
*
* @sa @ref ime_support
* @sa [GLFW_MANAGE_PREEDIT_CANDIDATE](@ref GLFW_MANAGE_PREEDIT_CANDIDATE_hint)
*
* @since Added in GLFW 3.X
*
* @ingroup input
*/
GLFWAPI GLFWpreeditcandidatefun glfwSetPreeditCandidateCallback(GLFWwindow* window, GLFWpreeditcandidatefun cbfun);

/*! @brief Sets the mouse button callback.
*
* This function sets the mouse button callback of the specified window, which
Expand Down
4 changes: 4 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ static _GLFWinitconfig _glfwInitHints =
.hatButtons = GLFW_TRUE,
.angleType = GLFW_ANGLE_PLATFORM_TYPE_NONE,
.platformID = GLFW_ANY_PLATFORM,
.managePreeditCandidate = GLFW_FALSE,
.vulkanLoader = NULL,
.ns =
{
Expand Down Expand Up @@ -474,6 +475,9 @@ GLFWAPI void glfwInitHint(int hint, int value)
case GLFW_PLATFORM:
_glfwInitHints.platformID = value;
return;
case GLFW_MANAGE_PREEDIT_CANDIDATE:
_glfwInitHints.managePreeditCandidate = value;
return;
case GLFW_COCOA_CHDIR_RESOURCES:
_glfwInitHints.ns.chdir = value;
return;
Expand Down
39 changes: 39 additions & 0 deletions src/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,21 @@ void _glfwInputIMEStatus(_GLFWwindow* window)
}
}

// Notifies shared code of a preedit candidate event
//
void _glfwInputPreeditCandidate(_GLFWwindow* window)
{
if (window->callbacks.preeditCandidate)
{
_GLFWpreedit* preedit = &window->preedit;
window->callbacks.preeditCandidate((GLFWwindow*) window,
preedit->candidateCount,
preedit->candidateSelection,
preedit->candidatePageStart,
preedit->candidatePageSize);
}
}

// Notifies shared code of a scroll event
//
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
Expand Down Expand Up @@ -1029,6 +1044,21 @@ GLFWAPI void glfwResetPreeditText(GLFWwindow* handle)
_glfw.platform.resetPreeditText(window);
}

GLFWAPI unsigned int* glfwGetPreeditCandidate(GLFWwindow* handle, int index, int* textCount)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFWpreedit* preedit = &window->preedit;

if (preedit->candidateCount <= index)
return NULL;

if (textCount)
*textCount = preedit->candidates[index].textCount;


return preedit->candidates[index].text;
}

GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
Expand Down Expand Up @@ -1078,6 +1108,15 @@ GLFWAPI GLFWimestatusfun glfwSetIMEStatusCallback(GLFWwindow* handle, GLFWimesta
return cbfun;
}

GLFWAPI GLFWpreeditcandidatefun glfwSetPreeditCandidateCallback(GLFWwindow* handle,
GLFWpreeditcandidatefun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP(GLFWpreeditcandidatefun, window->callbacks.preeditCandidate, cbfun);
return cbfun;
}

GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle,
GLFWmousebuttonfun cbfun)
{
Expand Down
Loading

0 comments on commit 4a2883b

Please sign in to comment.