Camilla Löwy 8 gadi atpakaļ
vecāks
revīzija
0df386d06a
7 mainītis faili ar 310 papildinājumiem un 213 dzēšanām
  1. 40 40
      include/GLFW/glfw3.h
  2. 74 41
      src/cocoa_window.m
  3. 43 17
      src/input.c
  4. 4 3
      src/internal.h
  5. 115 90
      src/win32_window.c
  6. 7 8
      src/window.c
  7. 27 14
      tests/events.c

+ 40 - 40
include/GLFW/glfw3.h

@@ -3457,62 +3457,64 @@ GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor);
  */
  */
 GLFWAPI void glfwSetCursor(GLFWwindow* window, 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
  *  @sa @ref input_char
  *
  *
- *  @since Added in GLFW 3.X.
+ *  @since Added in version 3.3.
  *
  *
  *  @ingroup input
  *  @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.
  *  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
  *  @sa @ref input_char
  *
  *
- *  @since Added in GLFW 3.X.
+ *  @since Added in version 3.3.
  *
  *
  *  @ingroup input
  *  @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.
 /*! @brief Reset IME input status.
  *
  *
  *  This function resets IME's preedit text.
  *  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
  *  @sa @ref preedit
  *
  *
- *  @since Added in GLFW 3.X.
+ *  @since Added in version 3.3.
  *
  *
  *  @ingroup input
  *  @ingroup input
  */
  */
@@ -3634,11 +3636,11 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods
 
 
 /*! @brief Sets the preedit callback.
 /*! @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
  *  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.
  *  with IME.
  *
  *
  *  @param[in] window The window whose callback to set.
  *  @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
  *  @return The previously set callback, or `NULL` if no callback was set or an
  *  error occurred.
  *  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
  *  @sa @ref input_char
  *
  *
- *  @since Added in GLFW 3.X
+ *  @since Added in version 3.3.
  *
  *
  *  @ingroup input
  *  @ingroup input
  */
  */
@@ -3660,12 +3661,12 @@ GLFWAPI GLFWpreeditfun glfwSetPreeditCallback(GLFWwindow* window, GLFWpreeditfun
 
 
 /*! @brief Sets the IME status change callback.
 /*! @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] window The window whose callback to set.
  *  @param[in] cbfun The new callback, or `NULL` to remove the currently 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
  *  @return The previously set callback, or `NULL` if no callback was set or an
  *  error occurred.
  *  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
  *  @sa @ref input_char
  *
  *
- *  @since Added in GLFW 3.X
+ *  @since Added in version 3.3.
  *
  *
  *  @ingroup input
  *  @ingroup input
  */
  */

+ 74 - 41
src/cocoa_window.m

@@ -717,55 +717,67 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
         [markedText initWithAttributedString:string];
         [markedText initWithAttributedString:string];
     else
     else
         [markedText initWithString:string];
         [markedText initWithString:string];
+
     NSString* markedTextString = markedText.string;
     NSString* markedTextString = markedText.string;
 
 
     NSUInteger i, length = [markedTextString length];
     NSUInteger i, length = [markedTextString length];
     int ctext = window->ctext;
     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;
             return;
-        }
+
         window->preeditText = preeditText;
         window->preeditText = preeditText;
         window->ctext = ctext;
         window->ctext = ctext;
     }
     }
+
     window->ntext = length;
     window->ntext = length;
     window->preeditText[length] = 0;
     window->preeditText[length] = 0;
+
     for (i = 0;  i < length;  i++)
     for (i = 0;  i < length;  i++)
     {
     {
         const unichar codepoint = [markedTextString characterAtIndex:i];
         const unichar codepoint = [markedTextString characterAtIndex:i];
         window->preeditText[i] = codepoint;
         window->preeditText[i] = codepoint;
     }
     }
+
     int focusedBlock = 0;
     int focusedBlock = 0;
     NSInteger offset = 0;
     NSInteger offset = 0;
+
     window->nblocks = 0;
     window->nblocks = 0;
-    while (offset < length) {
+
+    while (offset < length)
+    {
         NSRange effectiveRange;
         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 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;
                 return;
-            }
+
             window->preeditAttributeBlocks = blocks;
             window->preeditAttributeBlocks = blocks;
             window->cblocks = cblocks;
             window->cblocks = cblocks;
         }
         }
+
         window->preeditAttributeBlocks[window->nblocks] = effectiveRange.length;
         window->preeditAttributeBlocks[window->nblocks] = effectiveRange.length;
         offset += effectiveRange.length;
         offset += effectiveRange.length;
-        if (effectiveRange.length == 0) {
+        if (!effectiveRange.length)
             break;
             break;
-        }
+
         NSNumber* underline = (NSNumber*) [attributes objectForKey:@"NSUnderline"];
         NSNumber* underline = (NSNumber*) [attributes objectForKey:@"NSUnderline"];
-        if ([underline intValue] != 1) {
+        if ([underline intValue] != 1)
             focusedBlock = window->nblocks;
             focusedBlock = window->nblocks;
-        }
+
         window->nblocks++;
         window->nblocks++;
     }
     }
+
     _glfwInputPreedit(window, focusedBlock);
     _glfwInputPreedit(window, focusedBlock);
 }
 }
 
 
@@ -795,7 +807,10 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 {
 {
     int xpos, ypos;
     int xpos, ypos;
     _glfwPlatformGetWindowPos(window, &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
 - (void)insertText:(id)string replacementRange:(NSRange)replacementRange
@@ -1796,48 +1811,66 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
 
 
 void _glfwPlatformResetPreeditText(_GLFWwindow* window)
 void _glfwPlatformResetPreeditText(_GLFWwindow* window)
 {
 {
-    NSTextInputContext *context = [NSTextInputContext currentInputContext];
+    NSTextInputContext* context = [NSTextInputContext currentInputContext];
     [context discardMarkedText];
     [context discardMarkedText];
     [window->ns.view unmarkText];
     [window->ns.view unmarkText];
 }
 }
 
 
 void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active)
 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);
                 TISSelectInputSource(source);
                 break;
                 break;
             }
             }
         }
         }
-    } else if (asciiSource) {
-        TISSelectInputSource(asciiSource);
     }
     }
+    else if (asciiSource)
+        TISSelectInputSource(asciiSource);
 }
 }
 
 
 int _glfwPlatformGetIMEStatus(_GLFWwindow* window)
 int _glfwPlatformGetIMEStatus(_GLFWwindow* window)
 {
 {
     TISInputSourceRef currentSource = TISCopyCurrentKeyboardInputSource();
     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;
     return GLFW_FALSE;
 }
 }
 
 
+
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 //////                        GLFW native API                       //////
 //////                        GLFW native API                       //////
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////

+ 43 - 17
src/input.c

@@ -81,16 +81,21 @@ void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWb
 
 
 void _glfwInputPreedit(_GLFWwindow* window, int focusedBlock)
 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)
 void _glfwInputIMEStatus(_GLFWwindow* window)
 {
 {
-    if (window->callbacks.imestatus) {
+    if (window->callbacks.imestatus)
         window->callbacks.imestatus((GLFWwindow*) window);
         window->callbacks.imestatus((GLFWwindow*) window);
-    }
 }
 }
 
 
 void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
 void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
@@ -264,7 +269,8 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
 
 
         case GLFW_IME:
         case GLFW_IME:
             _glfwPlatformSetIMEStatus(window, value ? GLFW_TRUE : GLFW_FALSE);
             _glfwPlatformSetIMEStatus(window, value ? GLFW_TRUE : GLFW_FALSE);
-            break;    
+            break;
+
         default:
         default:
             _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode);
             _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode);
             break;
             break;
@@ -492,27 +498,47 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
     _glfwPlatformSetCursor(window, cursor);
     _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;
     _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;
     _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;
     _GLFWwindow* window = (_GLFWwindow*) handle;
+    assert(window != NULL);
+
+    _GLFW_REQUIRE_INIT();
+
     _glfwPlatformResetPreeditText(window);
     _glfwPlatformResetPreeditText(window);
 }
 }
 
 

+ 4 - 3
src/internal.h

@@ -381,7 +381,8 @@ struct _GLFWwindow
     int*                preeditAttributeBlocks;
     int*                preeditAttributeBlocks;
     int                 nblocks;
     int                 nblocks;
     int                 cblocks;
     int                 cblocks;
-    int                 preeditCursorPosX, preeditCursorPosY, preeditCursorHeight;
+    int                 preeditCaretPosX, preeditCaretPosY;
+    int                 preeditCaretHeight;
 
 
     _GLFWcontext        context;
     _GLFWcontext        context;
 
 
@@ -835,9 +836,9 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* wind
  */
  */
 void _glfwPlatformResetPreeditText(_GLFWwindow* window);
 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] window The window.
  *  @param[in] active Turns on IME if `GFLW_TRUE` is given. Otherwise (`GLFW_FALSE`) turns off.
  *  @param[in] active Turns on IME if `GFLW_TRUE` is given. Otherwise (`GLFW_FALSE`) turns off.

+ 115 - 90
src/win32_window.c

@@ -424,12 +424,14 @@ static void releaseMonitor(_GLFWwindow* window)
 }
 }
 
 
 // Set cursor position to decide candidate 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)
 // Window callback function (handles window messages)
@@ -580,93 +582,118 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
 
 
             break;
             break;
         }
         }
+
         case WM_IME_COMPOSITION:
         case WM_IME_COMPOSITION:
         {
         {
-            if (lParam & GCS_RESULTSTR) {
+            HIMC imc;
+            LONG preeditTextLength, attrLength, clauseLength;
+
+            if (lParam & GCS_RESULTSTR)
+            {
                 window->nblocks = 0;
                 window->nblocks = 0;
                 window->ntext = 0;
                 window->ntext = 0;
                 _glfwInputPreedit(window, 0);
                 _glfwInputPreedit(window, 0);
                 return TRUE;
                 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 (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;
+
+            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;
                     }
                     }
-                    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;
-                        }
+
+                    window->preeditText = preeditText;
+                    window->ctext = ctext;
+                }
+
+                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;
                     }
                     }
-                    free(buffer);
-                    free(attributes);
-                    free(clauses);
-                    _glfwInputPreedit(window, focusedBlock);
-                    _win32ChangeCursorPosition(hIMC, window);
+
+                    window->preeditAttributeBlocks = blocks;
+                    window->cblocks = cblocks;
                 }
                 }
-                ImmReleaseContext(hWnd, hIMC);
-                return TRUE;
+
+                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:
         case WM_IME_NOTIFY:
+        {
             if (wParam == IMN_SETOPENSTATUS)
             if (wParam == IMN_SETOPENSTATUS)
                 _glfwInputIMEStatus(window);
                 _glfwInputIMEStatus(window);
+
             break;
             break;
+        }
+
         case WM_LBUTTONDOWN:
         case WM_LBUTTONDOWN:
         case WM_RBUTTONDOWN:
         case WM_RBUTTONDOWN:
         case WM_MBUTTONDOWN:
         case WM_MBUTTONDOWN:
@@ -1803,29 +1830,27 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
 
 
 void _glfwPlatformResetPreeditText(_GLFWwindow* window)
 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)
 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)
 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                       //////
 //////                        GLFW native API                       //////
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////

+ 7 - 8
src/window.c

@@ -231,9 +231,9 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
                 _glfwPlatformFocusWindow(window);
                 _glfwPlatformFocusWindow(window);
         }
         }
 
 
-        window->preeditCursorPosX = 0;
-        window->preeditCursorPosY = height;
-        window->preeditCursorHeight = 0;
+        window->preeditCaretPosX = 0;
+        window->preeditCaretPosY = height;
+        window->preeditCaretHeight = 0;
     }
     }
 
 
     return (GLFWwindow*) window;
     return (GLFWwindow*) window;
@@ -403,6 +403,9 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
 
 
     _glfwPlatformDestroyWindow(window);
     _glfwPlatformDestroyWindow(window);
 
 
+    free(window->preeditText);
+    free(window->preeditAttributeBlocks);
+
     // Unlink window from global linked list
     // Unlink window from global linked list
     {
     {
         _GLFWwindow** prev = &_glfw.windowListHead;
         _GLFWwindow** prev = &_glfw.windowListHead;
@@ -412,11 +415,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
 
 
         *prev = window->next;
         *prev = window->next;
     }
     }
-    // Clear memory for preedit text
-    if (window->preeditText)
-        free(window->preeditText);
-    if (window->preeditAttributeBlocks)
-        free(window->preeditAttributeBlocks);
+
     free(window);
     free(window);
 }
 }
 
 

+ 27 - 14
tests/events.c

@@ -420,40 +420,53 @@ static void char_mods_callback(GLFWwindow* window, unsigned int codepoint, int m
             get_mods_name(mods));
             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);
     Slot* slot = glfwGetWindowUserPointer(window);
     int i, blockIndex = -1, blockCount = 0;
     int i, blockIndex = -1, blockCount = 0;
     int width, height;
     int width, height;
+
     printf("%08x to %i at %0.3f: Preedit text ",
     printf("%08x to %i at %0.3f: Preedit text ",
            counter++, slot->number, glfwGetTime());
            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("]");
                     printf("]");
-                }
+
                 blockIndex++;
                 blockIndex++;
                 blockCount = blocks[blockIndex];
                 blockCount = blocks[blockIndex];
                 printf("\n   block %d: ", blockIndex);
                 printf("\n   block %d: ", blockIndex);
-                if (blockIndex == focusedBlock) {
+                if (blockIndex == focusedBlock)
                     printf("[");
                     printf("[");
-                }
             }
             }
+
             printf("%s", get_character_string(string[i]));
             printf("%s", get_character_string(string[i]));
             blockCount--;
             blockCount--;
         }
         }
-        if (blockIndex == focusedBlock) {
+
+        if (blockIndex == focusedBlock)
             printf("]");
             printf("]");
-        }
+
         printf("\n");
         printf("\n");
         glfwGetWindowSize(window, &width, &height);
         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);
     Slot* slot = glfwGetWindowUserPointer(window);
     printf("%08x to %i at %0.3f: IME switched\n",
     printf("%08x to %i at %0.3f: IME switched\n",
            counter++, slot->number, glfwGetTime());
            counter++, slot->number, glfwGetTime());