mirror of
https://github.com/glfw/glfw.git
synced 2024-11-10 09:01:46 +00:00
Win32: Support IME
This commit re-organizes 9d9af132610829f295c34ceb81b17af8b567b76f. * Use dynamic load for Imm32. * Generalize platform-specific features to _GLFWplatform. * Add caret-position info to preedit-callback. * Add cursorWidth to preeditCursor and related APIs. * Handle UTF16 data correctly. * Handle GCS_RESULTSTR so that committed texts are processed correctly. * Handle WM_IME_ENDCOMPOSITION to clear preedit. * Handle WM_IME_SETCONTEXT. * https://learn.microsoft.com/en-us/windows/win32/intl/wm-ime-setcontext#remarks * Refactor code shapes and variable names. Co-authored-by: Takuro Ashie <ashie@clear-code.com>
This commit is contained in:
parent
2e30ad17fe
commit
9802d73c96
@ -1946,27 +1946,34 @@ typedef void (* GLFWcharfun)(GLFWwindow* window, unsigned int codepoint);
|
||||
*/
|
||||
typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int mods);
|
||||
|
||||
/*! @brief The function signature for preedit callbacks.
|
||||
/*! @brief The function pointer type for preedit callbacks.
|
||||
*
|
||||
* This is the function signature for preedit callback functions.
|
||||
* This is the function pointer type for preedit callback functions.
|
||||
*
|
||||
* @param[in] window The window that received the event.
|
||||
* @param[in] length Preedit string length.
|
||||
* @param[in] string Preedit string.
|
||||
* @param[in] count Attributed block count.
|
||||
* @param[in] blocksizes List of attributed block size.
|
||||
* @param[in] focusedblock Focused block index.
|
||||
* @param[in] preedit_count Preedit string count.
|
||||
* @param[in] preedit_string Preedit string.
|
||||
* @param[in] block_count Attributed block count.
|
||||
* @param[in] block_sizes List of attributed block size.
|
||||
* @param[in] focused_block Focused block index.
|
||||
* @param[in] caret Caret position.
|
||||
*
|
||||
* @sa @ref preedit
|
||||
* @sa glfwSetPreeditCallback
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef void (* GLFWpreeditfun)(GLFWwindow*,int,unsigned int*,int,int*,int);
|
||||
typedef void (* GLFWpreeditfun)(GLFWwindow* window,
|
||||
int preedit_count,
|
||||
unsigned int* preedit_string,
|
||||
int block_count,
|
||||
int* block_sizes,
|
||||
int focused_block,
|
||||
int caret);
|
||||
|
||||
/*! @brief The function signature for IME status change callbacks.
|
||||
/*! @brief The function pointer type for IME status change callbacks.
|
||||
*
|
||||
* This is the function signature for IME status change callback functions.
|
||||
* This is the function pointer type for IME status change callback functions.
|
||||
*
|
||||
* @param[in] window The window that received the event.
|
||||
*
|
||||
@ -1975,7 +1982,7 @@ typedef void (* GLFWpreeditfun)(GLFWwindow*,int,unsigned int*,int,int*,int);
|
||||
*
|
||||
* @ingroup monitor
|
||||
*/
|
||||
typedef void (* GLFWimestatusfun)(GLFWwindow*);
|
||||
typedef void (* GLFWimestatusfun)(GLFWwindow* window);
|
||||
|
||||
/*! @brief The function pointer type for path drop callbacks.
|
||||
*
|
||||
@ -4689,8 +4696,8 @@ GLFWAPI void glfwPostEmptyEvent(void);
|
||||
*
|
||||
* @param[in] window The window to query.
|
||||
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
|
||||
* `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or
|
||||
* `GLFW_RAW_MOUSE_MOTION`.
|
||||
* `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS`, `GLFW_RAW_MOUSE_MOTION`,
|
||||
* or `GLFW_IME`.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_INVALID_ENUM.
|
||||
@ -5192,14 +5199,16 @@ GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor);
|
||||
*/
|
||||
GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor);
|
||||
|
||||
/*! @brief Retrieves the position of the text cursor relative to the client area of window.
|
||||
/*! @brief Retrieves the area of the preedit text cursor.
|
||||
*
|
||||
* This function returns position hint to decide the candidate window.
|
||||
* This area is used to decide the position of the candidate window.
|
||||
* The cursor position is relative to the window.
|
||||
*
|
||||
* @param[in] window The window to set the text cursor for.
|
||||
* @param[out] x The text cursor x position (relative position from window coordinates).
|
||||
* @param[out] y The text cursor y position (relative position from window coordinates).
|
||||
* @param[out] h The text cursor height.
|
||||
* @param[in] window The window to set the preedit text cursor for.
|
||||
* @param[out] x The preedit text cursor x position (relative position from window coordinates).
|
||||
* @param[out] y The preedit text cursor y position (relative position from window coordinates).
|
||||
* @param[out] w The preedit text cursor width.
|
||||
* @param[out] h The preedit text cursor height.
|
||||
*
|
||||
* @par Thread Safety
|
||||
* This function may only be called from the main thread.
|
||||
@ -5210,20 +5219,18 @@ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor);
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI void glfwGetPreeditCursorPos(GLFWwindow* window, int *x, int *y, int *h);
|
||||
GLFWAPI void glfwGetPreeditCursorRectangle(GLFWwindow* window, int* x, int* y, int* w, int* h);
|
||||
|
||||
/*! @brief Notify the text cursor position to window system to decide the candidate window position.
|
||||
/*! @brief Sets the area of the preedit text cursor.
|
||||
*
|
||||
* This function teach position hint to decide the candidate window. The candidate window
|
||||
* is a part of IME(Input Method Editor) and show several candidate strings.
|
||||
*
|
||||
* Windows sytems decide proper pisition from text cursor geometry.
|
||||
* You should call this function in preedit callback.
|
||||
* This area is used to decide the position of the candidate window.
|
||||
* The cursor position is relative to the window.
|
||||
*
|
||||
* @param[in] window The window to set the text cursor for.
|
||||
* @param[in] x The text cursor x position (relative position from window coordinates).
|
||||
* @param[in] y The text cursor y position (relative position from window coordinates).
|
||||
* @param[in] h The text cursor height.
|
||||
* @param[in] x The preedit text cursor x position (relative position from window coordinates).
|
||||
* @param[in] y The preedit text cursor y position (relative position from window coordinates).
|
||||
* @param[in] w The preedit text cursor width.
|
||||
* @param[in] h The preedit text cursor height.
|
||||
*
|
||||
* @par Thread Safety
|
||||
* This function may only be called from the main thread.
|
||||
@ -5234,9 +5241,9 @@ GLFWAPI void glfwGetPreeditCursorPos(GLFWwindow* window, int *x, int *y, int *h)
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI void glfwSetPreeditCursorPos(GLFWwindow* window, int x, int y, int h);
|
||||
GLFWAPI void glfwSetPreeditCursorRectangle(GLFWwindow* window, int x, int y, int w, int h);
|
||||
|
||||
/*! @brief Reset IME input status.
|
||||
/*! @brief Resets IME input status.
|
||||
*
|
||||
* This function resets IME's preedit text.
|
||||
*
|
||||
@ -5390,11 +5397,11 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods
|
||||
|
||||
/*! @brief Sets the preedit callback.
|
||||
*
|
||||
* This function sets the preedit callback of the specified
|
||||
* window, which is called when an IME is processing text before commited.
|
||||
* This function sets the preedit callback of the specified
|
||||
* window, which is called when an IME is processing text before committed.
|
||||
*
|
||||
* Callback receives relative position of input cursor inside preedit text and
|
||||
* attributed text blocks. This callback is used for on-the-spot text editing
|
||||
* attributed text blocks. This callback is used for on-the-spot text editing
|
||||
* with IME.
|
||||
*
|
||||
* @param[in] window The window whose callback to set.
|
||||
@ -5403,6 +5410,19 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods
|
||||
* @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 preedit_count,
|
||||
unsigned int* preedit_string,
|
||||
int block_count,
|
||||
int* block_sizes,
|
||||
int focused_block,
|
||||
int caret)
|
||||
* @endcode
|
||||
* For more information about the callback parameters, see the
|
||||
* [function pointer type](@ref GLFWpreeditfun).
|
||||
*
|
||||
* @par Thread Safety
|
||||
* This function may only be called from the main thread.
|
||||
*
|
||||
@ -5416,12 +5436,8 @@ GLFWAPI GLFWpreeditfun glfwSetPreeditCallback(GLFWwindow* window, GLFWpreeditfun
|
||||
|
||||
/*! @brief Sets the IME status change callback.
|
||||
*
|
||||
* This function sets the preedit callback of the specified
|
||||
* window, which is called when an IME is processing text before commited.
|
||||
*
|
||||
* Callback receives relative position of input cursor inside preedit text and
|
||||
* attributed text blocks. This callback is used for on-the-spot text editing
|
||||
* with IME.
|
||||
* This function sets the IME status callback of the specified
|
||||
* window, which is called when an IME is switched on and off.
|
||||
*
|
||||
* @param[in] window The window whose callback to set.
|
||||
* @param[in] cbfun The new callback, or `NULL` to remove the currently set
|
||||
@ -5429,6 +5445,13 @@ GLFWAPI GLFWpreeditfun glfwSetPreeditCallback(GLFWwindow* window, GLFWpreeditfun
|
||||
* @return The previously set callback, or `NULL` if no callback was set or an
|
||||
* error occurred.
|
||||
*
|
||||
* @callback_signature
|
||||
* @code
|
||||
* void function_name(GLFWwindow* window)
|
||||
* @endcode
|
||||
* For more information about the callback parameters, see the
|
||||
* [function pointer type](@ref GLFWimestatusfun).
|
||||
*
|
||||
* @par Thread Safety
|
||||
* This function may only be called from the main thread.
|
||||
*
|
||||
|
@ -146,7 +146,6 @@ endif()
|
||||
|
||||
if (GLFW_BUILD_WIN32)
|
||||
list(APPEND glfw_PKG_LIBS "-lgdi32")
|
||||
list(APPEND glfw_LIBRARIES "imm32")
|
||||
endif()
|
||||
|
||||
if (GLFW_BUILD_COCOA)
|
||||
|
@ -509,6 +509,10 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform)
|
||||
.getKeyScancode = _glfwGetKeyScancodeCocoa,
|
||||
.setClipboardString = _glfwSetClipboardStringCocoa,
|
||||
.getClipboardString = _glfwGetClipboardStringCocoa,
|
||||
.updatePreeditCursorRectangle = _glfwUpdatePreeditCursorRectangleCocoa,
|
||||
.resetPreeditText = _glfwResetPreeditTextCocoa,
|
||||
.setIMEStatus = _glfwSetIMEStatusCocoa,
|
||||
.getIMEStatus = _glfwGetIMEStatusCocoa,
|
||||
.initJoysticks = _glfwInitJoysticksCocoa,
|
||||
.terminateJoysticks = _glfwTerminateJoysticksCocoa,
|
||||
.pollJoystick = _glfwPollJoystickCocoa,
|
||||
|
@ -268,6 +268,11 @@ void _glfwSetCursorCocoa(_GLFWwindow* window, _GLFWcursor* cursor);
|
||||
void _glfwSetClipboardStringCocoa(const char* string);
|
||||
const char* _glfwGetClipboardStringCocoa(void);
|
||||
|
||||
void _glfwUpdatePreeditCursorRectangleCocoa(_GLFWwindow* window);
|
||||
void _glfwResetPreeditTextCocoa(_GLFWwindow* window);
|
||||
void _glfwSetIMEStatusCocoa(_GLFWwindow* window, int active);
|
||||
int _glfwGetIMEStatusCocoa(_GLFWwindow* window);
|
||||
|
||||
EGLenum _glfwGetEGLPlatformCocoa(EGLint** attribs);
|
||||
EGLNativeDisplayType _glfwGetEGLNativeDisplayCocoa(void);
|
||||
EGLNativeWindowType _glfwGetEGLNativeWindowCocoa(_GLFWwindow* window);
|
||||
|
@ -1881,6 +1881,23 @@ const char* _glfwGetClipboardStringCocoa(void)
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
void _glfwUpdatePreeditCursorRectangleCocoa(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwResetPreeditTextCocoa(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwSetIMEStatusCocoa(_GLFWwindow* window, int active)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwGetIMEStatusCocoa(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
EGLenum _glfwGetEGLPlatformCocoa(EGLint** attribs)
|
||||
{
|
||||
if (_glfw.egl.ANGLE_platform_angle)
|
||||
|
62
src/input.c
62
src/input.c
@ -328,16 +328,29 @@ void _glfwInputChar(_GLFWwindow* window, uint32_t codepoint, int mods, GLFWbool
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwInputPreedit(_GLFWwindow* window, int focusedBlock)
|
||||
// Notifies shared code of a preedit event
|
||||
//
|
||||
void _glfwInputPreedit(_GLFWwindow* window)
|
||||
{
|
||||
if (window->callbacks.preedit) {
|
||||
window->callbacks.preedit((GLFWwindow*) window, window->ntext, window->preeditText, window->nblocks, window->preeditAttributeBlocks, focusedBlock);
|
||||
if (window->callbacks.preedit)
|
||||
{
|
||||
_GLFWpreedit *preedit = &window->preedit;
|
||||
window->callbacks.preedit((GLFWwindow*) window,
|
||||
preedit->textCount,
|
||||
preedit->text,
|
||||
preedit->blockSizesCount,
|
||||
preedit->blockSizes,
|
||||
preedit->focusedBlockIndex,
|
||||
preedit->caretIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Notifies shared code of a IME status event
|
||||
//
|
||||
void _glfwInputIMEStatus(_GLFWwindow* window)
|
||||
{
|
||||
if (window->callbacks.imestatus) {
|
||||
if (window->callbacks.imestatus)
|
||||
{
|
||||
window->callbacks.imestatus((GLFWwindow*) window);
|
||||
}
|
||||
}
|
||||
@ -595,7 +608,7 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
|
||||
case GLFW_UNLIMITED_MOUSE_BUTTONS:
|
||||
return window->disableMouseButtonLimit;
|
||||
case GLFW_IME:
|
||||
return _glfwPlatformGetIMEStatus(window);
|
||||
return _glfw.platform.getIMEStatus(window);
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
||||
@ -712,7 +725,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||
|
||||
case GLFW_IME:
|
||||
{
|
||||
_glfwPlatformSetIMEStatus(window, value ? GLFW_TRUE : GLFW_FALSE);
|
||||
_glfw.platform.setIMEStatus(window, value ? GLFW_TRUE : GLFW_FALSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -975,28 +988,45 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
|
||||
_glfw.platform.setCursor(window, cursor);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetPreeditCursorPos(GLFWwindow* handle, int *x, int *y, int *h)
|
||||
GLFWAPI void glfwGetPreeditCursorRectangle(GLFWwindow* handle, int* x, int* y, int* w, int* h)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFWpreedit* preedit = &window->preedit;
|
||||
if (x)
|
||||
*x = window->preeditCursorPosX;
|
||||
*x = preedit->cursorPosX;
|
||||
if (y)
|
||||
*y = window->preeditCursorPosY;
|
||||
*y = preedit->cursorPosY;
|
||||
if (w)
|
||||
*w = preedit->cursorWidth;
|
||||
if (h)
|
||||
*h = window->preeditCursorHeight;
|
||||
*h = preedit->cursorHeight;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetPreeditCursorPos(GLFWwindow* handle, int x, int y, int h)
|
||||
GLFWAPI void glfwSetPreeditCursorRectangle(GLFWwindow* handle, int x, int y, int w, int h)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
window->preeditCursorPosX = x;
|
||||
window->preeditCursorPosY = y;
|
||||
window->preeditCursorHeight = h;
|
||||
_GLFWpreedit* preedit = &window->preedit;
|
||||
|
||||
if (x == preedit->cursorPosX &&
|
||||
y == preedit->cursorPosY &&
|
||||
w == preedit->cursorWidth &&
|
||||
h == preedit->cursorHeight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
preedit->cursorPosX = x;
|
||||
preedit->cursorPosY = y;
|
||||
preedit->cursorWidth = w;
|
||||
preedit->cursorHeight = h;
|
||||
|
||||
_glfw.platform.updatePreeditCursorRectangle(window);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwResetPreeditText(GLFWwindow* handle) {
|
||||
GLFWAPI void glfwResetPreeditText(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_glfwPlatformResetPreeditText(window);
|
||||
_glfw.platform.resetPreeditText(window);
|
||||
}
|
||||
|
||||
GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
|
||||
|
@ -69,6 +69,7 @@ typedef struct _GLFWwndconfig _GLFWwndconfig;
|
||||
typedef struct _GLFWctxconfig _GLFWctxconfig;
|
||||
typedef struct _GLFWfbconfig _GLFWfbconfig;
|
||||
typedef struct _GLFWcontext _GLFWcontext;
|
||||
typedef struct _GLFWpreedit _GLFWpreedit;
|
||||
typedef struct _GLFWwindow _GLFWwindow;
|
||||
typedef struct _GLFWplatform _GLFWplatform;
|
||||
typedef struct _GLFWlibrary _GLFWlibrary;
|
||||
@ -525,6 +526,21 @@ struct _GLFWcontext
|
||||
GLFW_PLATFORM_CONTEXT_STATE
|
||||
};
|
||||
|
||||
// Preedit structure for Input Method Editor/Engine
|
||||
//
|
||||
struct _GLFWpreedit
|
||||
{
|
||||
unsigned int* text;
|
||||
int textCount;
|
||||
int textBufferCount;
|
||||
int* blockSizes;
|
||||
int blockSizesCount;
|
||||
int blockSizesBufferCount;
|
||||
int focusedBlockIndex;
|
||||
int caretIndex;
|
||||
int cursorPosX, cursorPosY, cursorWidth, cursorHeight;
|
||||
};
|
||||
|
||||
// Window and context structure
|
||||
//
|
||||
struct _GLFWwindow
|
||||
@ -561,17 +577,10 @@ struct _GLFWwindow
|
||||
double virtualCursorPosX, virtualCursorPosY;
|
||||
GLFWbool rawMouseMotion;
|
||||
|
||||
// Preedit texts
|
||||
unsigned int* preeditText;
|
||||
int ntext;
|
||||
int ctext;
|
||||
int* preeditAttributeBlocks;
|
||||
int nblocks;
|
||||
int cblocks;
|
||||
int preeditCursorPosX, preeditCursorPosY, preeditCursorHeight;
|
||||
|
||||
_GLFWcontext context;
|
||||
|
||||
_GLFWpreedit preedit;
|
||||
|
||||
struct {
|
||||
GLFWwindowposfun pos;
|
||||
GLFWwindowsizefun size;
|
||||
@ -710,6 +719,10 @@ struct _GLFWplatform
|
||||
int (*getKeyScancode)(int);
|
||||
void (*setClipboardString)(const char*);
|
||||
const char* (*getClipboardString)(void);
|
||||
void (*updatePreeditCursorRectangle)(_GLFWwindow*);
|
||||
void (*resetPreeditText)(_GLFWwindow*);
|
||||
void (*setIMEStatus)(_GLFWwindow*,int);
|
||||
int (*getIMEStatus)(_GLFWwindow*);
|
||||
GLFWbool (*initJoysticks)(void);
|
||||
void (*terminateJoysticks)(void);
|
||||
GLFWbool (*pollJoystick)(_GLFWjoystick*,int);
|
||||
@ -945,7 +958,7 @@ void _glfwInputKey(_GLFWwindow* window,
|
||||
int key, int scancode, int action, int mods);
|
||||
void _glfwInputChar(_GLFWwindow* window,
|
||||
uint32_t codepoint, int mods, GLFWbool plain);
|
||||
void _glfwInputPreedit(_GLFWwindow* window, int focusedBlock);
|
||||
void _glfwInputPreedit(_GLFWwindow* window);
|
||||
void _glfwInputIMEStatus(_GLFWwindow* window);
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset);
|
||||
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
||||
@ -967,9 +980,6 @@ void _glfwInputError(int code, const char* format, ...)
|
||||
void _glfwInputError(int code, const char* format, ...);
|
||||
#endif
|
||||
|
||||
void _glfwPlatformResetPreeditText(_GLFWwindow* window);
|
||||
void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active);
|
||||
int _glfwPlatformGetIMEStatus(_GLFWwindow* window);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
|
@ -55,6 +55,10 @@ GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform)
|
||||
.getKeyScancode = _glfwGetKeyScancodeNull,
|
||||
.setClipboardString = _glfwSetClipboardStringNull,
|
||||
.getClipboardString = _glfwGetClipboardStringNull,
|
||||
.updatePreeditCursorRectangle = _glfwUpdatePreeditCursorRectangleNull,
|
||||
.resetPreeditText = _glfwResetPreeditTextNull,
|
||||
.setIMEStatus = _glfwSetIMEStatusNull,
|
||||
.getIMEStatus = _glfwGetIMEStatusNull,
|
||||
.initJoysticks = _glfwInitJoysticksNull,
|
||||
.terminateJoysticks = _glfwTerminateJoysticksNull,
|
||||
.pollJoystick = _glfwPollJoystickNull,
|
||||
|
@ -270,6 +270,11 @@ const char* _glfwGetClipboardStringNull(void);
|
||||
const char* _glfwGetScancodeNameNull(int scancode);
|
||||
int _glfwGetKeyScancodeNull(int key);
|
||||
|
||||
void _glfwUpdatePreeditCursorRectangleNull(_GLFWwindow* window);
|
||||
void _glfwResetPreeditTextNull(_GLFWwindow* window);
|
||||
void _glfwSetIMEStatusNull(_GLFWwindow* window, int active);
|
||||
int _glfwGetIMEStatusNull(_GLFWwindow* window);
|
||||
|
||||
EGLenum _glfwGetEGLPlatformNull(EGLint** attribs);
|
||||
EGLNativeDisplayType _glfwGetEGLNativeDisplayNull(void);
|
||||
EGLNativeWindowType _glfwGetEGLNativeWindowNull(_GLFWwindow* window);
|
||||
|
@ -551,6 +551,23 @@ const char* _glfwGetClipboardStringNull(void)
|
||||
return _glfw.null.clipboardString;
|
||||
}
|
||||
|
||||
void _glfwUpdatePreeditCursorRectangleNull(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwResetPreeditTextNull(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwSetIMEStatusNull(_GLFWwindow* window, int active)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwGetIMEStatusNull(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
EGLenum _glfwGetEGLPlatformNull(EGLint** attribs)
|
||||
{
|
||||
if (_glfw.egl.EXT_platform_base && _glfw.egl.MESA_platform_surfaceless)
|
||||
|
@ -167,6 +167,29 @@ static GLFWbool loadLibraries(void)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo");
|
||||
}
|
||||
|
||||
_glfw.win32.imm32.instance = _glfwPlatformLoadModule("imm32.dll");
|
||||
if (_glfw.win32.imm32.instance)
|
||||
{
|
||||
_glfw.win32.imm32.ImmGetCompositionStringW_ = (PFN_ImmGetCompositionStringW)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmGetCompositionStringW");
|
||||
_glfw.win32.imm32.ImmGetContext_ = (PFN_ImmGetContext)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmGetContext");
|
||||
_glfw.win32.imm32.ImmGetConversionStatus_ = (PFN_ImmGetConversionStatus)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmGetConversionStatus");
|
||||
_glfw.win32.imm32.ImmGetDescriptionW_ = (PFN_ImmGetDescriptionW)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmGetDescriptionW");
|
||||
_glfw.win32.imm32.ImmGetOpenStatus_ = (PFN_ImmGetOpenStatus)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmGetOpenStatus");
|
||||
_glfw.win32.imm32.ImmNotifyIME_ = (PFN_ImmNotifyIME)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmNotifyIME");
|
||||
_glfw.win32.imm32.ImmReleaseContext_ = (PFN_ImmReleaseContext)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmReleaseContext");
|
||||
_glfw.win32.imm32.ImmSetCandidateWindow_ = (PFN_ImmSetCandidateWindow)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmSetCandidateWindow");
|
||||
_glfw.win32.imm32.ImmSetOpenStatus_ = (PFN_ImmSetOpenStatus)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.imm32.instance, "ImmSetOpenStatus");
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
@ -191,6 +214,9 @@ static void freeLibraries(void)
|
||||
|
||||
if (_glfw.win32.ntdll.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.ntdll.instance);
|
||||
|
||||
if (_glfw.win32.imm32.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.imm32.instance);
|
||||
}
|
||||
|
||||
// Create key code translation tables
|
||||
@ -618,6 +644,10 @@ GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform)
|
||||
.getKeyScancode = _glfwGetKeyScancodeWin32,
|
||||
.setClipboardString = _glfwSetClipboardStringWin32,
|
||||
.getClipboardString = _glfwGetClipboardStringWin32,
|
||||
.updatePreeditCursorRectangle = _glfwUpdatePreeditCursorRectangleWin32,
|
||||
.resetPreeditText = _glfwResetPreeditTextWin32,
|
||||
.setIMEStatus = _glfwSetIMEStatusWin32,
|
||||
.getIMEStatus = _glfwGetIMEStatusWin32,
|
||||
.initJoysticks = _glfwInitJoysticksWin32,
|
||||
.terminateJoysticks = _glfwTerminateJoysticksWin32,
|
||||
.pollJoystick = _glfwPollJoystickWin32,
|
||||
|
@ -69,6 +69,7 @@
|
||||
#include <dinput.h>
|
||||
#include <xinput.h>
|
||||
#include <dbt.h>
|
||||
#include <imm.h>
|
||||
|
||||
// HACK: Define macros that some windows.h variants don't
|
||||
#ifndef WM_MOUSEHWHEEL
|
||||
@ -316,6 +317,26 @@ typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,
|
||||
typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG);
|
||||
#define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_
|
||||
|
||||
// imm32 function pointer typedefs
|
||||
typedef LONG (WINAPI * PFN_ImmGetCompositionStringW)(HIMC,DWORD,LPVOID,DWORD);
|
||||
typedef HIMC (WINAPI * PFN_ImmGetContext)(HWND);
|
||||
typedef BOOL (WINAPI * PFN_ImmGetConversionStatus)(HIMC,LPDWORD,LPDWORD);
|
||||
typedef UINT (WINAPI * PFN_ImmGetDescriptionW)(HKL,LPWSTR,UINT);
|
||||
typedef BOOL (WINAPI * PFN_ImmGetOpenStatus)(HIMC);
|
||||
typedef BOOL (WINAPI * PFN_ImmNotifyIME)(HIMC,DWORD,DWORD,DWORD);
|
||||
typedef BOOL (WINAPI * PFN_ImmReleaseContext)(HWND,HIMC);
|
||||
typedef BOOL (WINAPI * PFN_ImmSetCandidateWindow)(HIMC,LPCANDIDATEFORM);
|
||||
typedef BOOL (WINAPI * PFN_ImmSetOpenStatus)(HIMC,BOOL);
|
||||
#define ImmGetCompositionStringW _glfw.win32.imm32.ImmGetCompositionStringW_
|
||||
#define ImmGetContext _glfw.win32.imm32.ImmGetContext_
|
||||
#define ImmGetConversionStatus _glfw.win32.imm32.ImmGetConversionStatus_
|
||||
#define ImmGetDescriptionW _glfw.win32.imm32.ImmGetDescriptionW_
|
||||
#define ImmGetOpenStatus _glfw.win32.imm32.ImmGetOpenStatus_
|
||||
#define ImmNotifyIME _glfw.win32.imm32.ImmNotifyIME_
|
||||
#define ImmReleaseContext _glfw.win32.imm32.ImmReleaseContext_
|
||||
#define ImmSetCandidateWindow _glfw.win32.imm32.ImmSetCandidateWindow_
|
||||
#define ImmSetOpenStatus _glfw.win32.imm32.ImmSetOpenStatus_
|
||||
|
||||
// WGL extension pointer typedefs
|
||||
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
|
||||
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
|
||||
@ -502,6 +523,19 @@ typedef struct _GLFWlibraryWin32
|
||||
HINSTANCE instance;
|
||||
PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_;
|
||||
} ntdll;
|
||||
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
PFN_ImmGetCompositionStringW ImmGetCompositionStringW_;
|
||||
PFN_ImmGetContext ImmGetContext_;
|
||||
PFN_ImmGetConversionStatus ImmGetConversionStatus_;
|
||||
PFN_ImmGetDescriptionW ImmGetDescriptionW_;
|
||||
PFN_ImmGetOpenStatus ImmGetOpenStatus_;
|
||||
PFN_ImmNotifyIME ImmNotifyIME_;
|
||||
PFN_ImmReleaseContext ImmReleaseContext_;
|
||||
PFN_ImmSetCandidateWindow ImmSetCandidateWindow_;
|
||||
PFN_ImmSetOpenStatus ImmSetOpenStatus_;
|
||||
} imm32;
|
||||
} _GLFWlibraryWin32;
|
||||
|
||||
// Win32-specific per-monitor data
|
||||
@ -596,6 +630,11 @@ void _glfwSetCursorWin32(_GLFWwindow* window, _GLFWcursor* cursor);
|
||||
void _glfwSetClipboardStringWin32(const char* string);
|
||||
const char* _glfwGetClipboardStringWin32(void);
|
||||
|
||||
void _glfwUpdatePreeditCursorRectangleWin32(_GLFWwindow* window);
|
||||
void _glfwResetPreeditTextWin32(_GLFWwindow* window);
|
||||
void _glfwSetIMEStatusWin32(_GLFWwindow* window, int active);
|
||||
int _glfwGetIMEStatusWin32(_GLFWwindow* window);
|
||||
|
||||
EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs);
|
||||
EGLNativeDisplayType _glfwGetEGLNativeDisplayWin32(void);
|
||||
EGLNativeWindowType _glfwGetEGLNativeWindowWin32(_GLFWwindow* window);
|
||||
|
@ -35,7 +35,41 @@
|
||||
#include <assert.h>
|
||||
#include <windowsx.h>
|
||||
#include <shellapi.h>
|
||||
#include <imm.h>
|
||||
|
||||
// Converts utf16 units to Unicode code points (UTF32).
|
||||
// Returns GLFW_TRUE when the converting completes and the result is assigned to
|
||||
// the argument `codepoint`.
|
||||
// Returns GLFW_FALSE when the converting is not yet completed (for
|
||||
// Surrogate-pair processing) and the unit is assigned to the argument
|
||||
// `highsurrogate`. It will be used in the next unit's processing.
|
||||
//
|
||||
static GLFWbool convertToUTF32FromUTF16(WCHAR utf16_unit,
|
||||
WCHAR* highsurrogate,
|
||||
uint32_t* codepoint)
|
||||
{
|
||||
*codepoint = 0;
|
||||
|
||||
if (utf16_unit >= 0xd800 && utf16_unit <= 0xdbff)
|
||||
{
|
||||
*highsurrogate = (WCHAR) utf16_unit;
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (utf16_unit >= 0xdc00 && utf16_unit <= 0xdfff)
|
||||
{
|
||||
if (*highsurrogate)
|
||||
{
|
||||
*codepoint += (*highsurrogate - 0xd800) << 10;
|
||||
*codepoint += (WCHAR) utf16_unit - 0xdc00;
|
||||
*codepoint += 0x10000;
|
||||
}
|
||||
}
|
||||
else
|
||||
*codepoint = (WCHAR) utf16_unit;
|
||||
|
||||
*highsurrogate = 0;
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Returns the window style for the specified window
|
||||
//
|
||||
@ -530,13 +564,205 @@ static void maximizeWindowManually(_GLFWwindow* window)
|
||||
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
}
|
||||
|
||||
// Set cursor position to decide candidate window
|
||||
static void _win32ChangeCursorPosition(HIMC hIMC, _GLFWwindow* window) {
|
||||
int x = window->preeditCursorPosX;
|
||||
int y = window->preeditCursorPosY;
|
||||
int h = window->preeditCursorHeight;
|
||||
CANDIDATEFORM excludeRect = {0, CFS_EXCLUDE, {x, y}, {x, y, x, y+h}};
|
||||
ImmSetCandidateWindow(hIMC, &excludeRect);
|
||||
// Get preedit texts of Imm32 and pass them to preedit-callback
|
||||
//
|
||||
static GLFWbool getImmPreedit(_GLFWwindow* window)
|
||||
{
|
||||
_GLFWpreedit* preedit = &window->preedit;
|
||||
HIMC hIMC = ImmGetContext(window->win32.handle);
|
||||
// get preedit data sizes
|
||||
LONG preeditBytes = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
|
||||
LONG attrBytes = ImmGetCompositionStringW(hIMC, GCS_COMPATTR, NULL, 0);
|
||||
LONG clauseBytes = ImmGetCompositionStringW(hIMC, GCS_COMPCLAUSE, NULL, 0);
|
||||
LONG cursorPos = ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, NULL, 0);
|
||||
|
||||
if (preeditBytes > 0)
|
||||
{
|
||||
int textBufferCount = preedit->textBufferCount;
|
||||
int blockBufferCount = preedit->blockSizesBufferCount;
|
||||
int textLen = preeditBytes / sizeof(WCHAR);
|
||||
LPWSTR buffer = _glfw_calloc(preeditBytes, 1);
|
||||
LPSTR attributes = _glfw_calloc(attrBytes, 1);
|
||||
DWORD* clauses = _glfw_calloc(clauseBytes, 1);
|
||||
|
||||
if (!buffer || (attrBytes > 0 && !attributes) || (clauseBytes > 0 && !clauses))
|
||||
{
|
||||
_glfw_free(buffer);
|
||||
_glfw_free(attributes);
|
||||
_glfw_free(clauses);
|
||||
ImmReleaseContext(window->win32.handle, hIMC);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
// get preedit data
|
||||
ImmGetCompositionStringW(hIMC, GCS_COMPSTR, buffer, preeditBytes);
|
||||
if (attributes)
|
||||
ImmGetCompositionStringW(hIMC, GCS_COMPATTR, attributes, attrBytes);
|
||||
if (clauses)
|
||||
ImmGetCompositionStringW(hIMC, GCS_COMPCLAUSE, clauses, clauseBytes);
|
||||
|
||||
// realloc preedit text
|
||||
while (textBufferCount < textLen + 1)
|
||||
textBufferCount = (textBufferCount == 0) ? 1 : textBufferCount * 2;
|
||||
if (textBufferCount != preedit->textBufferCount)
|
||||
{
|
||||
size_t bufsize = sizeof(unsigned int) * textBufferCount;
|
||||
unsigned int* preeditText = _glfw_realloc(preedit->text,
|
||||
bufsize);
|
||||
|
||||
if (preeditText == NULL)
|
||||
{
|
||||
_glfw_free(buffer);
|
||||
_glfw_free(attributes);
|
||||
_glfw_free(clauses);
|
||||
ImmReleaseContext(window->win32.handle, hIMC);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
preedit->text = preeditText;
|
||||
preedit->textBufferCount = textBufferCount;
|
||||
}
|
||||
|
||||
// realloc blocks
|
||||
preedit->blockSizesCount = clauses ? clauseBytes / sizeof(DWORD) - 1 : 1;
|
||||
while (blockBufferCount < preedit->blockSizesCount)
|
||||
blockBufferCount = (blockBufferCount == 0) ? 1 : blockBufferCount * 2;
|
||||
if (blockBufferCount != preedit->blockSizesBufferCount)
|
||||
{
|
||||
size_t bufsize = sizeof(int) * blockBufferCount;
|
||||
int* blocks = _glfw_realloc(preedit->blockSizes,
|
||||
bufsize);
|
||||
|
||||
if (blocks == NULL)
|
||||
{
|
||||
_glfw_free(buffer);
|
||||
_glfw_free(attributes);
|
||||
_glfw_free(clauses);
|
||||
ImmReleaseContext(window->win32.handle, hIMC);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
preedit->blockSizes = blocks;
|
||||
preedit->blockSizesBufferCount = blockBufferCount;
|
||||
}
|
||||
|
||||
// store preedit text & block sizes
|
||||
{
|
||||
// Win32 API handles text data in UTF16, so we have to convert them
|
||||
// to UTF32. Not only the encoding, but also the number of characters,
|
||||
// the position of each block and the cursor.
|
||||
int i;
|
||||
uint32_t codepoint;
|
||||
WCHAR highSurrogate = 0;
|
||||
int convertedLength = 0;
|
||||
int blockIndex = 0;
|
||||
int currentBlockLength = 0;
|
||||
|
||||
// The last element of clauses is a block count, but
|
||||
// text length is convenient.
|
||||
if (clauses)
|
||||
clauses[preedit->blockSizesCount] = textLen;
|
||||
|
||||
for (i = 0; i < textLen; i++)
|
||||
{
|
||||
if (clauses && clauses[blockIndex + 1] <= (DWORD) i)
|
||||
{
|
||||
preedit->blockSizes[blockIndex++] = currentBlockLength;
|
||||
currentBlockLength = 0;
|
||||
}
|
||||
|
||||
if (convertToUTF32FromUTF16(buffer[i],
|
||||
&highSurrogate,
|
||||
&codepoint))
|
||||
{
|
||||
preedit->text[convertedLength++] = codepoint;
|
||||
currentBlockLength++;
|
||||
}
|
||||
else if ((LONG) i < cursorPos)
|
||||
{
|
||||
// A high surrogate appears before cursorPos, so needs to
|
||||
// fix cursorPos on UTF16 for UTF32
|
||||
cursorPos--;
|
||||
}
|
||||
}
|
||||
preedit->blockSizes[blockIndex] = currentBlockLength;
|
||||
preedit->textCount = convertedLength;
|
||||
preedit->text[convertedLength] = 0;
|
||||
preedit->caretIndex = cursorPos;
|
||||
|
||||
preedit->focusedBlockIndex = 0;
|
||||
if (attributes && clauses)
|
||||
{
|
||||
for (i = 0; i < preedit->blockSizesCount; i++)
|
||||
{
|
||||
if (attributes[clauses[i]] == ATTR_TARGET_CONVERTED ||
|
||||
attributes[clauses[i]] == ATTR_TARGET_NOTCONVERTED)
|
||||
{
|
||||
preedit->focusedBlockIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_glfw_free(buffer);
|
||||
_glfw_free(attributes);
|
||||
_glfw_free(clauses);
|
||||
|
||||
_glfwInputPreedit(window);
|
||||
}
|
||||
|
||||
ImmReleaseContext(window->win32.handle, hIMC);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Clear peedit data
|
||||
//
|
||||
static void clearImmPreedit(_GLFWwindow* window)
|
||||
{
|
||||
window->preedit.blockSizesCount = 0;
|
||||
window->preedit.textCount = 0;
|
||||
window->preedit.focusedBlockIndex = 0;
|
||||
window->preedit.caretIndex = 0;
|
||||
_glfwInputPreedit(window);
|
||||
}
|
||||
|
||||
// Commit the result texts of Imm32 to character-callback
|
||||
//
|
||||
static GLFWbool commitImmResultStr(_GLFWwindow* window)
|
||||
{
|
||||
HIMC hIMC;
|
||||
LONG bytes;
|
||||
uint32_t codepoint;
|
||||
WCHAR highSurrogate = 0;
|
||||
|
||||
if (!window->callbacks.character)
|
||||
return GLFW_FALSE;
|
||||
|
||||
hIMC = ImmGetContext(window->win32.handle);
|
||||
// get preedit data sizes
|
||||
bytes = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
|
||||
|
||||
if (bytes > 0)
|
||||
{
|
||||
int i;
|
||||
int length = bytes / sizeof(WCHAR);
|
||||
LPWSTR buffer = _glfw_calloc(bytes, 1);
|
||||
|
||||
// get preedit data
|
||||
ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buffer, bytes);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
if (convertToUTF32FromUTF16(buffer[i],
|
||||
&highSurrogate,
|
||||
&codepoint))
|
||||
window->callbacks.character((GLFWwindow*) window, codepoint);
|
||||
}
|
||||
|
||||
_glfw_free(buffer);
|
||||
}
|
||||
|
||||
ImmReleaseContext(window->win32.handle, hIMC);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Window procedure for user-created windows
|
||||
@ -567,6 +793,14 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_IME_SETCONTEXT:
|
||||
{
|
||||
// To draw preedit text by an application side
|
||||
if (lParam & ISC_SHOWUICOMPOSITIONWINDOW)
|
||||
lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MOUSEACTIVATE:
|
||||
{
|
||||
// HACK: Postpone cursor disabling when the window was activated by
|
||||
@ -672,27 +906,11 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
case WM_CHAR:
|
||||
case WM_SYSCHAR:
|
||||
{
|
||||
if (wParam >= 0xd800 && wParam <= 0xdbff)
|
||||
window->win32.highSurrogate = (WCHAR) wParam;
|
||||
else
|
||||
{
|
||||
uint32_t codepoint = 0;
|
||||
|
||||
if (wParam >= 0xdc00 && wParam <= 0xdfff)
|
||||
{
|
||||
if (window->win32.highSurrogate)
|
||||
{
|
||||
codepoint += (window->win32.highSurrogate - 0xd800) << 10;
|
||||
codepoint += (WCHAR) wParam - 0xdc00;
|
||||
codepoint += 0x10000;
|
||||
}
|
||||
}
|
||||
else
|
||||
codepoint = (WCHAR) wParam;
|
||||
|
||||
window->win32.highSurrogate = 0;
|
||||
uint32_t codepoint;
|
||||
if (convertToUTF32FromUTF16((WCHAR) wParam,
|
||||
&window->win32.highSurrogate,
|
||||
&codepoint))
|
||||
_glfwInputChar(window, codepoint, getKeyMods(), uMsg != WM_SYSCHAR);
|
||||
}
|
||||
|
||||
if (uMsg == WM_SYSCHAR && window->win32.keymenu)
|
||||
break;
|
||||
@ -812,91 +1030,33 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
|
||||
case WM_IME_COMPOSITION:
|
||||
{
|
||||
if (lParam & GCS_RESULTSTR) {
|
||||
window->nblocks = 0;
|
||||
window->ntext = 0;
|
||||
_glfwInputPreedit(window, 0);
|
||||
return TRUE;
|
||||
}
|
||||
if (lParam & GCS_COMPSTR) {
|
||||
HIMC hIMC = ImmGetContext(hWnd);
|
||||
// get preedit data sizes
|
||||
LONG preeditTextLength = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
|
||||
LONG attrLength = ImmGetCompositionString(hIMC, GCS_COMPATTR, NULL, 0);
|
||||
LONG clauseLength = ImmGetCompositionString(hIMC, GCS_COMPCLAUSE, NULL, 0);
|
||||
if (preeditTextLength > 0) {
|
||||
// get preedit data
|
||||
int length = preeditTextLength/sizeof(WCHAR);
|
||||
LPWSTR buffer = (LPWSTR)_glfw_calloc(preeditTextLength, sizeof(WCHAR));
|
||||
LPSTR attributes = (LPSTR)_glfw_calloc(attrLength, 1);
|
||||
DWORD *clauses = (DWORD*)_glfw_calloc(clauseLength, 1);
|
||||
ImmGetCompositionStringW(hIMC, GCS_COMPSTR, buffer, preeditTextLength);
|
||||
ImmGetCompositionString(hIMC, GCS_COMPATTR, attributes, attrLength);
|
||||
ImmGetCompositionString(hIMC, GCS_COMPCLAUSE, clauses, clauseLength);
|
||||
// store preedit text
|
||||
int ctext = window->ctext;
|
||||
while (ctext < length+1) {
|
||||
ctext = (ctext == 0) ? 1 : ctext*2;
|
||||
}
|
||||
if (ctext != window->ctext) {
|
||||
unsigned int* preeditText = _glfw_realloc(window->preeditText, sizeof(unsigned int)*ctext);
|
||||
if (preeditText == NULL) {
|
||||
return 0;
|
||||
_glfw_free(buffer);
|
||||
_glfw_free(attributes);
|
||||
_glfw_free(clauses);
|
||||
}
|
||||
window->preeditText = preeditText;
|
||||
window->ctext = ctext;
|
||||
}
|
||||
window->ntext = length;
|
||||
window->preeditText[length] = 0;
|
||||
int i;
|
||||
for (i=0; i < length; i++) {
|
||||
window->preeditText[i] = buffer[i];
|
||||
}
|
||||
// store blocks
|
||||
window->nblocks = clauseLength/sizeof(DWORD)-1;
|
||||
// last element of clauses is a block count, but
|
||||
// text length is convenient.
|
||||
clauses[window->nblocks] = length;
|
||||
int cblocks = window->cblocks;
|
||||
while (cblocks < window->nblocks) {
|
||||
cblocks = (cblocks == 0) ? 1 : cblocks*2;
|
||||
}
|
||||
if (cblocks != window->cblocks) {
|
||||
int* blocks = _glfw_realloc(window->preeditAttributeBlocks, sizeof(int)*cblocks);
|
||||
if (blocks == NULL) {
|
||||
return 0;
|
||||
_glfw_free(buffer);
|
||||
_glfw_free(attributes);
|
||||
_glfw_free(clauses);
|
||||
}
|
||||
window->preeditAttributeBlocks = blocks;
|
||||
window->cblocks = cblocks;
|
||||
}
|
||||
int focusedBlock = 0;
|
||||
for (i=0; i < window->nblocks; i++) {
|
||||
window->preeditAttributeBlocks[i] = clauses[i+1]-clauses[i];
|
||||
if (attributes[clauses[i]] != ATTR_CONVERTED) {
|
||||
focusedBlock = i;
|
||||
}
|
||||
}
|
||||
_glfw_free(buffer);
|
||||
_glfw_free(attributes);
|
||||
_glfw_free(clauses);
|
||||
_glfwInputPreedit(window, focusedBlock);
|
||||
_win32ChangeCursorPosition(hIMC, window);
|
||||
}
|
||||
ImmReleaseContext(hWnd, hIMC);
|
||||
if (lParam & (GCS_RESULTSTR | GCS_COMPSTR))
|
||||
{
|
||||
if (lParam & GCS_RESULTSTR)
|
||||
commitImmResultStr(window);
|
||||
if (lParam & GCS_COMPSTR)
|
||||
getImmPreedit(window);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_IME_ENDCOMPOSITION:
|
||||
{
|
||||
clearImmPreedit(window);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case WM_IME_NOTIFY:
|
||||
{
|
||||
if (wParam == IMN_SETOPENSTATUS)
|
||||
{
|
||||
_glfwInputIMEStatus(window);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN:
|
||||
@ -2560,6 +2720,48 @@ const char* _glfwGetClipboardStringWin32(void)
|
||||
return _glfw.win32.clipboardString;
|
||||
}
|
||||
|
||||
void _glfwUpdatePreeditCursorRectangleWin32(_GLFWwindow* window)
|
||||
{
|
||||
_GLFWpreedit* preedit = &window->preedit;
|
||||
HWND hWnd = window->win32.handle;
|
||||
HIMC hIMC = ImmGetContext(hWnd);
|
||||
|
||||
int x = preedit->cursorPosX;
|
||||
int y = preedit->cursorPosY;
|
||||
int w = preedit->cursorWidth;
|
||||
int h = preedit->cursorHeight;
|
||||
CANDIDATEFORM excludeRect = { 0, CFS_EXCLUDE, { x, y }, { x, y, x + w, y + h } };
|
||||
|
||||
ImmSetCandidateWindow(hIMC, &excludeRect);
|
||||
|
||||
ImmReleaseContext(hWnd, hIMC);
|
||||
}
|
||||
|
||||
void _glfwResetPreeditTextWin32(_GLFWwindow* window)
|
||||
{
|
||||
HWND hWnd = window->win32.handle;
|
||||
HIMC hIMC = ImmGetContext(hWnd);
|
||||
ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||||
ImmReleaseContext(hWnd, hIMC);
|
||||
}
|
||||
|
||||
void _glfwSetIMEStatusWin32(_GLFWwindow* window, int active)
|
||||
{
|
||||
HWND hWnd = window->win32.handle;
|
||||
HIMC hIMC = ImmGetContext(hWnd);
|
||||
ImmSetOpenStatus(hIMC, active ? TRUE : FALSE);
|
||||
ImmReleaseContext(hWnd, hIMC);
|
||||
}
|
||||
|
||||
int _glfwGetIMEStatusWin32(_GLFWwindow* window)
|
||||
{
|
||||
HWND hWnd = window->win32.handle;
|
||||
HIMC hIMC = ImmGetContext(hWnd);
|
||||
BOOL result = ImmGetOpenStatus(hIMC);
|
||||
ImmReleaseContext(hWnd, hIMC);
|
||||
return result ? GLFW_TRUE : GLFW_FALSE;
|
||||
}
|
||||
|
||||
EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs)
|
||||
{
|
||||
if (_glfw.egl.ANGLE_platform_angle)
|
||||
@ -2672,31 +2874,6 @@ VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance,
|
||||
return err;
|
||||
}
|
||||
|
||||
void _glfwPlatformResetPreeditText(_GLFWwindow* window)
|
||||
{
|
||||
HWND hWnd = window->win32.handle;
|
||||
HIMC hIMC = ImmGetContext(hWnd);
|
||||
ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||||
ImmReleaseContext(hWnd, hIMC);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active)
|
||||
{
|
||||
HWND hWnd = window->win32.handle;
|
||||
HIMC hIMC = ImmGetContext(hWnd);
|
||||
ImmSetOpenStatus(hIMC, active ? TRUE : FALSE);
|
||||
ImmReleaseContext(hWnd, hIMC);
|
||||
}
|
||||
|
||||
int _glfwPlatformGetIMEStatus(_GLFWwindow* window)
|
||||
{
|
||||
HWND hWnd = window->win32.handle;
|
||||
HIMC hIMC = ImmGetContext(hWnd);
|
||||
BOOL result = ImmGetOpenStatus(hIMC);
|
||||
ImmReleaseContext(hWnd, hIMC);
|
||||
return result ? GLFW_TRUE : GLFW_FALSE;
|
||||
}
|
||||
|
||||
GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
13
src/window.c
13
src/window.c
@ -244,6 +244,11 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
||||
window->denom = GLFW_DONT_CARE;
|
||||
window->title = _glfw_strdup(title);
|
||||
|
||||
window->preedit.cursorPosX = 0;
|
||||
window->preedit.cursorPosY = height;
|
||||
window->preedit.cursorWidth = 0;
|
||||
window->preedit.cursorHeight = 0;
|
||||
|
||||
if (!_glfw.platform.createWindow(window, &wndconfig, &ctxconfig, &fbconfig))
|
||||
{
|
||||
glfwDestroyWindow((GLFWwindow*) window);
|
||||
@ -496,10 +501,10 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
|
||||
}
|
||||
|
||||
// Clear memory for preedit text
|
||||
if (window->preeditText)
|
||||
_glfw_free(window->preeditText);
|
||||
if (window->preeditAttributeBlocks)
|
||||
_glfw_free(window->preeditAttributeBlocks);
|
||||
if (window->preedit.text)
|
||||
_glfw_free(window->preedit.text);
|
||||
if (window->preedit.blockSizes)
|
||||
_glfw_free(window->preedit.blockSizes);
|
||||
_glfw_free(window->title);
|
||||
_glfw_free(window);
|
||||
}
|
||||
|
@ -452,6 +452,10 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
|
||||
.getKeyScancode = _glfwGetKeyScancodeWayland,
|
||||
.setClipboardString = _glfwSetClipboardStringWayland,
|
||||
.getClipboardString = _glfwGetClipboardStringWayland,
|
||||
.updatePreeditCursorRectangle = _glfwUpdatePreeditCursorRectangleWayland,
|
||||
.resetPreeditText = _glfwResetPreeditTextWayland,
|
||||
.setIMEStatus = _glfwSetIMEStatusWayland,
|
||||
.getIMEStatus = _glfwGetIMEStatusWayland,
|
||||
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
|
||||
.initJoysticks = _glfwInitJoysticksLinux,
|
||||
.terminateJoysticks = _glfwTerminateJoysticksLinux,
|
||||
|
@ -664,6 +664,11 @@ void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor);
|
||||
void _glfwSetClipboardStringWayland(const char* string);
|
||||
const char* _glfwGetClipboardStringWayland(void);
|
||||
|
||||
void _glfwUpdatePreeditCursorRectangleWayland(_GLFWwindow* window);
|
||||
void _glfwResetPreeditTextWayland(_GLFWwindow* window);
|
||||
void _glfwSetIMEStatusWayland(_GLFWwindow* window, int active);
|
||||
int _glfwGetIMEStatusWayland(_GLFWwindow* window);
|
||||
|
||||
EGLenum _glfwGetEGLPlatformWayland(EGLint** attribs);
|
||||
EGLNativeDisplayType _glfwGetEGLNativeDisplayWayland(void);
|
||||
EGLNativeWindowType _glfwGetEGLNativeWindowWayland(_GLFWwindow* window);
|
||||
|
@ -3195,6 +3195,23 @@ const char* _glfwGetClipboardStringWayland(void)
|
||||
return _glfw.wl.clipboardString;
|
||||
}
|
||||
|
||||
void _glfwUpdatePreeditCursorRectangleWayland(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwResetPreeditTextWayland(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwSetIMEStatusWayland(_GLFWwindow* window, int active)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwGetIMEStatusWayland(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
EGLenum _glfwGetEGLPlatformWayland(EGLint** attribs)
|
||||
{
|
||||
if (_glfw.egl.EXT_platform_base && _glfw.egl.EXT_platform_wayland)
|
||||
|
@ -1182,6 +1182,10 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
|
||||
.getKeyScancode = _glfwGetKeyScancodeX11,
|
||||
.setClipboardString = _glfwSetClipboardStringX11,
|
||||
.getClipboardString = _glfwGetClipboardStringX11,
|
||||
.updatePreeditCursorRectangle = _glfwUpdatePreeditCursorRectangleX11,
|
||||
.resetPreeditText = _glfwResetPreeditTextX11,
|
||||
.setIMEStatus = _glfwSetIMEStatusX11,
|
||||
.getIMEStatus = _glfwGetIMEStatusX11,
|
||||
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
|
||||
.initJoysticks = _glfwInitJoysticksLinux,
|
||||
.terminateJoysticks = _glfwTerminateJoysticksLinux,
|
||||
|
@ -955,6 +955,11 @@ void _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor);
|
||||
void _glfwSetClipboardStringX11(const char* string);
|
||||
const char* _glfwGetClipboardStringX11(void);
|
||||
|
||||
void _glfwUpdatePreeditCursorRectangleX11(_GLFWwindow* window);
|
||||
void _glfwResetPreeditTextX11(_GLFWwindow* window);
|
||||
void _glfwSetIMEStatusX11(_GLFWwindow* window, int active);
|
||||
int _glfwGetIMEStatusX11(_GLFWwindow* window);
|
||||
|
||||
EGLenum _glfwGetEGLPlatformX11(EGLint** attribs);
|
||||
EGLNativeDisplayType _glfwGetEGLNativeDisplayX11(void);
|
||||
EGLNativeWindowType _glfwGetEGLNativeWindowX11(_GLFWwindow* window);
|
||||
|
@ -3084,6 +3084,23 @@ const char* _glfwGetClipboardStringX11(void)
|
||||
return getSelectionString(_glfw.x11.CLIPBOARD);
|
||||
}
|
||||
|
||||
void _glfwUpdatePreeditCursorRectangleX11(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwResetPreeditTextX11(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwSetIMEStatusX11(_GLFWwindow* window, int active)
|
||||
{
|
||||
}
|
||||
|
||||
int _glfwGetIMEStatusX11(_GLFWwindow* window)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
EGLenum _glfwGetEGLPlatformX11(EGLint** attribs)
|
||||
{
|
||||
if (_glfw.egl.ANGLE_platform_angle)
|
||||
|
Loading…
Reference in New Issue
Block a user