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)
list(APPEND glfw_PKG_LIBS "-lgdi32")
list(APPEND glfw_LIBRARIES "imm32")
list(APPEND glfw_LIBRARIES "-limm32")
if (GLFW_USE_HYBRID_HPG)
set(_GLFW_USE_HYBRID_HPG 1)

View File

@ -206,35 +206,42 @@ void charmods_callback(GLFWwindow* window, unsigned int codepoint, int mods)
}
@endcode
@subsection preedit IME Support
All desktop operating systems support IME (Input Method Editor) to input characters
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.
@subsection preedit IME support
GLFW provides IME support functions to help
you implement better text input features. You should add suitable visualization code for
preedit text.
All modern operating systems provide a
[IME](https://en.wikipedia.org/wiki/Input_method) (Input Method Editor)
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).
If your application uses text input and you want to support IME,
you should register preedit callback to receive preedit text before committed.
If your application uses text input and you want to support IME, you should
register pre-edit callback to receive pre-edit text before committed.
@code
glfwSetPreeditCallback(window, preedit_callback);
@endcode
The callback function receives chunk of text and focused block information.
The callback function receives the pre-edit text and block information.
@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
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
-# preedit: [string: "", block: [1], focusedBlock: 0]
-# key event: u
@ -250,52 +257,61 @@ If you want to type the text "寿司(sushi)", Usually the callback is called sev
-# char: '寿'
-# char: '司'
-# 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: [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
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:
committed 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 (window coordinates and height). You should call this function in the
above pre-edit text callback function.
@code
glfwSetIMEStatusCallback(window, imestatus_callback);
int xpos, ypos, height;
glfwSetPreeditCursorPos(window, xpos, ypos, height);
glfwGetPreeditCursorPos(window, &xpos, &ypos, &height);
@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
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
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

View File

@ -1106,7 +1106,6 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int);
* This is the function signature for preedit callback functions.
*
* @param[in] window The window that received the event.
* @param[in] length Preedit string length.
* @param[in] string Preedit string.
* @param[in] count Attributed block count.
* @param[in] blocksizes List of attributed block size.
@ -1117,7 +1116,7 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int);
*
* @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.
*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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