winex11: Update caret position.
[wine/multimedia.git] / dlls / winex11.drv / ime.c
blobe4a2dd764ccc37fba61d7f4b63bed0e995d53319
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 implimenetaion.
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 "config.h"
45 #include <stdarg.h>
46 #include "windef.h"
47 #include "winbase.h"
48 #include "wingdi.h"
49 #include "winuser.h"
50 #include "winerror.h"
51 #include "wine/debug.h"
52 #include "imm.h"
53 #include "ddk/imm.h"
54 #include "winnls.h"
55 #include "x11drv.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(imm);
59 #define FROM_X11 ((HIMC)0xcafe1337)
61 typedef struct _IMEPRIVATE {
62 BOOL bInComposition;
63 BOOL bInternalState;
64 HFONT textfont;
65 HWND hwndDefault;
66 } IMEPRIVATE, *LPIMEPRIVATE;
68 typedef struct _tagTRANSMSG {
69 UINT message;
70 WPARAM wParam;
71 LPARAM lParam;
72 } TRANSMSG, *LPTRANSMSG;
74 static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e','X','1','1','I','M','E',0};
76 static HIMC *hSelectedFrom = NULL;
77 static INT hSelectedCount = 0;
78 static BOOL hXIMPresent = FALSE;
80 /* MSIME messages */
81 static UINT WM_MSIME_SERVICE;
82 static UINT WM_MSIME_RECONVERTOPTIONS;
83 static UINT WM_MSIME_MOUSE;
84 static UINT WM_MSIME_RECONVERTREQUEST;
85 static UINT WM_MSIME_RECONVERT;
86 static UINT WM_MSIME_QUERYPOSITION;
87 static UINT WM_MSIME_DOCUMENTFEED;
89 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
90 LPARAM lParam);
91 static void UpdateDataInDefaultIMEWindow(HIMC hHIMC, HWND hwnd, BOOL showable);
93 static HIMC RealIMC(HIMC hIMC)
95 if (hIMC == FROM_X11)
97 INT i;
98 HWND wnd = GetFocus();
99 HIMC winHimc = ImmGetContext(wnd);
100 for (i = 0; i < hSelectedCount; i++)
101 if (winHimc == hSelectedFrom[i])
102 return winHimc;
103 return NULL;
105 else
106 return hIMC;
109 static LPINPUTCONTEXT LockRealIMC(HIMC hIMC)
111 HIMC real_imc = RealIMC(hIMC);
112 if (real_imc)
113 return (LPINPUTCONTEXT)ImmLockIMC(real_imc);
114 else
115 return NULL;
118 static BOOL UnlockRealIMC(HIMC hIMC)
120 HIMC real_imc = RealIMC(hIMC);
121 if (real_imc)
122 return ImmUnlockIMC(real_imc);
123 else
124 return FALSE;
127 static HIMCC ImeCreateBlankCompStr(void)
129 HIMCC rc;
130 LPCOMPOSITIONSTRING ptr;
131 rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
132 ptr = (LPCOMPOSITIONSTRING)ImmLockIMCC(rc);
133 memset(ptr,0,sizeof(COMPOSITIONSTRING));
134 ptr->dwSize = sizeof(COMPOSITIONSTRING);
135 ImmUnlockIMCC(rc);
136 return rc;
139 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
140 LPBYTE target, LPBYTE source, DWORD* lenParam,
141 DWORD* offsetParam, BOOL wchars )
143 if (origLen > 0 && origOffset > 0)
145 int truelen = origLen;
146 if (wchars)
147 truelen *= sizeof(WCHAR);
149 memcpy(&target[currentOffset], &source[origOffset], truelen);
151 *lenParam = origLen;
152 *offsetParam = currentOffset;
153 currentOffset += truelen;
155 return currentOffset;
158 static HIMCC updateCompStr(HIMCC old, LPWSTR compstr, DWORD len)
160 /* we need to make sure the CompStr, CompClaus and CompAttr fields are all
161 * set and correct */
162 int needed_size;
163 HIMCC rc;
164 LPBYTE newdata = NULL;
165 LPBYTE olddata = NULL;
166 LPCOMPOSITIONSTRING new_one;
167 LPCOMPOSITIONSTRING lpcs = NULL;
168 INT current_offset = 0;
170 TRACE("%s, %i\n",debugstr_wn(compstr,len),len);
172 if (old == NULL && compstr == NULL && len == 0)
173 return NULL;
175 if (old != NULL)
177 olddata = ImmLockIMCC(old);
178 lpcs = (LPCOMPOSITIONSTRING)olddata;
181 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
182 len + sizeof(DWORD) * 2;
184 if (lpcs != NULL)
186 needed_size += lpcs->dwCompReadAttrLen;
187 needed_size += lpcs->dwCompReadClauseLen;
188 needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
189 needed_size += lpcs->dwResultReadClauseLen;
190 needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
191 needed_size += lpcs->dwResultClauseLen;
192 needed_size += lpcs->dwResultStrLen * sizeof(DWORD);
193 needed_size += lpcs->dwPrivateSize;
195 rc = ImmCreateIMCC(needed_size);
196 newdata = ImmLockIMCC(rc);
197 new_one = (LPCOMPOSITIONSTRING)newdata;
199 new_one->dwSize = needed_size;
200 current_offset = sizeof(COMPOSITIONSTRING);
201 if (lpcs != NULL)
203 current_offset = updateField(lpcs->dwCompReadAttrLen,
204 lpcs->dwCompReadAttrOffset,
205 current_offset, newdata, olddata,
206 &new_one->dwCompReadAttrLen,
207 &new_one->dwCompReadAttrOffset, FALSE);
209 current_offset = updateField(lpcs->dwCompReadClauseLen,
210 lpcs->dwCompReadClauseOffset,
211 current_offset, newdata, olddata,
212 &new_one->dwCompReadClauseLen,
213 &new_one->dwCompReadClauseOffset, FALSE);
215 current_offset = updateField(lpcs->dwCompReadStrLen,
216 lpcs->dwCompReadStrOffset,
217 current_offset, newdata, olddata,
218 &new_one->dwCompReadStrLen,
219 &new_one->dwCompReadStrOffset, TRUE);
221 /* new CompAttr, CompClause, CompStr, dwCursorPos */
222 new_one->dwDeltaStart = 0;
224 current_offset = updateField(lpcs->dwResultReadClauseLen,
225 lpcs->dwResultReadClauseOffset,
226 current_offset, newdata, olddata,
227 &new_one->dwResultReadClauseLen,
228 &new_one->dwResultReadClauseOffset, FALSE);
230 current_offset = updateField(lpcs->dwResultReadStrLen,
231 lpcs->dwResultReadStrOffset,
232 current_offset, newdata, olddata,
233 &new_one->dwResultReadStrLen,
234 &new_one->dwResultReadStrOffset, TRUE);
236 current_offset = updateField(lpcs->dwResultClauseLen,
237 lpcs->dwResultClauseOffset,
238 current_offset, newdata, olddata,
239 &new_one->dwResultClauseLen,
240 &new_one->dwResultClauseOffset, FALSE);
242 current_offset = updateField(lpcs->dwResultStrLen,
243 lpcs->dwResultStrOffset,
244 current_offset, newdata, olddata,
245 &new_one->dwResultStrLen,
246 &new_one->dwResultStrOffset, TRUE);
248 current_offset = updateField(lpcs->dwPrivateSize,
249 lpcs->dwPrivateOffset,
250 current_offset, newdata, olddata,
251 &new_one->dwPrivateSize,
252 &new_one->dwPrivateOffset, FALSE);
255 /* set new data */
256 /* CompAttr */
257 new_one->dwCompAttrLen = len;
258 if (len > 0)
260 new_one->dwCompAttrOffset = current_offset;
261 memset(&newdata[current_offset],ATTR_INPUT,len);
262 current_offset += len;
265 /* CompClause */
266 if (len > 0)
268 new_one->dwCompClauseLen = sizeof(DWORD) * 2;
269 new_one->dwCompClauseOffset = current_offset;
270 *(DWORD*)(&newdata[current_offset]) = 0;
271 current_offset += sizeof(DWORD);
272 *(DWORD*)(&newdata[current_offset]) = len;
273 current_offset += sizeof(DWORD);
276 /* CompStr */
277 new_one->dwCompStrLen = len;
278 if (len > 0)
280 new_one->dwCompStrOffset = current_offset;
281 memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
284 /* CursorPos */
285 new_one->dwCursorPos = len;
287 ImmUnlockIMCC(rc);
288 if (lpcs)
289 ImmUnlockIMCC(old);
291 return rc;
294 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
296 /* we need to make sure the ResultStr and ResultClause fields are all
297 * set and correct */
298 int needed_size;
299 HIMCC rc;
300 LPBYTE newdata = NULL;
301 LPBYTE olddata = NULL;
302 LPCOMPOSITIONSTRING new_one;
303 LPCOMPOSITIONSTRING lpcs = NULL;
304 INT current_offset = 0;
306 TRACE("%s, %i\n",debugstr_wn(resultstr,len),len);
308 if (old == NULL && resultstr == NULL && len == 0)
309 return NULL;
311 if (old != NULL)
313 olddata = ImmLockIMCC(old);
314 lpcs = (LPCOMPOSITIONSTRING)olddata;
317 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
318 sizeof(DWORD) * 2;
320 if (lpcs != NULL)
322 needed_size += lpcs->dwCompReadAttrLen;
323 needed_size += lpcs->dwCompReadClauseLen;
324 needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
325 needed_size += lpcs->dwCompAttrLen;
326 needed_size += lpcs->dwCompClauseLen;
327 needed_size += lpcs->dwCompStrLen * sizeof(DWORD);
328 needed_size += lpcs->dwResultReadClauseLen;
329 needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
330 needed_size += lpcs->dwPrivateSize;
332 rc = ImmCreateIMCC(needed_size);
333 newdata = ImmLockIMCC(rc);
334 new_one = (LPCOMPOSITIONSTRING)newdata;
336 new_one->dwSize = needed_size;
337 current_offset = sizeof(COMPOSITIONSTRING);
338 if (lpcs != NULL)
340 current_offset = updateField(lpcs->dwCompReadAttrLen,
341 lpcs->dwCompReadAttrOffset,
342 current_offset, newdata, olddata,
343 &new_one->dwCompReadAttrLen,
344 &new_one->dwCompReadAttrOffset, FALSE);
346 current_offset = updateField(lpcs->dwCompReadClauseLen,
347 lpcs->dwCompReadClauseOffset,
348 current_offset, newdata, olddata,
349 &new_one->dwCompReadClauseLen,
350 &new_one->dwCompReadClauseOffset, FALSE);
352 current_offset = updateField(lpcs->dwCompReadStrLen,
353 lpcs->dwCompReadStrOffset,
354 current_offset, newdata, olddata,
355 &new_one->dwCompReadStrLen,
356 &new_one->dwCompReadStrOffset, TRUE);
358 current_offset = updateField(lpcs->dwCompAttrLen,
359 lpcs->dwCompAttrOffset,
360 current_offset, newdata, olddata,
361 &new_one->dwCompAttrLen,
362 &new_one->dwCompAttrOffset, FALSE);
364 current_offset = updateField(lpcs->dwCompClauseLen,
365 lpcs->dwCompClauseOffset,
366 current_offset, newdata, olddata,
367 &new_one->dwCompClauseLen,
368 &new_one->dwCompClauseOffset, FALSE);
370 current_offset = updateField(lpcs->dwCompStrLen,
371 lpcs->dwCompStrOffset,
372 current_offset, newdata, olddata,
373 &new_one->dwCompStrLen,
374 &new_one->dwCompStrOffset, TRUE);
376 new_one->dwCursorPos = lpcs->dwCursorPos;
377 new_one->dwDeltaStart = 0;
379 current_offset = updateField(lpcs->dwResultReadClauseLen,
380 lpcs->dwResultReadClauseOffset,
381 current_offset, newdata, olddata,
382 &new_one->dwResultReadClauseLen,
383 &new_one->dwResultReadClauseOffset, FALSE);
385 current_offset = updateField(lpcs->dwResultReadStrLen,
386 lpcs->dwResultReadStrOffset,
387 current_offset, newdata, olddata,
388 &new_one->dwResultReadStrLen,
389 &new_one->dwResultReadStrOffset, TRUE);
391 /* new ResultClause , ResultStr */
393 current_offset = updateField(lpcs->dwPrivateSize,
394 lpcs->dwPrivateOffset,
395 current_offset, newdata, olddata,
396 &new_one->dwPrivateSize,
397 &new_one->dwPrivateOffset, FALSE);
400 /* set new data */
401 /* ResultClause */
402 if (len > 0)
404 new_one->dwResultClauseLen = sizeof(DWORD) * 2;
405 new_one->dwResultClauseOffset = current_offset;
406 *(DWORD*)(&newdata[current_offset]) = 0;
407 current_offset += sizeof(DWORD);
408 *(DWORD*)(&newdata[current_offset]) = len;
409 current_offset += sizeof(DWORD);
412 /* ResultStr */
413 new_one->dwResultStrLen = len;
414 if (len > 0)
416 new_one->dwResultStrOffset = current_offset;
417 memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
419 ImmUnlockIMCC(rc);
420 if (lpcs)
421 ImmUnlockIMCC(old);
423 return rc;
426 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam,
427 LPARAM lParam)
429 LPINPUTCONTEXT lpIMC;
430 LPTRANSMSG lpTransMsg;
432 lpIMC = LockRealIMC(hIMC);
433 if (lpIMC == NULL)
434 return;
436 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) *
437 sizeof(TRANSMSG));
438 if (!lpIMC->hMsgBuf)
439 return;
441 lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf);
442 if (!lpTransMsg)
443 return;
445 lpTransMsg += lpIMC->dwNumMsgBuf;
446 lpTransMsg->message = msg;
447 lpTransMsg->wParam = wParam;
448 lpTransMsg->lParam = lParam;
450 ImmUnlockIMCC(lpIMC->hMsgBuf);
451 lpIMC->dwNumMsgBuf++;
453 ImmGenerateMessage(RealIMC(hIMC));
454 UnlockRealIMC(hIMC);
457 static void GenerateIMECHARMessages(HIMC hIMC, LPWSTR String, DWORD length)
459 LPINPUTCONTEXT lpIMC;
460 LPTRANSMSG lpTransMsg;
461 INT i;
463 if (length <= 0)
464 return;
466 lpIMC = LockRealIMC(hIMC);
467 if (lpIMC == NULL)
468 return;
470 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf,
471 (lpIMC->dwNumMsgBuf + length) *
472 sizeof(TRANSMSG));
473 if (!lpIMC->hMsgBuf)
474 return;
476 lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf);
477 if (!lpTransMsg)
478 return;
480 lpTransMsg += lpIMC->dwNumMsgBuf;
481 for (i = 0; i < length; i++)
483 lpTransMsg->message = WM_IME_CHAR;
484 lpTransMsg->wParam = String[i];
485 lpTransMsg->lParam = 1;
486 lpTransMsg ++;
489 ImmUnlockIMCC(lpIMC->hMsgBuf);
490 lpIMC->dwNumMsgBuf+=length;
492 ImmGenerateMessage(RealIMC(hIMC));
493 UnlockRealIMC(hIMC);
496 static BOOL IME_RemoveFromSelected(HIMC hIMC)
498 int i;
499 for (i = 0; i < hSelectedCount; i++)
500 if (hSelectedFrom[i] == hIMC)
502 if (i < hSelectedCount - 1)
503 memcpy(&hSelectedFrom[i], &hSelectedFrom[i+1], (hSelectedCount - i - 1)*sizeof(HIMC));
504 hSelectedCount --;
505 return TRUE;
507 return FALSE;
510 static void IME_AddToSelected(HIMC hIMC)
512 hSelectedCount++;
513 if (hSelectedFrom)
514 hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount*sizeof(HIMC));
515 else
516 hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC));
517 hSelectedFrom[hSelectedCount-1] = hIMC;
520 BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass,
521 LPCWSTR lpszOption)
523 TRACE("\n");
524 if (!hXIMPresent)
526 ERR("No XIM in the back end\n");
527 return FALSE;
529 lpIMEInfo->dwPrivateDataSize = sizeof (IMEPRIVATE);
530 lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
531 lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE;
532 lpIMEInfo->fdwSentenceCaps = IME_SMODE_AUTOMATIC;
533 lpIMEInfo->fdwUICaps = UI_CAP_2700;
534 /* Tell App we cannot accept ImeSetCompositionString calls */
535 lpIMEInfo->fdwSCSCaps = 0;
536 lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
538 lstrcpyW(lpszUIClass,UI_CLASS_NAME);
540 return TRUE;
543 BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)
545 FIXME("(%p, %p, %d, %p): stub\n", hKL, hWnd, dwMode, lpData);
546 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
547 return FALSE;
550 DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource,
551 LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag)
554 FIXME("(%p, %s, %p, %d, %d): stub\n", hIMC, debugstr_w(lpSource),
555 lpCandList, dwBufLen, uFlag);
556 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
557 return 0;
560 BOOL WINAPI ImeDestroy(UINT uForce)
562 TRACE("\n");
563 HeapFree(GetProcessHeap(),0,hSelectedFrom);
564 hSelectedFrom = NULL;
565 hSelectedCount = 0;
566 return TRUE;
569 LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
571 FIXME("(%p, %d, %p): stub\n", hIMC, uSubFunc, lpData);
572 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
573 return 0;
576 BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData,
577 CONST LPBYTE lpbKeyState)
579 /* See the comment at the head of this file */
580 TRACE("We do no processing via this route\n");
581 return FALSE;
584 BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
586 LPINPUTCONTEXT lpIMC;
587 TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE");
589 if (hIMC == FROM_X11)
591 ERR("ImeSelect should never be called from X11\n");
592 return FALSE;
595 if (!hXIMPresent)
597 ERR("No XIM in the back end\n");
598 return FALSE;
601 if (!hIMC)
602 return TRUE;
604 /* not selected */
605 if (!fSelect)
606 return IME_RemoveFromSelected(hIMC);
608 IME_AddToSelected(hIMC);
610 /* Initialize our structures */
611 lpIMC = LockRealIMC(hIMC);
612 if (lpIMC != NULL)
614 LPIMEPRIVATE myPrivate;
615 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
616 myPrivate->bInComposition = FALSE;
617 myPrivate->bInternalState = FALSE;
618 myPrivate->textfont = NULL;
619 myPrivate->hwndDefault = NULL;
620 ImmUnlockIMCC(lpIMC->hPrivate);
621 UnlockRealIMC(hIMC);
624 return TRUE;
627 BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag)
629 FIXME("Stub");
630 return TRUE;
633 UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode,
634 CONST LPBYTE lpbKeyState, LPDWORD lpdwTransKey,
635 UINT fuState, HIMC hIMC)
637 /* See the comment at the head of this file */
638 TRACE("We do no processing via this route\n");
639 return 0;
642 BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
644 BOOL bRet = FALSE;
645 LPINPUTCONTEXT lpIMC;
647 TRACE("%p %i %i %i\n",hIMC,dwAction,dwIndex,dwValue);
649 lpIMC = LockRealIMC(hIMC);
650 if (lpIMC == NULL)
651 return FALSE;
653 switch (dwAction)
655 case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break;
656 case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break;
657 case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break;
658 case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break;
659 case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
660 case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
661 case NI_CONTEXTUPDATED:
662 FIXME("NI_CONTEXTUPDATED:");
663 switch (dwValue)
665 case IMC_SETCOMPOSITIONWINDOW: FIXME("IMC_SETCOMPOSITIONWINDOW\n"); break;
666 case IMC_SETCONVERSIONMODE: FIXME("IMC_SETCONVERSIONMODE\n"); break;
667 case IMC_SETSENTENCEMODE: FIXME("IMC_SETSENTENCEMODE\n"); break;
668 case IMC_SETCANDIDATEPOS: FIXME("IMC_SETCANDIDATEPOS\n"); break;
669 case IMC_SETCOMPOSITIONFONT:
671 LPIMEPRIVATE myPrivate;
672 TRACE("IMC_SETCOMPOSITIONFONT\n");
674 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
675 if (myPrivate->textfont)
677 DeleteObject(myPrivate->textfont);
678 myPrivate->textfont = NULL;
680 myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W);
681 ImmUnlockIMCC(lpIMC->hPrivate);
683 break;
684 case IMC_SETOPENSTATUS:
686 LPIMEPRIVATE myPrivate;
687 TRACE("IMC_SETOPENSTATUS\n");
689 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
690 if (lpIMC->fOpen != myPrivate->bInternalState)
692 if(lpIMC->fOpen == FALSE)
694 X11DRV_ForceXIMReset(lpIMC->hWnd);
695 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION,0,0);
697 else
698 GenerateIMEMessage(hIMC,WM_IME_STARTCOMPOSITION,0,0);
700 bRet = TRUE;
702 break;
703 default: FIXME("Unknown\n"); break;
705 break;
706 case NI_COMPOSITIONSTR:
707 TRACE("NI_COMPOSITIONSTR:");
708 switch (dwIndex)
710 case CPS_COMPLETE:
712 HIMCC newCompStr;
713 DWORD cplen = 0;
714 LPWSTR cpstr;
715 LPCOMPOSITIONSTRING cs = NULL;
716 LPBYTE cdata = NULL;
717 LPIMEPRIVATE myPrivate;
719 TRACE("CPS_COMPLETE\n");
721 /* clear existing result */
722 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
724 ImmDestroyIMCC(lpIMC->hCompStr);
725 lpIMC->hCompStr = newCompStr;
727 if (lpIMC->hCompStr)
729 cdata = ImmLockIMCC(lpIMC->hCompStr);
730 cs = (LPCOMPOSITIONSTRING)cdata;
731 cplen = cs->dwCompStrLen;
732 cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]);
733 ImmUnlockIMCC(lpIMC->hCompStr);
735 if (cplen > 0)
737 WCHAR param = cpstr[0];
739 newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen);
740 ImmDestroyIMCC(lpIMC->hCompStr);
741 lpIMC->hCompStr = newCompStr;
742 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
743 ImmDestroyIMCC(lpIMC->hCompStr);
744 lpIMC->hCompStr = newCompStr;
746 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0,
747 GCS_COMPSTR);
749 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param,
750 GCS_RESULTSTR|GCS_RESULTCLAUSE);
753 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
755 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
756 myPrivate->bInComposition = FALSE;
757 ImmUnlockIMCC(lpIMC->hPrivate);
759 bRet = TRUE;
761 break;
762 case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break;
763 case CPS_REVERT: FIXME("CPS_REVERT\n"); break;
764 case CPS_CANCEL:
766 BOOL send;
767 LPCOMPOSITIONSTRING lpCompStr;
769 TRACE("CPS_CANCEL\n");
771 X11DRV_ForceXIMReset(lpIMC->hWnd);
773 lpCompStr = ImmLockIMCC(lpIMC->hCompStr);
774 send = (lpCompStr->dwCompStrLen != 0);
775 ImmUnlockIMCC(lpIMC->hCompStr);
777 if (send)
779 HIMCC newCompStr;
780 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
781 ImmDestroyIMCC(lpIMC->hCompStr);
782 lpIMC->hCompStr = newCompStr;
783 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, GCS_COMPSTR);
785 bRet = TRUE;
787 break;
788 default: FIXME("Unknown\n"); break;
790 break;
791 default: FIXME("Unknown Message\n"); break;
794 UnlockRealIMC(hIMC);
795 return bRet;
798 BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle,
799 LPCWSTR lpszRegister)
801 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
802 debugstr_w(lpszRegister));
803 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
804 return FALSE;
807 BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle,
808 LPCWSTR lpszUnregister)
810 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
811 debugstr_w(lpszUnregister));
812 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
813 return FALSE;
816 UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf)
818 FIXME("(%d, %p): stub\n", nItem, lpStyleBuf);
819 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
820 return 0;
823 UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc,
824 LPCWSTR lpszReading, DWORD dwStyle,
825 LPCWSTR lpszRegister, LPVOID lpData)
827 FIXME("(%p, %s, %d, %s, %p): stub\n", lpfnEnumProc,
828 debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister),
829 lpData);
830 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
831 return 0;
834 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp,
835 DWORD dwCompLen, LPCVOID lpRead,
836 DWORD dwReadLen)
838 LPINPUTCONTEXT lpIMC;
839 DWORD flags = 0;
840 WCHAR wParam = 0;
841 LPIMEPRIVATE myPrivate;
843 TRACE("(%p, %d, %p, %d, %p, %d):\n",
844 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
847 if (hIMC != FROM_X11)
848 FIXME("PROBLEM: This only sets the wine level string\n");
851 * Explanation:
852 * this sets the composition string in the imm32.dll level
853 * of the composition buffer. we cannot manipulate the xim level
854 * buffer, which means that once the xim level buffer changes again
855 * any call to this function from the application will be lost
858 if (lpRead && dwReadLen)
859 FIXME("Reading string unimplemented\n");
861 lpIMC = LockRealIMC(hIMC);
863 if (lpIMC == NULL)
864 return FALSE;
866 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
868 if (dwIndex == SCS_SETSTR)
870 HIMCC newCompStr;
872 if (!myPrivate->bInComposition)
874 GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
875 myPrivate->bInComposition = TRUE;
878 flags = GCS_COMPSTR;
880 if (dwCompLen && lpComp)
882 newCompStr = updateCompStr(lpIMC->hCompStr, (LPWSTR)lpComp, dwCompLen / sizeof(WCHAR));
883 ImmDestroyIMCC(lpIMC->hCompStr);
884 lpIMC->hCompStr = newCompStr;
886 wParam = ((const WCHAR*)lpComp)[0];
887 flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
889 else
891 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
892 ImmDestroyIMCC(lpIMC->hCompStr);
893 lpIMC->hCompStr = newCompStr;
897 UpdateDataInDefaultIMEWindow(hIMC, myPrivate->hwndDefault,FALSE);
899 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
900 ImmUnlockIMCC(lpIMC->hPrivate);
901 UnlockRealIMC(hIMC);
903 return TRUE;
906 DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType,
907 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
908 DWORD dwSize)
910 FIXME("(%p, %x %x %p %p %x): stub\n", hIMC, dwFlags, dwType,
911 lpImeParentMenu, lpImeMenu, dwSize);
912 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
913 return 0;
916 /* Interfaces to XIM and other parts of winex11drv */
918 void IME_RegisterClasses(HINSTANCE hImeInst)
920 WNDCLASSW wndClass;
921 ZeroMemory(&wndClass, sizeof(WNDCLASSW));
922 wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
923 wndClass.lpfnWndProc = (WNDPROC) IME_WindowProc;
924 wndClass.cbClsExtra = 0;
925 wndClass.cbWndExtra = 2 * sizeof(LONG);
926 wndClass.hInstance = hImeInst;
927 wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
928 wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
929 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1);
930 wndClass.lpszMenuName = 0;
931 wndClass.lpszClassName = UI_CLASS_NAME;
933 RegisterClassW(&wndClass);
935 WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
936 WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
937 WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
938 WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
939 WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
940 WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
941 WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
944 void IME_UnregisterClasses(HINSTANCE hImeInst)
946 UnregisterClassW(UI_CLASS_NAME, hImeInst);
949 void IME_SetOpenStatus(BOOL fOpen)
951 LPINPUTCONTEXT lpIMC;
952 LPIMEPRIVATE myPrivate;
954 lpIMC = LockRealIMC(FROM_X11);
955 if (lpIMC == NULL)
956 return;
958 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
960 if (myPrivate->bInternalState && fOpen == FALSE)
962 ShowWindow(myPrivate->hwndDefault, SW_HIDE);
963 ImmDestroyIMCC(lpIMC->hCompStr);
964 lpIMC->hCompStr = ImeCreateBlankCompStr();
966 myPrivate->bInternalState = fOpen;
968 ImmUnlockIMCC(lpIMC->hPrivate);
969 UnlockRealIMC(FROM_X11);
971 ImmSetOpenStatus(RealIMC(FROM_X11), fOpen);
974 void IME_XIMPresent(BOOL present)
976 hXIMPresent = present;
979 LRESULT IME_SendMessageToSelectedHWND(UINT msg, WPARAM wParam, LPARAM lParam)
981 LPINPUTCONTEXT lpIMC;
982 LRESULT rc = 0;
984 if (!hSelectedFrom)
985 return rc;
987 lpIMC = LockRealIMC(FROM_X11);
988 if (lpIMC)
989 rc = SendMessageW(lpIMC->hWnd,msg,wParam,lParam);
991 UnlockRealIMC(FROM_X11);
992 return rc;
995 INT IME_GetCursorPos()
997 LPINPUTCONTEXT lpIMC;
998 INT rc = 0;
999 LPCOMPOSITIONSTRING compstr;
1001 if (!hSelectedFrom)
1002 return rc;
1004 lpIMC = LockRealIMC(FROM_X11);
1005 if (lpIMC)
1007 compstr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
1008 rc = compstr->dwCursorPos;
1009 ImmUnlockIMCC(lpIMC->hCompStr);
1011 UnlockRealIMC(FROM_X11);
1012 return rc;
1015 void IME_SetCursorPos(DWORD pos)
1017 LPINPUTCONTEXT lpIMC;
1018 LPCOMPOSITIONSTRING compstr;
1020 if (!hSelectedFrom)
1021 return;
1023 lpIMC = LockRealIMC(FROM_X11);
1024 if (!lpIMC)
1025 return;
1027 compstr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
1028 if (!compstr)
1030 UnlockRealIMC(FROM_X11);
1031 return;
1034 compstr->dwCursorPos = pos;
1035 ImmUnlockIMCC(lpIMC->hCompStr);
1036 UnlockRealIMC(FROM_X11);
1037 GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS);
1038 return;
1041 void IME_UpdateAssociation(HWND focus)
1043 ImmGetContext(focus);
1045 if (!focus || !hSelectedFrom)
1046 return;
1048 ImmAssociateContext(focus,RealIMC(FROM_X11));
1052 BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen,
1053 LPCVOID lpRead, DWORD dwReadLen)
1055 return ImeSetCompositionString(FROM_X11, dwIndex, lpComp, dwCompLen,
1056 lpRead, dwReadLen);
1059 BOOL IME_NotifyIME(DWORD dwAction, DWORD dwIndex, DWORD dwValue)
1061 return NotifyIME(FROM_X11, dwAction, dwIndex, dwValue);
1064 /*****
1065 * Internal functions to help with IME window management
1067 static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd)
1069 PAINTSTRUCT ps;
1070 RECT rect;
1071 HDC hdc;
1072 LPCOMPOSITIONSTRING compstr;
1073 LPBYTE compdata = NULL;
1074 HMONITOR monitor;
1075 MONITORINFO mon_info;
1076 INT offX=0, offY=0;
1077 LPINPUTCONTEXT lpIMC;
1079 lpIMC = LockRealIMC(hIMC);
1080 if (lpIMC == NULL)
1081 return;
1083 hdc = BeginPaint(hwnd,&ps);
1085 GetClientRect(hwnd,&rect);
1086 FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
1088 compdata = ImmLockIMCC(lpIMC->hCompStr);
1089 compstr = (LPCOMPOSITIONSTRING)compdata;
1091 if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
1093 SIZE size;
1094 POINT pt;
1095 HFONT oldfont = NULL;
1096 LPWSTR CompString;
1097 LPIMEPRIVATE myPrivate;
1099 CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1100 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
1102 if (myPrivate->textfont)
1103 oldfont = SelectObject(hdc,myPrivate->textfont);
1105 ImmUnlockIMCC(lpIMC->hPrivate);
1107 GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
1108 pt.x = size.cx;
1109 pt.y = size.cy;
1110 LPtoDP(hdc,&pt,1);
1113 * How this works based on tests on windows:
1114 * CFS_POINT: then we start our window at the point and grow it as large
1115 * as it needs to be for the string.
1116 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
1117 * window is only as large as we need for the string, but we do not
1118 * grow such that our window exceeds the given rect. Wrapping if
1119 * needed and possible. If our ptCurrentPos is outside of our rect
1120 * then no window is displayed.
1121 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
1122 * maybe becase the default MSIME does not do any IME adjusting.
1124 if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT)
1126 POINT cpt = lpIMC->cfCompForm.ptCurrentPos;
1127 ClientToScreen(lpIMC->hWnd,&cpt);
1128 rect.left = cpt.x;
1129 rect.top = cpt.y;
1130 rect.right = rect.left + pt.x;
1131 rect.bottom = rect.top + pt.y;
1132 monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY);
1134 else /* CFS_DEFAULT */
1136 /* Windows places the default IME window in the bottom left */
1137 HWND target = lpIMC->hWnd;
1138 if (!target) target = GetFocus();
1140 GetWindowRect(target,&rect);
1141 rect.top = rect.bottom;
1142 rect.right = rect.left + pt.x + 20;
1143 rect.bottom = rect.top + pt.y + 20;
1144 offX=offY=10;
1145 monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY);
1148 if (lpIMC->cfCompForm.dwStyle == CFS_RECT)
1150 RECT client;
1151 client =lpIMC->cfCompForm.rcArea;
1152 MapWindowPoints( lpIMC->hWnd, 0, (POINT *)&client, 2 );
1153 IntersectRect(&rect,&rect,&client);
1154 /* TODO: Wrap the input if needed */
1157 if (lpIMC->cfCompForm.dwStyle == CFS_DEFAULT)
1159 /* make sure we are on the desktop */
1160 mon_info.cbSize = sizeof(mon_info);
1161 GetMonitorInfoW(monitor, &mon_info);
1163 if (rect.bottom > mon_info.rcWork.bottom)
1165 int shift = rect.bottom - mon_info.rcWork.bottom;
1166 rect.top -= shift;
1167 rect.bottom -= shift;
1169 if (rect.left < 0)
1171 rect.right -= rect.left;
1172 rect.left = 0;
1174 if (rect.right > mon_info.rcWork.right)
1176 int shift = rect.right - mon_info.rcWork.right;
1177 rect.left -= shift;
1178 rect.right -= shift;
1182 SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);
1184 TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen);
1186 if (oldfont)
1187 SelectObject(hdc,oldfont);
1190 ImmUnlockIMCC(lpIMC->hCompStr);
1192 EndPaint(hwnd,&ps);
1193 UnlockRealIMC(hIMC);
1196 static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable)
1198 LPCOMPOSITIONSTRING compstr;
1199 LPINPUTCONTEXT lpIMC;
1201 lpIMC = LockRealIMC(hIMC);
1202 if (lpIMC == NULL)
1203 return;
1205 if (lpIMC->hCompStr)
1206 compstr = ImmLockIMCC(lpIMC->hCompStr);
1207 else
1208 compstr = NULL;
1210 if (compstr == NULL || compstr->dwCompStrLen == 0)
1211 ShowWindow(hwnd,SW_HIDE);
1212 else if (showable)
1213 ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1215 RedrawWindow(hwnd,NULL,NULL,RDW_ERASENOW|RDW_INVALIDATE);
1217 if (compstr != NULL)
1218 ImmUnlockIMCC(lpIMC->hCompStr);
1220 UnlockRealIMC(hIMC);
1223 static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam)
1225 TRACE("IME message WM_IME_COMPOSITION 0x%lx\n", lParam);
1226 if (lParam & GCS_RESULTSTR)
1228 LPCOMPOSITIONSTRING compstr;
1229 LPBYTE compdata;
1230 LPWSTR ResultStr;
1231 HIMCC newCompStr;
1232 LPINPUTCONTEXT lpIMC;
1234 lpIMC = LockRealIMC(hIMC);
1235 if (lpIMC == NULL)
1236 return;
1238 TRACE("Posting result as IME_CHAR\n");
1239 compdata = ImmLockIMCC(lpIMC->hCompStr);
1240 compstr = (LPCOMPOSITIONSTRING)compdata;
1241 ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1242 GenerateIMECHARMessages(hIMC, ResultStr, compstr->dwResultStrLen);
1243 ImmUnlockIMCC(lpIMC->hCompStr);
1245 /* clear the buffer */
1246 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
1247 ImmDestroyIMCC(lpIMC->hCompStr);
1248 lpIMC->hCompStr = newCompStr;
1249 UnlockRealIMC(hIMC);
1251 else
1252 UpdateDataInDefaultIMEWindow(hIMC,hwnd,TRUE);
1255 static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd )
1257 LPINPUTCONTEXT lpIMC;
1259 lpIMC = LockRealIMC(hIMC);
1260 if (lpIMC == NULL)
1261 return;
1263 TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1264 lpIMC->hWnd = GetFocus();
1265 ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1266 UnlockRealIMC(hIMC);
1269 static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam,
1270 LPARAM lParam)
1272 switch (wParam)
1274 case IMN_OPENSTATUSWINDOW:
1275 FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1276 break;
1277 case IMN_CLOSESTATUSWINDOW:
1278 FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1279 break;
1280 case IMN_OPENCANDIDATE:
1281 FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1282 break;
1283 case IMN_CHANGECANDIDATE:
1284 FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1285 break;
1286 case IMN_CLOSECANDIDATE:
1287 FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1288 break;
1289 case IMN_SETCONVERSIONMODE:
1290 FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1291 break;
1292 case IMN_SETSENTENCEMODE:
1293 FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1294 break;
1295 case IMN_SETOPENSTATUS:
1296 FIXME("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1297 break;
1298 case IMN_SETCANDIDATEPOS:
1299 FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1300 break;
1301 case IMN_SETCOMPOSITIONFONT:
1302 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1303 break;
1304 case IMN_SETCOMPOSITIONWINDOW:
1305 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1306 break;
1307 case IMN_GUIDELINE:
1308 FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1309 break;
1310 case IMN_SETSTATUSWINDOWPOS:
1311 FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1312 break;
1313 default:
1314 FIXME("WM_IME_NOTIFY:<Unknown 0x%lx>\n",wParam);
1315 break;
1317 return 0;
1320 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
1321 LPARAM lParam)
1323 LRESULT rc = 0;
1324 HIMC hIMC;
1326 TRACE("Incoming Message 0x%x (0x%08lx, 0x%08lx)\n", msg, wParam, lParam);
1329 * Each UI window contains the current Input Context.
1330 * This Input Context can be obtained by calling GetWindowLong
1331 * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message.
1332 * The UI window can refer to this Input Context and handles the
1333 * messages.
1336 hIMC = (HIMC)GetWindowLongW(hwnd,IMMGWL_IMC);
1337 if (!hIMC)
1338 hIMC = RealIMC(FROM_X11);
1340 /* if we have no hIMC there are many messages we cannot process */
1341 if (hIMC == NULL)
1343 switch (msg) {
1344 case WM_IME_STARTCOMPOSITION:
1345 case WM_IME_ENDCOMPOSITION:
1346 case WM_IME_COMPOSITION:
1347 case WM_IME_NOTIFY:
1348 case WM_IME_CONTROL:
1349 case WM_IME_COMPOSITIONFULL:
1350 case WM_IME_SELECT:
1351 case WM_IME_CHAR:
1352 return 0L;
1353 default:
1354 break;
1358 switch(msg)
1360 case WM_CREATE:
1362 LPIMEPRIVATE myPrivate;
1363 LPINPUTCONTEXT lpIMC;
1365 SetWindowTextA(hwnd,"Wine Ime Active");
1367 lpIMC = LockRealIMC(hIMC);
1368 if (lpIMC)
1370 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
1371 myPrivate->hwndDefault = hwnd;
1372 ImmUnlockIMCC(lpIMC->hPrivate);
1374 UnlockRealIMC(hIMC);
1376 return TRUE;
1378 case WM_PAINT:
1379 PaintDefaultIMEWnd(hIMC, hwnd);
1380 return FALSE;
1382 case WM_NCCREATE:
1383 return TRUE;
1385 case WM_SETFOCUS:
1386 if (wParam)
1387 SetFocus((HWND)wParam);
1388 else
1389 FIXME("Received focus, should never have focus\n");
1390 break;
1391 case WM_IME_COMPOSITION:
1392 DefaultIMEComposition(hIMC, hwnd, lParam);
1393 break;
1394 case WM_IME_STARTCOMPOSITION:
1395 DefaultIMEStartComposition(hIMC, hwnd);
1396 break;
1397 case WM_IME_ENDCOMPOSITION:
1398 TRACE("IME message %s, 0x%lx, 0x%lx\n",
1399 "WM_IME_ENDCOMPOSITION", wParam, lParam);
1400 ShowWindow(hwnd,SW_HIDE);
1401 break;
1402 case WM_IME_SELECT:
1403 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_SELECT", wParam, lParam);
1404 break;
1405 case WM_IME_CONTROL:
1406 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_CONTROL", wParam, lParam);
1407 rc = 1;
1408 break;
1409 case WM_IME_NOTIFY:
1410 rc = ImeHandleNotify(hIMC,hwnd,msg,wParam,lParam);
1411 break;
1412 default:
1413 TRACE("Non-standard message 0x%x\n",msg);
1415 /* check the MSIME messages */
1416 if (msg == WM_MSIME_SERVICE)
1418 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_SERVICE", wParam, lParam);
1419 rc = FALSE;
1421 else if (msg == WM_MSIME_RECONVERTOPTIONS)
1423 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTOPTIONS", wParam, lParam);
1425 else if (msg == WM_MSIME_MOUSE)
1427 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_MOUSE", wParam, lParam);
1429 else if (msg == WM_MSIME_RECONVERTREQUEST)
1431 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTREQUEST", wParam, lParam);
1433 else if (msg == WM_MSIME_RECONVERT)
1435 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERT", wParam, lParam);
1437 else if (msg == WM_MSIME_QUERYPOSITION)
1439 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_QUERYPOSITION", wParam, lParam);
1441 else if (msg == WM_MSIME_DOCUMENTFEED)
1443 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_DOCUMENTFEED", wParam, lParam);
1445 /* DefWndProc if not an IME message */
1446 if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1447 (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
1448 rc = DefWindowProcW(hwnd,msg,wParam,lParam);
1450 return rc;