This commit is contained in:
Camilla Löwy 2016-12-05 14:56:45 +01:00
parent 779b56276c
commit 0df386d06a
7 changed files with 311 additions and 214 deletions

View File

@ -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[in] window The desired window.
* @param[out] x The text cursor x position (relative position from window coordinates). * @param[out] xpos Where to store the caret x-coordinate, relative to the
* @param[out] y The text cursor y position (relative position from window coordinates). * left edge of the client area, or `NULL`.
* @param[out] h The text cursor height. * @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 * @thread_safety This function must only be called from the main thread.
* This function may 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 * This function teach position hint to decide the candidate window. The
* is a part of IME(Input Method Editor) and show several candidate strings. * 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] window The window to set the caret position for.
* @param[in] x The text cursor x position (relative position from window coordinates). * @param[in] xpos The x-coordinate of the caret within the window client area.
* @param[in] y The text cursor y position (relative position from window coordinates). * @param[in] ypos The y-coordinate of the caret within the window client area.
* @param[in] h The text cursor height. * @param[in] height The height of the caret.
* *
* @par Thread Safety * @thread_safety This function must only be called from the main thread.
* This function may 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 * @thread_safety This function must only be called from the main thread.
* This function may 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 * This function sets the preedit callback of the specified window, which is
* window, which is called when an IME is processing text before commited. * 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 * @thread_safety This function must only be called from the main thread.
* This function may 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 * This function sets the preedit callback of the specified window, which is
* window, which is called when an IME is processing text before commited. * called when an IME is processing text before commited.
* *
* Callback receives relative position of input cursor inside preedit text and * The callback receives the relative position of the input caret inside
* attributed text blocks. This callback is used for on-the-spot text editing * preedit text and attributed text blocks. This callback is used for
* with IME. * 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 * @thread_safety This function must only be called from the main thread.
* This function may 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
*/ */

View File

@ -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) { while (ctext < length + 1)
ctext = (ctext == 0) ? 1 : ctext*2; ctext = ctext ? ctext * 2 : 1;
}
if (ctext != window->ctext) { if (ctext != window->ctext)
unsigned int* preeditText = realloc(window->preeditText, sizeof(unsigned int)*ctext); {
if (preeditText == NULL) { 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]; NSDictionary *attributes = [markedText attributesAtIndex:offset
effectiveRange:&effectiveRange];
if (window->nblocks == window->cblocks) {
if (window->nblocks == window->cblocks)
{
int cblocks = window->cblocks * 2; int cblocks = window->cblocks * 2;
int* blocks = realloc(window->preeditAttributeBlocks, sizeof(int)*cblocks); int* blocks = realloc(window->preeditAttributeBlocks, sizeof(int) * cblocks);
if (blocks == NULL) { 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. // NOTE: macOS has several input sources, this code assumes input methods
// this code assumes input methods not in ascii capable inputs using IME. // not in ASCII capable inputs using IME
NSArray* asciiInputSources = CFBridgingRelease(TISCreateASCIICapableInputSourceList()); NSArray* asciiInputSources =
TISInputSourceRef asciiSource = (__bridge TISInputSourceRef)([asciiInputSources firstObject]); CFBridgingRelease(TISCreateASCIICapableInputSourceList());
if (active) { TISInputSourceRef asciiSource = (__bridge TISInputSourceRef)
NSArray* allInputSources = CFBridgingRelease(TISCreateInputSourceList(NULL, false)); [asciiInputSources firstObject];
NSString* asciiSourceID = (__bridge NSString *)(TISGetInputSourceProperty(asciiSource, kTISPropertyInputSourceID));
int i; if (active)
int count = [allInputSources count]; {
for (i = 0; i < count; i++) { NSArray* allInputSources =
TISInputSourceRef source = (__bridge TISInputSourceRef)([allInputSources objectAtIndex: i]); CFBridgingRelease(TISCreateInputSourceList(NULL, false));
NSString* sourceID = (__bridge NSString *)(TISGetInputSourceProperty(source, kTISPropertyInputSourceID)); NSString* asciiSourceID = (__bridge NSString*)
if ([asciiSourceID compare: sourceID] != NSOrderedSame) { 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)); NSString* currentSourceID = (__bridge NSString*)
NSArray* asciiInputSources = CFBridgingRelease(TISCreateASCIICapableInputSourceList()); TISGetInputSourceProperty(currentSource, kTISPropertyInputSourceID);
TISInputSourceRef asciiSource = (__bridge TISInputSourceRef)([asciiInputSources firstObject]); NSArray* asciiInputSources =
if (asciiSource) { CFBridgingRelease(TISCreateASCIICapableInputSourceList());
NSString* asciiSourceID = (__bridge NSString *)(TISGetInputSourceProperty(asciiSource, kTISPropertyInputSourceID)); TISInputSourceRef asciiSource = (__bridge TISInputSourceRef)
return ([asciiSourceID compare: currentSourceID] == NSOrderedSame) ? GLFW_FALSE : GLFW_TRUE; [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 //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -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) { if (window->callbacks.preedit)
window->callbacks.preedit((GLFWwindow*) window, window->ntext, window->preeditText, window->nblocks, window->preeditAttributeBlocks, focusedBlock); {
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) assert(window != NULL);
*x = window->preeditCursorPosX;
if (y) if (xpos)
*y = window->preeditCursorPosY; *xpos = 0;
if (h) if (ypos)
*h = window->preeditCursorHeight; *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; assert(window != NULL);
window->preeditCursorPosY = y;
window->preeditCursorHeight = h; _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);
} }

View File

@ -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.

View File

@ -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; static void changeCaretPosition(HIMC imc, _GLFWwindow* window)
int y = window->preeditCursorPosY; {
int h = window->preeditCursorHeight; const int x = window->preeditCaretPosX;
CANDIDATEFORM excludeRect = {0, CFS_EXCLUDE, {x, y}, {x, y, x, y+h}}; const int y = window->preeditCaretPosY;
ImmSetCandidateWindow(hIMC, &excludeRect); 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); if (!(lParam & GCS_COMPSTR))
// get preedit data sizes break;
LONG preeditTextLength = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
LONG attrLength = ImmGetCompositionString(hIMC, GCS_COMPATTR, NULL, 0); imc = ImmGetContext(hWnd);
LONG clauseLength = ImmGetCompositionString(hIMC, GCS_COMPCLAUSE, NULL, 0); preeditTextLength = ImmGetCompositionStringW(imc, GCS_COMPSTR, NULL, 0);
if (preeditTextLength > 0) { attrLength = ImmGetCompositionString(imc, GCS_COMPATTR, NULL, 0);
// get preedit data clauseLength = ImmGetCompositionString(imc, GCS_COMPCLAUSE, NULL, 0);
int length = preeditTextLength/sizeof(WCHAR);
LPWSTR buffer = (LPWSTR)malloc(sizeof(WCHAR)+preeditTextLength); if (preeditTextLength > 0)
LPSTR attributes = (LPSTR)malloc(attrLength); {
DWORD *clauses = (DWORD*)malloc(clauseLength); // get preedit data
ImmGetCompositionStringW(hIMC, GCS_COMPSTR, buffer, preeditTextLength); int i, ctext, cblocks, focusedBlock, length = preeditTextLength / sizeof(WCHAR);
ImmGetCompositionString(hIMC, GCS_COMPATTR, attributes, attrLength); LPWSTR buffer = malloc(sizeof(WCHAR) + preeditTextLength);
ImmGetCompositionString(hIMC, GCS_COMPCLAUSE, clauses, clauseLength); LPSTR attributes = malloc(attrLength);
// store preedit text DWORD* clauses = malloc(clauseLength);
int ctext = window->ctext;
while (ctext < length+1) { ImmGetCompositionStringW(imc, GCS_COMPSTR, buffer, preeditTextLength);
ctext = (ctext == 0) ? 1 : ctext*2; 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); window->preeditText = preeditText;
if (preeditText == NULL) { window->ctext = ctext;
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);
} }
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: 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 imc = ImmGetContext(window->win32.handle);
HIMC hIMC = ImmGetContext(hWnd); ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); ImmReleaseContext(window->win32.handle, imc);
ImmReleaseContext(hWnd, hIMC);
} }
void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active) void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active)
{ {
HWND hWnd = window->win32.handle; HIMC imc = ImmGetContext(window->win32.handle);
HIMC hIMC = ImmGetContext(hWnd); ImmSetOpenStatus(imc, active);
ImmSetOpenStatus(hIMC, active ? TRUE : FALSE); ImmReleaseContext(window->win32.handle, imc);
ImmReleaseContext(hWnd, hIMC);
} }
int _glfwPlatformGetIMEStatus(_GLFWwindow* window) int _glfwPlatformGetIMEStatus(_GLFWwindow* window)
{ {
HWND hWnd = window->win32.handle; HIMC imc = ImmGetContext(window->win32.handle);
HIMC hIMC = ImmGetContext(hWnd); BOOL result = ImmGetOpenStatus(imc);
BOOL result = ImmGetOpenStatus(hIMC); ImmReleaseContext(window->win32.handle, imc);
ImmReleaseContext(hWnd, hIMC); return result;
return result ? GLFW_TRUE : GLFW_FALSE;
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -231,9 +231,9 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
_glfwPlatformFocusWindow(window); _glfwPlatformFocusWindow(window);
} }
window->preeditCursorPosX = 0; window->preeditCaretPosX = 0;
window->preeditCursorPosY = height; window->preeditCaretPosY = height;
window->preeditCursorHeight = 0; 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);
} }

View File

@ -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"); if (strLength && blockLength)
} else { {
for (i = 0; i < strLength; i++) { for (i = 0; i < strLength; i++)
if (blockCount == 0) { {
if (blockIndex == focusedBlock) { 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());