winex11: Simplify NotifyIME with NI_COMPOSITIONSTR / CPS_COMPLETE.
[wine.git] / dlls / winex11.drv / ime.c
blob900a6a3e5d359106aca53f3ddf20d4c83ef895e9
1 /*
2 * The IME for interfacing with XIM
4 * Copyright 2008 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Notes:
23 * The normal flow for IMM/IME Processing is as follows.
24 * 1) The Keyboard Driver generates key messages which are first passed to
25 * the IMM and then to IME via ImeProcessKey. If the IME returns 0 then
26 * it does not want the key and the keyboard driver then generates the
27 * WM_KEYUP/WM_KEYDOWN messages. However if the IME is going to process the
28 * key it returns non-zero.
29 * 2) If the IME is going to process the key then the IMM calls ImeToAsciiEx to
30 * process the key. the IME modifies the HIMC structure to reflect the
31 * current state and generates any messages it needs the IMM to process.
32 * 3) IMM checks the messages and send them to the application in question. From
33 * here the IMM level deals with if the application is IME aware or not.
35 * This flow does not work well for the X11 driver and XIM.
36 * (It works fine for Mac)
37 * As such we will have to reroute step 1. Instead the x11drv driver will
38 * generate an XIM events and call directly into this IME implementation.
39 * As such we will have to use the alternative ImmGenerateMessage path to be
40 * generate the messages that we want the IMM layer to send to the application.
43 #include "x11drv_dll.h"
44 #include "wine/debug.h"
45 #include "imm.h"
46 #include "immdev.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(imm);
50 #define FROM_X11 ((HIMC)0xcafe1337)
52 static HIMC *hSelectedFrom = NULL;
53 static INT hSelectedCount = 0;
55 static void input_context_reset_comp_str( INPUTCONTEXT *ctx )
57 COMPOSITIONSTRING *compstr;
59 if (!(compstr = ImmLockIMCC( ctx->hCompStr )))
60 WARN( "Failed to lock input context composition string\n" );
61 else
63 memset( compstr, 0, sizeof(*compstr) );
64 compstr->dwSize = sizeof(*compstr);
65 ImmUnlockIMCC( ctx->hCompStr );
69 static HIMC RealIMC(HIMC hIMC)
71 if (hIMC == FROM_X11)
73 INT i;
74 HWND wnd = GetFocus();
75 HIMC winHimc = ImmGetContext(wnd);
76 for (i = 0; i < hSelectedCount; i++)
77 if (winHimc == hSelectedFrom[i])
78 return winHimc;
79 return NULL;
81 else
82 return hIMC;
85 static LPINPUTCONTEXT LockRealIMC(HIMC hIMC)
87 HIMC real_imc = RealIMC(hIMC);
88 if (real_imc)
89 return ImmLockIMC(real_imc);
90 else
91 return NULL;
94 static BOOL UnlockRealIMC(HIMC hIMC)
96 HIMC real_imc = RealIMC(hIMC);
97 if (real_imc)
98 return ImmUnlockIMC(real_imc);
99 else
100 return FALSE;
103 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
104 LPBYTE target, LPBYTE source, DWORD* lenParam,
105 DWORD* offsetParam, BOOL wchars )
107 if (origLen > 0 && origOffset > 0)
109 int truelen = origLen;
110 if (wchars)
111 truelen *= sizeof(WCHAR);
113 memcpy(&target[currentOffset], &source[origOffset], truelen);
115 *lenParam = origLen;
116 *offsetParam = currentOffset;
117 currentOffset += truelen;
119 return currentOffset;
122 static HIMCC updateCompStr(HIMCC old, LPCWSTR compstr, DWORD len)
124 /* We need to make sure the CompStr, CompClause and CompAttr fields are all
125 * set and correct. */
126 int needed_size;
127 HIMCC rc;
128 LPBYTE newdata = NULL;
129 LPBYTE olddata = NULL;
130 LPCOMPOSITIONSTRING new_one;
131 LPCOMPOSITIONSTRING lpcs = NULL;
132 INT current_offset = 0;
134 TRACE("%s, %li\n",debugstr_wn(compstr,len),len);
136 if (old == NULL && compstr == NULL && len == 0)
137 return NULL;
139 if (compstr == NULL && len != 0)
141 ERR("compstr is NULL however we have a len! Please report\n");
142 len = 0;
145 if (old != NULL)
147 olddata = ImmLockIMCC(old);
148 lpcs = (LPCOMPOSITIONSTRING)olddata;
151 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
152 len + sizeof(DWORD) * 2;
154 if (lpcs != NULL)
156 needed_size += lpcs->dwCompReadAttrLen;
157 needed_size += lpcs->dwCompReadClauseLen;
158 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
159 needed_size += lpcs->dwResultReadClauseLen;
160 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
161 needed_size += lpcs->dwResultClauseLen;
162 needed_size += lpcs->dwResultStrLen * sizeof(WCHAR);
163 needed_size += lpcs->dwPrivateSize;
165 rc = ImmCreateIMCC(needed_size);
166 newdata = ImmLockIMCC(rc);
167 new_one = (LPCOMPOSITIONSTRING)newdata;
169 new_one->dwSize = needed_size;
170 current_offset = sizeof(COMPOSITIONSTRING);
171 if (lpcs != NULL)
173 current_offset = updateField(lpcs->dwCompReadAttrLen,
174 lpcs->dwCompReadAttrOffset,
175 current_offset, newdata, olddata,
176 &new_one->dwCompReadAttrLen,
177 &new_one->dwCompReadAttrOffset, FALSE);
179 current_offset = updateField(lpcs->dwCompReadClauseLen,
180 lpcs->dwCompReadClauseOffset,
181 current_offset, newdata, olddata,
182 &new_one->dwCompReadClauseLen,
183 &new_one->dwCompReadClauseOffset, FALSE);
185 current_offset = updateField(lpcs->dwCompReadStrLen,
186 lpcs->dwCompReadStrOffset,
187 current_offset, newdata, olddata,
188 &new_one->dwCompReadStrLen,
189 &new_one->dwCompReadStrOffset, TRUE);
191 /* new CompAttr, CompClause, CompStr, dwCursorPos */
192 new_one->dwDeltaStart = 0;
194 current_offset = updateField(lpcs->dwResultReadClauseLen,
195 lpcs->dwResultReadClauseOffset,
196 current_offset, newdata, olddata,
197 &new_one->dwResultReadClauseLen,
198 &new_one->dwResultReadClauseOffset, FALSE);
200 current_offset = updateField(lpcs->dwResultReadStrLen,
201 lpcs->dwResultReadStrOffset,
202 current_offset, newdata, olddata,
203 &new_one->dwResultReadStrLen,
204 &new_one->dwResultReadStrOffset, TRUE);
206 current_offset = updateField(lpcs->dwResultClauseLen,
207 lpcs->dwResultClauseOffset,
208 current_offset, newdata, olddata,
209 &new_one->dwResultClauseLen,
210 &new_one->dwResultClauseOffset, FALSE);
212 current_offset = updateField(lpcs->dwResultStrLen,
213 lpcs->dwResultStrOffset,
214 current_offset, newdata, olddata,
215 &new_one->dwResultStrLen,
216 &new_one->dwResultStrOffset, TRUE);
218 current_offset = updateField(lpcs->dwPrivateSize,
219 lpcs->dwPrivateOffset,
220 current_offset, newdata, olddata,
221 &new_one->dwPrivateSize,
222 &new_one->dwPrivateOffset, FALSE);
225 /* set new data */
226 /* CompAttr */
227 new_one->dwCompAttrLen = len;
228 if (len > 0)
230 new_one->dwCompAttrOffset = current_offset;
231 memset(&newdata[current_offset],ATTR_INPUT,len);
232 current_offset += len;
235 /* CompClause */
236 if (len > 0)
238 new_one->dwCompClauseLen = sizeof(DWORD) * 2;
239 new_one->dwCompClauseOffset = current_offset;
240 *(DWORD*)(&newdata[current_offset]) = 0;
241 current_offset += sizeof(DWORD);
242 *(DWORD*)(&newdata[current_offset]) = len;
243 current_offset += sizeof(DWORD);
245 else
246 new_one->dwCompClauseLen = 0;
248 /* CompStr */
249 new_one->dwCompStrLen = len;
250 if (len > 0)
252 new_one->dwCompStrOffset = current_offset;
253 memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
256 /* CursorPos */
257 new_one->dwCursorPos = len;
259 ImmUnlockIMCC(rc);
260 if (lpcs)
261 ImmUnlockIMCC(old);
263 return rc;
266 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
268 /* we need to make sure the ResultStr and ResultClause fields are all
269 * set and correct */
270 int needed_size;
271 HIMCC rc;
272 LPBYTE newdata = NULL;
273 LPBYTE olddata = NULL;
274 LPCOMPOSITIONSTRING new_one;
275 LPCOMPOSITIONSTRING lpcs = NULL;
276 INT current_offset = 0;
278 TRACE("%s, %li\n",debugstr_wn(resultstr,len),len);
280 if (old == NULL && resultstr == NULL && len == 0)
281 return NULL;
283 if (resultstr == NULL && len != 0)
285 ERR("resultstr is NULL however we have a len! Please report\n");
286 len = 0;
289 if (old != NULL)
291 olddata = ImmLockIMCC(old);
292 lpcs = (LPCOMPOSITIONSTRING)olddata;
295 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
296 sizeof(DWORD) * 2;
298 if (lpcs != NULL)
300 needed_size += lpcs->dwCompReadAttrLen;
301 needed_size += lpcs->dwCompReadClauseLen;
302 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
303 needed_size += lpcs->dwCompAttrLen;
304 needed_size += lpcs->dwCompClauseLen;
305 needed_size += lpcs->dwCompStrLen * sizeof(WCHAR);
306 needed_size += lpcs->dwResultReadClauseLen;
307 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
308 needed_size += lpcs->dwPrivateSize;
310 rc = ImmCreateIMCC(needed_size);
311 newdata = ImmLockIMCC(rc);
312 new_one = (LPCOMPOSITIONSTRING)newdata;
314 new_one->dwSize = needed_size;
315 current_offset = sizeof(COMPOSITIONSTRING);
316 if (lpcs != NULL)
318 current_offset = updateField(lpcs->dwCompReadAttrLen,
319 lpcs->dwCompReadAttrOffset,
320 current_offset, newdata, olddata,
321 &new_one->dwCompReadAttrLen,
322 &new_one->dwCompReadAttrOffset, FALSE);
324 current_offset = updateField(lpcs->dwCompReadClauseLen,
325 lpcs->dwCompReadClauseOffset,
326 current_offset, newdata, olddata,
327 &new_one->dwCompReadClauseLen,
328 &new_one->dwCompReadClauseOffset, FALSE);
330 current_offset = updateField(lpcs->dwCompReadStrLen,
331 lpcs->dwCompReadStrOffset,
332 current_offset, newdata, olddata,
333 &new_one->dwCompReadStrLen,
334 &new_one->dwCompReadStrOffset, TRUE);
336 current_offset = updateField(lpcs->dwCompAttrLen,
337 lpcs->dwCompAttrOffset,
338 current_offset, newdata, olddata,
339 &new_one->dwCompAttrLen,
340 &new_one->dwCompAttrOffset, FALSE);
342 current_offset = updateField(lpcs->dwCompClauseLen,
343 lpcs->dwCompClauseOffset,
344 current_offset, newdata, olddata,
345 &new_one->dwCompClauseLen,
346 &new_one->dwCompClauseOffset, FALSE);
348 current_offset = updateField(lpcs->dwCompStrLen,
349 lpcs->dwCompStrOffset,
350 current_offset, newdata, olddata,
351 &new_one->dwCompStrLen,
352 &new_one->dwCompStrOffset, TRUE);
354 new_one->dwCursorPos = lpcs->dwCursorPos;
355 new_one->dwDeltaStart = 0;
357 current_offset = updateField(lpcs->dwResultReadClauseLen,
358 lpcs->dwResultReadClauseOffset,
359 current_offset, newdata, olddata,
360 &new_one->dwResultReadClauseLen,
361 &new_one->dwResultReadClauseOffset, FALSE);
363 current_offset = updateField(lpcs->dwResultReadStrLen,
364 lpcs->dwResultReadStrOffset,
365 current_offset, newdata, olddata,
366 &new_one->dwResultReadStrLen,
367 &new_one->dwResultReadStrOffset, TRUE);
369 /* new ResultClause , ResultStr */
371 current_offset = updateField(lpcs->dwPrivateSize,
372 lpcs->dwPrivateOffset,
373 current_offset, newdata, olddata,
374 &new_one->dwPrivateSize,
375 &new_one->dwPrivateOffset, FALSE);
378 /* set new data */
379 /* ResultClause */
380 if (len > 0)
382 new_one->dwResultClauseLen = sizeof(DWORD) * 2;
383 new_one->dwResultClauseOffset = current_offset;
384 *(DWORD*)(&newdata[current_offset]) = 0;
385 current_offset += sizeof(DWORD);
386 *(DWORD*)(&newdata[current_offset]) = len;
387 current_offset += sizeof(DWORD);
389 else
390 new_one->dwResultClauseLen = 0;
392 /* ResultStr */
393 new_one->dwResultStrLen = len;
394 if (len > 0)
396 new_one->dwResultStrOffset = current_offset;
397 memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
399 ImmUnlockIMCC(rc);
400 if (lpcs)
401 ImmUnlockIMCC(old);
403 return rc;
406 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam,
407 LPARAM lParam)
409 LPINPUTCONTEXT lpIMC;
410 LPTRANSMSG lpTransMsg;
412 lpIMC = LockRealIMC(hIMC);
413 if (lpIMC == NULL)
414 return;
416 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) *
417 sizeof(TRANSMSG));
418 if (!lpIMC->hMsgBuf)
419 return;
421 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
422 if (!lpTransMsg)
423 return;
425 lpTransMsg += lpIMC->dwNumMsgBuf;
426 lpTransMsg->message = msg;
427 lpTransMsg->wParam = wParam;
428 lpTransMsg->lParam = lParam;
430 ImmUnlockIMCC(lpIMC->hMsgBuf);
431 lpIMC->dwNumMsgBuf++;
433 ImmGenerateMessage(RealIMC(hIMC));
434 UnlockRealIMC(hIMC);
437 static void ime_set_composition_status( HIMC himc, BOOL composition )
439 struct ime_private *priv;
440 INPUTCONTEXT *ctx;
441 UINT msg = 0;
443 if (!(ctx = ImmLockIMC( himc ))) return;
444 if ((priv = ImmLockIMCC( ctx->hPrivate )))
446 if (!priv->bInComposition && composition) msg = WM_IME_STARTCOMPOSITION;
447 else if (priv->bInComposition && !composition) msg = WM_IME_ENDCOMPOSITION;
448 priv->bInComposition = composition;
449 ImmUnlockIMCC( ctx->hPrivate );
451 ImmUnlockIMC( himc );
453 if (msg) GenerateIMEMessage( himc, msg, 0, 0 );
456 static BOOL IME_RemoveFromSelected(HIMC hIMC)
458 int i;
459 for (i = 0; i < hSelectedCount; i++)
460 if (hSelectedFrom[i] == hIMC)
462 if (i < hSelectedCount - 1)
463 memmove(&hSelectedFrom[i], &hSelectedFrom[i+1], (hSelectedCount - i - 1)*sizeof(HIMC));
464 hSelectedCount --;
465 return TRUE;
467 return FALSE;
470 static void IME_AddToSelected(HIMC hIMC)
472 hSelectedCount++;
473 if (hSelectedFrom)
474 hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount*sizeof(HIMC));
475 else
476 hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC));
477 hSelectedFrom[hSelectedCount-1] = hIMC;
480 BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState)
482 /* See the comment at the head of this file */
483 TRACE("We do no processing via this route\n");
484 return FALSE;
487 BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
489 LPINPUTCONTEXT lpIMC;
490 TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE");
492 if (hIMC == FROM_X11)
494 ERR("ImeSelect should never be called from X11\n");
495 return FALSE;
498 if (!hIMC)
499 return TRUE;
501 /* not selected */
502 if (!fSelect)
503 return IME_RemoveFromSelected(hIMC);
505 IME_AddToSelected(hIMC);
507 /* Initialize our structures */
508 lpIMC = LockRealIMC(hIMC);
509 if (lpIMC != NULL)
511 LPIMEPRIVATE myPrivate;
512 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
513 myPrivate->bInComposition = FALSE;
514 myPrivate->bInternalState = FALSE;
515 myPrivate->textfont = NULL;
516 myPrivate->hwndDefault = NULL;
517 ImmUnlockIMCC(lpIMC->hPrivate);
518 UnlockRealIMC(hIMC);
521 return TRUE;
524 UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState,
525 TRANSMSGLIST *lpdwTransKey, UINT fuState, HIMC hIMC)
527 /* See the comment at the head of this file */
528 TRACE("We do no processing via this route\n");
529 return 0;
532 BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
534 struct xim_preedit_state_params preedit_params;
535 BOOL bRet = FALSE;
536 LPINPUTCONTEXT lpIMC;
538 TRACE("%p %li %li %li\n",hIMC,dwAction,dwIndex,dwValue);
540 lpIMC = LockRealIMC(hIMC);
541 if (lpIMC == NULL)
542 return FALSE;
544 switch (dwAction)
546 case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break;
547 case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break;
548 case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break;
549 case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break;
550 case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
551 case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
552 case NI_CONTEXTUPDATED:
553 switch (dwValue)
555 case IMC_SETCOMPOSITIONWINDOW: FIXME("IMC_SETCOMPOSITIONWINDOW\n"); break;
556 case IMC_SETCONVERSIONMODE: FIXME("IMC_SETCONVERSIONMODE\n"); break;
557 case IMC_SETSENTENCEMODE: FIXME("IMC_SETSENTENCEMODE\n"); break;
558 case IMC_SETCANDIDATEPOS: FIXME("IMC_SETCANDIDATEPOS\n"); break;
559 case IMC_SETCOMPOSITIONFONT:
561 LPIMEPRIVATE myPrivate;
562 TRACE("IMC_SETCOMPOSITIONFONT\n");
564 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
565 if (myPrivate->textfont)
567 DeleteObject(myPrivate->textfont);
568 myPrivate->textfont = NULL;
570 myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W);
571 ImmUnlockIMCC(lpIMC->hPrivate);
573 break;
574 case IMC_SETOPENSTATUS:
575 bRet = TRUE;
576 preedit_params.hwnd = lpIMC->hWnd;
577 preedit_params.open = lpIMC->fOpen;
578 X11DRV_CALL( xim_preedit_state, &preedit_params );
579 if (!lpIMC->fOpen)
581 X11DRV_CALL( xim_reset, lpIMC->hWnd );
582 input_context_reset_comp_str( lpIMC );
583 ime_set_composition_status( hIMC, FALSE );
585 break;
586 default: FIXME("Unknown\n"); break;
588 break;
589 case NI_COMPOSITIONSTR:
590 switch (dwIndex)
592 case CPS_COMPLETE:
594 COMPOSITIONSTRING *compstr;
596 if (!(compstr = ImmLockIMCC( lpIMC->hCompStr )))
597 WARN( "Failed to lock input context composition string\n" );
598 else
600 WCHAR wchr = *(WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset);
601 COMPOSITIONSTRING tmp = *compstr;
602 UINT flags = 0;
604 memset( compstr, 0, sizeof(*compstr) );
605 compstr->dwSize = tmp.dwSize;
606 compstr->dwResultStrLen = tmp.dwCompStrLen;
607 compstr->dwResultStrOffset = tmp.dwCompStrOffset;
608 compstr->dwResultClauseLen = tmp.dwCompClauseLen;
609 compstr->dwResultClauseOffset = tmp.dwCompClauseOffset;
610 ImmUnlockIMCC( lpIMC->hCompStr );
612 if (tmp.dwCompStrLen) flags |= GCS_RESULTSTR;
613 if (tmp.dwCompClauseLen) flags |= GCS_RESULTCLAUSE;
614 if (flags) GenerateIMEMessage( hIMC, WM_IME_COMPOSITION, wchr, flags );
617 ImmSetOpenStatus( hIMC, FALSE );
618 bRet = TRUE;
620 break;
621 case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break;
622 case CPS_REVERT: FIXME("CPS_REVERT\n"); break;
623 case CPS_CANCEL:
624 input_context_reset_comp_str( lpIMC );
625 ime_set_composition_status( hIMC, FALSE );
626 bRet = TRUE;
627 break;
628 default: FIXME("Unknown\n"); break;
630 break;
631 default: FIXME("Unknown Message\n"); break;
634 UnlockRealIMC(hIMC);
635 return bRet;
638 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp,
639 DWORD dwCompLen, LPCVOID lpRead,
640 DWORD dwReadLen)
642 LPINPUTCONTEXT lpIMC;
643 DWORD flags = 0;
644 WCHAR wParam = 0;
646 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
647 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
650 if (hIMC != FROM_X11)
651 FIXME("PROBLEM: This only sets the wine level string\n");
654 * Explanation:
655 * this sets the composition string in the imm32.dll level
656 * of the composition buffer. we cannot manipulate the xim level
657 * buffer, which means that once the xim level buffer changes again
658 * any call to this function from the application will be lost
661 if (lpRead && dwReadLen)
662 FIXME("Reading string unimplemented\n");
664 lpIMC = LockRealIMC(hIMC);
666 if (lpIMC == NULL)
667 return FALSE;
669 if (dwIndex == SCS_SETSTR)
671 HIMCC newCompStr;
673 ime_set_composition_status( hIMC, TRUE );
675 /* clear existing result */
676 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
677 ImmDestroyIMCC(lpIMC->hCompStr);
678 lpIMC->hCompStr = newCompStr;
680 flags = GCS_COMPSTR;
682 if (dwCompLen && lpComp)
684 newCompStr = updateCompStr(lpIMC->hCompStr, (LPCWSTR)lpComp, dwCompLen / sizeof(WCHAR));
685 ImmDestroyIMCC(lpIMC->hCompStr);
686 lpIMC->hCompStr = newCompStr;
688 wParam = ((const WCHAR*)lpComp)[0];
689 flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
691 else
693 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
694 ImmDestroyIMCC(lpIMC->hCompStr);
695 lpIMC->hCompStr = newCompStr;
699 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
700 ImmUnlockIMCC(lpIMC->hPrivate);
701 UnlockRealIMC(hIMC);
703 return TRUE;
706 /* Interfaces to XIM and other parts of winex11drv */
708 NTSTATUS x11drv_ime_set_open_status( UINT open )
710 HIMC imc;
712 imc = RealIMC(FROM_X11);
713 ImmSetOpenStatus(imc, open);
714 return 0;
717 NTSTATUS x11drv_ime_set_composition_status( UINT open )
719 HIMC imc;
720 LPINPUTCONTEXT lpIMC;
722 imc = RealIMC(FROM_X11);
723 lpIMC = ImmLockIMC(imc);
724 if (lpIMC == NULL)
725 return 0;
727 if (!open)
729 struct ime_private *myPrivate = ImmLockIMCC(lpIMC->hPrivate);
730 ShowWindow(myPrivate->hwndDefault, SW_HIDE);
731 input_context_reset_comp_str( lpIMC );
732 ImmUnlockIMCC(lpIMC->hPrivate);
735 ImmUnlockIMC(imc);
737 ime_set_composition_status( imc, open );
739 return 0;
742 NTSTATUS x11drv_ime_get_cursor_pos( UINT arg )
744 LPINPUTCONTEXT lpIMC;
745 INT rc = 0;
746 LPCOMPOSITIONSTRING compstr;
748 if (!hSelectedFrom)
749 return rc;
751 lpIMC = LockRealIMC(FROM_X11);
752 if (lpIMC)
754 compstr = ImmLockIMCC(lpIMC->hCompStr);
755 rc = compstr->dwCursorPos;
756 ImmUnlockIMCC(lpIMC->hCompStr);
758 UnlockRealIMC(FROM_X11);
759 return rc;
762 NTSTATUS x11drv_ime_set_cursor_pos( UINT pos )
764 LPINPUTCONTEXT lpIMC;
765 LPCOMPOSITIONSTRING compstr;
767 if (!hSelectedFrom)
768 return 0;
770 lpIMC = LockRealIMC(FROM_X11);
771 if (!lpIMC)
772 return 0;
774 compstr = ImmLockIMCC(lpIMC->hCompStr);
775 if (!compstr)
777 UnlockRealIMC(FROM_X11);
778 return 0;
781 compstr->dwCursorPos = pos;
782 ImmUnlockIMCC(lpIMC->hCompStr);
783 UnlockRealIMC(FROM_X11);
784 GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS);
785 return 0;
788 NTSTATUS x11drv_ime_update_association( UINT arg )
790 HWND focus = UlongToHandle( arg );
792 ImmGetContext(focus);
794 if (focus && hSelectedFrom)
795 ImmAssociateContext(focus,RealIMC(FROM_X11));
796 return 0;
800 NTSTATUS WINAPI x11drv_ime_set_composition_string( void *param, ULONG size )
802 return ImeSetCompositionString(FROM_X11, SCS_SETSTR, param, size, NULL, 0);
805 NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG len )
807 WCHAR *lpResult = params;
808 HIMC imc;
809 LPINPUTCONTEXT lpIMC;
810 HIMCC newCompStr;
811 LPIMEPRIVATE myPrivate;
812 BOOL inComp;
813 HWND focus;
815 len /= sizeof(WCHAR);
816 if ((focus = GetFocus()))
817 x11drv_ime_update_association( HandleToUlong( focus ));
819 imc = RealIMC(FROM_X11);
820 lpIMC = ImmLockIMC(imc);
821 if (lpIMC == NULL)
822 return 0;
824 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
825 ImmDestroyIMCC(lpIMC->hCompStr);
826 lpIMC->hCompStr = newCompStr;
828 newCompStr = updateResultStr(lpIMC->hCompStr, lpResult, len);
829 ImmDestroyIMCC(lpIMC->hCompStr);
830 lpIMC->hCompStr = newCompStr;
832 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
833 inComp = myPrivate->bInComposition;
834 ImmUnlockIMCC(lpIMC->hPrivate);
836 if (!inComp)
838 ImmSetOpenStatus(imc, TRUE);
839 GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0);
842 GenerateIMEMessage(imc, WM_IME_COMPOSITION, 0, GCS_COMPSTR);
843 GenerateIMEMessage(imc, WM_IME_COMPOSITION, lpResult[0], GCS_RESULTSTR|GCS_RESULTCLAUSE);
844 GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0);
846 if (!inComp)
847 ImmSetOpenStatus(imc, FALSE);
849 ImmUnlockIMC(imc);
850 return 0;