This commit is contained in:
Camilla Löwy 2016-12-05 18:14:04 +01:00
parent 0df386d06a
commit ed59b80cc7
10 changed files with 270 additions and 300 deletions

View File

@ -226,7 +226,7 @@ endif()
if (_GLFW_WIN32) if (_GLFW_WIN32)
list(APPEND glfw_PKG_LIBS "-lgdi32") list(APPEND glfw_PKG_LIBS "-lgdi32")
list(APPEND glfw_LIBRARIES "imm32") list(APPEND glfw_LIBRARIES "-limm32")
if (GLFW_USE_HYBRID_HPG) if (GLFW_USE_HYBRID_HPG)
set(_GLFW_USE_HYBRID_HPG 1) set(_GLFW_USE_HYBRID_HPG 1)

View File

@ -206,35 +206,42 @@ void charmods_callback(GLFWwindow* window, unsigned int codepoint, int mods)
} }
@endcode @endcode
@subsection preedit IME Support
All desktop operating systems support IME (Input Method Editor) to input characters @subsection preedit IME support
that are not mapped with physical keys. IME have been popular among Eeastern Asian people.
And some operating systems start supporting voice input via IME mechanism.
GLFW provides IME support functions to help All modern operating systems provide a
you implement better text input features. You should add suitable visualization code for [IME](https://en.wikipedia.org/wiki/Input_method) (Input Method Editor)
preedit text. mechanism to input character sets that cannot be mapped to physical keys, such
as [CJK characters](https://en.wikipedia.org/wiki/CJK_characters) (Chinese,
Japanese, Korean). Some operating systems also support speech-to-text input via
the IME mechanism.
GLFW provides IME support functions to help you implement better text input
features. You should add suitable visualization code for pre-edit text.
IME works in front of actual character input events (@ref input_char). IME works in front of actual character input events (@ref input_char).
If your application uses text input and you want to support IME, If your application uses text input and you want to support IME, you should
you should register preedit callback to receive preedit text before committed. register pre-edit callback to receive pre-edit text before committed.
@code @code
glfwSetPreeditCallback(window, preedit_callback); glfwSetPreeditCallback(window, preedit_callback);
@endcode @endcode
The callback function receives chunk of text and focused block information. The callback function receives the pre-edit text and block information.
@code @code
static void preedit_callback(GLFWwindow* window, int strLength, unsigned int* string, int blockLength, int* blocks, int focusedBlock) { static void preedit_callback(GLFWwindow* window, unsigned int* codepoints, int blockCount, int* blocks, int focusedBlock)
{
} }
@endcode @endcode
strLength and string parameter reprsent whole preedit text. Each character of the preedit string is a codepoint like @ref input_char. The codepoints parameter contains the whole pre-edit text. Each character of the
pre-edit string is a Unicode codepoint like with @ref input_char.
If you want to type the text "寿司(sushi)", Usually the callback is called several times like the following sequence: If you want to type the text "寿司" (sushi), usually the callback is called
several times like the following sequence:
@code
-# key event: s -# key event: s
-# preedit: [string: "", block: [1], focusedBlock: 0] -# preedit: [string: "", block: [1], focusedBlock: 0]
-# key event: u -# key event: u
@ -250,52 +257,61 @@ If you want to type the text "寿司(sushi)", Usually the callback is called sev
-# char: '寿' -# char: '寿'
-# char: '司' -# char: '司'
-# preedit: [string: "", block: [], focusedBlock: 0] -# preedit: [string: "", block: [], focusedBlock: 0]
@endcode
If preedit text includes several semantic blocks, preedit callbacks returns several blocks after a space key pressed: If pre-edit text includes several semantic blocks, pre-edit callbacks returns
several blocks after a space key pressed:
@code
-# preedit: [string: "わたしはすしをたべます", block: [11], focusedBlock: 0] -# preedit: [string: "わたしはすしをたべます", block: [11], focusedBlock: 0]
-# preedit: [string: "私は寿司を食べます", block: [2, 7], focusedBlock: 1] -# preedit: [string: "私は寿司を食べます", block: [2, 7], focusedBlock: 1]
@endcode
"blocks" is a list of block length. The above case, it contains the following blocks and second block is focused. "blocks" is a list of block length. The above case, it contains the following
blocks and second block is focused.
@code
- 私は - 私は
- [寿司を食べます] - [寿司を食べます]
commited text(passed via regular @ref input_char event), unfocused block, focused block should have different text style.
GLFW provides helper function to teach suitable position of the candidate window to window system.
Window system decides the best position from text cursor geometry (x, y coords and height). You should call this function
in the above preedit text callback function.
@code
glfwSetPreeditCursorPos(window, x, y, h);
glfwGetPreeditCursorPos(window, &x, &y, &h);
@endcode @endcode
Sometimes IME task is interrupted by user or application. There are several functions to support these situation. committed text (passed via regular @ref input_char event), unfocused block,
You can receive notification about IME status change(on/off) by using the following function: focused block should have different text style.
GLFW provides helper function to teach suitable position of the candidate window
to window system. Window system decides the best position from text cursor
geometry (window coordinates and height). You should call this function in the
above pre-edit text callback function.
@code @code
glfwSetIMEStatusCallback(window, imestatus_callback); int xpos, ypos, height;
glfwSetPreeditCursorPos(window, xpos, ypos, height);
glfwGetPreeditCursorPos(window, &xpos, &ypos, &height);
@endcode @endcode
imestatus_callback has simple sigunature like this: Sometimes IME task is interrupted by user or application. There are several
functions to support these situation. You can receive notification about IME
status change(on/off) by using the following function:
@code @code
static void imestatus_callback(GLFWwindow* window) { glfwSetIMEStatusCallback(window, ime_status_callback);
@endcode
The ime_status_callback has simple signature like this:
@code
static void ime_status_callback(GLFWwindow* window)
{
} }
@endcode @endcode
You can implement the code that resets or commits preedit text when IME status is changed and preedit text is not empty. You can implement the code that resets or commits pre-edit text when IME status
is changed and pre-edit text is not empty.
When the focus is gone from text box, you can use the following functions to reset IME status: When the focus is gone from text box, you can use @ref glfwSetInputMode, @ref
glfwGetInputMode with the `GLFW_IME` mode and the @ref glfwResetPreeditText
function.
@code
void glfwResetPreeditText(GLFWwindow* window);
void glfwSetIMEStatus(GLFWwindow* window, int active)
int glfwGetIMEStatus(GLFWwindow* window)
@endcode
@subsection input_key_name Key names @subsection input_key_name Key names

View File

@ -1106,7 +1106,6 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int);
* This is the function signature for preedit callback functions. * This is the function signature for preedit callback functions.
* *
* @param[in] window The window that received the event. * @param[in] window The window that received the event.
* @param[in] length Preedit string length.
* @param[in] string Preedit string. * @param[in] string Preedit string.
* @param[in] count Attributed block count. * @param[in] count Attributed block count.
* @param[in] blocksizes List of attributed block size. * @param[in] blocksizes List of attributed block size.
@ -1117,7 +1116,7 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int);
* *
* @ingroup input * @ingroup input
*/ */
typedef void (* GLFWpreeditfun)(GLFWwindow*,int,unsigned int*,int,int*,int); typedef void (* GLFWpreeditfun)(GLFWwindow*,unsigned int*,int,int*,int);
/*! @brief The function signature for IME status change callbacks. /*! @brief The function signature for IME status change callbacks.
* *

View File

@ -721,33 +721,17 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
NSString* markedTextString = markedText.string; NSString* markedTextString = markedText.string;
NSUInteger i, length = [markedTextString length]; NSUInteger i, length = [markedTextString length];
int ctext = window->ctext;
while (ctext < length + 1)
ctext = ctext ? ctext * 2 : 1;
if (ctext != window->ctext) free(window->preeditText);
{ window->preeditText = calloc(length + 1, sizeof(unsigned int));
unsigned int* preeditText = realloc(window->preeditText, sizeof(unsigned int) * ctext);
if (!preeditText)
return;
window->preeditText = preeditText;
window->ctext = ctext;
}
window->ntext = length;
window->preeditText[length] = 0;
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
{ window->preeditText[i] = [markedTextString characterAtIndex:i];
const unichar codepoint = [markedTextString characterAtIndex:i];
window->preeditText[i] = codepoint;
}
int focusedBlock = 0; int focusedBlock = 0;
NSInteger offset = 0; NSInteger offset = 0;
window->nblocks = 0; window->preeditBlockCount = 0;
while (offset < length) while (offset < length)
{ {
@ -755,27 +739,18 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
NSDictionary *attributes = [markedText attributesAtIndex:offset NSDictionary *attributes = [markedText attributesAtIndex:offset
effectiveRange:&effectiveRange]; effectiveRange:&effectiveRange];
if (window->nblocks == window->cblocks) window->preeditBlockCount++;
{ window->preeditBlocks = realloc(window->preeditBlocks,
int cblocks = window->cblocks * 2; window->preeditBlockCount * sizeof(int));
int* blocks = realloc(window->preeditAttributeBlocks, sizeof(int) * cblocks);
if (!blocks)
return;
window->preeditAttributeBlocks = blocks; window->preeditBlocks[window->preeditBlockCount - 1] = effectiveRange.length;
window->cblocks = cblocks;
}
window->preeditAttributeBlocks[window->nblocks] = effectiveRange.length;
offset += effectiveRange.length; offset += effectiveRange.length;
if (!effectiveRange.length) 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->preeditBlockCount - 1;
window->nblocks++;
} }
_glfwInputPreedit(window, focusedBlock); _glfwInputPreedit(window, focusedBlock);

View File

@ -84,10 +84,9 @@ void _glfwInputPreedit(_GLFWwindow* window, int focusedBlock)
if (window->callbacks.preedit) if (window->callbacks.preedit)
{ {
window->callbacks.preedit((GLFWwindow*) window, window->callbacks.preedit((GLFWwindow*) window,
window->ntext,
window->preeditText, window->preeditText,
window->nblocks, window->preeditBlockCount,
window->preeditAttributeBlocks, window->preeditBlocks,
focusedBlock); focusedBlock);
} }
} }

View File

@ -374,13 +374,10 @@ struct _GLFWwindow
// Virtual cursor position when cursor is disabled // Virtual cursor position when cursor is disabled
double virtualCursorPosX, virtualCursorPosY; double virtualCursorPosX, virtualCursorPosY;
// Preedit texts // IME preedit data
unsigned int* preeditText; unsigned int* preeditText;
int ntext; int* preeditBlocks;
int ctext; int preeditBlockCount;
int* preeditAttributeBlocks;
int nblocks;
int cblocks;
int preeditCaretPosX, preeditCaretPosY; int preeditCaretPosX, preeditCaretPosY;
int preeditCaretHeight; int preeditCaretHeight;

View File

@ -425,7 +425,7 @@ static void releaseMonitor(_GLFWwindow* window)
// Set cursor position to decide candidate window // Set cursor position to decide candidate window
// //
static void changeCaretPosition(HIMC imc, _GLFWwindow* window) static void updateCaretPosition(_GLFWwindow* window, HIMC imc)
{ {
const int x = window->preeditCaretPosX; const int x = window->preeditCaretPosX;
const int y = window->preeditCaretPosY; const int y = window->preeditCaretPosY;
@ -586,12 +586,15 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_IME_COMPOSITION: case WM_IME_COMPOSITION:
{ {
HIMC imc; HIMC imc;
LONG preeditTextLength, attrLength, clauseLength; LONG textSize, attrSize, clauseSize;
int i, focusedBlock, length;
LPWSTR buffer;
LPSTR attributes;
DWORD* clauses;
if (lParam & GCS_RESULTSTR) if (lParam & GCS_RESULTSTR)
{ {
window->nblocks = 0; window->preeditBlockCount = 0;
window->ntext = 0;
_glfwInputPreedit(window, 0); _glfwInputPreedit(window, 0);
return TRUE; return TRUE;
} }
@ -600,76 +603,38 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
break; break;
imc = ImmGetContext(hWnd); imc = ImmGetContext(hWnd);
preeditTextLength = ImmGetCompositionStringW(imc, GCS_COMPSTR, NULL, 0); textSize = ImmGetCompositionStringW(imc, GCS_COMPSTR, NULL, 0);
attrLength = ImmGetCompositionString(imc, GCS_COMPATTR, NULL, 0); attrSize = ImmGetCompositionStringW(imc, GCS_COMPATTR, NULL, 0);
clauseLength = ImmGetCompositionString(imc, GCS_COMPCLAUSE, NULL, 0); clauseSize = ImmGetCompositionStringW(imc, GCS_COMPCLAUSE, NULL, 0);
if (preeditTextLength > 0) if (textSize <= 0)
{ {
// get preedit data ImmReleaseContext(hWnd, imc);
int i, ctext, cblocks, focusedBlock, length = preeditTextLength / sizeof(WCHAR); return TRUE;
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;
} }
window->preeditText = preeditText; length = textSize / sizeof(WCHAR);
window->ctext = ctext; buffer = calloc(length + 1, sizeof(WCHAR));
} attributes = calloc(attrSize, 1);
clauses = calloc(clauseSize, 1);
window->ntext = length; ImmGetCompositionStringW(imc, GCS_COMPSTR, buffer, textSize);
window->preeditText[length] = 0; ImmGetCompositionStringW(imc, GCS_COMPATTR, attributes, attrSize);
for (i = 0; i < length; i++) ImmGetCompositionStringW(imc, GCS_COMPCLAUSE, clauses, clauseSize);
window->preeditText[i] = buffer[i];
// store blocks free(window->preeditText);
window->nblocks = clauseLength / sizeof(DWORD) - 1; window->preeditText = calloc(length + 1, sizeof(unsigned int));
memcpy(window->preeditText, buffer, sizeof(unsigned int) * length);
// 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; focusedBlock = 0;
for (i = 0; i < window->nblocks; i++)
window->preeditBlockCount = clauseSize / sizeof(DWORD) - 1;
free(window->preeditBlocks);
window->preeditBlocks = calloc(window->preeditBlockCount, sizeof(int));
for (i = 0; i < window->preeditBlockCount; i++)
{ {
window->preeditAttributeBlocks[i] = clauses[i + 1] - clauses[i]; window->preeditBlocks[i] = clauses[i + 1] - clauses[i];
if (attributes[clauses[i]] != ATTR_CONVERTED) if (attributes[clauses[i]] != ATTR_CONVERTED)
focusedBlock = i; focusedBlock = i;
} }
@ -679,8 +644,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
free(clauses); free(clauses);
_glfwInputPreedit(window, focusedBlock); _glfwInputPreedit(window, focusedBlock);
changeCaretPosition(imc, window); updateCaretPosition(window, imc);
}
ImmReleaseContext(hWnd, imc); ImmReleaseContext(hWnd, imc);
return TRUE; return TRUE;

View File

@ -404,7 +404,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
_glfwPlatformDestroyWindow(window); _glfwPlatformDestroyWindow(window);
free(window->preeditText); free(window->preeditText);
free(window->preeditAttributeBlocks); free(window->preeditBlocks);
// Unlink window from global linked list // Unlink window from global linked list
{ {

View File

@ -440,33 +440,37 @@ static char** parseUriList(char* text, int* count)
return paths; return paths;
} }
// Update cursor position to decide candidate window // Update caret position to decide candidate window
static void _ximChangeCursorPosition(XIC xic, _GLFWwindow* window) //
static void updateCaretPosition(_GLFWwindow* window, XIC xic)
{ {
XVaNestedList preedit_attr; XVaNestedList attributes;
XPoint spot; XPoint spot;
spot.x = window->preeditCursorPosX; spot.x = window->preeditCursorPosX;
spot.y = window->preeditCursorPosY + window->preeditCursorHeight; spot.y = window->preeditCursorPosY + window->preeditCursorHeight;
preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); attributes = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
XSetICValues(xic, XNPreeditAttributes, preedit_attr, NULL); XSetICValues(xic, XNPreeditAttributes, attributes, NULL);
XFree(preedit_attr); XFree(attributes);
} }
// IME Start callback (do nothing) // IME start callback (do nothing)
static void _ximPreeditStartCallback(XIC xic, XPointer clientData, XPointer callData) //
static void preeditStartCallback(XIC xic, XPointer clientData, XPointer callData)
{ {
} }
// IME Done callback (do nothing) // IME done callback (do nothing)
static void _ximPreeditDoneCallback(XIC xic, XPointer clientData, XPointer callData) //
static void preeditDoneCallback(XIC xic, XPointer clientData, XPointer callData)
{ {
} }
// IME Draw callback // IME draw callback
static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDrawCallbackStruct *callData) //
static void preeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDrawCallbackStruct* callData)
{ {
int i, j, length, ctext, rstart, rend; int i, j, length, rstart, rend;
XIMText* text; XIMText* text;
const char* src; const char* src;
unsigned int codePoint; unsigned int codePoint;
@ -479,154 +483,172 @@ static void _ximPreeditDrawCallback(XIC xic, XPointer clientData, XIMPreeditDraw
int cursorY = window->preeditCursorPosY; int cursorY = window->preeditCursorPosY;
int cursorHeight = window->preeditCursorHeight; int cursorHeight = window->preeditCursorHeight;
if (!callData->text) { if (!callData->text)
// preedit text is empty {
window->ntext = 0; // Composition string is empty
window->nblocks = 0; window->preeditBlockCount = 0;
_glfwInputPreedit(window, 0); _glfwInputPreedit(window, 0);
return; return;
} else { }
else
{
text = callData->text; text = callData->text;
length = callData->chg_length; length = callData->chg_length;
if (text->encoding_is_wchar) { if (text->encoding_is_wchar)
{
// wchar is not supported // wchar is not supported
return; return;
} }
ctext = window->ctext;
while (ctext < length+1) { free(window->preeditText);
ctext = (ctext == 0) ? 1 : ctext * 2; window->preeditText = calloc(length + 1, sizeof(unsigned int));
}
if (ctext != window->ctext) { if (!window->preeditBlocks)
preeditText = realloc(window->preeditText, sizeof(unsigned int)*ctext); window->preeditBlocks = calloc(4, sizeof(int));
if (preeditText == NULL) {
return;
}
window->preeditText = preeditText;
window->ctext = ctext;
}
window->ntext = length;
window->preeditText[length] = 0;
if (window->cblocks == 0) {
window->preeditAttributeBlocks = malloc(sizeof(int)*4);
window->cblocks = 4;
}
src = text->string.multi_byte; src = text->string.multi_byte;
rend = 0; rend = 0;
rstart = length; rstart = length;
for (i = 0, j = 0; i < text->length; i++) {
for (i = 0, j = 0; i < text->length; i++)
{
#if defined(X_HAVE_UTF8_STRING) #if defined(X_HAVE_UTF8_STRING)
codePoint = decodeUTF8(&src); codePoint = decodeUTF8(&src);
#else #else
codePoint = *src; codePoint = *src;
src++; src++;
#endif #endif
if (i < callData->chg_first || callData->chg_first+length < i) { if (i < callData->chg_first || callData->chg_first + length < i)
continue; continue;
}
window->preeditText[j++] = codePoint; window->preeditText[j++] = codePoint;
f = text->feedback[i]; f = text->feedback[i];
if ((f & XIMReverse) || (f & XIMHighlight)) {
if ((f & XIMReverse) || (f & XIMHighlight))
{
rend = i; rend = i;
if (i < rstart) { if (i < rstart)
rstart = i; rstart = i;
} }
} }
}
if (rstart == length) { if (rstart == length)
window->nblocks = 1; {
window->preeditAttributeBlocks[0] = length; window->preeditBlockCount = 1;
window->preeditAttributeBlocks[1] = 0; window->preeditBlocks[0] = length;
_glfwInputPreedit(window, 0); window->preeditBlocks[1] = 0;
} else if (rstart == 0) {
if (rend == length -1) {
window->nblocks = 1;
window->preeditAttributeBlocks[0] = length;
window->preeditAttributeBlocks[1] = 0;
_glfwInputPreedit(window, 0);
} else {
window->nblocks = 2;
window->preeditAttributeBlocks[0] = rend + 1;
window->preeditAttributeBlocks[1] = length - rend - 1;
window->preeditAttributeBlocks[2] = 0;
_glfwInputPreedit(window, 0); _glfwInputPreedit(window, 0);
} }
} else if (rend == length -1) { else if (rstart == 0)
window->nblocks = 2; {
window->preeditAttributeBlocks[0] = rstart; if (rend == length -1)
window->preeditAttributeBlocks[1] = length - rstart; {
window->preeditAttributeBlocks[2] = 0; window->preeditBlockCount = 1;
_glfwInputPreedit(window, 1); window->preeditBlocks[0] = length;
} else { window->preeditBlocks[1] = 0;
window->nblocks = 3; _glfwInputPreedit(window, 0);
window->preeditAttributeBlocks[0] = rstart; }
window->preeditAttributeBlocks[1] = rend - rstart + 1; else
window->preeditAttributeBlocks[2] = length - rend - 1; {
window->preeditAttributeBlocks[3] = 0; window->preeditBlockCount = 2;
window->preeditBlocks[0] = rend + 1;
window->preeditBlocks[1] = length - rend - 1;
window->preeditBlocks[2] = 0;
_glfwInputPreedit(window, 0);
}
}
else if (rend == length -1)
{
window->preeditBlockCount = 2;
window->preeditBlocks[0] = rstart;
window->preeditBlocks[1] = length - rstart;
window->preeditBlocks[2] = 0;
_glfwInputPreedit(window, 1); _glfwInputPreedit(window, 1);
} }
if ((cursorX != window->preeditCursorPosX) else
|| (cursorY != window->preeditCursorPosY) {
|| (cursorHeight != window->preeditCursorHeight)) { window->preeditBlockCount = 3;
_ximChangeCursorPosition(xic, window); window->preeditBlocks[0] = rstart;
window->preeditBlocks[1] = rend - rstart + 1;
window->preeditBlocks[2] = length - rend - 1;
window->preeditBlocks[3] = 0;
_glfwInputPreedit(window, 1);
}
if ((caretX != window->preeditCaretPosX) ||
(caretY != window->preeditCaretPosY) ||
(caretHeight != window->preeditCaretHeight))
{
updateCaretPosition(window, xic);
} }
} }
} }
// IME Caret callback (do nothing) // IME Caret callback (do nothing)
static void _ximPreeditCaretCallback(XIC xic, XPointer clientData, XPointer callData) //
static void preeditCaretCallback(XIC xic, XPointer clientData, XPointer callData)
{ {
} }
static void _ximStatusStartCallback(XIC xic, XPointer clientData, XPointer callData) static void statusStartCallback(XIC xic, XPointer clientData, XPointer callData)
{ {
_GLFWwindow* window = (_GLFWwindow*) clientData; _GLFWwindow* window = (_GLFWwindow*) clientData;
window->x11.imeFocus = GLFW_TRUE; window->x11.imeFocus = GLFW_TRUE;
} }
static void _ximStatusDoneCallback(XIC xic, XPointer clientData, XPointer callData) static void statusDoneCallback(XIC xic, XPointer clientData, XPointer callData)
{ {
_GLFWwindow* window = (_GLFWwindow*) clientData; _GLFWwindow* window = (_GLFWwindow*) clientData;
window->x11.imeFocus = GLFW_FALSE; window->x11.imeFocus = GLFW_FALSE;
} }
static void _ximStatusDrawCallback(XIC xic, XPointer clientData, XIMStatusDrawCallbackStruct* callData) static void statusDrawCallback(XIC xic, XPointer clientData, XIMStatusDrawCallbackStruct* callData)
{ {
_GLFWwindow* window = (_GLFWwindow*) clientData; _GLFWwindow* window = (_GLFWwindow*) clientData;
_glfwInputIMEStatus(window); _glfwInputIMEStatus(window);
} }
// Create XIM Preedit callback // Create XIM Preedit callback
//
static XVaNestedList _createXIMPreeditCallbacks(_GLFWwindow* window) static XVaNestedList _createXIMPreeditCallbacks(_GLFWwindow* window)
{ {
window->x11.preeditStartCallback.client_data = (XPointer)window; window->x11.preeditStartCallback.client_data = (XPointer)window;
window->x11.preeditStartCallback.callback = (XIMProc)_ximPreeditStartCallback; window->x11.preeditStartCallback.callback = (XIMProc) preeditStartCallback;
window->x11.preeditDoneCallback.client_data = (XPointer)window; window->x11.preeditDoneCallback.client_data = (XPointer)window;
window->x11.preeditDoneCallback.callback = (XIMProc)_ximPreeditDoneCallback; window->x11.preeditDoneCallback.callback = (XIMProc) preeditDoneCallback;
window->x11.preeditDrawCallback.client_data = (XPointer)window; window->x11.preeditDrawCallback.client_data = (XPointer)window;
window->x11.preeditDrawCallback.callback = (XIMProc)_ximPreeditDrawCallback; window->x11.preeditDrawCallback.callback = (XIMProc) preeditDrawCallback;
window->x11.preeditCaretCallback.client_data = (XPointer)window; window->x11.preeditCaretCallback.client_data = (XPointer)window;
window->x11.preeditCaretCallback.callback = (XIMProc)_ximPreeditCaretCallback; window->x11.preeditCaretCallback.callback = (XIMProc) preeditCaretCallback;
return XVaCreateNestedList(0, return XVaCreateNestedList(0,
XNPreeditStartCallback, &window->x11.preeditStartCallback.client_data, XNPreeditStartCallback,
XNPreeditDoneCallback, &window->x11.preeditDoneCallback.client_data, &window->x11.preeditStartCallback.client_data,
XNPreeditDrawCallback, &window->x11.preeditDrawCallback.client_data, XNPreeditDoneCallback,
XNPreeditCaretCallback, &window->x11.preeditCaretCallback.client_data, &window->x11.preeditDoneCallback.client_data,
XNPreeditDrawCallback,
&window->x11.preeditDrawCallback.client_data,
XNPreeditCaretCallback,
&window->x11.preeditCaretCallback.client_data,
NULL); NULL);
} }
// Create XIM status callback // Create XIM status callback
//
static XVaNestedList _createXIMStatusCallbacks(_GLFWwindow* window) static XVaNestedList _createXIMStatusCallbacks(_GLFWwindow* window)
{ {
window->x11.statusStartCallback.client_data = (XPointer)window; window->x11.statusStartCallback.client_data = (XPointer)window;
window->x11.statusStartCallback.callback = (XIMProc)_ximStatusStartCallback; window->x11.statusStartCallback.callback = (XIMProc) statusStartCallback;
window->x11.statusDoneCallback.client_data = (XPointer)window; window->x11.statusDoneCallback.client_data = (XPointer)window;
window->x11.statusDoneCallback.callback = (XIMProc)_ximStatusDoneCallback; window->x11.statusDoneCallback.callback = (XIMProc) statusDoneCallback;
window->x11.statusDrawCallback.client_data = (XPointer)window; window->x11.statusDrawCallback.client_data = (XPointer)window;
window->x11.statusDrawCallback.callback = (XIMProc)_ximStatusDrawCallback; window->x11.statusDrawCallback.callback = (XIMProc) statusDrawCallback;
return XVaCreateNestedList(0, return XVaCreateNestedList(0,
XNStatusStartCallback, &window->x11.statusStartCallback.client_data, XNStatusStartCallback,
XNStatusDoneCallback, &window->x11.statusDoneCallback.client_data, &window->x11.statusStartCallback.client_data,
XNStatusDrawCallback, &window->x11.statusDrawCallback.client_data, XNStatusDoneCallback,
&window->x11.statusDoneCallback.client_data,
XNStatusDrawCallback,
&window->x11.statusDrawCallback.client_data,
NULL); NULL);
} }
@ -2682,47 +2704,46 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
} }
} }
void _glfwPlatformResetPreeditText(_GLFWwindow* window) { void _glfwPlatformResetPreeditText(_GLFWwindow* window)
XIC ic = window->x11.ic; {
// Restore conversion state after resetting ic later
/* restore conversion state after resetting ic later */ XIMPreeditState state = XIMPreeditUnKnown;
XIMPreeditState preedit_state = XIMPreeditUnKnown; XVaNestedList attributes;
XVaNestedList preedit_attr;
char* result; char* result;
if (window->ntext == 0) if (*window->preeditText == 0)
return; return;
preedit_attr = XVaCreateNestedList(0, XNPreeditState, &preedit_state, NULL); attributes = XVaCreateNestedList(0, XNPreeditState, &state, NULL);
XGetICValues(ic, XNPreeditAttributes, preedit_attr, NULL); XGetICValues(window->x11.ic, XNPreeditAttributes, attributes, NULL);
XFree(preedit_attr); XFree(attributes);
result = XmbResetIC(ic); result = XmbResetIC(window->x11.ic);
preedit_attr = XVaCreateNestedList(0, XNPreeditState, preedit_state, NULL); attributes = XVaCreateNestedList(0, XNPreeditState, state, NULL);
XSetICValues(ic, XNPreeditAttributes, preedit_attr, NULL); XSetICValues(window->x11.ic, XNPreeditAttributes, attributes, NULL);
XFree(preedit_attr); XFree(attributes);
window->ntext = 0; window->preeditBlockCount = 0;
window->nblocks = 0;
_glfwInputPreedit(window, 0); _glfwInputPreedit(window, 0);
XFree(result); XFree(result);
} }
void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active) { void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active)
XIC ic = window->x11.ic; {
if (active) { if (active)
XSetICFocus(ic); XSetICFocus(window->x11.ic);
} else { else
XUnsetICFocus(ic); XUnsetICFocus(window->x11.ic);
}
} }
int _glfwPlatformGetIMEStatus(_GLFWwindow* window) { int _glfwPlatformGetIMEStatus(_GLFWwindow* window)
{
return window->x11.imeFocus; return window->x11.imeFocus;
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -421,7 +421,6 @@ static void char_mods_callback(GLFWwindow* window, unsigned int codepoint, int m
} }
static void preedit_callback(GLFWwindow* window, static void preedit_callback(GLFWwindow* window,
int strLength,
unsigned int* string, unsigned int* string,
int blockLength, int blockLength,
int* blocks, int* blocks,
@ -434,9 +433,9 @@ static void preedit_callback(GLFWwindow* window,
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 && blockLength) if (*string && blockLength)
{ {
for (i = 0; i < strLength; i++) for (i = 0; string[i]; i++)
{ {
if (blockCount == 0) if (blockCount == 0)
{ {