user32: Handle VK_RETURN WM_KEYDOWN events better in edit controls.
[wine] / dlls / winex11.drv / ime.c
1 /*
2  * The IME for interfacing with XIM
3  *
4  * Copyright 2008 CodeWeavers, Aric Stewart
5  *
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.
10  *
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.
15  *
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
19  */
20
21 /*
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.
34  *
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.
41  */
42
43 #include "config.h"
44
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"
56
57 WINE_DEFAULT_DEBUG_CHANNEL(imm);
58
59 #define FROM_X11 ((HIMC)0xcafe1337)
60
61 typedef struct _IMEPRIVATE {
62     BOOL bInComposition;
63     BOOL bInternalState;
64     HFONT textfont;
65     HWND hwndDefault;
66 } IMEPRIVATE, *LPIMEPRIVATE;
67
68 typedef struct _tagTRANSMSG {
69     UINT message;
70     WPARAM wParam;
71     LPARAM lParam;
72 } TRANSMSG, *LPTRANSMSG;
73
74 static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e','X','1','1','I','M','E',0};
75
76 static HIMC *hSelectedFrom = NULL;
77 static INT  hSelectedCount = 0;
78 static BOOL hXIMPresent = FALSE;
79
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;
88
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);
92
93 static HIMC RealIMC(HIMC hIMC)
94 {
95     if (hIMC == FROM_X11)
96     {
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;
104     }
105     else
106         return hIMC;
107 }
108
109 static LPINPUTCONTEXT LockRealIMC(HIMC hIMC)
110 {
111     HIMC real_imc = RealIMC(hIMC);
112     if (real_imc)
113         return (LPINPUTCONTEXT)ImmLockIMC(real_imc);
114     else
115         return NULL;
116 }
117
118 static BOOL UnlockRealIMC(HIMC hIMC)
119 {
120     HIMC real_imc = RealIMC(hIMC);
121     if (real_imc)
122         return ImmUnlockIMC(real_imc);
123     else
124         return FALSE;
125 }
126
127 static HIMCC ImeCreateBlankCompStr(void)
128 {
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;
137 }
138
139 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
140                        LPBYTE target, LPBYTE source, DWORD* lenParam,
141                        DWORD* offsetParam, BOOL wchars )
142 {
143      if (origLen > 0 && origOffset > 0)
144      {
145         int truelen = origLen;
146         if (wchars)
147             truelen *= sizeof(WCHAR);
148
149         memcpy(&target[currentOffset], &source[origOffset], truelen);
150
151         *lenParam = origLen;
152         *offsetParam = currentOffset;
153         currentOffset += truelen;
154      }
155      return currentOffset;
156 }
157
158 static HIMCC updateCompStr(HIMCC old, LPWSTR compstr, DWORD len)
159 {
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;
169
170     TRACE("%s, %i\n",debugstr_wn(compstr,len),len);
171
172     if (old == NULL && compstr == NULL && len == 0)
173         return NULL;
174
175     if (old != NULL)
176     {
177         olddata = ImmLockIMCC(old);
178         lpcs = (LPCOMPOSITIONSTRING)olddata;
179     }
180
181     needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
182                   len + sizeof(DWORD) * 2;
183
184     if (lpcs != NULL)
185     {
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;
194     }
195     rc = ImmCreateIMCC(needed_size);
196     newdata = ImmLockIMCC(rc);
197     new_one = (LPCOMPOSITIONSTRING)newdata;
198
199     new_one->dwSize = needed_size;
200     current_offset = sizeof(COMPOSITIONSTRING);
201     if (lpcs != NULL)
202     {
203         current_offset = updateField(lpcs->dwCompReadAttrLen,
204                                      lpcs->dwCompReadAttrOffset,
205                                      current_offset, newdata, olddata,
206                                      &new_one->dwCompReadAttrLen,
207                                      &new_one->dwCompReadAttrOffset, FALSE);
208
209         current_offset = updateField(lpcs->dwCompReadClauseLen,
210                                      lpcs->dwCompReadClauseOffset,
211                                      current_offset, newdata, olddata,
212                                      &new_one->dwCompReadClauseLen,
213                                      &new_one->dwCompReadClauseOffset, FALSE);
214
215         current_offset = updateField(lpcs->dwCompReadStrLen,
216                                      lpcs->dwCompReadStrOffset,
217                                      current_offset, newdata, olddata,
218                                      &new_one->dwCompReadStrLen,
219                                      &new_one->dwCompReadStrOffset, TRUE);
220
221         /* new CompAttr, CompClause, CompStr, dwCursorPos */
222         new_one->dwDeltaStart = 0;
223
224         current_offset = updateField(lpcs->dwResultReadClauseLen,
225                                      lpcs->dwResultReadClauseOffset,
226                                      current_offset, newdata, olddata,
227                                      &new_one->dwResultReadClauseLen,
228                                      &new_one->dwResultReadClauseOffset, FALSE);
229
230         current_offset = updateField(lpcs->dwResultReadStrLen,
231                                      lpcs->dwResultReadStrOffset,
232                                      current_offset, newdata, olddata,
233                                      &new_one->dwResultReadStrLen,
234                                      &new_one->dwResultReadStrOffset, TRUE);
235
236         current_offset = updateField(lpcs->dwResultClauseLen,
237                                      lpcs->dwResultClauseOffset,
238                                      current_offset, newdata, olddata,
239                                      &new_one->dwResultClauseLen,
240                                      &new_one->dwResultClauseOffset, FALSE);
241
242         current_offset = updateField(lpcs->dwResultStrLen,
243                                      lpcs->dwResultStrOffset,
244                                      current_offset, newdata, olddata,
245                                      &new_one->dwResultStrLen,
246                                      &new_one->dwResultStrOffset, TRUE);
247
248         current_offset = updateField(lpcs->dwPrivateSize,
249                                      lpcs->dwPrivateOffset,
250                                      current_offset, newdata, olddata,
251                                      &new_one->dwPrivateSize,
252                                      &new_one->dwPrivateOffset, FALSE);
253     }
254
255     /* set new data */
256     /* CompAttr */
257     new_one->dwCompAttrLen = len;
258     if (len > 0)
259     {
260         new_one->dwCompAttrOffset = current_offset;
261         memset(&newdata[current_offset],ATTR_INPUT,len);
262         current_offset += len;
263     }
264
265     /* CompClause */
266     if (len > 0)
267     {
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);
274     }
275
276     /* CompStr */
277     new_one->dwCompStrLen = len;
278     if (len > 0)
279     {
280         new_one->dwCompStrOffset = current_offset;
281         memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
282     }
283
284     /* CursorPos */
285     new_one->dwCursorPos = len;
286
287     ImmUnlockIMCC(rc);
288     if (lpcs)
289         ImmUnlockIMCC(old);
290
291     return rc;
292 }
293
294 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
295 {
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;
305
306     TRACE("%s, %i\n",debugstr_wn(resultstr,len),len);
307
308     if (old == NULL && resultstr == NULL && len == 0)
309         return NULL;
310
311     if (old != NULL)
312     {
313         olddata = ImmLockIMCC(old);
314         lpcs = (LPCOMPOSITIONSTRING)olddata;
315     }
316
317     needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
318                   sizeof(DWORD) * 2;
319
320     if (lpcs != NULL)
321     {
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;
331     }
332     rc = ImmCreateIMCC(needed_size);
333     newdata = ImmLockIMCC(rc);
334     new_one = (LPCOMPOSITIONSTRING)newdata;
335
336     new_one->dwSize = needed_size;
337     current_offset = sizeof(COMPOSITIONSTRING);
338     if (lpcs != NULL)
339     {
340         current_offset = updateField(lpcs->dwCompReadAttrLen,
341                                      lpcs->dwCompReadAttrOffset,
342                                      current_offset, newdata, olddata,
343                                      &new_one->dwCompReadAttrLen,
344                                      &new_one->dwCompReadAttrOffset, FALSE);
345
346         current_offset = updateField(lpcs->dwCompReadClauseLen,
347                                      lpcs->dwCompReadClauseOffset,
348                                      current_offset, newdata, olddata,
349                                      &new_one->dwCompReadClauseLen,
350                                      &new_one->dwCompReadClauseOffset, FALSE);
351
352         current_offset = updateField(lpcs->dwCompReadStrLen,
353                                      lpcs->dwCompReadStrOffset,
354                                      current_offset, newdata, olddata,
355                                      &new_one->dwCompReadStrLen,
356                                      &new_one->dwCompReadStrOffset, TRUE);
357
358         current_offset = updateField(lpcs->dwCompAttrLen,
359                                      lpcs->dwCompAttrOffset,
360                                      current_offset, newdata, olddata,
361                                      &new_one->dwCompAttrLen,
362                                      &new_one->dwCompAttrOffset, FALSE);
363
364         current_offset = updateField(lpcs->dwCompClauseLen,
365                                      lpcs->dwCompClauseOffset,
366                                      current_offset, newdata, olddata,
367                                      &new_one->dwCompClauseLen,
368                                      &new_one->dwCompClauseOffset, FALSE);
369
370         current_offset = updateField(lpcs->dwCompStrLen,
371                                      lpcs->dwCompStrOffset,
372                                      current_offset, newdata, olddata,
373                                      &new_one->dwCompStrLen,
374                                      &new_one->dwCompStrOffset, TRUE);
375
376         new_one->dwCursorPos = lpcs->dwCursorPos;
377         new_one->dwDeltaStart = 0;
378
379         current_offset = updateField(lpcs->dwResultReadClauseLen,
380                                      lpcs->dwResultReadClauseOffset,
381                                      current_offset, newdata, olddata,
382                                      &new_one->dwResultReadClauseLen,
383                                      &new_one->dwResultReadClauseOffset, FALSE);
384
385         current_offset = updateField(lpcs->dwResultReadStrLen,
386                                      lpcs->dwResultReadStrOffset,
387                                      current_offset, newdata, olddata,
388                                      &new_one->dwResultReadStrLen,
389                                      &new_one->dwResultReadStrOffset, TRUE);
390
391         /* new ResultClause , ResultStr */
392
393         current_offset = updateField(lpcs->dwPrivateSize,
394                                      lpcs->dwPrivateOffset,
395                                      current_offset, newdata, olddata,
396                                      &new_one->dwPrivateSize,
397                                      &new_one->dwPrivateOffset, FALSE);
398     }
399
400     /* set new data */
401     /* ResultClause */
402     if (len > 0)
403     {
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);
410     }
411
412     /* ResultStr */
413     new_one->dwResultStrLen = len;
414     if (len > 0)
415     {
416         new_one->dwResultStrOffset = current_offset;
417         memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
418     }
419     ImmUnlockIMCC(rc);
420     if (lpcs)
421         ImmUnlockIMCC(old);
422
423     return rc;
424 }
425
426 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam,
427                                LPARAM lParam)
428 {
429     LPINPUTCONTEXT lpIMC;
430     LPTRANSMSG lpTransMsg;
431
432     lpIMC = LockRealIMC(hIMC);
433     if (lpIMC == NULL)
434         return;
435
436     lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) *
437                                     sizeof(TRANSMSG));
438     if (!lpIMC->hMsgBuf)
439         return;
440
441     lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf);
442     if (!lpTransMsg)
443         return;
444
445     lpTransMsg += lpIMC->dwNumMsgBuf;
446     lpTransMsg->message = msg;
447     lpTransMsg->wParam = wParam;
448     lpTransMsg->lParam = lParam;
449
450     ImmUnlockIMCC(lpIMC->hMsgBuf);
451     lpIMC->dwNumMsgBuf++;
452
453     ImmGenerateMessage(RealIMC(hIMC));
454     UnlockRealIMC(hIMC);
455 }
456
457 static void GenerateIMECHARMessages(HIMC hIMC, LPWSTR String, DWORD length)
458 {
459     LPINPUTCONTEXT lpIMC;
460     LPTRANSMSG lpTransMsg;
461     INT i;
462
463     if (length <= 0)
464         return;
465
466     lpIMC = LockRealIMC(hIMC);
467     if (lpIMC == NULL)
468         return;
469
470     lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf,
471                                   (lpIMC->dwNumMsgBuf + length) *
472                                     sizeof(TRANSMSG));
473     if (!lpIMC->hMsgBuf)
474         return;
475
476     lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf);
477     if (!lpTransMsg)
478         return;
479
480     lpTransMsg += lpIMC->dwNumMsgBuf;
481     for (i = 0; i < length; i++)
482     {
483         lpTransMsg->message = WM_IME_CHAR;
484         lpTransMsg->wParam = String[i];
485         lpTransMsg->lParam = 1;
486         lpTransMsg ++;
487     }
488
489     ImmUnlockIMCC(lpIMC->hMsgBuf);
490     lpIMC->dwNumMsgBuf+=length;
491
492     ImmGenerateMessage(RealIMC(hIMC));
493     UnlockRealIMC(hIMC);
494 }
495
496 static BOOL IME_RemoveFromSelected(HIMC hIMC)
497 {
498     int i;
499     for (i = 0; i < hSelectedCount; i++)
500         if (hSelectedFrom[i] == hIMC)
501         {
502             if (i < hSelectedCount - 1)
503                 memcpy(&hSelectedFrom[i], &hSelectedFrom[i+1], (hSelectedCount - i - 1)*sizeof(HIMC));
504             hSelectedCount --;
505             return TRUE;
506         }
507     return FALSE;
508 }
509
510 static void IME_AddToSelected(HIMC hIMC)
511 {
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;
518 }
519
520 BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass,
521                        LPCWSTR lpszOption)
522 {
523     TRACE("\n");
524     if (!hXIMPresent)
525     {
526         ERR("No XIM in the back end\n");
527         return FALSE;
528     }
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;
537
538     lstrcpyW(lpszUIClass,UI_CLASS_NAME);
539
540     return TRUE;
541 }
542
543 BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)
544 {
545     FIXME("(%p, %p, %d, %p): stub\n", hKL, hWnd, dwMode, lpData);
546     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
547     return FALSE;
548 }
549
550 DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource,
551                 LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag)
552
553 {
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;
558 }
559
560 BOOL WINAPI ImeDestroy(UINT uForce)
561 {
562     TRACE("\n");
563     HeapFree(GetProcessHeap(),0,hSelectedFrom);
564     hSelectedFrom = NULL;
565     hSelectedCount = 0;
566     return TRUE;
567 }
568
569 LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
570 {
571     FIXME("(%p, %d, %p): stub\n", hIMC, uSubFunc, lpData);
572     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
573     return 0;
574 }
575
576 BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData,
577                              CONST LPBYTE lpbKeyState)
578 {
579     /* See the comment at the head of this file */
580     TRACE("We do no processing via this route\n");
581     return FALSE;
582 }
583
584 BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
585 {
586     LPINPUTCONTEXT lpIMC;
587     TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE");
588
589     if (hIMC == FROM_X11)
590     {
591         ERR("ImeSelect should never be called from X11\n");
592         return FALSE;
593     }
594
595     if (!hXIMPresent)
596     {
597         ERR("No XIM in the back end\n");
598         return FALSE;
599     }
600
601     if (!hIMC)
602         return TRUE;
603
604     /* not selected */
605     if (!fSelect)
606         return IME_RemoveFromSelected(hIMC);
607
608     IME_AddToSelected(hIMC);
609
610     /* Initialize our structures */
611     lpIMC = LockRealIMC(hIMC);
612     if (lpIMC != NULL)
613     {
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);
622     }
623
624     return TRUE;
625 }
626
627 BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag)
628 {
629     FIXME("Stub");
630     return TRUE;
631 }
632
633 UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode,
634                           CONST LPBYTE lpbKeyState, LPDWORD lpdwTransKey,
635                           UINT fuState, HIMC hIMC)
636 {
637     /* See the comment at the head of this file */
638     TRACE("We do no processing via this route\n");
639     return 0;
640 }
641
642 BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
643 {
644     BOOL bRet = FALSE;
645     LPINPUTCONTEXT lpIMC;
646
647     TRACE("%p %i %i %i\n",hIMC,dwAction,dwIndex,dwValue);
648
649     lpIMC = LockRealIMC(hIMC);
650     if (lpIMC == NULL)
651         return FALSE;
652
653     switch (dwAction)
654     {
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)
664             {
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:
670                     {
671                         LPIMEPRIVATE myPrivate;
672                         TRACE("IMC_SETCOMPOSITIONFONT\n");
673
674                         myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
675                         if (myPrivate->textfont)
676                         {
677                             DeleteObject(myPrivate->textfont);
678                             myPrivate->textfont = NULL;
679                         }
680                         myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W);
681                         ImmUnlockIMCC(lpIMC->hPrivate);
682                     }
683                     break;
684                 case IMC_SETOPENSTATUS:
685                 {
686                     LPIMEPRIVATE myPrivate;
687                     TRACE("IMC_SETOPENSTATUS\n");
688
689                     myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
690                     if (lpIMC->fOpen != myPrivate->bInternalState &&
691                         myPrivate->bInComposition)
692                     {
693                         if(lpIMC->fOpen == FALSE)
694                         {
695                             X11DRV_ForceXIMReset(lpIMC->hWnd);
696                             GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION,0,0);
697                             myPrivate->bInComposition = FALSE;
698                         }
699                         else
700                         {
701                             GenerateIMEMessage(hIMC,WM_IME_STARTCOMPOSITION,0,0);
702                             GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, 0);
703                         }
704                     }
705                     myPrivate->bInternalState = lpIMC->fOpen;
706                     bRet = TRUE;
707                 }
708                 break;
709                 default: FIXME("Unknown\n"); break;
710             }
711             break;
712         case NI_COMPOSITIONSTR:
713             TRACE("NI_COMPOSITIONSTR:");
714             switch (dwIndex)
715             {
716                 case CPS_COMPLETE:
717                 {
718                     HIMCC newCompStr;
719                     DWORD cplen = 0;
720                     LPWSTR cpstr;
721                     LPCOMPOSITIONSTRING cs = NULL;
722                     LPBYTE cdata = NULL;
723                     LPIMEPRIVATE myPrivate;
724
725                     TRACE("CPS_COMPLETE\n");
726
727                     /* clear existing result */
728                     newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
729
730                     ImmDestroyIMCC(lpIMC->hCompStr);
731                     lpIMC->hCompStr = newCompStr;
732
733                     if (lpIMC->hCompStr)
734                     {
735                         cdata = ImmLockIMCC(lpIMC->hCompStr);
736                         cs = (LPCOMPOSITIONSTRING)cdata;
737                         cplen = cs->dwCompStrLen;
738                         cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]);
739                         ImmUnlockIMCC(lpIMC->hCompStr);
740                     }
741                     if (cplen > 0)
742                     {
743                         WCHAR param = cpstr[0];
744
745                         newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen);
746                         ImmDestroyIMCC(lpIMC->hCompStr);
747                         lpIMC->hCompStr = newCompStr;
748                         newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
749                         ImmDestroyIMCC(lpIMC->hCompStr);
750                         lpIMC->hCompStr = newCompStr;
751
752                         GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0,
753                                                   GCS_COMPSTR);
754
755                         GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param,
756                                             GCS_RESULTSTR|GCS_RESULTCLAUSE);
757                     }
758
759                     GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
760
761                     myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
762                     myPrivate->bInComposition = FALSE;
763                     ImmUnlockIMCC(lpIMC->hPrivate);
764
765                     bRet = TRUE;
766                 }
767                 break;
768                 case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break;
769                 case CPS_REVERT: FIXME("CPS_REVERT\n"); break;
770                 case CPS_CANCEL:
771                 {
772                     BOOL send;
773                     LPCOMPOSITIONSTRING lpCompStr;
774
775                     TRACE("CPS_CANCEL\n");
776
777                     X11DRV_ForceXIMReset(lpIMC->hWnd);
778
779                     lpCompStr = ImmLockIMCC(lpIMC->hCompStr);
780                     send = (lpCompStr->dwCompStrLen != 0);
781                     ImmUnlockIMCC(lpIMC->hCompStr);
782
783                     if (send)
784                     {
785                         HIMCC newCompStr;
786                         newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
787                         ImmDestroyIMCC(lpIMC->hCompStr);
788                         lpIMC->hCompStr = newCompStr;
789                         GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, GCS_COMPSTR);
790                     }
791                     bRet = TRUE;
792                 }
793                 break;
794                 default: FIXME("Unknown\n"); break;
795             }
796             break;
797         default: FIXME("Unknown Message\n"); break;
798     }
799
800     UnlockRealIMC(hIMC);
801     return bRet;
802 }
803
804 BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle,
805                             LPCWSTR lpszRegister)
806 {
807     FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
808                                   debugstr_w(lpszRegister));
809     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
810     return FALSE;
811 }
812
813 BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle,
814                               LPCWSTR lpszUnregister)
815 {
816     FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
817                                   debugstr_w(lpszUnregister));
818     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
819     return FALSE;
820 }
821
822 UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf)
823 {
824     FIXME("(%d, %p): stub\n", nItem, lpStyleBuf);
825     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
826     return 0;
827 }
828
829 UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc,
830                                 LPCWSTR lpszReading, DWORD dwStyle,
831                                 LPCWSTR lpszRegister, LPVOID lpData)
832 {
833     FIXME("(%p, %s, %d, %s, %p): stub\n", lpfnEnumProc,
834             debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister),
835             lpData);
836     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
837     return 0;
838 }
839
840 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp,
841                                     DWORD dwCompLen, LPCVOID lpRead,
842                                     DWORD dwReadLen)
843 {
844     LPINPUTCONTEXT lpIMC;
845     DWORD flags = 0;
846     WCHAR wParam  = 0;
847     LPIMEPRIVATE myPrivate;
848
849     TRACE("(%p, %d, %p, %d, %p, %d):\n",
850          hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
851
852
853     if (hIMC != FROM_X11)
854         FIXME("PROBLEM: This only sets the wine level string\n");
855
856     /*
857     * Explanation:
858     *  this sets the composition string in the imm32.dll level
859     *  of the composition buffer. we cannot manipulate the xim level
860     *  buffer, which means that once the xim level buffer changes again
861     *  any call to this function from the application will be lost
862     */
863
864     if (lpRead && dwReadLen)
865         FIXME("Reading string unimplemented\n");
866
867     lpIMC = LockRealIMC(hIMC);
868
869     if (lpIMC == NULL)
870         return FALSE;
871
872     myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
873
874     if (dwIndex == SCS_SETSTR)
875     {
876         HIMCC newCompStr;
877
878         if (!myPrivate->bInComposition)
879         {
880             GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
881             myPrivate->bInComposition = TRUE;
882         }
883
884         flags = GCS_COMPSTR;
885
886         if (dwCompLen && lpComp)
887         {
888             newCompStr = updateCompStr(lpIMC->hCompStr, (LPWSTR)lpComp, dwCompLen / sizeof(WCHAR));
889             ImmDestroyIMCC(lpIMC->hCompStr);
890             lpIMC->hCompStr = newCompStr;
891
892              wParam = ((const WCHAR*)lpComp)[0];
893              flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
894         }
895         else
896         {
897             newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
898             ImmDestroyIMCC(lpIMC->hCompStr);
899             lpIMC->hCompStr = newCompStr;
900         }
901     }
902
903     UpdateDataInDefaultIMEWindow(hIMC, myPrivate->hwndDefault,FALSE);
904
905     GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
906     ImmUnlockIMCC(lpIMC->hPrivate);
907     UnlockRealIMC(hIMC);
908
909     return TRUE;
910 }
911
912 DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC,  DWORD dwFlags,  DWORD dwType,
913             LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
914             DWORD dwSize)
915 {
916     FIXME("(%p, %x %x %p %p %x): stub\n", hIMC, dwFlags, dwType,
917                                 lpImeParentMenu, lpImeMenu, dwSize);
918     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
919     return 0;
920 }
921
922 /* Interfaces to XIM and other parts of winex11drv */
923
924 void IME_RegisterClasses(HINSTANCE hImeInst)
925 {
926     WNDCLASSW wndClass;
927     ZeroMemory(&wndClass, sizeof(WNDCLASSW));
928     wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
929     wndClass.lpfnWndProc = (WNDPROC) IME_WindowProc;
930     wndClass.cbClsExtra = 0;
931     wndClass.cbWndExtra = 2 * sizeof(LONG);
932     wndClass.hInstance = hImeInst;
933     wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
934     wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
935     wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1);
936     wndClass.lpszMenuName   = 0;
937     wndClass.lpszClassName = UI_CLASS_NAME;
938
939     RegisterClassW(&wndClass);
940
941     WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
942     WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
943     WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
944     WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
945     WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
946     WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
947     WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
948 }
949
950 void IME_UnregisterClasses(HINSTANCE hImeInst)
951 {
952     UnregisterClassW(UI_CLASS_NAME, hImeInst);
953 }
954
955 void IME_SetOpenStatus(BOOL fOpen)
956 {
957     LPINPUTCONTEXT lpIMC;
958     LPIMEPRIVATE myPrivate;
959
960     lpIMC = LockRealIMC(FROM_X11);
961     if (lpIMC == NULL)
962         return;
963
964     myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
965
966     if (myPrivate->bInternalState && fOpen == FALSE)
967     {
968         ShowWindow(myPrivate->hwndDefault, SW_HIDE);
969         ImmDestroyIMCC(lpIMC->hCompStr);
970         lpIMC->hCompStr = ImeCreateBlankCompStr();
971     }
972
973     ImmUnlockIMCC(lpIMC->hPrivate);
974     UnlockRealIMC(FROM_X11);
975
976     if (myPrivate->bInComposition && fOpen == FALSE)
977     {
978         GenerateIMEMessage(FROM_X11, WM_IME_ENDCOMPOSITION, 0, 0);
979         myPrivate->bInComposition = FALSE;
980     }
981
982     if (!myPrivate->bInternalState && fOpen == TRUE)
983         ImmSetOpenStatus(RealIMC(FROM_X11), fOpen);
984 }
985
986 void IME_XIMPresent(BOOL present)
987 {
988     hXIMPresent  = present;
989 }
990
991 LRESULT IME_SendMessageToSelectedHWND(UINT msg, WPARAM wParam, LPARAM lParam)
992 {
993     LPINPUTCONTEXT lpIMC;
994     LRESULT rc = 0;
995
996     if (!hSelectedFrom)
997         return rc;
998
999     lpIMC = LockRealIMC(FROM_X11);
1000     if (lpIMC)
1001         rc = SendMessageW(lpIMC->hWnd,msg,wParam,lParam);
1002
1003     UnlockRealIMC(FROM_X11);
1004     return rc;
1005 }
1006
1007 INT IME_GetCursorPos()
1008 {
1009     LPINPUTCONTEXT lpIMC;
1010     INT rc = 0;
1011     LPCOMPOSITIONSTRING compstr;
1012
1013     if (!hSelectedFrom)
1014         return rc;
1015
1016     lpIMC = LockRealIMC(FROM_X11);
1017     if (lpIMC)
1018     {
1019         compstr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
1020         rc = compstr->dwCursorPos;
1021         ImmUnlockIMCC(lpIMC->hCompStr);
1022     }
1023     UnlockRealIMC(FROM_X11);
1024     return rc;
1025 }
1026
1027 void IME_SetCursorPos(DWORD pos)
1028 {
1029     LPINPUTCONTEXT lpIMC;
1030     LPCOMPOSITIONSTRING compstr;
1031
1032     if (!hSelectedFrom)
1033         return;
1034
1035     lpIMC = LockRealIMC(FROM_X11);
1036     if (!lpIMC)
1037         return;
1038
1039     compstr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
1040     if (!compstr)
1041     {
1042         UnlockRealIMC(FROM_X11);
1043         return;
1044     }
1045
1046     compstr->dwCursorPos = pos;
1047     ImmUnlockIMCC(lpIMC->hCompStr);
1048     UnlockRealIMC(FROM_X11);
1049     GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS);
1050     return;
1051 }
1052
1053 void IME_UpdateAssociation(HWND focus)
1054 {
1055     ImmGetContext(focus);
1056
1057     if (!focus || !hSelectedFrom)
1058         return;
1059
1060     ImmAssociateContext(focus,RealIMC(FROM_X11));
1061 }
1062
1063
1064 BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen,
1065                               LPCVOID lpRead, DWORD dwReadLen)
1066 {
1067     return ImeSetCompositionString(FROM_X11, dwIndex, lpComp, dwCompLen,
1068                                     lpRead, dwReadLen);
1069 }
1070
1071 BOOL IME_NotifyIME(DWORD dwAction, DWORD dwIndex, DWORD dwValue)
1072 {
1073     return NotifyIME(FROM_X11, dwAction, dwIndex, dwValue);
1074 }
1075
1076 /*****
1077  * Internal functions to help with IME window management
1078  */
1079 static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd)
1080 {
1081     PAINTSTRUCT ps;
1082     RECT rect;
1083     HDC hdc;
1084     LPCOMPOSITIONSTRING compstr;
1085     LPBYTE compdata = NULL;
1086     HMONITOR monitor;
1087     MONITORINFO mon_info;
1088     INT offX=0, offY=0;
1089     LPINPUTCONTEXT lpIMC;
1090
1091     lpIMC = LockRealIMC(hIMC);
1092     if (lpIMC == NULL)
1093         return;
1094
1095     hdc = BeginPaint(hwnd,&ps);
1096
1097     GetClientRect(hwnd,&rect);
1098     FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
1099
1100     compdata = ImmLockIMCC(lpIMC->hCompStr);
1101     compstr = (LPCOMPOSITIONSTRING)compdata;
1102
1103     if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
1104     {
1105         SIZE size;
1106         POINT pt;
1107         HFONT oldfont = NULL;
1108         LPWSTR CompString;
1109         LPIMEPRIVATE myPrivate;
1110
1111         CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1112         myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
1113
1114         if (myPrivate->textfont)
1115             oldfont = SelectObject(hdc,myPrivate->textfont);
1116
1117         ImmUnlockIMCC(lpIMC->hPrivate);
1118
1119         GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
1120         pt.x = size.cx;
1121         pt.y = size.cy;
1122         LPtoDP(hdc,&pt,1);
1123
1124         /*
1125          * How this works based on tests on windows:
1126          * CFS_POINT: then we start our window at the point and grow it as large
1127          *    as it needs to be for the string.
1128          * CFS_RECT:  we still use the ptCurrentPos as a starting point and our
1129          *    window is only as large as we need for the string, but we do not
1130          *    grow such that our window exceeds the given rect.  Wrapping if
1131          *    needed and possible.   If our ptCurrentPos is outside of our rect
1132          *    then no window is displayed.
1133          * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
1134          *    maybe becase the default MSIME does not do any IME adjusting.
1135          */
1136         if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT)
1137         {
1138             POINT cpt = lpIMC->cfCompForm.ptCurrentPos;
1139             ClientToScreen(lpIMC->hWnd,&cpt);
1140             rect.left = cpt.x;
1141             rect.top = cpt.y;
1142             rect.right = rect.left + pt.x;
1143             rect.bottom = rect.top + pt.y;
1144             monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY);
1145         }
1146         else /* CFS_DEFAULT */
1147         {
1148             /* Windows places the default IME window in the bottom left */
1149             HWND target = lpIMC->hWnd;
1150             if (!target) target = GetFocus();
1151
1152             GetWindowRect(target,&rect);
1153             rect.top = rect.bottom;
1154             rect.right = rect.left + pt.x + 20;
1155             rect.bottom = rect.top + pt.y + 20;
1156             offX=offY=10;
1157             monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY);
1158         }
1159
1160         if (lpIMC->cfCompForm.dwStyle == CFS_RECT)
1161         {
1162             RECT client;
1163             client =lpIMC->cfCompForm.rcArea;
1164             MapWindowPoints( lpIMC->hWnd, 0, (POINT *)&client, 2 );
1165             IntersectRect(&rect,&rect,&client);
1166             /* TODO:  Wrap the input if needed */
1167         }
1168
1169         if (lpIMC->cfCompForm.dwStyle == CFS_DEFAULT)
1170         {
1171             /* make sure we are on the desktop */
1172             mon_info.cbSize = sizeof(mon_info);
1173             GetMonitorInfoW(monitor, &mon_info);
1174
1175             if (rect.bottom > mon_info.rcWork.bottom)
1176             {
1177                 int shift = rect.bottom - mon_info.rcWork.bottom;
1178                 rect.top -= shift;
1179                 rect.bottom -= shift;
1180             }
1181             if (rect.left < 0)
1182             {
1183                 rect.right -= rect.left;
1184                 rect.left = 0;
1185             }
1186             if (rect.right > mon_info.rcWork.right)
1187             {
1188                 int shift = rect.right - mon_info.rcWork.right;
1189                 rect.left -= shift;
1190                 rect.right -= shift;
1191             }
1192         }
1193
1194         SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);
1195
1196         TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen);
1197
1198         if (oldfont)
1199             SelectObject(hdc,oldfont);
1200     }
1201
1202     ImmUnlockIMCC(lpIMC->hCompStr);
1203
1204     EndPaint(hwnd,&ps);
1205     UnlockRealIMC(hIMC);
1206 }
1207
1208 static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable)
1209 {
1210     LPCOMPOSITIONSTRING compstr;
1211     LPINPUTCONTEXT lpIMC;
1212
1213     lpIMC = LockRealIMC(hIMC);
1214     if (lpIMC == NULL)
1215         return;
1216
1217     if (lpIMC->hCompStr)
1218         compstr = ImmLockIMCC(lpIMC->hCompStr);
1219     else
1220         compstr = NULL;
1221
1222     if (compstr == NULL || compstr->dwCompStrLen == 0)
1223         ShowWindow(hwnd,SW_HIDE);
1224     else if (showable)
1225         ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1226
1227     RedrawWindow(hwnd,NULL,NULL,RDW_ERASENOW|RDW_INVALIDATE);
1228
1229     if (compstr != NULL)
1230         ImmUnlockIMCC(lpIMC->hCompStr);
1231
1232     UnlockRealIMC(hIMC);
1233 }
1234
1235 static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam)
1236 {
1237     TRACE("IME message WM_IME_COMPOSITION 0x%lx\n", lParam);
1238     if (lParam & GCS_RESULTSTR)
1239     {
1240         LPCOMPOSITIONSTRING compstr;
1241         LPBYTE compdata;
1242         LPWSTR ResultStr;
1243         HIMCC newCompStr;
1244         LPINPUTCONTEXT lpIMC;
1245
1246         lpIMC = LockRealIMC(hIMC);
1247         if (lpIMC == NULL)
1248             return;
1249
1250         TRACE("Posting result as IME_CHAR\n");
1251         compdata = ImmLockIMCC(lpIMC->hCompStr);
1252         compstr = (LPCOMPOSITIONSTRING)compdata;
1253         ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1254         GenerateIMECHARMessages(hIMC, ResultStr, compstr->dwResultStrLen);
1255         ImmUnlockIMCC(lpIMC->hCompStr);
1256
1257         /* clear the buffer */
1258         newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
1259         ImmDestroyIMCC(lpIMC->hCompStr);
1260         lpIMC->hCompStr = newCompStr;
1261         UnlockRealIMC(hIMC);
1262     }
1263     else
1264          UpdateDataInDefaultIMEWindow(hIMC,hwnd,TRUE);
1265 }
1266
1267 static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd )
1268 {
1269     LPINPUTCONTEXT lpIMC;
1270
1271     lpIMC = LockRealIMC(hIMC);
1272     if (lpIMC == NULL)
1273         return;
1274
1275     TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1276     lpIMC->hWnd = GetFocus();
1277     ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1278     UnlockRealIMC(hIMC);
1279 }
1280
1281 static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam,
1282                                LPARAM lParam)
1283 {
1284     switch (wParam)
1285     {
1286         case IMN_OPENSTATUSWINDOW:
1287             FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1288             break;
1289         case IMN_CLOSESTATUSWINDOW:
1290             FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1291             break;
1292         case IMN_OPENCANDIDATE:
1293             FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1294             break;
1295         case IMN_CHANGECANDIDATE:
1296             FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1297             break;
1298         case IMN_CLOSECANDIDATE:
1299             FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1300             break;
1301         case IMN_SETCONVERSIONMODE:
1302             FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1303             break;
1304         case IMN_SETSENTENCEMODE:
1305             FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1306             break;
1307         case IMN_SETOPENSTATUS:
1308             FIXME("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1309             break;
1310         case IMN_SETCANDIDATEPOS:
1311             FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1312             break;
1313         case IMN_SETCOMPOSITIONFONT:
1314             FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1315             break;
1316         case IMN_SETCOMPOSITIONWINDOW:
1317             FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1318             break;
1319         case IMN_GUIDELINE:
1320             FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1321             break;
1322         case IMN_SETSTATUSWINDOWPOS:
1323             FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1324             break;
1325         default:
1326             FIXME("WM_IME_NOTIFY:<Unknown 0x%lx>\n",wParam);
1327             break;
1328     }
1329     return 0;
1330 }
1331
1332 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
1333                                           LPARAM lParam)
1334 {
1335     LRESULT rc = 0;
1336     HIMC    hIMC;
1337
1338     TRACE("Incoming Message 0x%x  (0x%08lx, 0x%08lx)\n", msg, wParam, lParam);
1339
1340     /*
1341      * Each UI window contains the current Input Context.
1342      * This Input Context can be obtained by calling GetWindowLong
1343      * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message.
1344      * The UI window can refer to this Input Context and handles the
1345      * messages.
1346      */
1347
1348     hIMC = (HIMC)GetWindowLongW(hwnd,IMMGWL_IMC);
1349     if (!hIMC)
1350         hIMC = RealIMC(FROM_X11);
1351
1352     /* if we have no hIMC there are many messages we cannot process */
1353     if (hIMC == NULL)
1354     {
1355         switch (msg) {
1356         case WM_IME_STARTCOMPOSITION:
1357         case WM_IME_ENDCOMPOSITION:
1358         case WM_IME_COMPOSITION:
1359         case WM_IME_NOTIFY:
1360         case WM_IME_CONTROL:
1361         case WM_IME_COMPOSITIONFULL:
1362         case WM_IME_SELECT:
1363         case WM_IME_CHAR:
1364             return 0L;
1365         default:
1366             break;
1367         }
1368     }
1369
1370     switch(msg)
1371     {
1372         case WM_CREATE:
1373         {
1374             LPIMEPRIVATE myPrivate;
1375             LPINPUTCONTEXT lpIMC;
1376
1377             SetWindowTextA(hwnd,"Wine Ime Active");
1378
1379             lpIMC = LockRealIMC(hIMC);
1380             if (lpIMC)
1381             {
1382                 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
1383                 myPrivate->hwndDefault = hwnd;
1384                 ImmUnlockIMCC(lpIMC->hPrivate);
1385             }
1386             UnlockRealIMC(hIMC);
1387
1388             return TRUE;
1389         }
1390         case WM_PAINT:
1391             PaintDefaultIMEWnd(hIMC, hwnd);
1392             return FALSE;
1393
1394         case WM_NCCREATE:
1395             return TRUE;
1396
1397         case WM_SETFOCUS:
1398             if (wParam)
1399                 SetFocus((HWND)wParam);
1400             else
1401                 FIXME("Received focus, should never have focus\n");
1402             break;
1403         case WM_IME_COMPOSITION:
1404             DefaultIMEComposition(hIMC, hwnd, lParam);
1405             break;
1406         case WM_IME_STARTCOMPOSITION:
1407             DefaultIMEStartComposition(hIMC, hwnd);
1408             break;
1409         case WM_IME_ENDCOMPOSITION:
1410             TRACE("IME message %s, 0x%lx, 0x%lx\n",
1411                     "WM_IME_ENDCOMPOSITION", wParam, lParam);
1412             ShowWindow(hwnd,SW_HIDE);
1413             break;
1414         case WM_IME_SELECT:
1415             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_SELECT", wParam, lParam);
1416             break;
1417         case WM_IME_CONTROL:
1418             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_CONTROL", wParam, lParam);
1419             rc = 1;
1420             break;
1421         case WM_IME_NOTIFY:
1422             rc = ImeHandleNotify(hIMC,hwnd,msg,wParam,lParam);
1423             break;
1424        default:
1425             TRACE("Non-standard message 0x%x\n",msg);
1426     }
1427     /* check the MSIME messages */
1428     if (msg == WM_MSIME_SERVICE)
1429     {
1430             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_SERVICE", wParam, lParam);
1431             rc = FALSE;
1432     }
1433     else if (msg == WM_MSIME_RECONVERTOPTIONS)
1434     {
1435             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTOPTIONS", wParam, lParam);
1436     }
1437     else if (msg == WM_MSIME_MOUSE)
1438     {
1439             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_MOUSE", wParam, lParam);
1440     }
1441     else if (msg == WM_MSIME_RECONVERTREQUEST)
1442     {
1443             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTREQUEST", wParam, lParam);
1444     }
1445     else if (msg == WM_MSIME_RECONVERT)
1446     {
1447             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERT", wParam, lParam);
1448     }
1449     else if (msg == WM_MSIME_QUERYPOSITION)
1450     {
1451             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_QUERYPOSITION", wParam, lParam);
1452     }
1453     else if (msg == WM_MSIME_DOCUMENTFEED)
1454     {
1455             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_DOCUMENTFEED", wParam, lParam);
1456     }
1457     /* DefWndProc if not an IME message */
1458     if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1459                       (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
1460         rc = DefWindowProcW(hwnd,msg,wParam,lParam);
1461
1462     return rc;
1463 }