mshtml: Implement MediaQueryList's addListener method.
[wine.git] / dlls / winex11.drv / ime.c
blob55485bfbfcfd22ee38979ead73a882bffb9b8974
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 WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length )
57 COMPOSITIONSTRING *string;
58 WCHAR *text = NULL;
59 UINT len, off;
61 if (!(string = ImmLockIMCC( ctx->hCompStr ))) return NULL;
62 len = result ? string->dwResultStrLen : string->dwCompStrLen;
63 off = result ? string->dwResultStrOffset : string->dwCompStrOffset;
65 if (len && off && (text = malloc( (len + 1) * sizeof(WCHAR) )))
67 memcpy( text, (BYTE *)string + off, len * sizeof(WCHAR) );
68 text[len] = 0;
69 *length = len;
72 ImmUnlockIMCC( ctx->hCompStr );
73 return text;
76 static HIMC RealIMC(HIMC hIMC)
78 if (hIMC == FROM_X11)
80 INT i;
81 HWND wnd = GetFocus();
82 HIMC winHimc = ImmGetContext(wnd);
83 for (i = 0; i < hSelectedCount; i++)
84 if (winHimc == hSelectedFrom[i])
85 return winHimc;
86 return NULL;
88 else
89 return hIMC;
92 static LPINPUTCONTEXT LockRealIMC(HIMC hIMC)
94 HIMC real_imc = RealIMC(hIMC);
95 if (real_imc)
96 return ImmLockIMC(real_imc);
97 else
98 return NULL;
101 static BOOL UnlockRealIMC(HIMC hIMC)
103 HIMC real_imc = RealIMC(hIMC);
104 if (real_imc)
105 return ImmUnlockIMC(real_imc);
106 else
107 return FALSE;
110 static HIMCC ImeCreateBlankCompStr(void)
112 HIMCC rc;
113 LPCOMPOSITIONSTRING ptr;
114 rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
115 ptr = ImmLockIMCC(rc);
116 memset(ptr,0,sizeof(COMPOSITIONSTRING));
117 ptr->dwSize = sizeof(COMPOSITIONSTRING);
118 ImmUnlockIMCC(rc);
119 return rc;
122 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
123 LPBYTE target, LPBYTE source, DWORD* lenParam,
124 DWORD* offsetParam, BOOL wchars )
126 if (origLen > 0 && origOffset > 0)
128 int truelen = origLen;
129 if (wchars)
130 truelen *= sizeof(WCHAR);
132 memcpy(&target[currentOffset], &source[origOffset], truelen);
134 *lenParam = origLen;
135 *offsetParam = currentOffset;
136 currentOffset += truelen;
138 return currentOffset;
141 static HIMCC updateCompStr(HIMCC old, LPCWSTR compstr, DWORD len)
143 /* We need to make sure the CompStr, CompClause and CompAttr fields are all
144 * set and correct. */
145 int needed_size;
146 HIMCC rc;
147 LPBYTE newdata = NULL;
148 LPBYTE olddata = NULL;
149 LPCOMPOSITIONSTRING new_one;
150 LPCOMPOSITIONSTRING lpcs = NULL;
151 INT current_offset = 0;
153 TRACE("%s, %li\n",debugstr_wn(compstr,len),len);
155 if (old == NULL && compstr == NULL && len == 0)
156 return NULL;
158 if (compstr == NULL && len != 0)
160 ERR("compstr is NULL however we have a len! Please report\n");
161 len = 0;
164 if (old != NULL)
166 olddata = ImmLockIMCC(old);
167 lpcs = (LPCOMPOSITIONSTRING)olddata;
170 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
171 len + sizeof(DWORD) * 2;
173 if (lpcs != NULL)
175 needed_size += lpcs->dwCompReadAttrLen;
176 needed_size += lpcs->dwCompReadClauseLen;
177 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
178 needed_size += lpcs->dwResultReadClauseLen;
179 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
180 needed_size += lpcs->dwResultClauseLen;
181 needed_size += lpcs->dwResultStrLen * sizeof(WCHAR);
182 needed_size += lpcs->dwPrivateSize;
184 rc = ImmCreateIMCC(needed_size);
185 newdata = ImmLockIMCC(rc);
186 new_one = (LPCOMPOSITIONSTRING)newdata;
188 new_one->dwSize = needed_size;
189 current_offset = sizeof(COMPOSITIONSTRING);
190 if (lpcs != NULL)
192 current_offset = updateField(lpcs->dwCompReadAttrLen,
193 lpcs->dwCompReadAttrOffset,
194 current_offset, newdata, olddata,
195 &new_one->dwCompReadAttrLen,
196 &new_one->dwCompReadAttrOffset, FALSE);
198 current_offset = updateField(lpcs->dwCompReadClauseLen,
199 lpcs->dwCompReadClauseOffset,
200 current_offset, newdata, olddata,
201 &new_one->dwCompReadClauseLen,
202 &new_one->dwCompReadClauseOffset, FALSE);
204 current_offset = updateField(lpcs->dwCompReadStrLen,
205 lpcs->dwCompReadStrOffset,
206 current_offset, newdata, olddata,
207 &new_one->dwCompReadStrLen,
208 &new_one->dwCompReadStrOffset, TRUE);
210 /* new CompAttr, CompClause, CompStr, dwCursorPos */
211 new_one->dwDeltaStart = 0;
213 current_offset = updateField(lpcs->dwResultReadClauseLen,
214 lpcs->dwResultReadClauseOffset,
215 current_offset, newdata, olddata,
216 &new_one->dwResultReadClauseLen,
217 &new_one->dwResultReadClauseOffset, FALSE);
219 current_offset = updateField(lpcs->dwResultReadStrLen,
220 lpcs->dwResultReadStrOffset,
221 current_offset, newdata, olddata,
222 &new_one->dwResultReadStrLen,
223 &new_one->dwResultReadStrOffset, TRUE);
225 current_offset = updateField(lpcs->dwResultClauseLen,
226 lpcs->dwResultClauseOffset,
227 current_offset, newdata, olddata,
228 &new_one->dwResultClauseLen,
229 &new_one->dwResultClauseOffset, FALSE);
231 current_offset = updateField(lpcs->dwResultStrLen,
232 lpcs->dwResultStrOffset,
233 current_offset, newdata, olddata,
234 &new_one->dwResultStrLen,
235 &new_one->dwResultStrOffset, TRUE);
237 current_offset = updateField(lpcs->dwPrivateSize,
238 lpcs->dwPrivateOffset,
239 current_offset, newdata, olddata,
240 &new_one->dwPrivateSize,
241 &new_one->dwPrivateOffset, FALSE);
244 /* set new data */
245 /* CompAttr */
246 new_one->dwCompAttrLen = len;
247 if (len > 0)
249 new_one->dwCompAttrOffset = current_offset;
250 memset(&newdata[current_offset],ATTR_INPUT,len);
251 current_offset += len;
254 /* CompClause */
255 if (len > 0)
257 new_one->dwCompClauseLen = sizeof(DWORD) * 2;
258 new_one->dwCompClauseOffset = current_offset;
259 *(DWORD*)(&newdata[current_offset]) = 0;
260 current_offset += sizeof(DWORD);
261 *(DWORD*)(&newdata[current_offset]) = len;
262 current_offset += sizeof(DWORD);
264 else
265 new_one->dwCompClauseLen = 0;
267 /* CompStr */
268 new_one->dwCompStrLen = len;
269 if (len > 0)
271 new_one->dwCompStrOffset = current_offset;
272 memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
275 /* CursorPos */
276 new_one->dwCursorPos = len;
278 ImmUnlockIMCC(rc);
279 if (lpcs)
280 ImmUnlockIMCC(old);
282 return rc;
285 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
287 /* we need to make sure the ResultStr and ResultClause fields are all
288 * set and correct */
289 int needed_size;
290 HIMCC rc;
291 LPBYTE newdata = NULL;
292 LPBYTE olddata = NULL;
293 LPCOMPOSITIONSTRING new_one;
294 LPCOMPOSITIONSTRING lpcs = NULL;
295 INT current_offset = 0;
297 TRACE("%s, %li\n",debugstr_wn(resultstr,len),len);
299 if (old == NULL && resultstr == NULL && len == 0)
300 return NULL;
302 if (resultstr == NULL && len != 0)
304 ERR("resultstr is NULL however we have a len! Please report\n");
305 len = 0;
308 if (old != NULL)
310 olddata = ImmLockIMCC(old);
311 lpcs = (LPCOMPOSITIONSTRING)olddata;
314 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
315 sizeof(DWORD) * 2;
317 if (lpcs != NULL)
319 needed_size += lpcs->dwCompReadAttrLen;
320 needed_size += lpcs->dwCompReadClauseLen;
321 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
322 needed_size += lpcs->dwCompAttrLen;
323 needed_size += lpcs->dwCompClauseLen;
324 needed_size += lpcs->dwCompStrLen * sizeof(WCHAR);
325 needed_size += lpcs->dwResultReadClauseLen;
326 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
327 needed_size += lpcs->dwPrivateSize;
329 rc = ImmCreateIMCC(needed_size);
330 newdata = ImmLockIMCC(rc);
331 new_one = (LPCOMPOSITIONSTRING)newdata;
333 new_one->dwSize = needed_size;
334 current_offset = sizeof(COMPOSITIONSTRING);
335 if (lpcs != NULL)
337 current_offset = updateField(lpcs->dwCompReadAttrLen,
338 lpcs->dwCompReadAttrOffset,
339 current_offset, newdata, olddata,
340 &new_one->dwCompReadAttrLen,
341 &new_one->dwCompReadAttrOffset, FALSE);
343 current_offset = updateField(lpcs->dwCompReadClauseLen,
344 lpcs->dwCompReadClauseOffset,
345 current_offset, newdata, olddata,
346 &new_one->dwCompReadClauseLen,
347 &new_one->dwCompReadClauseOffset, FALSE);
349 current_offset = updateField(lpcs->dwCompReadStrLen,
350 lpcs->dwCompReadStrOffset,
351 current_offset, newdata, olddata,
352 &new_one->dwCompReadStrLen,
353 &new_one->dwCompReadStrOffset, TRUE);
355 current_offset = updateField(lpcs->dwCompAttrLen,
356 lpcs->dwCompAttrOffset,
357 current_offset, newdata, olddata,
358 &new_one->dwCompAttrLen,
359 &new_one->dwCompAttrOffset, FALSE);
361 current_offset = updateField(lpcs->dwCompClauseLen,
362 lpcs->dwCompClauseOffset,
363 current_offset, newdata, olddata,
364 &new_one->dwCompClauseLen,
365 &new_one->dwCompClauseOffset, FALSE);
367 current_offset = updateField(lpcs->dwCompStrLen,
368 lpcs->dwCompStrOffset,
369 current_offset, newdata, olddata,
370 &new_one->dwCompStrLen,
371 &new_one->dwCompStrOffset, TRUE);
373 new_one->dwCursorPos = lpcs->dwCursorPos;
374 new_one->dwDeltaStart = 0;
376 current_offset = updateField(lpcs->dwResultReadClauseLen,
377 lpcs->dwResultReadClauseOffset,
378 current_offset, newdata, olddata,
379 &new_one->dwResultReadClauseLen,
380 &new_one->dwResultReadClauseOffset, FALSE);
382 current_offset = updateField(lpcs->dwResultReadStrLen,
383 lpcs->dwResultReadStrOffset,
384 current_offset, newdata, olddata,
385 &new_one->dwResultReadStrLen,
386 &new_one->dwResultReadStrOffset, TRUE);
388 /* new ResultClause , ResultStr */
390 current_offset = updateField(lpcs->dwPrivateSize,
391 lpcs->dwPrivateOffset,
392 current_offset, newdata, olddata,
393 &new_one->dwPrivateSize,
394 &new_one->dwPrivateOffset, FALSE);
397 /* set new data */
398 /* ResultClause */
399 if (len > 0)
401 new_one->dwResultClauseLen = sizeof(DWORD) * 2;
402 new_one->dwResultClauseOffset = current_offset;
403 *(DWORD*)(&newdata[current_offset]) = 0;
404 current_offset += sizeof(DWORD);
405 *(DWORD*)(&newdata[current_offset]) = len;
406 current_offset += sizeof(DWORD);
408 else
409 new_one->dwResultClauseLen = 0;
411 /* ResultStr */
412 new_one->dwResultStrLen = len;
413 if (len > 0)
415 new_one->dwResultStrOffset = current_offset;
416 memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
418 ImmUnlockIMCC(rc);
419 if (lpcs)
420 ImmUnlockIMCC(old);
422 return rc;
425 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam,
426 LPARAM lParam)
428 LPINPUTCONTEXT lpIMC;
429 LPTRANSMSG lpTransMsg;
431 lpIMC = LockRealIMC(hIMC);
432 if (lpIMC == NULL)
433 return;
435 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) *
436 sizeof(TRANSMSG));
437 if (!lpIMC->hMsgBuf)
438 return;
440 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
441 if (!lpTransMsg)
442 return;
444 lpTransMsg += lpIMC->dwNumMsgBuf;
445 lpTransMsg->message = msg;
446 lpTransMsg->wParam = wParam;
447 lpTransMsg->lParam = lParam;
449 ImmUnlockIMCC(lpIMC->hMsgBuf);
450 lpIMC->dwNumMsgBuf++;
452 ImmGenerateMessage(RealIMC(hIMC));
453 UnlockRealIMC(hIMC);
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 TRACE("IMC_SETOPENSTATUS\n");
577 bRet = TRUE;
578 preedit_params.hwnd = lpIMC->hWnd;
579 preedit_params.open = lpIMC->fOpen;
580 X11DRV_CALL( xim_preedit_state, &preedit_params );
581 if (!lpIMC->fOpen)
583 LPIMEPRIVATE myPrivate;
585 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
586 if (myPrivate->bInComposition)
588 X11DRV_CALL( xim_reset, lpIMC->hWnd );
589 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
590 myPrivate->bInComposition = FALSE;
592 ImmUnlockIMCC(lpIMC->hPrivate);
595 break;
596 default: FIXME("Unknown\n"); break;
598 break;
599 case NI_COMPOSITIONSTR:
600 switch (dwIndex)
602 case CPS_COMPLETE:
604 HIMCC newCompStr;
605 LPIMEPRIVATE myPrivate;
606 WCHAR *str;
607 UINT len;
609 TRACE("CPS_COMPLETE\n");
611 /* clear existing result */
612 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
614 ImmDestroyIMCC(lpIMC->hCompStr);
615 lpIMC->hCompStr = newCompStr;
617 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
618 if ((str = input_context_get_comp_str( lpIMC, FALSE, &len )))
620 WCHAR param = str[0];
622 newCompStr = updateResultStr( lpIMC->hCompStr, str, len );
623 ImmDestroyIMCC(lpIMC->hCompStr);
624 lpIMC->hCompStr = newCompStr;
625 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
626 ImmDestroyIMCC(lpIMC->hCompStr);
627 lpIMC->hCompStr = newCompStr;
629 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0,
630 GCS_COMPSTR);
632 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param,
633 GCS_RESULTSTR|GCS_RESULTCLAUSE);
635 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
636 free( str );
638 else if (myPrivate->bInComposition)
639 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
641 myPrivate->bInComposition = FALSE;
642 ImmUnlockIMCC(lpIMC->hPrivate);
644 bRet = TRUE;
646 break;
647 case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break;
648 case CPS_REVERT: FIXME("CPS_REVERT\n"); break;
649 case CPS_CANCEL:
651 LPIMEPRIVATE myPrivate;
653 TRACE("CPS_CANCEL\n");
655 X11DRV_CALL( xim_reset, lpIMC->hWnd );
657 if (lpIMC->hCompStr)
658 ImmDestroyIMCC(lpIMC->hCompStr);
659 lpIMC->hCompStr = ImeCreateBlankCompStr();
661 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
662 if (myPrivate->bInComposition)
664 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
665 myPrivate->bInComposition = FALSE;
667 ImmUnlockIMCC(lpIMC->hPrivate);
668 bRet = TRUE;
670 break;
671 default: FIXME("Unknown\n"); break;
673 break;
674 default: FIXME("Unknown Message\n"); break;
677 UnlockRealIMC(hIMC);
678 return bRet;
681 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp,
682 DWORD dwCompLen, LPCVOID lpRead,
683 DWORD dwReadLen)
685 LPINPUTCONTEXT lpIMC;
686 DWORD flags = 0;
687 WCHAR wParam = 0;
688 LPIMEPRIVATE myPrivate;
690 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
691 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
694 if (hIMC != FROM_X11)
695 FIXME("PROBLEM: This only sets the wine level string\n");
698 * Explanation:
699 * this sets the composition string in the imm32.dll level
700 * of the composition buffer. we cannot manipulate the xim level
701 * buffer, which means that once the xim level buffer changes again
702 * any call to this function from the application will be lost
705 if (lpRead && dwReadLen)
706 FIXME("Reading string unimplemented\n");
708 lpIMC = LockRealIMC(hIMC);
710 if (lpIMC == NULL)
711 return FALSE;
713 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
715 if (dwIndex == SCS_SETSTR)
717 HIMCC newCompStr;
719 if (!myPrivate->bInComposition)
721 GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
722 myPrivate->bInComposition = TRUE;
725 /* clear existing result */
726 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
727 ImmDestroyIMCC(lpIMC->hCompStr);
728 lpIMC->hCompStr = newCompStr;
730 flags = GCS_COMPSTR;
732 if (dwCompLen && lpComp)
734 newCompStr = updateCompStr(lpIMC->hCompStr, (LPCWSTR)lpComp, dwCompLen / sizeof(WCHAR));
735 ImmDestroyIMCC(lpIMC->hCompStr);
736 lpIMC->hCompStr = newCompStr;
738 wParam = ((const WCHAR*)lpComp)[0];
739 flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
741 else
743 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
744 ImmDestroyIMCC(lpIMC->hCompStr);
745 lpIMC->hCompStr = newCompStr;
749 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
750 ImmUnlockIMCC(lpIMC->hPrivate);
751 UnlockRealIMC(hIMC);
753 return TRUE;
756 /* Interfaces to XIM and other parts of winex11drv */
758 NTSTATUS x11drv_ime_set_open_status( UINT open )
760 HIMC imc;
762 imc = RealIMC(FROM_X11);
763 ImmSetOpenStatus(imc, open);
764 return 0;
767 NTSTATUS x11drv_ime_set_composition_status( UINT open )
769 HIMC imc;
770 LPINPUTCONTEXT lpIMC;
771 LPIMEPRIVATE myPrivate;
773 imc = RealIMC(FROM_X11);
774 lpIMC = ImmLockIMC(imc);
775 if (lpIMC == NULL)
776 return 0;
778 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
780 if (open && !myPrivate->bInComposition)
782 GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0);
784 else if (!open && myPrivate->bInComposition)
786 ShowWindow(myPrivate->hwndDefault, SW_HIDE);
787 ImmDestroyIMCC(lpIMC->hCompStr);
788 lpIMC->hCompStr = ImeCreateBlankCompStr();
789 GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0);
791 myPrivate->bInComposition = open;
793 ImmUnlockIMCC(lpIMC->hPrivate);
794 ImmUnlockIMC(imc);
795 return 0;
798 NTSTATUS x11drv_ime_get_cursor_pos( UINT arg )
800 LPINPUTCONTEXT lpIMC;
801 INT rc = 0;
802 LPCOMPOSITIONSTRING compstr;
804 if (!hSelectedFrom)
805 return rc;
807 lpIMC = LockRealIMC(FROM_X11);
808 if (lpIMC)
810 compstr = ImmLockIMCC(lpIMC->hCompStr);
811 rc = compstr->dwCursorPos;
812 ImmUnlockIMCC(lpIMC->hCompStr);
814 UnlockRealIMC(FROM_X11);
815 return rc;
818 NTSTATUS x11drv_ime_set_cursor_pos( UINT pos )
820 LPINPUTCONTEXT lpIMC;
821 LPCOMPOSITIONSTRING compstr;
823 if (!hSelectedFrom)
824 return 0;
826 lpIMC = LockRealIMC(FROM_X11);
827 if (!lpIMC)
828 return 0;
830 compstr = ImmLockIMCC(lpIMC->hCompStr);
831 if (!compstr)
833 UnlockRealIMC(FROM_X11);
834 return 0;
837 compstr->dwCursorPos = pos;
838 ImmUnlockIMCC(lpIMC->hCompStr);
839 UnlockRealIMC(FROM_X11);
840 GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS);
841 return 0;
844 NTSTATUS x11drv_ime_update_association( UINT arg )
846 HWND focus = UlongToHandle( arg );
848 ImmGetContext(focus);
850 if (focus && hSelectedFrom)
851 ImmAssociateContext(focus,RealIMC(FROM_X11));
852 return 0;
856 NTSTATUS WINAPI x11drv_ime_set_composition_string( void *param, ULONG size )
858 return ImeSetCompositionString(FROM_X11, SCS_SETSTR, param, size, NULL, 0);
861 NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG len )
863 WCHAR *lpResult = params;
864 HIMC imc;
865 LPINPUTCONTEXT lpIMC;
866 HIMCC newCompStr;
867 LPIMEPRIVATE myPrivate;
868 BOOL inComp;
869 HWND focus;
871 len /= sizeof(WCHAR);
872 if ((focus = GetFocus()))
873 x11drv_ime_update_association( HandleToUlong( focus ));
875 imc = RealIMC(FROM_X11);
876 lpIMC = ImmLockIMC(imc);
877 if (lpIMC == NULL)
878 return 0;
880 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
881 ImmDestroyIMCC(lpIMC->hCompStr);
882 lpIMC->hCompStr = newCompStr;
884 newCompStr = updateResultStr(lpIMC->hCompStr, lpResult, len);
885 ImmDestroyIMCC(lpIMC->hCompStr);
886 lpIMC->hCompStr = newCompStr;
888 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
889 inComp = myPrivate->bInComposition;
890 ImmUnlockIMCC(lpIMC->hPrivate);
892 if (!inComp)
894 ImmSetOpenStatus(imc, TRUE);
895 GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0);
898 GenerateIMEMessage(imc, WM_IME_COMPOSITION, 0, GCS_COMPSTR);
899 GenerateIMEMessage(imc, WM_IME_COMPOSITION, lpResult[0], GCS_RESULTSTR|GCS_RESULTCLAUSE);
900 GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0);
902 if (!inComp)
903 ImmSetOpenStatus(imc, FALSE);
905 ImmUnlockIMC(imc);
906 return 0;