mirror of
https://github.com/glfw/glfw.git
synced 2024-11-22 21:14:35 +00:00
Win32: Support preedit candidate feature
You can use this feature when you need to manage the drawing of the preedit candidates on the application side.
This commit is contained in:
parent
79fe47e970
commit
4a2883b4e2
@ -140,10 +140,17 @@ information on what to include when reporting a bug.
|
|||||||
area (#2130)
|
area (#2130)
|
||||||
- Added `glfwResetPreeditText` function to reset preedit of input method
|
- Added `glfwResetPreeditText` function to reset preedit of input method
|
||||||
(#2130)
|
(#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`
|
- Added `GLFW_IME` input mode for `glfwGetInputMode` and `glfwSetInputMode`
|
||||||
(#2130)
|
(#2130)
|
||||||
- Added `GLFW_X11_ONTHESPOT` init hint for using on-the-spot input method
|
- Added `GLFW_X11_ONTHESPOT` init hint for using on-the-spot input method
|
||||||
style on X11 (#2130)
|
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
|
## Contact
|
||||||
|
@ -414,6 +414,80 @@ glfwResetPreeditText(window);
|
|||||||
@endcode
|
@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 {#input_mouse}
|
||||||
|
|
||||||
Mouse input comes in many forms, including mouse motion, button presses and
|
Mouse input comes in many forms, including mouse motion, button presses and
|
||||||
|
@ -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
|
extension. This extension is not used if this hint is
|
||||||
`GLFW_ANGLE_PLATFORM_TYPE_NONE`, which is the default value.
|
`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}
|
#### macOS specific init hints {#init_hints_osx}
|
||||||
|
|
||||||
@ -165,10 +175,11 @@ it is recommended not to use this hint in normal cases. Possible values are
|
|||||||
#### Supported and default values {#init_hints_values}
|
#### Supported and default values {#init_hints_values}
|
||||||
|
|
||||||
Initialization hint | Default value | Supported 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_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_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_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_CHDIR_RESOURCES | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
|
||||||
@ref GLFW_COCOA_MENUBAR | `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_WAYLAND_LIBDECOR | `GLFW_WAYLAND_PREFER_LIBDECOR` | `GLFW_WAYLAND_PREFER_LIBDECOR` or `GLFW_WAYLAND_DISABLE_LIBDECOR`
|
||||||
|
@ -1309,6 +1309,11 @@ extern "C" {
|
|||||||
* Platform selection [init hint](@ref GLFW_PLATFORM).
|
* Platform selection [init hint](@ref GLFW_PLATFORM).
|
||||||
*/
|
*/
|
||||||
#define GLFW_PLATFORM 0x00050003
|
#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.
|
/*! @brief macOS specific init hint.
|
||||||
*
|
*
|
||||||
* macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint).
|
* macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint).
|
||||||
@ -1989,6 +1994,29 @@ typedef void (* GLFWpreeditfun)(GLFWwindow* window,
|
|||||||
*/
|
*/
|
||||||
typedef void (* GLFWimestatusfun)(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.
|
/*! @brief The function pointer type for path drop callbacks.
|
||||||
*
|
*
|
||||||
* This is the function pointer type for path drop callbacks. A path drop
|
* This is the function pointer type for path drop callbacks. A path drop
|
||||||
@ -5270,6 +5298,34 @@ GLFWAPI void glfwSetPreeditCursorRectangle(GLFWwindow* window, int x, int y, int
|
|||||||
*/
|
*/
|
||||||
GLFWAPI void glfwResetPreeditText(GLFWwindow* window);
|
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.
|
/*! @brief Sets the key callback.
|
||||||
*
|
*
|
||||||
* This function sets the key callback of the specified window, which is called
|
* This function sets the key callback of the specified window, which is called
|
||||||
@ -5478,6 +5534,51 @@ GLFWAPI GLFWpreeditfun glfwSetPreeditCallback(GLFWwindow* window, GLFWpreeditfun
|
|||||||
*/
|
*/
|
||||||
GLFWAPI GLFWimestatusfun glfwSetIMEStatusCallback(GLFWwindow* window, GLFWimestatusfun cbfun);
|
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.
|
/*! @brief Sets the mouse button callback.
|
||||||
*
|
*
|
||||||
* This function sets the mouse button callback of the specified window, which
|
* This function sets the mouse button callback of the specified window, which
|
||||||
|
@ -52,6 +52,7 @@ static _GLFWinitconfig _glfwInitHints =
|
|||||||
.hatButtons = GLFW_TRUE,
|
.hatButtons = GLFW_TRUE,
|
||||||
.angleType = GLFW_ANGLE_PLATFORM_TYPE_NONE,
|
.angleType = GLFW_ANGLE_PLATFORM_TYPE_NONE,
|
||||||
.platformID = GLFW_ANY_PLATFORM,
|
.platformID = GLFW_ANY_PLATFORM,
|
||||||
|
.managePreeditCandidate = GLFW_FALSE,
|
||||||
.vulkanLoader = NULL,
|
.vulkanLoader = NULL,
|
||||||
.ns =
|
.ns =
|
||||||
{
|
{
|
||||||
@ -474,6 +475,9 @@ GLFWAPI void glfwInitHint(int hint, int value)
|
|||||||
case GLFW_PLATFORM:
|
case GLFW_PLATFORM:
|
||||||
_glfwInitHints.platformID = value;
|
_glfwInitHints.platformID = value;
|
||||||
return;
|
return;
|
||||||
|
case GLFW_MANAGE_PREEDIT_CANDIDATE:
|
||||||
|
_glfwInitHints.managePreeditCandidate = value;
|
||||||
|
return;
|
||||||
case GLFW_COCOA_CHDIR_RESOURCES:
|
case GLFW_COCOA_CHDIR_RESOURCES:
|
||||||
_glfwInitHints.ns.chdir = value;
|
_glfwInitHints.ns.chdir = value;
|
||||||
return;
|
return;
|
||||||
|
39
src/input.c
39
src/input.c
@ -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
|
// Notifies shared code of a scroll event
|
||||||
//
|
//
|
||||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
|
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
|
||||||
@ -1029,6 +1044,21 @@ GLFWAPI void glfwResetPreeditText(GLFWwindow* handle)
|
|||||||
_glfw.platform.resetPreeditText(window);
|
_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)
|
GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
|
||||||
{
|
{
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
@ -1078,6 +1108,15 @@ GLFWAPI GLFWimestatusfun glfwSetIMEStatusCallback(GLFWwindow* handle, GLFWimesta
|
|||||||
return cbfun;
|
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,
|
GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle,
|
||||||
GLFWmousebuttonfun cbfun)
|
GLFWmousebuttonfun cbfun)
|
||||||
{
|
{
|
||||||
|
@ -70,6 +70,7 @@ typedef struct _GLFWctxconfig _GLFWctxconfig;
|
|||||||
typedef struct _GLFWfbconfig _GLFWfbconfig;
|
typedef struct _GLFWfbconfig _GLFWfbconfig;
|
||||||
typedef struct _GLFWcontext _GLFWcontext;
|
typedef struct _GLFWcontext _GLFWcontext;
|
||||||
typedef struct _GLFWpreedit _GLFWpreedit;
|
typedef struct _GLFWpreedit _GLFWpreedit;
|
||||||
|
typedef struct _GLFWpreeditcandidate _GLFWpreeditcandidate;
|
||||||
typedef struct _GLFWwindow _GLFWwindow;
|
typedef struct _GLFWwindow _GLFWwindow;
|
||||||
typedef struct _GLFWplatform _GLFWplatform;
|
typedef struct _GLFWplatform _GLFWplatform;
|
||||||
typedef struct _GLFWlibrary _GLFWlibrary;
|
typedef struct _GLFWlibrary _GLFWlibrary;
|
||||||
@ -378,6 +379,7 @@ struct _GLFWinitconfig
|
|||||||
GLFWbool hatButtons;
|
GLFWbool hatButtons;
|
||||||
int angleType;
|
int angleType;
|
||||||
int platformID;
|
int platformID;
|
||||||
|
GLFWbool managePreeditCandidate;
|
||||||
PFN_vkGetInstanceProcAddr vulkanLoader;
|
PFN_vkGetInstanceProcAddr vulkanLoader;
|
||||||
struct {
|
struct {
|
||||||
GLFWbool menubar;
|
GLFWbool menubar;
|
||||||
@ -540,6 +542,24 @@ struct _GLFWpreedit
|
|||||||
int focusedBlockIndex;
|
int focusedBlockIndex;
|
||||||
int caretIndex;
|
int caretIndex;
|
||||||
int cursorPosX, cursorPosY, cursorWidth, cursorHeight;
|
int cursorPosX, cursorPosY, cursorWidth, cursorHeight;
|
||||||
|
|
||||||
|
// Used only when apps display candidates by themselves.
|
||||||
|
// Usually, OS displays them, so apps don't need to do it.
|
||||||
|
_GLFWpreeditcandidate* candidates;
|
||||||
|
int candidateCount;
|
||||||
|
int candidateBufferCount;
|
||||||
|
int candidateSelection;
|
||||||
|
int candidatePageStart;
|
||||||
|
int candidatePageSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Preedit candidate structure
|
||||||
|
//
|
||||||
|
struct _GLFWpreeditcandidate
|
||||||
|
{
|
||||||
|
unsigned int* text;
|
||||||
|
int textCount;
|
||||||
|
int textBufferCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Window and context structure
|
// Window and context structure
|
||||||
@ -601,6 +621,7 @@ struct _GLFWwindow
|
|||||||
GLFWcharmodsfun charmods;
|
GLFWcharmodsfun charmods;
|
||||||
GLFWpreeditfun preedit;
|
GLFWpreeditfun preedit;
|
||||||
GLFWimestatusfun imestatus;
|
GLFWimestatusfun imestatus;
|
||||||
|
GLFWpreeditcandidatefun preeditCandidate;
|
||||||
GLFWdropfun drop;
|
GLFWdropfun drop;
|
||||||
} callbacks;
|
} callbacks;
|
||||||
|
|
||||||
@ -961,6 +982,7 @@ void _glfwInputChar(_GLFWwindow* window,
|
|||||||
uint32_t codepoint, int mods, GLFWbool plain);
|
uint32_t codepoint, int mods, GLFWbool plain);
|
||||||
void _glfwInputPreedit(_GLFWwindow* window);
|
void _glfwInputPreedit(_GLFWwindow* window);
|
||||||
void _glfwInputIMEStatus(_GLFWwindow* window);
|
void _glfwInputIMEStatus(_GLFWwindow* window);
|
||||||
|
void _glfwInputPreeditCandidate(_GLFWwindow* window);
|
||||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset);
|
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset);
|
||||||
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
||||||
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
||||||
|
@ -170,6 +170,8 @@ static GLFWbool loadLibraries(void)
|
|||||||
_glfw.win32.imm32.instance = _glfwPlatformLoadModule("imm32.dll");
|
_glfw.win32.imm32.instance = _glfwPlatformLoadModule("imm32.dll");
|
||||||
if (_glfw.win32.imm32.instance)
|
if (_glfw.win32.imm32.instance)
|
||||||
{
|
{
|
||||||
|
_glfw.win32.imm32.ImmGetCandidateListW_ = (PFN_ImmGetCandidateListW)
|
||||||
|
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmGetCandidateListW");
|
||||||
_glfw.win32.imm32.ImmGetCompositionStringW_ = (PFN_ImmGetCompositionStringW)
|
_glfw.win32.imm32.ImmGetCompositionStringW_ = (PFN_ImmGetCompositionStringW)
|
||||||
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmGetCompositionStringW");
|
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmGetCompositionStringW");
|
||||||
_glfw.win32.imm32.ImmGetContext_ = (PFN_ImmGetContext)
|
_glfw.win32.imm32.ImmGetContext_ = (PFN_ImmGetContext)
|
||||||
|
@ -318,6 +318,7 @@ typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLO
|
|||||||
#define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_
|
#define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_
|
||||||
|
|
||||||
// imm32 function pointer typedefs
|
// imm32 function pointer typedefs
|
||||||
|
typedef DWORD (WINAPI * PFN_ImmGetCandidateListW)(HIMC,DWORD,LPCANDIDATELIST,DWORD);
|
||||||
typedef LONG (WINAPI * PFN_ImmGetCompositionStringW)(HIMC,DWORD,LPVOID,DWORD);
|
typedef LONG (WINAPI * PFN_ImmGetCompositionStringW)(HIMC,DWORD,LPVOID,DWORD);
|
||||||
typedef HIMC (WINAPI * PFN_ImmGetContext)(HWND);
|
typedef HIMC (WINAPI * PFN_ImmGetContext)(HWND);
|
||||||
typedef BOOL (WINAPI * PFN_ImmGetConversionStatus)(HIMC,LPDWORD,LPDWORD);
|
typedef BOOL (WINAPI * PFN_ImmGetConversionStatus)(HIMC,LPDWORD,LPDWORD);
|
||||||
@ -327,6 +328,7 @@ typedef BOOL (WINAPI * PFN_ImmNotifyIME)(HIMC,DWORD,DWORD,DWORD);
|
|||||||
typedef BOOL (WINAPI * PFN_ImmReleaseContext)(HWND,HIMC);
|
typedef BOOL (WINAPI * PFN_ImmReleaseContext)(HWND,HIMC);
|
||||||
typedef BOOL (WINAPI * PFN_ImmSetCandidateWindow)(HIMC,LPCANDIDATEFORM);
|
typedef BOOL (WINAPI * PFN_ImmSetCandidateWindow)(HIMC,LPCANDIDATEFORM);
|
||||||
typedef BOOL (WINAPI * PFN_ImmSetOpenStatus)(HIMC,BOOL);
|
typedef BOOL (WINAPI * PFN_ImmSetOpenStatus)(HIMC,BOOL);
|
||||||
|
#define ImmGetCandidateListW _glfw.win32.imm32.ImmGetCandidateListW_
|
||||||
#define ImmGetCompositionStringW _glfw.win32.imm32.ImmGetCompositionStringW_
|
#define ImmGetCompositionStringW _glfw.win32.imm32.ImmGetCompositionStringW_
|
||||||
#define ImmGetContext _glfw.win32.imm32.ImmGetContext_
|
#define ImmGetContext _glfw.win32.imm32.ImmGetContext_
|
||||||
#define ImmGetConversionStatus _glfw.win32.imm32.ImmGetConversionStatus_
|
#define ImmGetConversionStatus _glfw.win32.imm32.ImmGetConversionStatus_
|
||||||
@ -526,6 +528,7 @@ typedef struct _GLFWlibraryWin32
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
HINSTANCE instance;
|
HINSTANCE instance;
|
||||||
|
PFN_ImmGetCandidateListW ImmGetCandidateListW_;
|
||||||
PFN_ImmGetCompositionStringW ImmGetCompositionStringW_;
|
PFN_ImmGetCompositionStringW ImmGetCompositionStringW_;
|
||||||
PFN_ImmGetContext ImmGetContext_;
|
PFN_ImmGetContext ImmGetContext_;
|
||||||
PFN_ImmGetConversionStatus ImmGetConversionStatus_;
|
PFN_ImmGetConversionStatus ImmGetConversionStatus_;
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
// Converts utf16 units to Unicode code points (UTF32).
|
// Converts utf16 units to Unicode code points (UTF32).
|
||||||
// Returns GLFW_TRUE when the converting completes and the result is assigned to
|
// Returns GLFW_TRUE when the converting completes and the result is assigned to
|
||||||
@ -564,6 +565,117 @@ static void maximizeWindowManually(_GLFWwindow* window)
|
|||||||
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store candidate text from the buffer data
|
||||||
|
//
|
||||||
|
static void setCandidate(_GLFWpreeditcandidate* candidate, LPWSTR buffer)
|
||||||
|
{
|
||||||
|
size_t bufferCount = wcslen(buffer);
|
||||||
|
int textBufferCount = candidate->textBufferCount;
|
||||||
|
uint32_t codepoint;
|
||||||
|
WCHAR highSurrogate = 0;
|
||||||
|
int convertedLength = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
while ((size_t) textBufferCount < bufferCount + 1)
|
||||||
|
textBufferCount = (textBufferCount == 0) ? 1 : textBufferCount * 2;
|
||||||
|
if (textBufferCount != candidate->textBufferCount)
|
||||||
|
{
|
||||||
|
unsigned int* text =
|
||||||
|
_glfw_realloc(candidate->text,
|
||||||
|
sizeof(unsigned int) * textBufferCount);
|
||||||
|
if (text == NULL)
|
||||||
|
return;
|
||||||
|
candidate->text = text;
|
||||||
|
candidate->textBufferCount = textBufferCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; (size_t) i < bufferCount; ++i)
|
||||||
|
{
|
||||||
|
if (convertToUTF32FromUTF16(buffer[i],
|
||||||
|
&highSurrogate,
|
||||||
|
&codepoint))
|
||||||
|
candidate->text[convertedLength++] = codepoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
candidate->textCount = convertedLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get preedit candidates of Imm32 and pass them to candidate-callback
|
||||||
|
//
|
||||||
|
static void getImmCandidates(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
_GLFWpreedit* preedit = &window->preedit;
|
||||||
|
HIMC hIMC = ImmGetContext(window->win32.handle);
|
||||||
|
DWORD candidateListBytes = ImmGetCandidateListW(hIMC, 0, NULL, 0);
|
||||||
|
|
||||||
|
if (candidateListBytes == 0)
|
||||||
|
{
|
||||||
|
ImmReleaseContext(window->win32.handle, hIMC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int bufferCount = preedit->candidateBufferCount;
|
||||||
|
LPCANDIDATELIST candidateList = _glfw_calloc(candidateListBytes, 1);
|
||||||
|
if (candidateList == NULL)
|
||||||
|
{
|
||||||
|
ImmReleaseContext(window->win32.handle, hIMC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ImmGetCandidateListW(hIMC, 0, candidateList, candidateListBytes);
|
||||||
|
ImmReleaseContext(window->win32.handle, hIMC);
|
||||||
|
|
||||||
|
while ((DWORD) bufferCount < candidateList->dwCount + 1)
|
||||||
|
bufferCount = (bufferCount == 0) ? 1 : bufferCount * 2;
|
||||||
|
if (bufferCount != preedit->candidateBufferCount)
|
||||||
|
{
|
||||||
|
_GLFWpreeditcandidate* candidates =
|
||||||
|
_glfw_realloc(preedit->candidates,
|
||||||
|
sizeof(_GLFWpreeditcandidate) * bufferCount);
|
||||||
|
if (candidates == NULL)
|
||||||
|
{
|
||||||
|
_glfw_free(candidateList);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// `realloc` does not initialize the increased area with 0.
|
||||||
|
// This logic should be moved to a more appropriate place to share
|
||||||
|
// when other platforms support this feature.
|
||||||
|
for (i = preedit->candidateBufferCount; i < bufferCount; ++i)
|
||||||
|
{
|
||||||
|
candidates[i].text = NULL;
|
||||||
|
candidates[i].textCount = 0;
|
||||||
|
candidates[i].textBufferCount = 0;
|
||||||
|
}
|
||||||
|
preedit->candidates = candidates;
|
||||||
|
preedit->candidateBufferCount = bufferCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; (DWORD) i < candidateList->dwCount; ++i)
|
||||||
|
setCandidate(&preedit->candidates[i],
|
||||||
|
(LPWSTR)((char*) candidateList + candidateList->dwOffset[i]));
|
||||||
|
|
||||||
|
preedit->candidateCount = candidateList->dwCount;
|
||||||
|
preedit->candidateSelection = candidateList->dwSelection;
|
||||||
|
preedit->candidatePageStart = candidateList->dwPageStart;
|
||||||
|
preedit->candidatePageSize = candidateList->dwPageSize;
|
||||||
|
|
||||||
|
_glfw_free(candidateList);
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwInputPreeditCandidate(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear preedit candidates
|
||||||
|
static void clearImmCandidate(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
window->preedit.candidateCount = 0;
|
||||||
|
window->preedit.candidateSelection = 0;
|
||||||
|
window->preedit.candidatePageStart = 0;
|
||||||
|
window->preedit.candidatePageSize = 0;
|
||||||
|
_glfwInputPreeditCandidate(window);
|
||||||
|
}
|
||||||
|
|
||||||
// Get preedit texts of Imm32 and pass them to preedit-callback
|
// Get preedit texts of Imm32 and pass them to preedit-callback
|
||||||
//
|
//
|
||||||
static GLFWbool getImmPreedit(_GLFWwindow* window)
|
static GLFWbool getImmPreedit(_GLFWwindow* window)
|
||||||
@ -798,6 +910,12 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
|||||||
// To draw preedit text by an application side
|
// To draw preedit text by an application side
|
||||||
if (lParam & ISC_SHOWUICOMPOSITIONWINDOW)
|
if (lParam & ISC_SHOWUICOMPOSITIONWINDOW)
|
||||||
lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
|
lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
|
||||||
|
|
||||||
|
if (_glfw.hints.init.managePreeditCandidate &&
|
||||||
|
(lParam & ISC_SHOWUICANDIDATEWINDOW))
|
||||||
|
{
|
||||||
|
lParam &= ~ISC_SHOWUICANDIDATEWINDOW;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1044,16 +1162,35 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
|||||||
case WM_IME_ENDCOMPOSITION:
|
case WM_IME_ENDCOMPOSITION:
|
||||||
{
|
{
|
||||||
clearImmPreedit(window);
|
clearImmPreedit(window);
|
||||||
|
// Usually clearing candidates in IMN_CLOSECANDIDATE is sufficient.
|
||||||
|
// However, some IME need it here, e.g. Google Japanese Input.
|
||||||
|
clearImmCandidate(window);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WM_IME_NOTIFY:
|
case WM_IME_NOTIFY:
|
||||||
{
|
{
|
||||||
if (wParam == IMN_SETOPENSTATUS)
|
switch (wParam)
|
||||||
|
{
|
||||||
|
case IMN_SETOPENSTATUS:
|
||||||
{
|
{
|
||||||
_glfwInputIMEStatus(window);
|
_glfwInputIMEStatus(window);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case IMN_OPENCANDIDATE:
|
||||||
|
case IMN_CHANGECANDIDATE:
|
||||||
|
{
|
||||||
|
getImmCandidates(window);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
case IMN_CLOSECANDIDATE:
|
||||||
|
{
|
||||||
|
clearImmCandidate(window);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,11 +119,16 @@ static int currentIMEStatus = GLFW_FALSE;
|
|||||||
#define MAX_PREEDIT_LEN 128
|
#define MAX_PREEDIT_LEN 128
|
||||||
static char preeditBuf[MAX_PREEDIT_LEN] = "";
|
static char preeditBuf[MAX_PREEDIT_LEN] = "";
|
||||||
|
|
||||||
|
// Assuming that the page-size is 10 at most.
|
||||||
|
static char candidateBuf[9][MAX_PREEDIT_LEN];
|
||||||
|
static int candidatePageSize = 0;
|
||||||
|
|
||||||
void usage(void)
|
void usage(void)
|
||||||
{
|
{
|
||||||
printf("Usage: input_text [-h] [-s]\n");
|
printf("Usage: input_text [-h] [-s] [-c]\n");
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -s Use on-the-spot sytle on X11. This is ignored on other platforms.\n");
|
printf(" -s Use on-the-spot sytle on X11. This is ignored on other platforms.\n");
|
||||||
|
printf(" -c Use manage-preedit-candidate on Win32. This is ignored on other platforms.\n");
|
||||||
printf(" -h Show this help\n");
|
printf(" -h Show this help\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,11 +571,32 @@ static void set_preedit_labels(GLFWwindow* window, struct nk_context* nk, int he
|
|||||||
nk_layout_row_end(nk);
|
nk_layout_row_end(nk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_candidate_labels(GLFWwindow* window, struct nk_context* nk)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 5; ++i)
|
||||||
|
{
|
||||||
|
nk_layout_row_begin(nk, NK_DYNAMIC, 30, 3);
|
||||||
|
nk_layout_row_push(nk, 1.f / 3.f);
|
||||||
|
if (i == 0)
|
||||||
|
nk_label(nk, "Candidates:", NK_TEXT_LEFT);
|
||||||
|
else
|
||||||
|
nk_label(nk, "", NK_TEXT_LEFT);
|
||||||
|
nk_layout_row_push(nk, 1.f / 3.f);
|
||||||
|
if (candidatePageSize > i)
|
||||||
|
nk_label(nk, (const char*) candidateBuf[i], NK_TEXT_LEFT);
|
||||||
|
nk_layout_row_push(nk, 1.f / 3.f);
|
||||||
|
if (candidatePageSize > i + 5)
|
||||||
|
nk_label(nk, (const char*) candidateBuf[i + 5], NK_TEXT_LEFT);
|
||||||
|
nk_layout_row_end(nk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If it is possible to take the text-cursor position calculated in `nk_do_edit` function in `deps/nuklear.h`,
|
// If it is possible to take the text-cursor position calculated in `nk_do_edit` function in `deps/nuklear.h`,
|
||||||
// we can set preedit-cursor position more easily.
|
// we can set preedit-cursor position more easily.
|
||||||
// However, there doesn't seem to be a way to do that, so this does a simplified calculation only for the end
|
// However, there doesn't seem to be a way to do that, so this does a simplified calculation only for the end
|
||||||
// of the text. (Can not trace the cursor movement)
|
// of the text. (Can not trace the cursor movement)
|
||||||
static void update_cursor_pos(GLFWwindow* window, struct nk_context* nk, struct nk_user_font* f, char* boxBuffer, int boxLen)
|
static void update_cursor_pos(GLFWwindow* window, struct nk_context* nk, struct nk_user_font* f,
|
||||||
|
char* boxBuffer, int boxLen, int boxX, int boxY)
|
||||||
{
|
{
|
||||||
float lineWidth = 0;
|
float lineWidth = 0;
|
||||||
int totalLines = 1;
|
int totalLines = 1;
|
||||||
@ -606,14 +632,10 @@ static void update_cursor_pos(GLFWwindow* window, struct nk_context* nk, struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// I don't know how to get these info.
|
|
||||||
int widgetLayoutX = 10;
|
|
||||||
int widgetLayoutY = 220;
|
|
||||||
|
|
||||||
int lineHeight = f->height + nk->style.edit.row_padding;
|
int lineHeight = f->height + nk->style.edit.row_padding;
|
||||||
|
|
||||||
int cursorPosX = widgetLayoutX + lineWidth;
|
int cursorPosX = boxX + lineWidth;
|
||||||
int cursorPosY = widgetLayoutY + lineHeight * (totalLines - 1);
|
int cursorPosY = boxY + lineHeight * (totalLines - 1);
|
||||||
int cursorHeight = lineHeight;
|
int cursorHeight = lineHeight;
|
||||||
int cursorWidth;
|
int cursorWidth;
|
||||||
|
|
||||||
@ -686,6 +708,30 @@ static void preedit_callback(GLFWwindow* window, int preeditCount,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void candidate_callback(GLFWwindow* window, int candidates_count,
|
||||||
|
int selected_index, int page_start, int page_size)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
candidatePageSize = page_size;
|
||||||
|
for (i = 0; i < page_size; ++i)
|
||||||
|
{
|
||||||
|
int index = i + page_start;
|
||||||
|
int textCount;
|
||||||
|
unsigned int* text = glfwGetPreeditCandidate(window, index, &textCount);
|
||||||
|
if (index == selected_index)
|
||||||
|
strcpy(candidateBuf[i], "> ");
|
||||||
|
else
|
||||||
|
strcpy(candidateBuf[i], "");
|
||||||
|
for (j = 0; j < textCount; ++j)
|
||||||
|
{
|
||||||
|
char encoded[5] = "";
|
||||||
|
encode_utf8(encoded, text[j]);
|
||||||
|
if (strlen(candidateBuf[i]) + strlen(encoded) < MAX_PREEDIT_LEN)
|
||||||
|
strcat(candidateBuf[i], encoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
@ -694,9 +740,10 @@ int main(int argc, char** argv)
|
|||||||
char boxBuffer[MAX_BUFFER_LEN] = "Input text here.";
|
char boxBuffer[MAX_BUFFER_LEN] = "Input text here.";
|
||||||
int boxLen = strlen(boxBuffer);
|
int boxLen = strlen(boxBuffer);
|
||||||
int isAutoUpdatingCursorPosEnabled = GLFW_TRUE;
|
int isAutoUpdatingCursorPosEnabled = GLFW_TRUE;
|
||||||
|
int managePreeditCandidate = GLFW_FALSE;
|
||||||
int ch;
|
int ch;
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "hs")) != -1)
|
while ((ch = getopt(argc, argv, "hsc")) != -1)
|
||||||
{
|
{
|
||||||
switch (ch)
|
switch (ch)
|
||||||
{
|
{
|
||||||
@ -707,6 +754,11 @@ int main(int argc, char** argv)
|
|||||||
case 's':
|
case 's':
|
||||||
glfwInitHint(GLFW_X11_ONTHESPOT, GLFW_TRUE);
|
glfwInitHint(GLFW_X11_ONTHESPOT, GLFW_TRUE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
glfwInitHint(GLFW_MANAGE_PREEDIT_CANDIDATE, GLFW_TRUE);
|
||||||
|
managePreeditCandidate = GLFW_TRUE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,6 +781,7 @@ int main(int argc, char** argv)
|
|||||||
glfwSetPreeditCursorRectangle(window, 0, 0, 1, 1);
|
glfwSetPreeditCursorRectangle(window, 0, 0, 1, 1);
|
||||||
glfwSetIMEStatusCallback(window, ime_callback);
|
glfwSetIMEStatusCallback(window, ime_callback);
|
||||||
glfwSetPreeditCallback(window, preedit_callback);
|
glfwSetPreeditCallback(window, preedit_callback);
|
||||||
|
glfwSetPreeditCandidateCallback(window, candidate_callback);
|
||||||
|
|
||||||
glfwMakeContextCurrent(window);
|
glfwMakeContextCurrent(window);
|
||||||
gladLoadGL(glfwGetProcAddress);
|
gladLoadGL(glfwGetProcAddress);
|
||||||
@ -757,6 +810,8 @@ int main(int argc, char** argv)
|
|||||||
set_preedit_cursor_edit(window, nk, 30, &isAutoUpdatingCursorPosEnabled);
|
set_preedit_cursor_edit(window, nk, 30, &isAutoUpdatingCursorPosEnabled);
|
||||||
set_ime_stauts_labels(window, nk, 30);
|
set_ime_stauts_labels(window, nk, 30);
|
||||||
set_preedit_labels(window, nk, 30);
|
set_preedit_labels(window, nk, 30);
|
||||||
|
if (managePreeditCandidate)
|
||||||
|
set_candidate_labels(window, nk);
|
||||||
|
|
||||||
nk_layout_row_dynamic(nk, height - 250, 1);
|
nk_layout_row_dynamic(nk, height - 250, 1);
|
||||||
nk_edit_string(nk, NK_EDIT_BOX, boxBuffer, &boxLen, MAX_BUFFER_LEN, nk_filter_default);
|
nk_edit_string(nk, NK_EDIT_BOX, boxBuffer, &boxLen, MAX_BUFFER_LEN, nk_filter_default);
|
||||||
@ -768,7 +823,9 @@ int main(int argc, char** argv)
|
|||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
|
|
||||||
if (isAutoUpdatingCursorPosEnabled)
|
if (isAutoUpdatingCursorPosEnabled)
|
||||||
update_cursor_pos(window, nk, ¤tFont->handle, boxBuffer, boxLen);
|
// I don't know how to get the layout info of `nk_edit_string`.
|
||||||
|
update_cursor_pos(window, nk, ¤tFont->handle, boxBuffer, boxLen, 10,
|
||||||
|
managePreeditCandidate ? 385 : 220);
|
||||||
|
|
||||||
glfwWaitEvents();
|
glfwWaitEvents();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user