Cleanup
This commit is contained in:
parent
779b56276c
commit
0df386d06a
@ -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,8 +3636,8 @@ 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
|
||||||
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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);
|
unsigned int* preeditText = realloc(window->preeditText, sizeof(unsigned int) * ctext);
|
||||||
if (preeditText == NULL) {
|
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;
|
|
||||||
while (offset < length) {
|
|
||||||
NSRange effectiveRange;
|
|
||||||
NSDictionary *attributes = [markedText attributesAtIndex:offset effectiveRange:&effectiveRange];
|
|
||||||
|
|
||||||
if (window->nblocks == window->cblocks) {
|
window->nblocks = 0;
|
||||||
|
|
||||||
|
while (offset < length)
|
||||||
|
{
|
||||||
|
NSRange effectiveRange;
|
||||||
|
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);
|
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
|
||||||
@ -1803,41 +1818,59 @@ void _glfwPlatformResetPreeditText(_GLFWwindow* window)
|
|||||||
|
|
||||||
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 //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
58
src/input.c
58
src/input.c
@ -81,17 +81,22 @@ 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)
|
||||||
{
|
{
|
||||||
@ -265,6 +270,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
const int y = window->preeditCaretPosY;
|
||||||
|
const int h = window->preeditCaretHeight;
|
||||||
CANDIDATEFORM excludeRect = {0, CFS_EXCLUDE, {x, y}, {x, y, x, y + h}};
|
CANDIDATEFORM excludeRect = {0, CFS_EXCLUDE, {x, y}, {x, y, x, y + h}};
|
||||||
ImmSetCandidateWindow(hIMC, &excludeRect);
|
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);
|
||||||
|
clauseLength = ImmGetCompositionString(imc, GCS_COMPCLAUSE, NULL, 0);
|
||||||
|
|
||||||
|
if (preeditTextLength > 0)
|
||||||
|
{
|
||||||
// get preedit data
|
// get preedit data
|
||||||
int length = preeditTextLength/sizeof(WCHAR);
|
int i, ctext, cblocks, focusedBlock, length = preeditTextLength / sizeof(WCHAR);
|
||||||
LPWSTR buffer = (LPWSTR)malloc(sizeof(WCHAR)+preeditTextLength);
|
LPWSTR buffer = malloc(sizeof(WCHAR) + preeditTextLength);
|
||||||
LPSTR attributes = (LPSTR)malloc(attrLength);
|
LPSTR attributes = malloc(attrLength);
|
||||||
DWORD *clauses = (DWORD*)malloc(clauseLength);
|
DWORD* clauses = malloc(clauseLength);
|
||||||
ImmGetCompositionStringW(hIMC, GCS_COMPSTR, buffer, preeditTextLength);
|
|
||||||
ImmGetCompositionString(hIMC, GCS_COMPATTR, attributes, attrLength);
|
ImmGetCompositionStringW(imc, GCS_COMPSTR, buffer, preeditTextLength);
|
||||||
ImmGetCompositionString(hIMC, GCS_COMPCLAUSE, clauses, clauseLength);
|
ImmGetCompositionString(imc, GCS_COMPATTR, attributes, attrLength);
|
||||||
|
ImmGetCompositionString(imc, GCS_COMPCLAUSE, clauses, clauseLength);
|
||||||
|
|
||||||
// store preedit text
|
// store preedit text
|
||||||
int ctext = window->ctext;
|
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);
|
unsigned int* preeditText = realloc(window->preeditText, sizeof(unsigned int) * ctext);
|
||||||
if (preeditText == NULL) {
|
if (!preeditText)
|
||||||
return 0;
|
{
|
||||||
free(buffer);
|
free(buffer);
|
||||||
free(attributes);
|
free(attributes);
|
||||||
free(clauses);
|
free(clauses);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
int i;
|
for (i = 0; i < length; i++)
|
||||||
for (i=0; i < length; i++) {
|
|
||||||
window->preeditText[i] = buffer[i];
|
window->preeditText[i] = buffer[i];
|
||||||
}
|
|
||||||
// store blocks
|
// store blocks
|
||||||
window->nblocks = clauseLength / sizeof(DWORD) - 1;
|
window->nblocks = clauseLength / sizeof(DWORD) - 1;
|
||||||
|
|
||||||
// last element of clauses is a block count, but
|
// last element of clauses is a block count, but
|
||||||
// text length is convenient.
|
// text length is convenient.
|
||||||
clauses[window->nblocks] = length;
|
clauses[window->nblocks] = length;
|
||||||
int cblocks = window->cblocks;
|
cblocks = window->cblocks;
|
||||||
while (cblocks < window->nblocks) {
|
while (cblocks < window->nblocks)
|
||||||
cblocks = (cblocks == 0) ? 1 : cblocks * 2;
|
cblocks = (cblocks == 0) ? 1 : cblocks * 2;
|
||||||
}
|
|
||||||
if (cblocks != window->cblocks) {
|
if (cblocks != window->cblocks)
|
||||||
|
{
|
||||||
int* blocks = realloc(window->preeditAttributeBlocks, sizeof(int) * cblocks);
|
int* blocks = realloc(window->preeditAttributeBlocks, sizeof(int) * cblocks);
|
||||||
if (blocks == NULL) {
|
if (!blocks)
|
||||||
return 0;
|
{
|
||||||
free(buffer);
|
free(buffer);
|
||||||
free(attributes);
|
free(attributes);
|
||||||
free(clauses);
|
free(clauses);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
window->preeditAttributeBlocks = blocks;
|
window->preeditAttributeBlocks = blocks;
|
||||||
window->cblocks = cblocks;
|
window->cblocks = cblocks;
|
||||||
}
|
}
|
||||||
int focusedBlock = 0;
|
|
||||||
for (i=0; i < window->nblocks; i++) {
|
focusedBlock = 0;
|
||||||
|
for (i = 0; i < window->nblocks; i++)
|
||||||
|
{
|
||||||
window->preeditAttributeBlocks[i] = clauses[i + 1] - clauses[i];
|
window->preeditAttributeBlocks[i] = clauses[i + 1] - clauses[i];
|
||||||
if (attributes[clauses[i]] != ATTR_CONVERTED) {
|
if (attributes[clauses[i]] != ATTR_CONVERTED)
|
||||||
focusedBlock = i;
|
focusedBlock = i;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
free(attributes);
|
free(attributes);
|
||||||
free(clauses);
|
free(clauses);
|
||||||
|
|
||||||
_glfwInputPreedit(window, focusedBlock);
|
_glfwInputPreedit(window, focusedBlock);
|
||||||
_win32ChangeCursorPosition(hIMC, window);
|
changeCaretPosition(imc, window);
|
||||||
}
|
}
|
||||||
ImmReleaseContext(hWnd, hIMC);
|
|
||||||
|
ImmReleaseContext(hWnd, imc);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
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 //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
15
src/window.c
15
src/window.c
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
Loading…
Reference in New Issue
Block a user