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