Cleanup
This commit is contained in:
parent
0df386d06a
commit
ed59b80cc7
@ -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)
|
||||||
|
@ -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: "s", block: [1], focusedBlock: 0]
|
-# preedit: [string: "s", 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
|
||||||
|
|
||||||
|
@ -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.
|
||||||
*
|
*
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -425,12 +425,12 @@ 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;
|
||||||
const int h = window->preeditCaretHeight;
|
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);
|
ImmSetCandidateWindow(imc, &excludeRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
275
src/x11_window.c
275
src/x11_window.c
@ -440,193 +440,215 @@ 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;
|
||||||
unsigned int* preeditText;
|
unsigned int* preeditText;
|
||||||
XIMFeedback f;
|
XIMFeedback f;
|
||||||
_GLFWwindow* window = (_GLFWwindow*)clientData;
|
_GLFWwindow* window = (_GLFWwindow*) clientData;
|
||||||
|
|
||||||
// keep cursor position to reduce API call
|
// keep cursor position to reduce API call
|
||||||
int cursorX = window->preeditCursorPosX;
|
int cursorX = window->preeditCursorPosX;
|
||||||
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++) {
|
|
||||||
#if defined(X_HAVE_UTF8_STRING)
|
for (i = 0, j = 0; i < text->length; i++)
|
||||||
|
{
|
||||||
|
#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 //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user