diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index be3dbd16..a402673f 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3457,62 +3457,64 @@ 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 position of the caret. * - * This function returns position hint to decide the candidate window. + * This function returns the position of the caret, in screen coordinates, + * relative to the upper-left corner of the client area of the specified + * 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 desired window. + * @param[out] xpos Where to store the caret x-coordinate, relative to the + * left edge of the client area, or `NULL`. + * @param[out] ypos Where to store the caret y-coordinate, relative to the to + * top edge of the client area, or `NULL`. + * @param[out] ypos Where to store the caret height, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_char * - * @since Added in GLFW 3.X. + * @since Added in version 3.3. * * @ingroup input */ -GLFWAPI void glfwGetPreeditCursorPos(GLFWwindow* window, int *x, int *y, int *h); +GLFWAPI void glfwGetPreeditCaretPos(GLFWwindow* window, int* xpos, int* ypos, int* height); -/*! @brief Notify the text cursor position to window system to decide the candidate window position. +/*! @brief Sets the caret position used to place the IME candidate window. * - * 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. + * This function teach position hint to decide the candidate window. The + * candidate window is a part of IME (Input Method Editor) and shows several + * candidate strings. * - * Windows sytems decide proper pisition from text cursor geometry. + * Windows sytems decide proper position from text cursor geometry. * You should call this function in preedit callback. * - * @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] window The window to set the caret position for. + * @param[in] xpos The x-coordinate of the caret within the window client area. + * @param[in] ypos The y-coordinate of the caret within the window client area. + * @param[in] height The height of the caret. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_char * - * @since Added in GLFW 3.X. + * @since Added in version 3.3. * * @ingroup input */ -GLFWAPI void glfwSetPreeditCursorPos(GLFWwindow* window, int x, int y, int h); +GLFWAPI void glfwSetPreeditCaretPos(GLFWwindow* window, int xpos, int ypos, int height); /*! @brief Reset IME input status. * * This function resets IME's preedit text. * - * @param[in] window The window. + * @param[in] window The desired window. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref preedit * - * @since Added in GLFW 3.X. + * @since Added in version 3.3. * * @ingroup input */ @@ -3634,11 +3636,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 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 + * attributed text blocks. This callback is used for on-the-spot text editing * with IME. * * @param[in] window The window whose callback to set. @@ -3647,12 +3649,11 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods * @return The previously set callback, or `NULL` if no callback was set or an * error occurred. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_char * - * @since Added in GLFW 3.X + * @since Added in version 3.3. * * @ingroup input */ @@ -3660,12 +3661,12 @@ 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. + * 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. + * The callback receives the relative position of the input caret inside + * preedit text and attributed text blocks. This callback is used for + * on-the-spot text editing with IME. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set @@ -3673,12 +3674,11 @@ GLFWAPI GLFWpreeditfun glfwSetPreeditCallback(GLFWwindow* window, GLFWpreeditfun * @return The previously set callback, or `NULL` if no callback was set or an * error occurred. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_char * - * @since Added in GLFW 3.X + * @since Added in version 3.3. * * @ingroup input */ diff --git a/src/cocoa_window.m b/src/cocoa_window.m index eb63d3c8..95516f94 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -717,55 +717,67 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; [markedText initWithAttributedString:string]; else [markedText initWithString:string]; + NSString* markedTextString = markedText.string; NSUInteger i, length = [markedTextString length]; int ctext = window->ctext; - while (ctext < length+1) { - ctext = (ctext == 0) ? 1 : ctext*2; - } - if (ctext != window->ctext) { - unsigned int* preeditText = realloc(window->preeditText, sizeof(unsigned int)*ctext); - if (preeditText == NULL) { + while (ctext < length + 1) + ctext = ctext ? ctext * 2 : 1; + + if (ctext != window->ctext) + { + unsigned int* preeditText = realloc(window->preeditText, sizeof(unsigned int) * ctext); + if (!preeditText) return; - } + window->preeditText = preeditText; window->ctext = ctext; } + window->ntext = length; window->preeditText[length] = 0; + for (i = 0; i < length; i++) { const unichar codepoint = [markedTextString characterAtIndex:i]; window->preeditText[i] = codepoint; } + int focusedBlock = 0; NSInteger offset = 0; + window->nblocks = 0; - while (offset < length) { + + while (offset < length) + { NSRange effectiveRange; - NSDictionary *attributes = [markedText attributesAtIndex:offset effectiveRange:&effectiveRange]; - - if (window->nblocks == window->cblocks) { + NSDictionary *attributes = [markedText attributesAtIndex:offset + effectiveRange:&effectiveRange]; + + if (window->nblocks == window->cblocks) + { int cblocks = window->cblocks * 2; - int* blocks = realloc(window->preeditAttributeBlocks, sizeof(int)*cblocks); - if (blocks == NULL) { + int* blocks = realloc(window->preeditAttributeBlocks, sizeof(int) * cblocks); + if (!blocks) return; - } + window->preeditAttributeBlocks = blocks; window->cblocks = cblocks; } + window->preeditAttributeBlocks[window->nblocks] = effectiveRange.length; offset += effectiveRange.length; - if (effectiveRange.length == 0) { + if (!effectiveRange.length) break; - } + NSNumber* underline = (NSNumber*) [attributes objectForKey:@"NSUnderline"]; - if ([underline intValue] != 1) { + if ([underline intValue] != 1) focusedBlock = window->nblocks; - } + window->nblocks++; } + _glfwInputPreedit(window, focusedBlock); } @@ -795,7 +807,10 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; { int xpos, ypos; _glfwPlatformGetWindowPos(window, &xpos, &ypos); - return NSMakeRect(xpos + window->preeditCursorPosX, transformY(ypos + window->preeditCursorPosY), 0.0, window->preeditCursorHeight); + return NSMakeRect(xpos + window->preeditCursorPosX, + transformY(ypos + window->preeditCursorPosY), + 0.0, + window->preeditCursorHeight); } - (void)insertText:(id)string replacementRange:(NSRange)replacementRange @@ -1796,48 +1811,66 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, void _glfwPlatformResetPreeditText(_GLFWwindow* window) { - NSTextInputContext *context = [NSTextInputContext currentInputContext]; + NSTextInputContext* context = [NSTextInputContext currentInputContext]; [context discardMarkedText]; [window->ns.view unmarkText]; } void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active) { - // Mac OS has several input sources. - // this code assumes input methods not in ascii capable inputs using IME. - NSArray* asciiInputSources = CFBridgingRelease(TISCreateASCIICapableInputSourceList()); - TISInputSourceRef asciiSource = (__bridge TISInputSourceRef)([asciiInputSources firstObject]); - if (active) { - NSArray* allInputSources = CFBridgingRelease(TISCreateInputSourceList(NULL, false)); - NSString* asciiSourceID = (__bridge NSString *)(TISGetInputSourceProperty(asciiSource, kTISPropertyInputSourceID)); - int i; - int count = [allInputSources count]; - for (i = 0; i < count; i++) { - TISInputSourceRef source = (__bridge TISInputSourceRef)([allInputSources objectAtIndex: i]); - NSString* sourceID = (__bridge NSString *)(TISGetInputSourceProperty(source, kTISPropertyInputSourceID)); - if ([asciiSourceID compare: sourceID] != NSOrderedSame) { + // NOTE: macOS has several input sources, this code assumes input methods + // not in ASCII capable inputs using IME + NSArray* asciiInputSources = + CFBridgingRelease(TISCreateASCIICapableInputSourceList()); + TISInputSourceRef asciiSource = (__bridge TISInputSourceRef) + [asciiInputSources firstObject]; + + if (active) + { + NSArray* allInputSources = + CFBridgingRelease(TISCreateInputSourceList(NULL, false)); + NSString* asciiSourceID = (__bridge NSString*) + TISGetInputSourceProperty(asciiSource, kTISPropertyInputSourceID); + int i, count = [allInputSources count]; + + for (i = 0; i < count; i++) + { + TISInputSourceRef source = (__bridge TISInputSourceRef) + [allInputSources objectAtIndex:i]; + NSString* sourceID = (__bridge NSString*) + TISGetInputSourceProperty(source, kTISPropertyInputSourceID); + if ([asciiSourceID compare: sourceID] != NSOrderedSame) + { TISSelectInputSource(source); break; } } - } else if (asciiSource) { - TISSelectInputSource(asciiSource); } + else if (asciiSource) + TISSelectInputSource(asciiSource); } int _glfwPlatformGetIMEStatus(_GLFWwindow* window) { TISInputSourceRef currentSource = TISCopyCurrentKeyboardInputSource(); - NSString* currentSourceID = (__bridge NSString *)(TISGetInputSourceProperty(currentSource, kTISPropertyInputSourceID)); - NSArray* asciiInputSources = CFBridgingRelease(TISCreateASCIICapableInputSourceList()); - TISInputSourceRef asciiSource = (__bridge TISInputSourceRef)([asciiInputSources firstObject]); - if (asciiSource) { - NSString* asciiSourceID = (__bridge NSString *)(TISGetInputSourceProperty(asciiSource, kTISPropertyInputSourceID)); - return ([asciiSourceID compare: currentSourceID] == NSOrderedSame) ? GLFW_FALSE : GLFW_TRUE; + NSString* currentSourceID = (__bridge NSString*) + TISGetInputSourceProperty(currentSource, kTISPropertyInputSourceID); + NSArray* asciiInputSources = + CFBridgingRelease(TISCreateASCIICapableInputSourceList()); + TISInputSourceRef asciiSource = (__bridge TISInputSourceRef) + [asciiInputSources firstObject]; + + if (asciiSource) + { + NSString* asciiSourceID = (__bridge NSString*) + TISGetInputSourceProperty(asciiSource, kTISPropertyInputSourceID); + return [asciiSourceID compare:currentSourceID] != NSOrderedSame; } + return GLFW_FALSE; } + ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// diff --git a/src/input.c b/src/input.c index dd8dfac1..1574dda3 100644 --- a/src/input.c +++ b/src/input.c @@ -81,16 +81,21 @@ void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWb void _glfwInputPreedit(_GLFWwindow* window, int focusedBlock) { - if (window->callbacks.preedit) { - window->callbacks.preedit((GLFWwindow*) window, window->ntext, window->preeditText, window->nblocks, window->preeditAttributeBlocks, focusedBlock); + if (window->callbacks.preedit) + { + window->callbacks.preedit((GLFWwindow*) window, + window->ntext, + window->preeditText, + window->nblocks, + window->preeditAttributeBlocks, + focusedBlock); } } void _glfwInputIMEStatus(_GLFWwindow* window) { - if (window->callbacks.imestatus) { + if (window->callbacks.imestatus) window->callbacks.imestatus((GLFWwindow*) window); - } } void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) @@ -264,7 +269,8 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) case GLFW_IME: _glfwPlatformSetIMEStatus(window, value ? GLFW_TRUE : GLFW_FALSE); - break; + break; + default: _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode); break; @@ -492,27 +498,47 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) _glfwPlatformSetCursor(window, cursor); } -GLFWAPI void glfwGetPreeditCursorPos(GLFWwindow* handle, int *x, int *y, int *h) +GLFWAPI void glfwGetPreeditCaretPos(GLFWwindow* handle, int* xpos, int* ypos, int* height) { _GLFWwindow* window = (_GLFWwindow*) handle; - if (x) - *x = window->preeditCursorPosX; - if (y) - *y = window->preeditCursorPosY; - if (h) - *h = window->preeditCursorHeight; + assert(window != NULL); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + if (height) + *height = 0; + + _GLFW_REQUIRE_INIT(); + + if (xpos) + *xpos = window->preeditCaretPosX; + if (ypos) + *ypos = window->preeditCaretPosY; + if (height) + *height = window->preeditCaretHeight; } -GLFWAPI void glfwSetPreeditCursorPos(GLFWwindow* handle, int x, int y, int h) +GLFWAPI void glfwSetPreeditCaretPos(GLFWwindow* handle, int xpos, int ypos, int height) { _GLFWwindow* window = (_GLFWwindow*) handle; - window->preeditCursorPosX = x; - window->preeditCursorPosY = y; - window->preeditCursorHeight = h; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + window->preeditCaretPosX = xpos; + window->preeditCaretPosY = ypos; + window->preeditCaretHeight = height; } -GLFWAPI void glfwResetPreeditText(GLFWwindow* handle) { +GLFWAPI void glfwResetPreeditText(GLFWwindow* handle) +{ _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + _glfwPlatformResetPreeditText(window); } diff --git a/src/internal.h b/src/internal.h index 5052cf1c..53c8fa0f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -381,7 +381,8 @@ struct _GLFWwindow int* preeditAttributeBlocks; int nblocks; int cblocks; - int preeditCursorPosX, preeditCursorPosY, preeditCursorHeight; + int preeditCaretPosX, preeditCaretPosY; + int preeditCaretHeight; _GLFWcontext context; @@ -835,9 +836,9 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* wind */ void _glfwPlatformResetPreeditText(_GLFWwindow* window); -/*! @brief Set IME status. +/*! @brief Sets whether the IME is enabled. * - * This function set IME status. + * This function sets whether the IME is enabled. * * @param[in] window The window. * @param[in] active Turns on IME if `GFLW_TRUE` is given. Otherwise (`GLFW_FALSE`) turns off. diff --git a/src/win32_window.c b/src/win32_window.c index 6b7cc568..d2c97845 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -424,12 +424,14 @@ static void releaseMonitor(_GLFWwindow* window) } // 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); +// +static void changeCaretPosition(HIMC imc, _GLFWwindow* window) +{ + const int x = window->preeditCaretPosX; + const int y = window->preeditCaretPosY; + const int h = window->preeditCaretHeight; + CANDIDATEFORM excludeRect = {0, CFS_EXCLUDE, {x, y}, {x, y, x, y + h}}; + ImmSetCandidateWindow(imc, &excludeRect); } // Window callback function (handles window messages) @@ -580,93 +582,118 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, break; } + case WM_IME_COMPOSITION: { - if (lParam & GCS_RESULTSTR) { + HIMC imc; + LONG preeditTextLength, attrLength, clauseLength; + + 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)malloc(sizeof(WCHAR)+preeditTextLength); - LPSTR attributes = (LPSTR)malloc(attrLength); - DWORD *clauses = (DWORD*)malloc(clauseLength); - 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 (!(lParam & GCS_COMPSTR)) + break; + + imc = ImmGetContext(hWnd); + preeditTextLength = ImmGetCompositionStringW(imc, GCS_COMPSTR, NULL, 0); + attrLength = ImmGetCompositionString(imc, GCS_COMPATTR, NULL, 0); + clauseLength = ImmGetCompositionString(imc, GCS_COMPCLAUSE, NULL, 0); + + if (preeditTextLength > 0) + { + // get preedit data + int i, ctext, cblocks, focusedBlock, length = preeditTextLength / sizeof(WCHAR); + LPWSTR buffer = malloc(sizeof(WCHAR) + preeditTextLength); + LPSTR attributes = malloc(attrLength); + DWORD* clauses = malloc(clauseLength); + + ImmGetCompositionStringW(imc, GCS_COMPSTR, buffer, preeditTextLength); + ImmGetCompositionString(imc, GCS_COMPATTR, attributes, attrLength); + ImmGetCompositionString(imc, GCS_COMPCLAUSE, clauses, clauseLength); + + // store preedit text + ctext = window->ctext; + while (ctext < length + 1) + ctext = ctext ? ctext * 2 : 1; + + if (ctext != window->ctext) + { + unsigned int* preeditText = realloc(window->preeditText, sizeof(unsigned int) * ctext); + if (!preeditText) + { + free(buffer); + free(attributes); + free(clauses); + return FALSE; } - if (ctext != window->ctext) { - unsigned int* preeditText = realloc(window->preeditText, sizeof(unsigned int)*ctext); - if (preeditText == NULL) { - return 0; - free(buffer); - free(attributes); - 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 = realloc(window->preeditAttributeBlocks, sizeof(int)*cblocks); - if (blocks == NULL) { - return 0; - free(buffer); - free(attributes); - 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; - } - } - free(buffer); - free(attributes); - free(clauses); - _glfwInputPreedit(window, focusedBlock); - _win32ChangeCursorPosition(hIMC, window); + + window->preeditText = preeditText; + window->ctext = ctext; } - ImmReleaseContext(hWnd, hIMC); - return TRUE; + + window->ntext = length; + window->preeditText[length] = 0; + 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; + cblocks = window->cblocks; + while (cblocks < window->nblocks) + cblocks = (cblocks == 0) ? 1 : cblocks * 2; + + if (cblocks != window->cblocks) + { + int* blocks = realloc(window->preeditAttributeBlocks, sizeof(int) * cblocks); + if (!blocks) + { + free(buffer); + free(attributes); + free(clauses); + return FALSE; + } + + window->preeditAttributeBlocks = blocks; + window->cblocks = cblocks; + } + + 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; + } + + free(buffer); + free(attributes); + free(clauses); + + _glfwInputPreedit(window, focusedBlock); + changeCaretPosition(imc, window); } - break; + + ImmReleaseContext(hWnd, imc); + return TRUE; } + case WM_IME_NOTIFY: + { if (wParam == IMN_SETOPENSTATUS) _glfwInputIMEStatus(window); + break; + } + case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: @@ -1803,29 +1830,27 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, void _glfwPlatformResetPreeditText(_GLFWwindow* window) { - HWND hWnd = window->win32.handle; - HIMC hIMC = ImmGetContext(hWnd); - ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); - ImmReleaseContext(hWnd, hIMC); + HIMC imc = ImmGetContext(window->win32.handle); + ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); + ImmReleaseContext(window->win32.handle, imc); } void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active) { - HWND hWnd = window->win32.handle; - HIMC hIMC = ImmGetContext(hWnd); - ImmSetOpenStatus(hIMC, active ? TRUE : FALSE); - ImmReleaseContext(hWnd, hIMC); + HIMC imc = ImmGetContext(window->win32.handle); + ImmSetOpenStatus(imc, active); + ImmReleaseContext(window->win32.handle, imc); } 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; + HIMC imc = ImmGetContext(window->win32.handle); + BOOL result = ImmGetOpenStatus(imc); + ImmReleaseContext(window->win32.handle, imc); + return result; } + ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// diff --git a/src/window.c b/src/window.c index 75b92764..c6ce32b1 100644 --- a/src/window.c +++ b/src/window.c @@ -231,9 +231,9 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, _glfwPlatformFocusWindow(window); } - window->preeditCursorPosX = 0; - window->preeditCursorPosY = height; - window->preeditCursorHeight = 0; + window->preeditCaretPosX = 0; + window->preeditCaretPosY = height; + window->preeditCaretHeight = 0; } return (GLFWwindow*) window; @@ -403,6 +403,9 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) _glfwPlatformDestroyWindow(window); + free(window->preeditText); + free(window->preeditAttributeBlocks); + // Unlink window from global linked list { _GLFWwindow** prev = &_glfw.windowListHead; @@ -412,11 +415,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) *prev = window->next; } - // Clear memory for preedit text - if (window->preeditText) - free(window->preeditText); - if (window->preeditAttributeBlocks) - free(window->preeditAttributeBlocks); + free(window); } diff --git a/tests/events.c b/tests/events.c index 5915078f..9a9c3e2b 100644 --- a/tests/events.c +++ b/tests/events.c @@ -420,40 +420,53 @@ static void char_mods_callback(GLFWwindow* window, unsigned int codepoint, int m get_mods_name(mods)); } -static void preedit_callback(GLFWwindow* window, int strLength, unsigned int* string, int blockLength, int* blocks, int focusedBlock) { +static void preedit_callback(GLFWwindow* window, + int strLength, + unsigned int* string, + int blockLength, + int* blocks, + int focusedBlock) +{ Slot* slot = glfwGetWindowUserPointer(window); int i, blockIndex = -1, blockCount = 0; int width, height; + printf("%08x to %i at %0.3f: Preedit text ", counter++, slot->number, glfwGetTime()); - if (strLength == 0 || blockLength == 0) { - printf("(empty)\n"); - } else { - for (i = 0; i < strLength; i++) { - if (blockCount == 0) { - if (blockIndex == focusedBlock) { + + if (strLength && blockLength) + { + for (i = 0; i < strLength; i++) + { + if (blockCount == 0) + { + if (blockIndex == focusedBlock) printf("]"); - } + blockIndex++; blockCount = blocks[blockIndex]; printf("\n block %d: ", blockIndex); - if (blockIndex == focusedBlock) { + if (blockIndex == focusedBlock) printf("["); - } } + printf("%s", get_character_string(string[i])); blockCount--; } - if (blockIndex == focusedBlock) { + + if (blockIndex == focusedBlock) printf("]"); - } + printf("\n"); glfwGetWindowSize(window, &width, &height); - glfwSetPreeditCursorPos(window, width/2, height/2, 20); + glfwSetPreeditCaretPos(window, width / 2, height / 2, 20); } + else + printf("(empty)\n"); } -static void ime_callback(GLFWwindow* window) { +static void ime_callback(GLFWwindow* window) +{ Slot* slot = glfwGetWindowUserPointer(window); printf("%08x to %i at %0.3f: IME switched\n", counter++, slot->number, glfwGetTime());