imm32: Load a default IME if a specific one is not specified. This defaults to x11.
[wine] / dlls / imm32 / imm.c
1 /*
2  * IMM32 library
3  *
4  * Copyright 1998 Patrik Stridvall
5  * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23 #include <stdio.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "wine/debug.h"
31 #include "imm.h"
32 #include "ddk/imm.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "wine/list.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(imm);
38
39 #define FROM_IME 0xcafe1337
40
41 static void (*pX11DRV_ForceXIMReset)(HWND);
42
43 typedef struct tagIMCCInternal
44 {
45     DWORD dwLock;
46     DWORD dwSize;
47 } IMCCInternal;
48
49 #define MAKE_FUNCPTR(f) typeof(f) * p##f
50 typedef struct _tagImmHkl{
51     struct list entry;
52     HKL         hkl;
53     HMODULE     hIME;
54     IMEINFO     imeInfo;
55     WCHAR       imeClassName[17]; /* 16 character max */
56     ULONG       uSelected;
57
58     /* Function Pointers */
59     MAKE_FUNCPTR(ImeInquire);
60     MAKE_FUNCPTR(ImeConfigure);
61     MAKE_FUNCPTR(ImeDestroy);
62     MAKE_FUNCPTR(ImeEscape);
63     MAKE_FUNCPTR(ImeSelect);
64     MAKE_FUNCPTR(ImeSetActiveContext);
65     MAKE_FUNCPTR(ImeToAsciiEx);
66     MAKE_FUNCPTR(NotifyIME);
67     MAKE_FUNCPTR(ImeRegisterWord);
68     MAKE_FUNCPTR(ImeUnregisterWord);
69     MAKE_FUNCPTR(ImeEnumRegisterWord);
70     MAKE_FUNCPTR(ImeSetCompositionString);
71     MAKE_FUNCPTR(ImeConversionList);
72     MAKE_FUNCPTR(ImeProcessKey);
73     MAKE_FUNCPTR(ImeGetRegisterWordStyle);
74     MAKE_FUNCPTR(ImeGetImeMenuItems);
75 } ImmHkl;
76 #undef MAKE_FUNCPTR
77
78 typedef struct tagInputContextData
79 {
80         BOOL            bInternalState;
81         BOOL            bRead;
82         BOOL            bInComposition;
83         HFONT           textfont;
84
85         DWORD           dwLock;
86         INPUTCONTEXT    IMC;
87
88         ImmHkl          *immKbd;
89 } InputContextData;
90
91 typedef struct _tagTRANSMSG {
92     UINT message;
93     WPARAM wParam;
94     LPARAM lParam;
95 } TRANSMSG, *LPTRANSMSG;
96
97 static InputContextData *root_context = NULL;
98 static HWND hwndDefault = NULL;
99 static HANDLE hImeInst;
100 static const WCHAR WC_IMECLASSNAME[] = {'I','M','E',0};
101 static ATOM atIMEClass = 0;
102
103 static struct list ImmHklList = LIST_INIT(ImmHklList);
104
105 /* MSIME messages */
106 static UINT WM_MSIME_SERVICE;
107 static UINT WM_MSIME_RECONVERTOPTIONS;
108 static UINT WM_MSIME_MOUSE;
109 static UINT WM_MSIME_RECONVERTREQUEST;
110 static UINT WM_MSIME_RECONVERT;
111 static UINT WM_MSIME_QUERYPOSITION;
112 static UINT WM_MSIME_DOCUMENTFEED;
113
114 static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
115 /*
116  * prototypes
117  */
118 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
119                                           LPARAM lParam);
120 static void UpdateDataInDefaultIMEWindow(HWND hwnd, BOOL showable);
121 static void ImmInternalPostIMEMessage(InputContextData*, UINT, WPARAM, LPARAM);
122 static void ImmInternalSetOpenStatus(BOOL fOpen);
123 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len);
124
125 #define is_kbd_ime_unicode(p)  (p->imeInfo.fdwProperty & IME_PROP_UNICODE)
126
127 static inline WCHAR *strdupAtoW( const char *str )
128 {
129     WCHAR *ret = NULL;
130     if (str)
131     {
132         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
133         if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
134             MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
135     }
136     return ret;
137 }
138
139 static inline CHAR *strdupWtoA( const WCHAR *str )
140 {
141     CHAR *ret = NULL;
142     if (str)
143     {
144         DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
145         if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
146             WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
147     }
148     return ret;
149 }
150
151 static HMODULE LoadDefaultWineIME(void)
152 {
153     char buffer[MAX_PATH], libname[32], *name, *next;
154     HMODULE module = 0;
155     HKEY hkey;
156
157     TRACE("Attempting to fall back to wine default IME\n");
158
159     strcpy( buffer, "x11" );  /* default value */
160     /* @@ Wine registry key: HKCU\Software\Wine\Drivers */
161     if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Drivers", &hkey ))
162     {
163         DWORD type, count = sizeof(buffer);
164         RegQueryValueExA( hkey, "Ime", 0, &type, (LPBYTE) buffer, &count );
165         RegCloseKey( hkey );
166     }
167
168     name = buffer;
169     while (name)
170     {
171         next = strchr( name, ',' );
172         if (next) *next++ = 0;
173
174         snprintf( libname, sizeof(libname), "wine%s.drv", name );
175         if ((module = LoadLibraryA( libname )) != 0) break;
176         name = next;
177     }
178
179     return module;
180 }
181
182 /* ImmHkl loading and freeing */
183 #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
184 static ImmHkl *IMM_GetImmHkl(HKL hkl)
185 {
186     ImmHkl *ptr;
187     WCHAR filename[MAX_PATH];
188
189     TRACE("Seeking ime for keyboard 0x%x\n",(unsigned)hkl);
190
191     LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
192     {
193         if (ptr->hkl == hkl)
194             return ptr;
195     }
196     /* not found... create it */
197
198     ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl));
199
200     ptr->hkl = hkl;
201     if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
202     if (!ptr->hIME)
203         ptr->hIME = LoadDefaultWineIME();
204     if (ptr->hIME)
205     {
206         LOAD_FUNCPTR(ImeInquire);
207         if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
208         {
209             FreeLibrary(ptr->hIME);
210             ptr->hIME = NULL;
211         }
212         else
213         {
214             LOAD_FUNCPTR(ImeDestroy);
215             LOAD_FUNCPTR(ImeSelect);
216             if (!ptr->pImeSelect || !ptr->pImeDestroy)
217             {
218                 FreeLibrary(ptr->hIME);
219                 ptr->hIME = NULL;
220             }
221             else
222             {
223                 LOAD_FUNCPTR(ImeConfigure);
224                 LOAD_FUNCPTR(ImeEscape);
225                 LOAD_FUNCPTR(ImeSetActiveContext);
226                 LOAD_FUNCPTR(ImeToAsciiEx);
227                 LOAD_FUNCPTR(NotifyIME);
228                 LOAD_FUNCPTR(ImeRegisterWord);
229                 LOAD_FUNCPTR(ImeUnregisterWord);
230                 LOAD_FUNCPTR(ImeEnumRegisterWord);
231                 LOAD_FUNCPTR(ImeSetCompositionString);
232                 LOAD_FUNCPTR(ImeConversionList);
233                 LOAD_FUNCPTR(ImeProcessKey);
234                 LOAD_FUNCPTR(ImeGetRegisterWordStyle);
235                 LOAD_FUNCPTR(ImeGetImeMenuItems);
236                 /* make sure our classname is WCHAR */
237                 if (!is_kbd_ime_unicode(ptr))
238                 {
239                     WCHAR bufW[17];
240                     MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
241                                         -1, bufW, 17);
242                     lstrcpyW(ptr->imeClassName, bufW);
243                 }
244             }
245         }
246     }
247     list_add_head(&ImmHklList,&ptr->entry);
248
249     return ptr;
250 }
251 #undef LOAD_FUNCPTR
252
253 static void IMM_FreeAllImmHkl(void)
254 {
255     ImmHkl *ptr,*cursor2;
256
257     LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &ImmHklList, ImmHkl, entry)
258     {
259         list_remove(&ptr->entry);
260         if (ptr->hIME)
261         {
262             ptr->pImeDestroy(1);
263             FreeLibrary(ptr->hIME);
264         }
265         HeapFree(GetProcessHeap(),0,ptr);
266     }
267 }
268
269 static VOID IMM_PostResult(InputContextData *data)
270 {
271     unsigned int i;
272     LPCOMPOSITIONSTRING compstr;
273     LPBYTE compdata;
274     LPWSTR ResultStr;
275     HIMCC newCompStr;
276
277     TRACE("Posting result as IME_CHAR\n");
278     compdata = ImmLockIMCC(root_context->IMC.hCompStr);
279     compstr = (LPCOMPOSITIONSTRING)compdata;
280     ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
281
282     for (i = 0; i < compstr->dwResultStrLen; i++)
283         ImmInternalPostIMEMessage (root_context, WM_IME_CHAR, ResultStr[i], 1);
284
285     ImmUnlockIMCC(root_context->IMC.hCompStr);
286
287     /* clear the buffer */
288     newCompStr = updateResultStr(root_context->IMC.hCompStr, NULL, 0);
289     ImmDestroyIMCC(root_context->IMC.hCompStr);
290     root_context->IMC.hCompStr = newCompStr;
291 }
292
293 static void IMM_Register(void)
294 {
295     WNDCLASSW wndClass;
296     ZeroMemory(&wndClass, sizeof(WNDCLASSW));
297     wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
298     wndClass.lpfnWndProc = (WNDPROC) IME_WindowProc;
299     wndClass.cbClsExtra = 0;
300     wndClass.cbWndExtra = 0;
301     wndClass.hInstance = hImeInst;
302     wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
303     wndClass.hIcon = NULL;
304     wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1);
305     wndClass.lpszMenuName   = 0;
306     wndClass.lpszClassName = WC_IMECLASSNAME;
307     atIMEClass = RegisterClassW(&wndClass);
308 }
309
310 static void IMM_Unregister(void)
311 {
312     if (atIMEClass) {
313         UnregisterClassW(WC_IMECLASSNAME, NULL);
314     }
315 }
316
317 static void IMM_RegisterMessages(void)
318 {
319     WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
320     WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
321     WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
322     WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
323     WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
324     WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
325     WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
326 }
327
328
329 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
330 {
331     HMODULE x11drv;
332
333     TRACE("%p, %x, %p\n",hInstDLL,fdwReason,lpReserved);
334     switch (fdwReason)
335     {
336         case DLL_PROCESS_ATTACH:
337             DisableThreadLibraryCalls(hInstDLL);
338             hImeInst = hInstDLL;
339             IMM_RegisterMessages();
340             x11drv = GetModuleHandleA("winex11.drv");
341             if (x11drv) pX11DRV_ForceXIMReset = (void *)GetProcAddress( x11drv, "ForceXIMReset");
342             break;
343         case DLL_PROCESS_DETACH:
344             if (hwndDefault)
345             {
346                 DestroyWindow(hwndDefault);
347                 hwndDefault = 0;
348             }
349             IMM_Unregister();
350             IMM_FreeAllImmHkl();
351             break;
352     }
353     return TRUE;
354 }
355
356 /* for posting messages as the IME */
357 static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
358 {
359     HWND target = GetFocus();
360     if (!target)
361        PostMessageW(data->IMC.hWnd,msg,wParam,lParam);
362     else
363        PostMessageW(target, msg, wParam, lParam);
364 }
365
366 static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam)
367 {
368     HWND target;
369
370     target = data->IMC.hWnd;
371     if (!target) target = GetFocus();
372
373     if (target)
374        return SendMessageW(target, WM_IME_NOTIFY, notify, lParam);
375
376     return 0;
377 }
378
379 static HIMCC ImmCreateBlankCompStr(void)
380 {
381     HIMCC rc;
382     LPCOMPOSITIONSTRING ptr;
383     rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
384     ptr = (LPCOMPOSITIONSTRING)ImmLockIMCC(rc);
385     memset(ptr,0,sizeof(COMPOSITIONSTRING));
386     ptr->dwSize = sizeof(COMPOSITIONSTRING);
387     ImmUnlockIMCC(rc);
388     return rc;
389 }
390
391 static void ImmInternalSetOpenStatus(BOOL fOpen)
392 {
393     TRACE("Setting internal state to %s\n",(fOpen)?"OPEN":"CLOSED");
394
395     if (root_context->IMC.fOpen && fOpen == FALSE)
396     {
397         ShowWindow(hwndDefault,SW_HIDE);
398         ImmDestroyIMCC(root_context->IMC.hCompStr);
399         root_context->IMC.hCompStr = ImmCreateBlankCompStr();
400     }
401
402     root_context->IMC.fOpen = fOpen;
403     root_context->bInternalState = fOpen;
404
405     ImmInternalSendIMENotify(root_context, IMN_SETOPENSTATUS, 0);
406 }
407
408 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
409                        LPBYTE target, LPBYTE source, DWORD* lenParam,
410                        DWORD* offsetParam, BOOL wchars )
411 {
412      if (origLen > 0 && origOffset > 0)
413      {
414         int truelen = origLen;
415         if (wchars)
416             truelen *= sizeof(WCHAR);
417
418         memcpy(&target[currentOffset], &source[origOffset], truelen);
419
420         *lenParam = origLen;
421         *offsetParam = currentOffset;
422         currentOffset += truelen;
423      }
424      return currentOffset;
425 }
426
427 static HIMCC updateCompStr(HIMCC old, LPWSTR compstr, DWORD len)
428 {
429     /* we need to make sure the CompStr, CompClaus and CompAttr fields are all
430      * set and correct */
431     int needed_size;
432     HIMCC   rc;
433     LPBYTE newdata = NULL;
434     LPBYTE olddata = NULL;
435     LPCOMPOSITIONSTRING new_one;
436     LPCOMPOSITIONSTRING lpcs = NULL;
437     INT current_offset = 0;
438
439     TRACE("%s, %i\n",debugstr_wn(compstr,len),len);
440
441     if (old == NULL && compstr == NULL && len == 0)
442         return NULL;
443
444     if (old != NULL)
445     {
446         olddata = ImmLockIMCC(old);
447         lpcs = (LPCOMPOSITIONSTRING)olddata;
448     }
449
450     needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
451                   len + sizeof(DWORD) * 2;
452
453     if (lpcs != NULL)
454     {
455         needed_size += lpcs->dwCompReadAttrLen;
456         needed_size += lpcs->dwCompReadClauseLen;
457         needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
458         needed_size += lpcs->dwResultReadClauseLen;
459         needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
460         needed_size += lpcs->dwResultClauseLen;
461         needed_size += lpcs->dwResultStrLen * sizeof(DWORD);
462         needed_size += lpcs->dwPrivateSize;
463     }
464     rc = ImmCreateIMCC(needed_size);
465     newdata = ImmLockIMCC(rc);
466     new_one = (LPCOMPOSITIONSTRING)newdata;
467
468     new_one->dwSize = needed_size;
469     current_offset = sizeof(COMPOSITIONSTRING);
470     if (lpcs != NULL)
471     {
472         current_offset = updateField(lpcs->dwCompReadAttrLen,
473                                      lpcs->dwCompReadAttrOffset,
474                                      current_offset, newdata, olddata,
475                                      &new_one->dwCompReadAttrLen,
476                                      &new_one->dwCompReadAttrOffset, FALSE);
477
478         current_offset = updateField(lpcs->dwCompReadClauseLen,
479                                      lpcs->dwCompReadClauseOffset,
480                                      current_offset, newdata, olddata,
481                                      &new_one->dwCompReadClauseLen,
482                                      &new_one->dwCompReadClauseOffset, FALSE);
483
484         current_offset = updateField(lpcs->dwCompReadStrLen,
485                                      lpcs->dwCompReadStrOffset,
486                                      current_offset, newdata, olddata,
487                                      &new_one->dwCompReadStrLen,
488                                      &new_one->dwCompReadStrOffset, TRUE);
489
490         /* new CompAttr, CompClause, CompStr, dwCursorPos */
491         new_one->dwDeltaStart = 0;
492
493         current_offset = updateField(lpcs->dwResultReadClauseLen,
494                                      lpcs->dwResultReadClauseOffset,
495                                      current_offset, newdata, olddata,
496                                      &new_one->dwResultReadClauseLen,
497                                      &new_one->dwResultReadClauseOffset, FALSE);
498
499         current_offset = updateField(lpcs->dwResultReadStrLen,
500                                      lpcs->dwResultReadStrOffset,
501                                      current_offset, newdata, olddata,
502                                      &new_one->dwResultReadStrLen,
503                                      &new_one->dwResultReadStrOffset, TRUE);
504
505         current_offset = updateField(lpcs->dwResultClauseLen,
506                                      lpcs->dwResultClauseOffset,
507                                      current_offset, newdata, olddata,
508                                      &new_one->dwResultClauseLen,
509                                      &new_one->dwResultClauseOffset, FALSE);
510
511         current_offset = updateField(lpcs->dwResultStrLen,
512                                      lpcs->dwResultStrOffset,
513                                      current_offset, newdata, olddata,
514                                      &new_one->dwResultStrLen,
515                                      &new_one->dwResultStrOffset, TRUE);
516
517         current_offset = updateField(lpcs->dwPrivateSize,
518                                      lpcs->dwPrivateOffset,
519                                      current_offset, newdata, olddata,
520                                      &new_one->dwPrivateSize,
521                                      &new_one->dwPrivateOffset, FALSE);
522     }
523
524     /* set new data */
525     /* CompAttr */
526     new_one->dwCompAttrLen = len;
527     if (len > 0)
528     {
529         new_one->dwCompAttrOffset = current_offset;
530         memset(&newdata[current_offset],ATTR_INPUT,len);
531         current_offset += len;
532     }
533
534     /* CompClause */
535     if (len > 0)
536     {
537         new_one->dwCompClauseLen = sizeof(DWORD) * 2;
538         new_one->dwCompClauseOffset = current_offset;
539         *(DWORD*)(&newdata[current_offset]) = 0;
540         current_offset += sizeof(DWORD);
541         *(DWORD*)(&newdata[current_offset]) = len;
542         current_offset += sizeof(DWORD);
543     }
544
545     /* CompStr */
546     new_one->dwCompStrLen = len;
547     if (len > 0)
548     {
549         new_one->dwCompStrOffset = current_offset;
550         memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
551     }
552
553     /* CursorPos */
554     new_one->dwCursorPos = len;
555
556     ImmUnlockIMCC(rc);
557     if (lpcs)
558         ImmUnlockIMCC(old);
559
560     return rc;
561 }
562
563 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
564 {
565     /* we need to make sure the ResultStr and ResultClause fields are all
566      * set and correct */
567     int needed_size;
568     HIMCC   rc;
569     LPBYTE newdata = NULL;
570     LPBYTE olddata = NULL;
571     LPCOMPOSITIONSTRING new_one;
572     LPCOMPOSITIONSTRING lpcs = NULL;
573     INT current_offset = 0;
574
575     TRACE("%s, %i\n",debugstr_wn(resultstr,len),len);
576
577     if (old == NULL && resultstr == NULL && len == 0)
578         return NULL;
579
580     if (old != NULL)
581     {
582         olddata = ImmLockIMCC(old);
583         lpcs = (LPCOMPOSITIONSTRING)olddata;
584     }
585
586     needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
587                   sizeof(DWORD) * 2;
588
589     if (lpcs != NULL)
590     {
591         needed_size += lpcs->dwCompReadAttrLen;
592         needed_size += lpcs->dwCompReadClauseLen;
593         needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
594         needed_size += lpcs->dwCompAttrLen;
595         needed_size += lpcs->dwCompClauseLen;
596         needed_size += lpcs->dwCompStrLen * sizeof(DWORD);
597         needed_size += lpcs->dwResultReadClauseLen;
598         needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
599         needed_size += lpcs->dwPrivateSize;
600     }
601     rc = ImmCreateIMCC(needed_size);
602     newdata = ImmLockIMCC(rc);
603     new_one = (LPCOMPOSITIONSTRING)newdata;
604
605     new_one->dwSize = needed_size;
606     current_offset = sizeof(COMPOSITIONSTRING);
607     if (lpcs != NULL)
608     {
609         current_offset = updateField(lpcs->dwCompReadAttrLen,
610                                      lpcs->dwCompReadAttrOffset,
611                                      current_offset, newdata, olddata,
612                                      &new_one->dwCompReadAttrLen,
613                                      &new_one->dwCompReadAttrOffset, FALSE);
614
615         current_offset = updateField(lpcs->dwCompReadClauseLen,
616                                      lpcs->dwCompReadClauseOffset,
617                                      current_offset, newdata, olddata,
618                                      &new_one->dwCompReadClauseLen,
619                                      &new_one->dwCompReadClauseOffset, FALSE);
620
621         current_offset = updateField(lpcs->dwCompReadStrLen,
622                                      lpcs->dwCompReadStrOffset,
623                                      current_offset, newdata, olddata,
624                                      &new_one->dwCompReadStrLen,
625                                      &new_one->dwCompReadStrOffset, TRUE);
626
627         current_offset = updateField(lpcs->dwCompAttrLen,
628                                      lpcs->dwCompAttrOffset,
629                                      current_offset, newdata, olddata,
630                                      &new_one->dwCompAttrLen,
631                                      &new_one->dwCompAttrOffset, FALSE);
632
633         current_offset = updateField(lpcs->dwCompClauseLen,
634                                      lpcs->dwCompClauseOffset,
635                                      current_offset, newdata, olddata,
636                                      &new_one->dwCompClauseLen,
637                                      &new_one->dwCompClauseOffset, FALSE);
638
639         current_offset = updateField(lpcs->dwCompStrLen,
640                                      lpcs->dwCompStrOffset,
641                                      current_offset, newdata, olddata,
642                                      &new_one->dwCompStrLen,
643                                      &new_one->dwCompStrOffset, TRUE);
644
645         new_one->dwCursorPos = lpcs->dwCursorPos;
646         new_one->dwDeltaStart = 0;
647
648         current_offset = updateField(lpcs->dwResultReadClauseLen,
649                                      lpcs->dwResultReadClauseOffset,
650                                      current_offset, newdata, olddata,
651                                      &new_one->dwResultReadClauseLen,
652                                      &new_one->dwResultReadClauseOffset, FALSE);
653
654         current_offset = updateField(lpcs->dwResultReadStrLen,
655                                      lpcs->dwResultReadStrOffset,
656                                      current_offset, newdata, olddata,
657                                      &new_one->dwResultReadStrLen,
658                                      &new_one->dwResultReadStrOffset, TRUE);
659
660         /* new ResultClause , ResultStr */
661
662         current_offset = updateField(lpcs->dwPrivateSize,
663                                      lpcs->dwPrivateOffset,
664                                      current_offset, newdata, olddata,
665                                      &new_one->dwPrivateSize,
666                                      &new_one->dwPrivateOffset, FALSE);
667     }
668
669     /* set new data */
670     /* ResultClause */
671     if (len > 0)
672     {
673         new_one->dwResultClauseLen = sizeof(DWORD) * 2;
674         new_one->dwResultClauseOffset = current_offset;
675         *(DWORD*)(&newdata[current_offset]) = 0;
676         current_offset += sizeof(DWORD);
677         *(DWORD*)(&newdata[current_offset]) = len;
678         current_offset += sizeof(DWORD);
679     }
680
681     /* ResultStr */
682     new_one->dwResultStrLen = len;
683     if (len > 0)
684     {
685         new_one->dwResultStrOffset = current_offset;
686         memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
687     }
688     ImmUnlockIMCC(rc);
689     if (lpcs)
690         ImmUnlockIMCC(old);
691
692     return rc;
693 }
694
695
696
697 /***********************************************************************
698  *              ImmAssociateContext (IMM32.@)
699  */
700 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
701 {
702     HIMC old = NULL;
703     InputContextData *data = (InputContextData*)hIMC;
704
705     TRACE("(%p, %p):\n", hWnd, hIMC);
706
707     /*
708      * WINE SPECIFIC! MAY CONFLICT
709      * associate the root context we have an XIM created
710      */
711     if (hWnd == 0x000)
712     {
713         root_context = (InputContextData*)hIMC;
714     }
715
716     /*
717      * If already associated just return
718      */
719     if (hIMC && data->IMC.hWnd == hWnd)
720         return hIMC;
721
722     if (hWnd)
723     {
724         old = (HIMC)RemovePropW(hWnd,szwWineIMCProperty);
725
726         if (old == NULL)
727             old = (HIMC)root_context;
728         else if (old == (HIMC)-1)
729             old = NULL;
730
731         if (hIMC != (HIMC)root_context)
732         {
733             if (hIMC == NULL) /* Meaning disable imm for that window*/
734                 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
735             else
736                 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)hIMC);
737         }
738     }
739
740     if (!hIMC)
741         return old;
742
743     if (IsWindow(data->IMC.hWnd))
744     {
745         /*
746          * Post a message that your context is switching
747          */
748         SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL);
749     }
750
751     data->IMC.hWnd = hWnd;
752
753     if (IsWindow(data->IMC.hWnd))
754     {
755         /*
756          * Post a message that your context is switching
757          */
758         SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
759     }
760
761     return old;
762 }
763
764 /***********************************************************************
765  *              ImmAssociateContextEx (IMM32.@)
766  */
767 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
768 {
769     FIXME("(%p, %p, %d): stub\n", hWnd, hIMC, dwFlags);
770     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
771     return FALSE;
772 }
773
774 /***********************************************************************
775  *              ImmConfigureIMEA (IMM32.@)
776  */
777 BOOL WINAPI ImmConfigureIMEA(
778   HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
779 {
780     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
781
782     TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
783
784     if (immHkl->hIME && immHkl->pImeConfigure)
785     {
786         if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
787             return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
788         else
789         {
790             REGISTERWORDW rww;
791             REGISTERWORDA *rwa = (REGISTERWORDA*)lpData;
792             BOOL rc;
793
794             rww.lpReading = strdupAtoW(rwa->lpReading);
795             rww.lpWord = strdupAtoW(rwa->lpWord);
796             rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
797             HeapFree(GetProcessHeap(),0,rww.lpReading);
798             HeapFree(GetProcessHeap(),0,rww.lpWord);
799             return rc;
800         }
801     }
802     else
803         return FALSE;
804 }
805
806 /***********************************************************************
807  *              ImmConfigureIMEW (IMM32.@)
808  */
809 BOOL WINAPI ImmConfigureIMEW(
810   HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
811 {
812     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
813
814     TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
815
816     if (immHkl->hIME && immHkl->pImeConfigure)
817     {
818         if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
819             return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
820         else
821         {
822             REGISTERWORDW *rww = (REGISTERWORDW*)lpData;
823             REGISTERWORDA rwa;
824             BOOL rc;
825
826             rwa.lpReading = strdupWtoA(rww->lpReading);
827             rwa.lpWord = strdupWtoA(rww->lpWord);
828             rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
829             HeapFree(GetProcessHeap(),0,rwa.lpReading);
830             HeapFree(GetProcessHeap(),0,rwa.lpWord);
831             return rc;
832         }
833     }
834     else
835         return FALSE;
836 }
837
838 /***********************************************************************
839  *              ImmCreateContext (IMM32.@)
840  */
841 HIMC WINAPI ImmCreateContext(void)
842 {
843     InputContextData *new_context;
844
845     new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData));
846
847     /* Load the IME */
848     new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0));
849
850     /*
851      * Once we depend on the IME for all the processing like we should
852      * these will become hard errors and result in creation failures
853      */
854     if (!new_context->immKbd->hIME)
855         TRACE("IME dll could not be loaded\n");
856
857     /* hCompStr is never NULL */
858     new_context->IMC.hCompStr = ImmCreateBlankCompStr();
859     new_context->IMC.hMsgBuf = ImmCreateIMCC(1);
860
861     /* Initialize the IME Private */
862     new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize);
863
864     if (new_context->immKbd->hIME &&
865         !new_context->immKbd->pImeSelect(new_context, TRUE))
866     {
867         TRACE("Selection of IME failed\n");
868         ImmDestroyContext(new_context);
869         return 0;
870     }
871
872     new_context->immKbd->uSelected++;
873     TRACE("Created context 0x%x\n",(UINT)new_context);
874
875     return (HIMC)new_context;
876 }
877
878 /***********************************************************************
879  *              ImmDestroyContext (IMM32.@)
880  */
881 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
882 {
883     InputContextData *data = (InputContextData*)hIMC;
884
885     TRACE("Destroying %p\n",hIMC);
886
887     if (hIMC)
888     {
889         data->immKbd->uSelected --;
890         if (data->immKbd->hIME)
891             data->immKbd->pImeSelect(hIMC, FALSE);
892
893         ImmDestroyIMCC(data->IMC.hCompStr);
894         ImmDestroyIMCC(data->IMC.hCandInfo);
895         ImmDestroyIMCC(data->IMC.hGuideLine);
896         ImmDestroyIMCC(data->IMC.hPrivate);
897         ImmDestroyIMCC(data->IMC.hMsgBuf);
898
899         if (data->textfont)
900         {
901             DeleteObject(data->textfont);
902             data->textfont = NULL;
903         }
904
905         HeapFree(GetProcessHeap(),0,data);
906     }
907     return TRUE;
908 }
909
910 /***********************************************************************
911  *              ImmDisableIME (IMM32.@)
912  */
913 BOOL WINAPI ImmDisableIME(DWORD idThread)
914 {
915     FIXME("(%d): stub\n", idThread);
916     return TRUE;
917 }
918
919 /***********************************************************************
920  *              ImmEnumRegisterWordA (IMM32.@)
921  */
922 UINT WINAPI ImmEnumRegisterWordA(
923   HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc,
924   LPCSTR lpszReading, DWORD dwStyle,
925   LPCSTR lpszRegister, LPVOID lpData)
926 {
927   FIXME("(%p, %p, %s, %d, %s, %p): stub\n",
928     hKL, lpfnEnumProc,
929     debugstr_a(lpszReading), dwStyle,
930     debugstr_a(lpszRegister), lpData
931   );
932   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
933   return 0;
934 }
935
936 /***********************************************************************
937  *              ImmEnumRegisterWordW (IMM32.@)
938  */
939 UINT WINAPI ImmEnumRegisterWordW(
940   HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc,
941   LPCWSTR lpszReading, DWORD dwStyle,
942   LPCWSTR lpszRegister, LPVOID lpData)
943 {
944   FIXME("(%p, %p, %s, %d, %s, %p): stub\n",
945     hKL, lpfnEnumProc,
946     debugstr_w(lpszReading), dwStyle,
947     debugstr_w(lpszRegister), lpData
948   );
949   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
950   return 0;
951 }
952
953 /***********************************************************************
954  *              ImmEscapeA (IMM32.@)
955  */
956 LRESULT WINAPI ImmEscapeA(
957   HKL hKL, HIMC hIMC,
958   UINT uEscape, LPVOID lpData)
959 {
960   FIXME("(%p, %p, %d, %p): stub\n",
961     hKL, hIMC, uEscape, lpData
962   );
963   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
964   return 0;
965 }
966
967 /***********************************************************************
968  *              ImmEscapeW (IMM32.@)
969  */
970 LRESULT WINAPI ImmEscapeW(
971   HKL hKL, HIMC hIMC,
972   UINT uEscape, LPVOID lpData)
973 {
974   FIXME("(%p, %p, %d, %p): stub\n",
975     hKL, hIMC, uEscape, lpData
976   );
977   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
978   return 0;
979 }
980
981 /***********************************************************************
982  *              ImmGetCandidateListA (IMM32.@)
983  */
984 DWORD WINAPI ImmGetCandidateListA(
985   HIMC hIMC, DWORD deIndex,
986   LPCANDIDATELIST lpCandList, DWORD dwBufLen)
987 {
988   FIXME("(%p, %d, %p, %d): stub\n",
989     hIMC, deIndex,
990     lpCandList, dwBufLen
991   );
992   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
993   return 0;
994 }
995
996 /***********************************************************************
997  *              ImmGetCandidateListCountA (IMM32.@)
998  */
999 DWORD WINAPI ImmGetCandidateListCountA(
1000   HIMC hIMC, LPDWORD lpdwListCount)
1001 {
1002   FIXME("(%p, %p): stub\n", hIMC, lpdwListCount);
1003   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1004   return 0;
1005 }
1006
1007 /***********************************************************************
1008  *              ImmGetCandidateListCountW (IMM32.@)
1009  */
1010 DWORD WINAPI ImmGetCandidateListCountW(
1011   HIMC hIMC, LPDWORD lpdwListCount)
1012 {
1013   FIXME("(%p, %p): stub\n", hIMC, lpdwListCount);
1014   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1015   return 0;
1016 }
1017
1018 /***********************************************************************
1019  *              ImmGetCandidateListW (IMM32.@)
1020  */
1021 DWORD WINAPI ImmGetCandidateListW(
1022   HIMC hIMC, DWORD deIndex,
1023   LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1024 {
1025   FIXME("(%p, %d, %p, %d): stub\n",
1026     hIMC, deIndex,
1027     lpCandList, dwBufLen
1028   );
1029   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1030   return 0;
1031 }
1032
1033 /***********************************************************************
1034  *              ImmGetCandidateWindow (IMM32.@)
1035  */
1036 BOOL WINAPI ImmGetCandidateWindow(
1037   HIMC hIMC, DWORD dwBufLen, LPCANDIDATEFORM lpCandidate)
1038 {
1039   FIXME("(%p, %d, %p): stub\n", hIMC, dwBufLen, lpCandidate);
1040   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1041   return FALSE;
1042 }
1043
1044 /***********************************************************************
1045  *              ImmGetCompositionFontA (IMM32.@)
1046  */
1047 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1048 {
1049     LOGFONTW lfW;
1050     BOOL rc;
1051
1052     TRACE("(%p, %p):\n", hIMC, lplf);
1053
1054     rc = ImmGetCompositionFontW(hIMC,&lfW);
1055     if (rc)
1056     {
1057         memcpy(lplf,&lfW,sizeof(LOGFONTA));
1058         WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName,
1059                         LF_FACESIZE, NULL, NULL);
1060     }
1061     return rc;
1062 }
1063
1064 /***********************************************************************
1065  *              ImmGetCompositionFontW (IMM32.@)
1066  */
1067 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1068 {
1069     InputContextData *data = (InputContextData*)hIMC;
1070
1071     TRACE("(%p, %p):\n", hIMC, lplf);
1072
1073     if (!data)
1074         return FALSE;
1075
1076     *lplf = data->IMC.lfFont.W;
1077
1078     return TRUE;
1079 }
1080
1081 /***********************************************************************
1082  *              ImmGetCompositionStringA (IMM32.@)
1083  */
1084 LONG WINAPI ImmGetCompositionStringA(
1085   HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
1086 {
1087     CHAR *buf;
1088     LONG rc = 0;
1089     InputContextData *data = (InputContextData*)hIMC;
1090     LPCOMPOSITIONSTRING compstr;
1091     LPBYTE compdata;
1092
1093     TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1094
1095     if (!data)
1096        return FALSE;
1097
1098     if (!data->IMC.hCompStr)
1099        return FALSE;
1100
1101     compdata = ImmLockIMCC(data->IMC.hCompStr);
1102     compstr = (LPCOMPOSITIONSTRING)compdata;
1103
1104     if (dwIndex == GCS_RESULTSTR && compstr->dwResultStrLen > 0 &&
1105         compstr->dwResultStrOffset > 0)
1106     {
1107         LPWSTR ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1108
1109         TRACE("GSC_RESULTSTR %p %i\n",ResultStr,
1110                                     compstr->dwResultStrLen);
1111
1112         buf = HeapAlloc( GetProcessHeap(), 0, compstr->dwResultStrLen * 3 );
1113         rc = WideCharToMultiByte(CP_ACP, 0, ResultStr,
1114                                  compstr->dwResultStrLen , buf,
1115                                  compstr->dwResultStrLen * 3, NULL, NULL);
1116         if (dwBufLen >= rc)
1117             memcpy(lpBuf,buf,rc);
1118
1119         data->bRead = TRUE;
1120         HeapFree( GetProcessHeap(), 0, buf );
1121     }
1122     else if (dwIndex == GCS_COMPSTR && compstr->dwCompStrLen > 0 &&
1123               compstr->dwCompStrOffset > 0)
1124     {
1125         LPWSTR CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1126
1127         TRACE("GSC_COMPSTR %p %i\n", CompString, compstr->dwCompStrLen);
1128
1129         buf = HeapAlloc( GetProcessHeap(), 0, compstr->dwCompStrLen * 3 );
1130         rc = WideCharToMultiByte(CP_ACP, 0, CompString,
1131                                  compstr->dwCompStrLen, buf,
1132                                  compstr->dwCompStrLen * 3, NULL, NULL);
1133         if (dwBufLen >= rc)
1134             memcpy(lpBuf,buf,rc);
1135         HeapFree( GetProcessHeap(), 0, buf );
1136     }
1137     else if (dwIndex == GCS_COMPATTR && compstr->dwCompAttrLen > 0 &&
1138              compstr->dwCompAttrOffset > 0)
1139     {
1140         LPWSTR Compattr = (LPWSTR)(compdata + compstr->dwCompAttrOffset);
1141         TRACE("GSC_COMPATTR %p %i\n", Compattr , compstr->dwCompAttrLen);
1142
1143         rc = compstr->dwCompAttrLen;
1144         if (dwBufLen >= rc)
1145             memcpy(lpBuf,Compattr,rc);
1146     }
1147     else if (dwIndex == GCS_COMPCLAUSE && compstr->dwCompClauseLen > 0 &&
1148              compstr->dwCompClauseOffset > 0)
1149     {
1150         LPWSTR Compclause = (LPWSTR)(compdata + compstr->dwCompClauseOffset);
1151         TRACE("GSC_COMPCLAUSE %p %i\n", Compclause, compstr->dwCompClauseLen);
1152
1153         rc = compstr->dwCompClauseLen;
1154         if (dwBufLen >= compstr->dwCompClauseLen)
1155             memcpy(lpBuf,Compclause,rc);
1156     }
1157     else if (dwIndex == GCS_RESULTCLAUSE && compstr->dwResultClauseLen > 0 &&
1158              compstr->dwResultClauseOffset > 0)
1159     {
1160         LPWSTR Resultclause = (LPWSTR)(compdata + compstr->dwResultClauseOffset);
1161         TRACE("GSC_RESULTCLAUSE %p %i\n", Resultclause, compstr->dwResultClauseLen);
1162
1163         rc = compstr->dwResultClauseLen;
1164         if (dwBufLen >= compstr->dwResultClauseLen)
1165             memcpy(lpBuf,Resultclause,rc);
1166     }
1167     else if (dwIndex == GCS_CURSORPOS)
1168     {
1169         TRACE("GSC_CURSORPOS\n");
1170         rc = compstr->dwCursorPos;
1171     }
1172     else if (dwIndex == GCS_DELTASTART)
1173     {
1174         TRACE("GCS_DELTASTART\n");
1175         rc = compstr->dwDeltaStart;
1176     }
1177     else
1178     {
1179         FIXME("Unhandled index 0x%x\n",dwIndex);
1180     }
1181
1182     ImmUnlockIMCC(data->IMC.hCompStr);
1183
1184     return rc;
1185 }
1186
1187 /***********************************************************************
1188  *              ImmGetCompositionStringW (IMM32.@)
1189  */
1190 LONG WINAPI ImmGetCompositionStringW(
1191   HIMC hIMC, DWORD dwIndex,
1192   LPVOID lpBuf, DWORD dwBufLen)
1193 {
1194     LONG rc = 0;
1195     InputContextData *data = (InputContextData*)hIMC;
1196     LPCOMPOSITIONSTRING compstr;
1197     LPBYTE compdata;
1198
1199     TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1200
1201     if (!data)
1202        return FALSE;
1203
1204     if (!data->IMC.hCompStr)
1205        return FALSE;
1206
1207     compdata = ImmLockIMCC(data->IMC.hCompStr);
1208     compstr = (LPCOMPOSITIONSTRING)compdata;
1209
1210     if (dwIndex == GCS_RESULTSTR && compstr->dwResultStrLen > 0 &&
1211         compstr->dwResultStrOffset > 0)
1212     {
1213         LPWSTR ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1214         data->bRead = TRUE;
1215         rc =  compstr->dwResultStrLen * sizeof(WCHAR);
1216
1217         if (dwBufLen >= rc)
1218             memcpy(lpBuf,ResultStr,rc);
1219     }
1220     else if (dwIndex == GCS_RESULTREADSTR && compstr->dwResultReadStrLen > 0 &&
1221              compstr->dwResultReadStrOffset > 0)
1222     {
1223         LPWSTR ResultReadString = (LPWSTR)(compdata + compstr->dwResultReadStrOffset);
1224
1225         rc = compstr->dwResultReadStrLen * sizeof(WCHAR);
1226         if (dwBufLen >= rc)
1227             memcpy(lpBuf,ResultReadString,rc);
1228     }
1229     else if (dwIndex == GCS_COMPSTR && compstr->dwCompStrLen > 0 &&
1230               compstr->dwCompStrOffset > 0)
1231     {
1232         LPWSTR CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1233         rc = compstr->dwCompStrLen * sizeof(WCHAR);
1234         if (dwBufLen >= rc)
1235             memcpy(lpBuf,CompString,rc);
1236     }
1237     else if (dwIndex == GCS_COMPATTR && compstr->dwCompAttrLen > 0 &&
1238              compstr->dwCompAttrOffset > 0)
1239     {
1240
1241         LPWSTR Compattr = (LPWSTR)(compdata + compstr->dwCompAttrOffset);
1242
1243         rc = compstr->dwCompAttrLen;
1244         if (dwBufLen >= rc)
1245             memcpy(lpBuf,Compattr,rc);
1246     }
1247     else if (dwIndex == GCS_COMPCLAUSE && compstr->dwCompClauseLen > 0 &&
1248              compstr->dwCompClauseOffset > 0)
1249     {
1250         LPWSTR Compclause = (LPWSTR)(compdata + compstr->dwCompClauseOffset);
1251
1252         rc = compstr->dwCompClauseLen;
1253         if (dwBufLen >= compstr->dwCompClauseLen)
1254             memcpy(lpBuf,Compclause,rc);
1255     }
1256     else if (dwIndex == GCS_COMPREADSTR && compstr->dwCompReadStrLen > 0 &&
1257               compstr->dwCompReadStrOffset > 0)
1258     {
1259         LPWSTR CompReadString = (LPWSTR)(compdata + compstr->dwCompReadStrOffset);
1260
1261         rc = compstr->dwCompReadStrLen * sizeof(WCHAR);
1262
1263         if (dwBufLen >= rc)
1264             memcpy(lpBuf,CompReadString,rc);
1265     }
1266     else if (dwIndex == GCS_CURSORPOS)
1267     {
1268         TRACE("GSC_CURSORPOS\n");
1269         rc = compstr->dwCursorPos;
1270     }
1271     else if (dwIndex == GCS_DELTASTART)
1272     {
1273         TRACE("GCS_DELTASTART\n");
1274         rc = compstr->dwDeltaStart;
1275     }
1276     else
1277     {
1278         FIXME("Unhandled index 0x%x\n",dwIndex);
1279     }   
1280
1281     ImmUnlockIMCC(data->IMC.hCompStr);
1282
1283     return rc;
1284 }
1285
1286 /***********************************************************************
1287  *              ImmGetCompositionWindow (IMM32.@)
1288  */
1289 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1290 {
1291     InputContextData *data = (InputContextData*)hIMC;
1292
1293     TRACE("(%p, %p)\n", hIMC, lpCompForm);
1294
1295     if (!data)
1296         return FALSE;
1297
1298     *lpCompForm = data->IMC.cfCompForm;
1299     return 1;
1300 }
1301
1302 /***********************************************************************
1303  *              ImmGetContext (IMM32.@)
1304  *
1305  */
1306 HIMC WINAPI ImmGetContext(HWND hWnd)
1307 {
1308     HIMC rc = NULL;
1309
1310     TRACE("%p\n", hWnd);
1311
1312     rc = (HIMC)GetPropW(hWnd,szwWineIMCProperty);
1313     if (rc == (HIMC)-1)
1314         rc = NULL;
1315     else if (rc == NULL)
1316         rc = (HIMC)root_context;
1317
1318     if (rc)
1319     {
1320         InputContextData *data = (InputContextData*)rc;
1321         data->IMC.hWnd = hWnd;
1322     }
1323     TRACE("returning %p\n", rc);
1324
1325     return rc;
1326 }
1327
1328 /***********************************************************************
1329  *              ImmGetConversionListA (IMM32.@)
1330  */
1331 DWORD WINAPI ImmGetConversionListA(
1332   HKL hKL, HIMC hIMC,
1333   LPCSTR pSrc, LPCANDIDATELIST lpDst,
1334   DWORD dwBufLen, UINT uFlag)
1335 {
1336   FIXME("(%p, %p, %s, %p, %d, %d): stub\n",
1337     hKL, hIMC, debugstr_a(pSrc), lpDst, dwBufLen, uFlag
1338   );
1339   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1340   return 0;
1341 }
1342
1343 /***********************************************************************
1344  *              ImmGetConversionListW (IMM32.@)
1345  */
1346 DWORD WINAPI ImmGetConversionListW(
1347   HKL hKL, HIMC hIMC,
1348   LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1349   DWORD dwBufLen, UINT uFlag)
1350 {
1351   FIXME("(%p, %p, %s, %p, %d, %d): stub\n",
1352     hKL, hIMC, debugstr_w(pSrc), lpDst, dwBufLen, uFlag
1353   );
1354   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1355   return 0;
1356 }
1357
1358 /***********************************************************************
1359  *              ImmGetConversionStatus (IMM32.@)
1360  */
1361 BOOL WINAPI ImmGetConversionStatus(
1362   HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1363 {
1364     TRACE("(%p, %p, %p): best guess\n", hIMC, lpfdwConversion, lpfdwSentence);
1365     if (lpfdwConversion)
1366         *lpfdwConversion = IME_CMODE_NATIVE;
1367     if (lpfdwSentence)
1368         *lpfdwSentence = IME_SMODE_NONE;
1369     return TRUE;
1370 }
1371
1372 /***********************************************************************
1373  *              ImmGetDefaultIMEWnd (IMM32.@)
1374  */
1375 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
1376 {
1377   static int shown = 0;
1378
1379   if (!shown) {
1380         FIXME("(%p - %p %p ): semi-stub\n", hWnd,hwndDefault, root_context);
1381         shown = 1;
1382   }
1383
1384   if (hwndDefault == NULL)
1385   {
1386         static const WCHAR the_name[] = {'I','M','E','\0'};
1387
1388         IMM_Register();
1389         hwndDefault = CreateWindowExW( WS_EX_TOOLWINDOW, WC_IMECLASSNAME,
1390                 the_name, WS_POPUP, 0, 0, 1, 1, 0, 0,
1391                 hImeInst, 0);
1392
1393         TRACE("Default created (%p)\n",hwndDefault);
1394   }
1395
1396   return hwndDefault;
1397 }
1398
1399 /***********************************************************************
1400  *              ImmGetDescriptionA (IMM32.@)
1401  */
1402 UINT WINAPI ImmGetDescriptionA(
1403   HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1404 {
1405   WCHAR *buf;
1406   DWORD len;
1407
1408   TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen);
1409
1410   /* find out how many characters in the unicode buffer */
1411   len = ImmGetDescriptionW( hKL, NULL, 0 );
1412
1413   /* allocate a buffer of that size */
1414   buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) );
1415   if( !buf )
1416   return 0;
1417
1418   /* fetch the unicode buffer */
1419   len = ImmGetDescriptionW( hKL, buf, len + 1 );
1420
1421   /* convert it back to ASCII */
1422   len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1,
1423                              lpszDescription, uBufLen, NULL, NULL );
1424
1425   HeapFree( GetProcessHeap(), 0, buf );
1426
1427   return len;
1428 }
1429
1430 /***********************************************************************
1431  *              ImmGetDescriptionW (IMM32.@)
1432  */
1433 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1434 {
1435   static const WCHAR name[] = { 'W','i','n','e',' ','X','I','M',0 };
1436
1437   FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen);
1438
1439   if (!uBufLen) return lstrlenW( name );
1440   lstrcpynW( lpszDescription, name, uBufLen );
1441   return lstrlenW( lpszDescription );
1442 }
1443
1444 /***********************************************************************
1445  *              ImmGetGuideLineA (IMM32.@)
1446  */
1447 DWORD WINAPI ImmGetGuideLineA(
1448   HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
1449 {
1450   FIXME("(%p, %d, %s, %d): stub\n",
1451     hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
1452   );
1453   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1454   return 0;
1455 }
1456
1457 /***********************************************************************
1458  *              ImmGetGuideLineW (IMM32.@)
1459  */
1460 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
1461 {
1462   FIXME("(%p, %d, %s, %d): stub\n",
1463     hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
1464   );
1465   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1466   return 0;
1467 }
1468
1469 /***********************************************************************
1470  *              ImmGetIMEFileNameA (IMM32.@)
1471  */
1472 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
1473 {
1474     LPWSTR bufW = NULL;
1475     UINT wBufLen = uBufLen;
1476     UINT rc;
1477
1478     if (uBufLen && lpszFileName)
1479         bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR));
1480     else /* We need this to get the number of byte required */
1481     {
1482         bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR));
1483         wBufLen = MAX_PATH;
1484     }
1485
1486     rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen);
1487
1488     if (rc > 0)
1489     {
1490         if (uBufLen && lpszFileName)
1491             rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName,
1492                                  uBufLen, NULL, NULL);
1493         else /* get the length */
1494             rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL,
1495                                      NULL);
1496     }
1497
1498     HeapFree(GetProcessHeap(),0,bufW);
1499     return rc;
1500 }
1501
1502 /***********************************************************************
1503  *              ImmGetIMEFileNameW (IMM32.@)
1504  */
1505 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
1506 {
1507     static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
1508     static const WCHAR fmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','x',0};
1509
1510     HKEY hkey;
1511     DWORD length;
1512     DWORD rc;
1513     WCHAR regKey[sizeof(fmt)/sizeof(WCHAR)+8];
1514
1515     wsprintfW( regKey, fmt, (unsigned)hKL );
1516     rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
1517     if (rc != ERROR_SUCCESS)
1518     {
1519         SetLastError(rc);
1520         return 0;
1521     }
1522
1523     length = 0;
1524     rc = RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, NULL, &length);
1525
1526     if (rc != ERROR_SUCCESS)
1527     {
1528         RegCloseKey(hkey);
1529         SetLastError(rc);
1530         return 0;
1531     }
1532     if (length > uBufLen * sizeof(WCHAR) || !lpszFileName)
1533     {
1534         RegCloseKey(hkey);
1535         if (lpszFileName)
1536         {
1537             SetLastError(ERROR_INSUFFICIENT_BUFFER);
1538             return 0;
1539         }
1540         else
1541             return length / sizeof(WCHAR);
1542     }
1543
1544     RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, lpszFileName, &length);
1545
1546     RegCloseKey(hkey);
1547
1548     return length / sizeof(WCHAR);
1549 }
1550
1551 /***********************************************************************
1552  *              ImmGetOpenStatus (IMM32.@)
1553  */
1554 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1555 {
1556   InputContextData *data = (InputContextData*)hIMC;
1557
1558     if (!data)
1559         return FALSE;
1560   FIXME("(%p): semi-stub\n", hIMC);
1561
1562   return data->IMC.fOpen;
1563 }
1564
1565 /***********************************************************************
1566  *              ImmGetProperty (IMM32.@)
1567  */
1568 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
1569 {
1570     DWORD rc = 0;
1571     TRACE("(%p, %d)\n", hKL, fdwIndex);
1572
1573     switch (fdwIndex)
1574     {
1575         case IGP_PROPERTY:
1576             TRACE("(%s)\n", "IGP_PROPERTY");
1577             rc = IME_PROP_UNICODE | IME_PROP_AT_CARET;
1578             break;
1579         case IGP_CONVERSION:
1580             FIXME("(%s)\n", "IGP_CONVERSION");
1581             rc = IME_CMODE_NATIVE;
1582             break;
1583         case IGP_SENTENCE:
1584             FIXME("%s)\n", "IGP_SENTENCE");
1585             rc = IME_SMODE_AUTOMATIC;
1586             break;
1587         case IGP_SETCOMPSTR:
1588             TRACE("(%s)\n", "IGP_SETCOMPSTR");
1589             rc = 0;
1590             break;
1591         case IGP_SELECT:
1592             TRACE("(%s)\n", "IGP_SELECT");
1593             rc = SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE;
1594             break;
1595         case IGP_GETIMEVERSION:
1596             TRACE("(%s)\n", "IGP_GETIMEVERSION");
1597             rc = IMEVER_0400;
1598             break;
1599         case IGP_UI:
1600             TRACE("(%s)\n", "IGP_UI");
1601             rc = 0;
1602             break;
1603         default:
1604             rc = 0;
1605     }
1606     return rc;
1607 }
1608
1609 /***********************************************************************
1610  *              ImmGetRegisterWordStyleA (IMM32.@)
1611  */
1612 UINT WINAPI ImmGetRegisterWordStyleA(
1613   HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
1614 {
1615   FIXME("(%p, %d, %p): stub\n", hKL, nItem, lpStyleBuf);
1616   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1617   return 0;
1618 }
1619
1620 /***********************************************************************
1621  *              ImmGetRegisterWordStyleW (IMM32.@)
1622  */
1623 UINT WINAPI ImmGetRegisterWordStyleW(
1624   HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
1625 {
1626   FIXME("(%p, %d, %p): stub\n", hKL, nItem, lpStyleBuf);
1627   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1628   return 0;
1629 }
1630
1631 /***********************************************************************
1632  *              ImmGetStatusWindowPos (IMM32.@)
1633  */
1634 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1635 {
1636   FIXME("(%p, %p): stub\n", hIMC, lpptPos);
1637   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1638   return FALSE;
1639 }
1640
1641 /***********************************************************************
1642  *              ImmGetVirtualKey (IMM32.@)
1643  */
1644 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
1645 {
1646   OSVERSIONINFOA version;
1647   FIXME("(%p): stub\n", hWnd);
1648   GetVersionExA( &version );
1649   switch(version.dwPlatformId)
1650   {
1651   case VER_PLATFORM_WIN32_WINDOWS:
1652       return VK_PROCESSKEY;
1653   case VER_PLATFORM_WIN32_NT:
1654       return 0;
1655   default:
1656       FIXME("%d not supported\n",version.dwPlatformId);
1657       return VK_PROCESSKEY;
1658   }
1659 }
1660
1661 /***********************************************************************
1662  *              ImmInstallIMEA (IMM32.@)
1663  */
1664 HKL WINAPI ImmInstallIMEA(
1665   LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
1666 {
1667   FIXME("(%s, %s): stub\n",
1668     debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText)
1669   );
1670   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1671   return NULL;
1672 }
1673
1674 /***********************************************************************
1675  *              ImmInstallIMEW (IMM32.@)
1676  */
1677 HKL WINAPI ImmInstallIMEW(
1678   LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
1679 {
1680   FIXME("(%s, %s): stub\n",
1681     debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText)
1682   );
1683   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1684   return NULL;
1685 }
1686
1687 /***********************************************************************
1688  *              ImmIsIME (IMM32.@)
1689  */
1690 BOOL WINAPI ImmIsIME(HKL hKL)
1691 {
1692   TRACE("(%p): semi-stub\n", hKL);
1693   /*
1694    * FIXME: Dead key locales will return TRUE here when they should not
1695    * There is probably a more proper way to check this.
1696    */
1697   return (root_context != NULL);
1698 }
1699
1700 /***********************************************************************
1701  *              ImmIsUIMessageA (IMM32.@)
1702  */
1703 BOOL WINAPI ImmIsUIMessageA(
1704   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
1705 {
1706     BOOL rc = FALSE;
1707
1708     TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
1709     if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1710         (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP) ||
1711         (msg == WM_MSIME_SERVICE) ||
1712         (msg == WM_MSIME_RECONVERTOPTIONS) ||
1713         (msg == WM_MSIME_MOUSE) ||
1714         (msg == WM_MSIME_RECONVERTREQUEST) ||
1715         (msg == WM_MSIME_RECONVERT) ||
1716         (msg == WM_MSIME_QUERYPOSITION) ||
1717         (msg == WM_MSIME_DOCUMENTFEED))
1718
1719     {
1720         if (!hwndDefault)
1721             ImmGetDefaultIMEWnd(NULL);
1722
1723         if (hWndIME == NULL)
1724             PostMessageA(hwndDefault, msg, wParam, lParam);
1725
1726         rc = TRUE;
1727     }
1728     return rc;
1729 }
1730
1731 /***********************************************************************
1732  *              ImmIsUIMessageW (IMM32.@)
1733  */
1734 BOOL WINAPI ImmIsUIMessageW(
1735   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
1736 {
1737     BOOL rc = FALSE;
1738     TRACE("(%p, %d, %ld, %ld): stub\n", hWndIME, msg, wParam, lParam);
1739     if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1740         (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP) ||
1741         (msg == WM_MSIME_SERVICE) ||
1742         (msg == WM_MSIME_RECONVERTOPTIONS) ||
1743         (msg == WM_MSIME_MOUSE) ||
1744         (msg == WM_MSIME_RECONVERTREQUEST) ||
1745         (msg == WM_MSIME_RECONVERT) ||
1746         (msg == WM_MSIME_QUERYPOSITION) ||
1747         (msg == WM_MSIME_DOCUMENTFEED))
1748         rc = TRUE;
1749     return rc;
1750 }
1751
1752 /***********************************************************************
1753  *              ImmNotifyIME (IMM32.@)
1754  */
1755 BOOL WINAPI ImmNotifyIME(
1756   HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
1757 {
1758     BOOL rc = FALSE;
1759
1760     TRACE("(%p, %d, %d, %d)\n",
1761         hIMC, dwAction, dwIndex, dwValue);
1762
1763     if (!root_context)
1764         return rc;
1765
1766     switch(dwAction)
1767     {
1768         case NI_CHANGECANDIDATELIST:
1769             FIXME("%s\n","NI_CHANGECANDIDATELIST");
1770             break;
1771         case NI_CLOSECANDIDATE:
1772             FIXME("%s\n","NI_CLOSECANDIDATE");
1773             break;
1774         case NI_COMPOSITIONSTR:
1775             switch (dwIndex)
1776             {
1777                 case CPS_CANCEL:
1778                     TRACE("%s - %s\n","NI_COMPOSITIONSTR","CPS_CANCEL");
1779                     {
1780                         BOOL send;
1781                         LPCOMPOSITIONSTRING lpCompStr;
1782
1783                         if (pX11DRV_ForceXIMReset)
1784                             pX11DRV_ForceXIMReset(root_context->IMC.hWnd);
1785
1786                         lpCompStr = ImmLockIMCC(root_context->IMC.hCompStr);
1787                         send = (lpCompStr->dwCompStrLen != 0);
1788                         ImmUnlockIMCC(root_context->IMC.hCompStr);
1789
1790                         ImmDestroyIMCC(root_context->IMC.hCompStr);
1791                         root_context->IMC.hCompStr = ImmCreateBlankCompStr();
1792
1793                         if (send)
1794                             ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION, 0,
1795                                                   GCS_COMPSTR);
1796                         rc = TRUE;
1797                     }
1798                     break;
1799                 case CPS_COMPLETE:
1800                     TRACE("%s - %s\n","NI_COMPOSITIONSTR","CPS_COMPLETE");
1801                     if (hIMC != (HIMC)FROM_IME && pX11DRV_ForceXIMReset)
1802                         pX11DRV_ForceXIMReset(root_context->IMC.hWnd);
1803                     {
1804                         HIMCC newCompStr;
1805                         DWORD cplen = 0;
1806                         LPWSTR cpstr;
1807                         LPCOMPOSITIONSTRING cs = NULL;
1808                         LPBYTE cdata = NULL;
1809
1810                         /* clear existing result */
1811                         newCompStr = updateResultStr(root_context->IMC.hCompStr, NULL, 0);
1812                         ImmDestroyIMCC(root_context->IMC.hCompStr);
1813                         root_context->IMC.hCompStr = newCompStr;
1814
1815                         if (root_context->IMC.hCompStr)
1816                         {
1817                             cdata = ImmLockIMCC(root_context->IMC.hCompStr);
1818                             cs = (LPCOMPOSITIONSTRING)cdata;
1819                             cplen = cs->dwCompStrLen;
1820                             cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]);
1821                             ImmUnlockIMCC(root_context->IMC.hCompStr);
1822                         }
1823                         if (cplen > 0)
1824                         {
1825                             WCHAR param = cpstr[0];
1826                             newCompStr = updateResultStr(root_context->IMC.hCompStr, cpstr, cplen);
1827                             ImmDestroyIMCC(root_context->IMC.hCompStr);
1828                             root_context->IMC.hCompStr = newCompStr;
1829                             newCompStr = updateCompStr(root_context->IMC.hCompStr, NULL, 0);
1830                             ImmDestroyIMCC(root_context->IMC.hCompStr);
1831                             root_context->IMC.hCompStr = newCompStr;
1832
1833                             root_context->bRead = FALSE;
1834
1835                             ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION, 0,
1836                                                   GCS_COMPSTR);
1837
1838                             ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION,
1839                                             param,
1840                                             GCS_RESULTSTR|GCS_RESULTCLAUSE);
1841                         }
1842
1843                         ImmInternalPostIMEMessage(root_context, WM_IME_ENDCOMPOSITION, 0, 0);
1844                         root_context->bInComposition = FALSE;
1845                     }
1846                     break;
1847                 case CPS_CONVERT:
1848                     FIXME("%s - %s\n","NI_COMPOSITIONSTR","CPS_CONVERT");
1849                     break;
1850                 case CPS_REVERT:
1851                     FIXME("%s - %s\n","NI_COMPOSITIONSTR","CPS_REVERT");
1852                     break;
1853                 default:
1854                     ERR("%s - %s (%i)\n","NI_COMPOSITIONSTR","UNKNOWN",dwIndex);
1855                     break;
1856             }
1857             break;
1858         case NI_IMEMENUSELECTED:
1859             FIXME("%s\n", "NI_IMEMENUSELECTED");
1860             break;
1861         case NI_OPENCANDIDATE:
1862             FIXME("%s\n", "NI_OPENCANDIDATE");
1863             break;
1864         case NI_SELECTCANDIDATESTR:
1865             FIXME("%s\n", "NI_SELECTCANDIDATESTR");
1866             break;
1867         case NI_SETCANDIDATE_PAGESIZE:
1868             FIXME("%s\n", "NI_SETCANDIDATE_PAGESIZE");
1869             break;
1870         case NI_SETCANDIDATE_PAGESTART:
1871             FIXME("%s\n", "NI_SETCANDIDATE_PAGESTART");
1872             break;
1873         default:
1874             ERR("Unknown\n");
1875     }
1876
1877     return rc;
1878 }
1879
1880 /***********************************************************************
1881  *              ImmRegisterWordA (IMM32.@)
1882  */
1883 BOOL WINAPI ImmRegisterWordA(
1884   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
1885 {
1886   FIXME("(%p, %s, %d, %s): stub\n",
1887     hKL, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister)
1888   );
1889   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1890   return FALSE;
1891 }
1892
1893 /***********************************************************************
1894  *              ImmRegisterWordW (IMM32.@)
1895  */
1896 BOOL WINAPI ImmRegisterWordW(
1897   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
1898 {
1899   FIXME("(%p, %s, %d, %s): stub\n",
1900     hKL, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister)
1901   );
1902   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1903   return FALSE;
1904 }
1905
1906 /***********************************************************************
1907  *              ImmReleaseContext (IMM32.@)
1908  */
1909 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
1910 {
1911   static int shown = 0;
1912
1913   if (!shown) {
1914      FIXME("(%p, %p): stub\n", hWnd, hIMC);
1915      shown = 1;
1916   }
1917   return TRUE;
1918 }
1919
1920 /***********************************************************************
1921  *              ImmSetCandidateWindow (IMM32.@)
1922  */
1923 BOOL WINAPI ImmSetCandidateWindow(
1924   HIMC hIMC, LPCANDIDATEFORM lpCandidate)
1925 {
1926   FIXME("(%p, %p): stub\n", hIMC, lpCandidate);
1927   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1928   return FALSE;
1929 }
1930
1931 /***********************************************************************
1932  *              ImmSetCompositionFontA (IMM32.@)
1933  */
1934 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1935 {
1936     InputContextData *data = (InputContextData*)hIMC;
1937     TRACE("(%p, %p)\n", hIMC, lplf);
1938
1939     if (!data)
1940         return FALSE;
1941
1942     memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
1943     MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
1944                         LF_FACESIZE);
1945
1946     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
1947
1948     if (data->textfont)
1949     {
1950         DeleteObject(data->textfont);
1951         data->textfont = NULL;
1952     }
1953
1954     data->textfont = CreateFontIndirectW(&data->IMC.lfFont.W);
1955     return TRUE;
1956 }
1957
1958 /***********************************************************************
1959  *              ImmSetCompositionFontW (IMM32.@)
1960  */
1961 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1962 {
1963     InputContextData *data = (InputContextData*)hIMC;
1964     TRACE("(%p, %p)\n", hIMC, lplf);
1965
1966     if (!data)
1967         return FALSE;
1968
1969     data->IMC.lfFont.W = *lplf;
1970     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
1971
1972     if (data->textfont)
1973     {
1974         DeleteObject(data->textfont);
1975         data->textfont = NULL;
1976     }
1977     data->textfont = CreateFontIndirectW(&data->IMC.lfFont.W);
1978     return TRUE;
1979 }
1980
1981 /***********************************************************************
1982  *              ImmSetCompositionStringA (IMM32.@)
1983  */
1984 BOOL WINAPI ImmSetCompositionStringA(
1985   HIMC hIMC, DWORD dwIndex,
1986   LPCVOID lpComp, DWORD dwCompLen,
1987   LPCVOID lpRead, DWORD dwReadLen)
1988 {
1989     DWORD comp_len;
1990     DWORD read_len;
1991     WCHAR *CompBuffer = NULL;
1992     WCHAR *ReadBuffer = NULL;
1993     BOOL rc;
1994
1995     TRACE("(%p, %d, %p, %d, %p, %d): stub\n",
1996             hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1997
1998     comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
1999     if (comp_len)
2000     {
2001         CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
2002         MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
2003     }
2004
2005     read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
2006     if (read_len)
2007     {
2008         ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
2009         MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
2010     }
2011
2012     rc =  ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
2013                                    ReadBuffer, read_len);
2014
2015     HeapFree(GetProcessHeap(), 0, CompBuffer);
2016     HeapFree(GetProcessHeap(), 0, ReadBuffer);
2017
2018     return rc;
2019 }
2020
2021 /***********************************************************************
2022  *              ImmSetCompositionStringW (IMM32.@)
2023  */
2024 BOOL WINAPI ImmSetCompositionStringW(
2025         HIMC hIMC, DWORD dwIndex,
2026         LPCVOID lpComp, DWORD dwCompLen,
2027         LPCVOID lpRead, DWORD dwReadLen)
2028 {
2029      DWORD flags = 0;
2030      WCHAR wParam  = 0;
2031
2032      TRACE("(%p, %d, %p, %d, %p, %d): stub\n",
2033              hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2034
2035
2036      if (hIMC != (HIMC)FROM_IME)
2037          FIXME("PROBLEM: This only sets the wine level string\n");
2038
2039      /*
2040       * Explanation:
2041       *  this sets the composition string in the imm32.dll level
2042       *  of the composition buffer. we cannot manipulate the xim level
2043       *  buffer, which means that once the xim level buffer changes again
2044       *  any call to this function from the application will be lost
2045       */
2046
2047      if (lpRead && dwReadLen)
2048          FIXME("Reading string unimplemented\n");
2049
2050      /*
2051       * app operating this api to also receive the message from xim
2052       */
2053
2054     if (dwIndex == SCS_SETSTR)
2055     {
2056         HIMCC newCompStr;
2057         if (!root_context->bInComposition)
2058         {
2059             ImmInternalPostIMEMessage(root_context, WM_IME_STARTCOMPOSITION, 0, 0);
2060             root_context->bInComposition = TRUE;
2061         }
2062
2063         flags = GCS_COMPSTR;
2064
2065         if (dwCompLen && lpComp)
2066         {
2067             newCompStr = updateCompStr(root_context->IMC.hCompStr, (LPWSTR)lpComp, dwCompLen / sizeof(WCHAR));
2068             ImmDestroyIMCC(root_context->IMC.hCompStr);
2069             root_context->IMC.hCompStr = newCompStr;
2070
2071              wParam = ((const WCHAR*)lpComp)[0];
2072              flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
2073         }
2074         else
2075         {
2076             newCompStr = updateCompStr(root_context->IMC.hCompStr, NULL, 0);
2077             ImmDestroyIMCC(root_context->IMC.hCompStr);
2078             root_context->IMC.hCompStr = newCompStr;
2079         }
2080     }
2081
2082      UpdateDataInDefaultIMEWindow(hwndDefault,FALSE);
2083
2084      ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION, wParam, flags);
2085
2086      return TRUE;
2087 }
2088
2089 /***********************************************************************
2090  *              ImmSetCompositionWindow (IMM32.@)
2091  */
2092 BOOL WINAPI ImmSetCompositionWindow(
2093   HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
2094 {
2095     BOOL reshow = FALSE;
2096     InputContextData *data = (InputContextData*)hIMC;
2097
2098     TRACE("(%p, %p)\n", hIMC, lpCompForm);
2099     TRACE("\t%x, (%i,%i), (%i,%i - %i,%i)\n",lpCompForm->dwStyle,
2100           lpCompForm->ptCurrentPos.x, lpCompForm->ptCurrentPos.y, lpCompForm->rcArea.top,
2101           lpCompForm->rcArea.left, lpCompForm->rcArea.bottom, lpCompForm->rcArea.right);
2102
2103     if (!data)
2104         return FALSE;
2105
2106     data->IMC.cfCompForm = *lpCompForm;
2107
2108     if (IsWindowVisible(hwndDefault))
2109     {
2110         reshow = TRUE;
2111         ShowWindow(hwndDefault,SW_HIDE);
2112     }
2113
2114     /* FIXME: this is a partial stub */
2115
2116     if (reshow)
2117         ShowWindow(hwndDefault,SW_SHOWNOACTIVATE);
2118
2119     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
2120     return TRUE;
2121 }
2122
2123 /***********************************************************************
2124  *              ImmSetConversionStatus (IMM32.@)
2125  */
2126 BOOL WINAPI ImmSetConversionStatus(
2127   HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
2128 {
2129   static int shown = 0;
2130
2131   if (!shown) {
2132       FIXME("(%p, %d, %d): stub\n",
2133           hIMC, fdwConversion, fdwSentence
2134       );
2135       shown = 1;
2136   }
2137   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2138   return FALSE;
2139 }
2140
2141 /***********************************************************************
2142  *              ImmSetOpenStatus (IMM32.@)
2143  */
2144 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
2145 {
2146     InputContextData *data = (InputContextData*)hIMC;
2147
2148     TRACE("%p %d\n", hIMC, fOpen);
2149
2150     if (hIMC == (HIMC)FROM_IME)
2151     {
2152         ImmInternalSetOpenStatus(fOpen);
2153         ImmInternalSendIMENotify(root_context, IMN_SETOPENSTATUS, 0);
2154         return TRUE;
2155     }
2156
2157     if (!data)
2158         return FALSE;
2159
2160     if (fOpen != data->bInternalState)
2161     {
2162         if (fOpen == FALSE && pX11DRV_ForceXIMReset)
2163             pX11DRV_ForceXIMReset(data->IMC.hWnd);
2164
2165         if (fOpen == FALSE)
2166             ImmInternalPostIMEMessage(data, WM_IME_ENDCOMPOSITION,0,0);
2167         else
2168             ImmInternalPostIMEMessage(data, WM_IME_STARTCOMPOSITION,0,0);
2169
2170         ImmInternalSetOpenStatus(fOpen);
2171         ImmInternalSetOpenStatus(!fOpen);
2172
2173         if (data->IMC.fOpen == FALSE)
2174             ImmInternalPostIMEMessage(data, WM_IME_ENDCOMPOSITION,0,0);
2175         else
2176             ImmInternalPostIMEMessage(data, WM_IME_STARTCOMPOSITION,0,0);
2177
2178         return FALSE;
2179     }
2180     return TRUE;
2181 }
2182
2183 /***********************************************************************
2184  *              ImmSetStatusWindowPos (IMM32.@)
2185  */
2186 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2187 {
2188   FIXME("(%p, %p): stub\n", hIMC, lpptPos);
2189   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2190   return FALSE;
2191 }
2192
2193 /***********************************************************************
2194  *              ImmSimulateHotKey (IMM32.@)
2195  */
2196 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
2197 {
2198   FIXME("(%p, %d): stub\n", hWnd, dwHotKeyID);
2199   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2200   return FALSE;
2201 }
2202
2203 /***********************************************************************
2204  *              ImmUnregisterWordA (IMM32.@)
2205  */
2206 BOOL WINAPI ImmUnregisterWordA(
2207   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
2208 {
2209   FIXME("(%p, %s, %d, %s): stub\n",
2210     hKL, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszUnregister)
2211   );
2212   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2213   return FALSE;
2214 }
2215
2216 /***********************************************************************
2217  *              ImmUnregisterWordW (IMM32.@)
2218  */
2219 BOOL WINAPI ImmUnregisterWordW(
2220   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
2221 {
2222   FIXME("(%p, %s, %d, %s): stub\n",
2223     hKL, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszUnregister)
2224   );
2225   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2226   return FALSE;
2227 }
2228
2229 /***********************************************************************
2230  *              ImmGetImeMenuItemsA (IMM32.@)
2231  */
2232 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2233    LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
2234     DWORD dwSize)
2235 {
2236   FIXME("(%p, %i, %i, %p, %p, %i): stub\n", hIMC, dwFlags, dwType,
2237     lpImeParentMenu, lpImeMenu, dwSize);
2238   return 0;
2239 }
2240
2241 /***********************************************************************
2242 *               ImmGetImeMenuItemsW (IMM32.@)
2243 */
2244 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2245    LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
2246    DWORD dwSize)
2247 {
2248   FIXME("(%p, %i, %i, %p, %p, %i): stub\n", hIMC, dwFlags, dwType,
2249     lpImeParentMenu, lpImeMenu, dwSize);
2250   return 0;
2251 }
2252
2253 /***********************************************************************
2254 *               ImmLockIMC(IMM32.@)
2255 */
2256 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
2257 {
2258     InputContextData *data = (InputContextData*)hIMC;
2259
2260     if (!data)
2261         return NULL;
2262     data->dwLock++;
2263     return &data->IMC;
2264 }
2265
2266 /***********************************************************************
2267 *               ImmUnlockIMC(IMM32.@)
2268 */
2269 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
2270 {
2271     InputContextData *data = (InputContextData*)hIMC;
2272     data->dwLock--;
2273     return (data->dwLock!=0);
2274 }
2275
2276 /***********************************************************************
2277 *               ImmGetIMCLockCount(IMM32.@)
2278 */
2279 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
2280 {
2281     InputContextData *data = (InputContextData*)hIMC;
2282     return data->dwLock;
2283 }
2284
2285 /***********************************************************************
2286 *               ImmCreateIMCC(IMM32.@)
2287 */
2288 HIMCC  WINAPI ImmCreateIMCC(DWORD size)
2289 {
2290     IMCCInternal *internal;
2291     int real_size = size + sizeof(IMCCInternal);
2292
2293     internal = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, real_size);
2294     if (internal == NULL)
2295         return NULL;
2296
2297     internal->dwSize = size;
2298     return  (HIMCC)internal;
2299 }
2300
2301 /***********************************************************************
2302 *       ImmDestroyIMCC(IMM32.@)
2303 */
2304 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
2305 {
2306     HeapFree(GetProcessHeap(),0,block);
2307     return NULL;
2308 }
2309
2310 /***********************************************************************
2311 *               ImmLockIMCC(IMM32.@)
2312 */
2313 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
2314 {
2315     IMCCInternal *internal;
2316     internal = (IMCCInternal*) imcc;
2317
2318     internal->dwLock ++;
2319     return internal + 1;
2320 }
2321
2322 /***********************************************************************
2323 *               ImmUnlockIMCC(IMM32.@)
2324 */
2325 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
2326 {
2327     IMCCInternal *internal;
2328     internal = (IMCCInternal*) imcc;
2329
2330     internal->dwLock --;
2331     return (internal->dwLock!=0);
2332 }
2333
2334 /***********************************************************************
2335 *               ImmGetIMCCLockCount(IMM32.@)
2336 */
2337 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
2338 {
2339     IMCCInternal *internal;
2340     internal = (IMCCInternal*) imcc;
2341
2342     return internal->dwLock;
2343 }
2344
2345 /***********************************************************************
2346 *               ImmReSizeIMCC(IMM32.@)
2347 */
2348 HIMCC  WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
2349 {
2350     IMCCInternal *internal,*newone;
2351     int real_size = size + sizeof(IMCCInternal);
2352
2353     internal = (IMCCInternal*) imcc;
2354
2355     newone = HeapReAlloc(GetProcessHeap(), 0, internal, real_size);
2356     newone->dwSize = size;
2357
2358     return newone;
2359 }
2360
2361 /***********************************************************************
2362 *               ImmGetIMCCSize(IMM32.@)
2363 */
2364 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
2365 {
2366     IMCCInternal *internal;
2367     internal = (IMCCInternal*) imcc;
2368
2369     return internal->dwSize;
2370 }
2371
2372 /***********************************************************************
2373 *               ImmGenerateMessage(IMM32.@)
2374 */
2375 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
2376 {
2377     InputContextData *data = (InputContextData*)hIMC;
2378
2379     TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
2380     if (data->IMC.dwNumMsgBuf > 0)
2381     {
2382         LPTRANSMSG lpTransMsg;
2383         INT i;
2384
2385         lpTransMsg = (LPTRANSMSG)ImmLockIMCC(data->IMC.hMsgBuf);
2386         for (i = 0; i < data->IMC.dwNumMsgBuf; i++)
2387             ImmInternalPostIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
2388
2389         ImmUnlockIMCC(data->IMC.hMsgBuf);
2390
2391         data->IMC.dwNumMsgBuf = 0;
2392     }
2393
2394     return TRUE;
2395 }
2396
2397 /*****
2398  * Internal functions to help with IME window management
2399  */
2400 static void PaintDefaultIMEWnd(HWND hwnd)
2401 {
2402     PAINTSTRUCT ps;
2403     RECT rect;
2404     HDC hdc = BeginPaint(hwnd,&ps);
2405     LPCOMPOSITIONSTRING compstr;
2406     LPBYTE compdata = NULL;
2407     HMONITOR monitor;
2408     MONITORINFO mon_info;
2409     INT offX=0, offY=0;
2410
2411     GetClientRect(hwnd,&rect);
2412     FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
2413
2414     compdata = ImmLockIMCC(root_context->IMC.hCompStr);
2415     compstr = (LPCOMPOSITIONSTRING)compdata;
2416
2417     if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
2418     {
2419         SIZE size;
2420         POINT pt;
2421         HFONT oldfont = NULL;
2422         LPWSTR CompString;
2423
2424         CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
2425         if (root_context->textfont)
2426             oldfont = SelectObject(hdc,root_context->textfont);
2427
2428
2429         GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
2430         pt.x = size.cx;
2431         pt.y = size.cy;
2432         LPtoDP(hdc,&pt,1);
2433
2434         /*
2435          * How this works based on tests on windows:
2436          * CFS_POINT: then we start our window at the point and grow it as large
2437          *    as it needs to be for the string.
2438          * CFS_RECT:  we still use the ptCurrentPos as a starting point and our
2439          *    window is only as large as we need for the string, but we do not
2440          *    grow such that our window exceeds the given rect.  Wrapping if
2441          *    needed and possible.   If our ptCurrentPos is outside of our rect
2442          *    then no window is displayed.
2443          * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
2444          *    maybe becase the default MSIME does not do any IME adjusting.
2445          */
2446         if (root_context->IMC.cfCompForm.dwStyle != CFS_DEFAULT)
2447         {
2448             POINT cpt = root_context->IMC.cfCompForm.ptCurrentPos;
2449             ClientToScreen(root_context->IMC.hWnd,&cpt);
2450             rect.left = cpt.x;
2451             rect.top = cpt.y;
2452             rect.right = rect.left + pt.x;
2453             rect.bottom = rect.top + pt.y;
2454             monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY);
2455         }
2456         else /* CFS_DEFAULT */
2457         {
2458             /* Windows places the default IME window in the bottom left */
2459             HWND target = root_context->IMC.hWnd;
2460             if (!target) target = GetFocus();
2461
2462             GetWindowRect(target,&rect);
2463             rect.top = rect.bottom;
2464             rect.right = rect.left + pt.x + 20;
2465             rect.bottom = rect.top + pt.y + 20;
2466             offX=offY=10;
2467             monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY);
2468         }
2469
2470         if (root_context->IMC.cfCompForm.dwStyle == CFS_RECT)
2471         {
2472             RECT client;
2473             client =root_context->IMC.cfCompForm.rcArea;
2474             MapWindowPoints( root_context->IMC.hWnd, 0, (POINT *)&client, 2 );
2475             IntersectRect(&rect,&rect,&client);
2476             /* TODO:  Wrap the input if needed */
2477         }
2478
2479         if (root_context->IMC.cfCompForm.dwStyle == CFS_DEFAULT)
2480         {
2481             /* make sure we are on the desktop */
2482             mon_info.cbSize = sizeof(mon_info);
2483             GetMonitorInfoW(monitor, &mon_info);
2484
2485             if (rect.bottom > mon_info.rcWork.bottom)
2486             {
2487                 int shift = rect.bottom - mon_info.rcWork.bottom;
2488                 rect.top -= shift;
2489                 rect.bottom -= shift;
2490             }
2491             if (rect.left < 0)
2492             {
2493                 rect.right -= rect.left;
2494                 rect.left = 0;
2495             }
2496             if (rect.right > mon_info.rcWork.right)
2497             {
2498                 int shift = rect.right - mon_info.rcWork.right;
2499                 rect.left -= shift;
2500                 rect.right -= shift;
2501             }
2502         }
2503
2504         SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);
2505
2506         TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen);
2507
2508         if (oldfont)
2509             SelectObject(hdc,oldfont);
2510     }
2511
2512     ImmUnlockIMCC(root_context->IMC.hCompStr);
2513
2514     EndPaint(hwnd,&ps);
2515 }
2516
2517 static void UpdateDataInDefaultIMEWindow(HWND hwnd, BOOL showable)
2518 {
2519     LPCOMPOSITIONSTRING compstr;
2520
2521     if (root_context->IMC.hCompStr)
2522         compstr = ImmLockIMCC(root_context->IMC.hCompStr);
2523     else
2524         compstr = NULL;
2525
2526     if (compstr == NULL || compstr->dwCompStrLen == 0)
2527         ShowWindow(hwndDefault,SW_HIDE);
2528     else if (showable)
2529         ShowWindow(hwndDefault,SW_SHOWNOACTIVATE);
2530
2531     RedrawWindow(hwnd,NULL,NULL,RDW_ERASENOW|RDW_INVALIDATE);
2532
2533     if (compstr != NULL)
2534         ImmUnlockIMCC(root_context->IMC.hCompStr);
2535 }
2536
2537 /*
2538  * The window proc for the default IME window
2539  */
2540 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
2541                                           LPARAM lParam)
2542 {
2543     LRESULT rc = 0;
2544
2545     TRACE("Incoming Message 0x%x  (0x%08x, 0x%08x)\n", msg, (UINT)wParam,
2546            (UINT)lParam);
2547
2548     switch(msg)
2549     {
2550         case WM_PAINT:
2551             PaintDefaultIMEWnd(hwnd);
2552             return FALSE;
2553
2554         case WM_NCCREATE:
2555             return TRUE;
2556
2557         case WM_CREATE:
2558             SetWindowTextA(hwnd,"Wine Ime Active");
2559             return TRUE;
2560
2561         case WM_SETFOCUS:
2562             if (wParam)
2563                 SetFocus((HWND)wParam);
2564             else
2565                 FIXME("Received focus, should never have focus\n");
2566             break;
2567         case WM_IME_COMPOSITION:
2568             TRACE("IME message %s, 0x%x, 0x%x (%i)\n",
2569                     "WM_IME_COMPOSITION", (UINT)wParam, (UINT)lParam,
2570                      root_context->bRead);
2571             if (lParam & GCS_RESULTSTR)
2572                     IMM_PostResult(root_context);
2573             else
2574                  UpdateDataInDefaultIMEWindow(hwnd,TRUE);
2575             break;
2576         case WM_IME_STARTCOMPOSITION:
2577             TRACE("IME message %s, 0x%x, 0x%x\n",
2578                     "WM_IME_STARTCOMPOSITION", (UINT)wParam, (UINT)lParam);
2579             root_context->IMC.hWnd = GetFocus();
2580             ShowWindow(hwndDefault,SW_SHOWNOACTIVATE);
2581             break;
2582         case WM_IME_ENDCOMPOSITION:
2583             TRACE("IME message %s, 0x%x, 0x%x\n",
2584                     "WM_IME_ENDCOMPOSITION", (UINT)wParam, (UINT)lParam);
2585             ShowWindow(hwndDefault,SW_HIDE);
2586             break;
2587         case WM_IME_SELECT:
2588             TRACE("IME message %s, 0x%x, 0x%x\n","WM_IME_SELECT",
2589                 (UINT)wParam, (UINT)lParam);
2590             break;
2591         case WM_IME_CONTROL:
2592             TRACE("IME message %s, 0x%x, 0x%x\n","WM_IME_CONTROL",
2593                 (UINT)wParam, (UINT)lParam);
2594             rc = 1;
2595             break;
2596         case WM_IME_NOTIFY:
2597             TRACE("!! IME NOTIFY\n");
2598             break;
2599        default:
2600             TRACE("Non-standard message 0x%x\n",msg);
2601     }
2602     /* check the MSIME messages */
2603     if (msg == WM_MSIME_SERVICE)
2604     {
2605             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_SERVICE",
2606                 (UINT)wParam, (UINT)lParam);
2607             rc = FALSE;
2608     }
2609     else if (msg == WM_MSIME_RECONVERTOPTIONS)
2610     {
2611             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERTOPTIONS",
2612                 (UINT)wParam, (UINT)lParam);
2613     }
2614     else if (msg == WM_MSIME_MOUSE)
2615     {
2616             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_MOUSE",
2617                 (UINT)wParam, (UINT)lParam);
2618     }
2619     else if (msg == WM_MSIME_RECONVERTREQUEST)
2620     {
2621             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERTREQUEST",
2622                 (UINT)wParam, (UINT)lParam);
2623     }
2624     else if (msg == WM_MSIME_RECONVERT)
2625     {
2626             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERT",
2627                 (UINT)wParam, (UINT)lParam);
2628     }
2629     else if (msg == WM_MSIME_QUERYPOSITION)
2630     {
2631             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_QUERYPOSITION",
2632                 (UINT)wParam, (UINT)lParam);
2633     }
2634     else if (msg == WM_MSIME_DOCUMENTFEED)
2635     {
2636             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_DOCUMENTFEED",
2637                 (UINT)wParam, (UINT)lParam);
2638     }
2639     /* DefWndProc if not an IME message */
2640     else if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2641                       (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
2642         rc = DefWindowProcW(hwnd,msg,wParam,lParam);
2643
2644     return rc;
2645 }