wined3d: Add ARB_clip_control extension.
[wine.git] / dlls / winemac.drv / ime.c
blob7681e8e9c870bf152ff4e4e1daff41b9d6477c4e
1 /*
2 * The IME for interfacing with Mac input methods
4 * Copyright 2008, 2013 CodeWeavers, Aric Stewart
5 * Copyright 2013 Ken Thomases for CodeWeavers Inc.
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.
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.
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
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.
37 #include "config.h"
39 #include <stdarg.h>
41 #include "macdrv.h"
42 #include "winuser.h"
43 #include "imm.h"
44 #include "ddk/imm.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(imm);
48 #define FROM_MACDRV ((HIMC)0xcafe1337)
50 typedef struct _IMEPRIVATE {
51 BOOL bInComposition;
52 BOOL bInternalState;
53 HFONT textfont;
54 HWND hwndDefault;
56 UINT repeat;
57 } IMEPRIVATE, *LPIMEPRIVATE;
59 typedef struct _tagTRANSMSG {
60 UINT message;
61 WPARAM wParam;
62 LPARAM lParam;
63 } TRANSMSG, *LPTRANSMSG;
65 static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e',' ','M','a','c',' ','I','M','E',0};
67 static HIMC *hSelectedFrom = NULL;
68 static INT hSelectedCount = 0;
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;
80 static HIMC RealIMC(HIMC hIMC)
82 if (hIMC == FROM_MACDRV)
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;
92 else
93 return hIMC;
96 static LPINPUTCONTEXT LockRealIMC(HIMC hIMC)
98 HIMC real_imc = RealIMC(hIMC);
99 if (real_imc)
100 return ImmLockIMC(real_imc);
101 else
102 return NULL;
105 static BOOL UnlockRealIMC(HIMC hIMC)
107 HIMC real_imc = RealIMC(hIMC);
108 if (real_imc)
109 return ImmUnlockIMC(real_imc);
110 else
111 return FALSE;
114 static HIMCC ImeCreateBlankCompStr(void)
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;
126 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
127 LPBYTE target, LPBYTE source, DWORD* lenParam,
128 DWORD* offsetParam, BOOL wchars)
130 if (origLen > 0 && origOffset > 0)
132 int truelen = origLen;
133 if (wchars)
134 truelen *= sizeof(WCHAR);
136 memcpy(&target[currentOffset], &source[origOffset], truelen);
138 *lenParam = origLen;
139 *offsetParam = currentOffset;
140 currentOffset += truelen;
142 return currentOffset;
145 static HIMCC updateCompStr(HIMCC old, LPCWSTR compstr, DWORD len, DWORD *flags)
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;
157 TRACE("%s, %i\n", debugstr_wn(compstr, len), len);
159 if (old == NULL && compstr == NULL && len == 0)
160 return NULL;
162 if (compstr == NULL && len != 0)
164 ERR("compstr is NULL however we have a len! Please report\n");
165 len = 0;
168 if (old != NULL)
170 olddata = ImmLockIMCC(old);
171 lpcs = (LPCOMPOSITIONSTRING)olddata;
174 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
175 len + sizeof(DWORD) * 2;
177 if (lpcs != NULL)
179 needed_size += lpcs->dwCompReadAttrLen;
180 needed_size += lpcs->dwCompReadClauseLen;
181 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
182 needed_size += lpcs->dwResultReadClauseLen;
183 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
184 needed_size += lpcs->dwResultClauseLen;
185 needed_size += lpcs->dwResultStrLen * sizeof(WCHAR);
186 needed_size += lpcs->dwPrivateSize;
188 rc = ImmCreateIMCC(needed_size);
189 newdata = ImmLockIMCC(rc);
190 new_one = (LPCOMPOSITIONSTRING)newdata;
192 new_one->dwSize = needed_size;
193 current_offset = sizeof(COMPOSITIONSTRING);
194 if (lpcs != NULL)
196 current_offset = updateField(lpcs->dwCompReadAttrLen,
197 lpcs->dwCompReadAttrOffset,
198 current_offset, newdata, olddata,
199 &new_one->dwCompReadAttrLen,
200 &new_one->dwCompReadAttrOffset, FALSE);
202 current_offset = updateField(lpcs->dwCompReadClauseLen,
203 lpcs->dwCompReadClauseOffset,
204 current_offset, newdata, olddata,
205 &new_one->dwCompReadClauseLen,
206 &new_one->dwCompReadClauseOffset, FALSE);
208 current_offset = updateField(lpcs->dwCompReadStrLen,
209 lpcs->dwCompReadStrOffset,
210 current_offset, newdata, olddata,
211 &new_one->dwCompReadStrLen,
212 &new_one->dwCompReadStrOffset, TRUE);
214 /* new CompAttr, CompClause, CompStr, dwCursorPos */
215 new_one->dwDeltaStart = 0;
216 new_one->dwCursorPos = lpcs->dwCursorPos;
218 current_offset = updateField(lpcs->dwResultReadClauseLen,
219 lpcs->dwResultReadClauseOffset,
220 current_offset, newdata, olddata,
221 &new_one->dwResultReadClauseLen,
222 &new_one->dwResultReadClauseOffset, FALSE);
224 current_offset = updateField(lpcs->dwResultReadStrLen,
225 lpcs->dwResultReadStrOffset,
226 current_offset, newdata, olddata,
227 &new_one->dwResultReadStrLen,
228 &new_one->dwResultReadStrOffset, TRUE);
230 current_offset = updateField(lpcs->dwResultClauseLen,
231 lpcs->dwResultClauseOffset,
232 current_offset, newdata, olddata,
233 &new_one->dwResultClauseLen,
234 &new_one->dwResultClauseOffset, FALSE);
236 current_offset = updateField(lpcs->dwResultStrLen,
237 lpcs->dwResultStrOffset,
238 current_offset, newdata, olddata,
239 &new_one->dwResultStrLen,
240 &new_one->dwResultStrOffset, TRUE);
242 current_offset = updateField(lpcs->dwPrivateSize,
243 lpcs->dwPrivateOffset,
244 current_offset, newdata, olddata,
245 &new_one->dwPrivateSize,
246 &new_one->dwPrivateOffset, FALSE);
248 else
250 new_one->dwCursorPos = len;
251 *flags |= GCS_CURSORPOS;
254 /* set new data */
255 /* CompAttr */
256 new_one->dwCompAttrLen = len;
257 if (len > 0)
259 new_one->dwCompAttrOffset = current_offset;
260 memset(&newdata[current_offset], ATTR_INPUT, len);
261 current_offset += len;
264 /* CompClause */
265 if (len > 0)
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);
274 else
275 new_one->dwCompClauseLen = 0;
277 /* CompStr */
278 new_one->dwCompStrLen = len;
279 if (len > 0)
281 new_one->dwCompStrOffset = current_offset;
282 memcpy(&newdata[current_offset], compstr, len * sizeof(WCHAR));
286 ImmUnlockIMCC(rc);
287 if (lpcs)
288 ImmUnlockIMCC(old);
290 return rc;
293 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
295 /* we need to make sure the ResultStr and ResultClause fields are all
296 * set and correct */
297 int needed_size;
298 HIMCC rc;
299 LPBYTE newdata = NULL;
300 LPBYTE olddata = NULL;
301 LPCOMPOSITIONSTRING new_one;
302 LPCOMPOSITIONSTRING lpcs = NULL;
303 INT current_offset = 0;
305 TRACE("%s, %i\n", debugstr_wn(resultstr, len), len);
307 if (old == NULL && resultstr == NULL && len == 0)
308 return NULL;
310 if (resultstr == NULL && len != 0)
312 ERR("resultstr is NULL however we have a len! Please report\n");
313 len = 0;
316 if (old != NULL)
318 olddata = ImmLockIMCC(old);
319 lpcs = (LPCOMPOSITIONSTRING)olddata;
322 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
323 sizeof(DWORD) * 2;
325 if (lpcs != NULL)
327 needed_size += lpcs->dwCompReadAttrLen;
328 needed_size += lpcs->dwCompReadClauseLen;
329 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
330 needed_size += lpcs->dwCompAttrLen;
331 needed_size += lpcs->dwCompClauseLen;
332 needed_size += lpcs->dwCompStrLen * sizeof(WCHAR);
333 needed_size += lpcs->dwResultReadClauseLen;
334 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
335 needed_size += lpcs->dwPrivateSize;
337 rc = ImmCreateIMCC(needed_size);
338 newdata = ImmLockIMCC(rc);
339 new_one = (LPCOMPOSITIONSTRING)newdata;
341 new_one->dwSize = needed_size;
342 current_offset = sizeof(COMPOSITIONSTRING);
343 if (lpcs != NULL)
345 current_offset = updateField(lpcs->dwCompReadAttrLen,
346 lpcs->dwCompReadAttrOffset,
347 current_offset, newdata, olddata,
348 &new_one->dwCompReadAttrLen,
349 &new_one->dwCompReadAttrOffset, FALSE);
351 current_offset = updateField(lpcs->dwCompReadClauseLen,
352 lpcs->dwCompReadClauseOffset,
353 current_offset, newdata, olddata,
354 &new_one->dwCompReadClauseLen,
355 &new_one->dwCompReadClauseOffset, FALSE);
357 current_offset = updateField(lpcs->dwCompReadStrLen,
358 lpcs->dwCompReadStrOffset,
359 current_offset, newdata, olddata,
360 &new_one->dwCompReadStrLen,
361 &new_one->dwCompReadStrOffset, TRUE);
363 current_offset = updateField(lpcs->dwCompAttrLen,
364 lpcs->dwCompAttrOffset,
365 current_offset, newdata, olddata,
366 &new_one->dwCompAttrLen,
367 &new_one->dwCompAttrOffset, FALSE);
369 current_offset = updateField(lpcs->dwCompClauseLen,
370 lpcs->dwCompClauseOffset,
371 current_offset, newdata, olddata,
372 &new_one->dwCompClauseLen,
373 &new_one->dwCompClauseOffset, FALSE);
375 current_offset = updateField(lpcs->dwCompStrLen,
376 lpcs->dwCompStrOffset,
377 current_offset, newdata, olddata,
378 &new_one->dwCompStrLen,
379 &new_one->dwCompStrOffset, TRUE);
381 new_one->dwCursorPos = lpcs->dwCursorPos;
382 new_one->dwDeltaStart = 0;
384 current_offset = updateField(lpcs->dwResultReadClauseLen,
385 lpcs->dwResultReadClauseOffset,
386 current_offset, newdata, olddata,
387 &new_one->dwResultReadClauseLen,
388 &new_one->dwResultReadClauseOffset, FALSE);
390 current_offset = updateField(lpcs->dwResultReadStrLen,
391 lpcs->dwResultReadStrOffset,
392 current_offset, newdata, olddata,
393 &new_one->dwResultReadStrLen,
394 &new_one->dwResultReadStrOffset, TRUE);
396 /* new ResultClause , ResultStr */
398 current_offset = updateField(lpcs->dwPrivateSize,
399 lpcs->dwPrivateOffset,
400 current_offset, newdata, olddata,
401 &new_one->dwPrivateSize,
402 &new_one->dwPrivateOffset, FALSE);
405 /* set new data */
406 /* ResultClause */
407 if (len > 0)
409 new_one->dwResultClauseLen = sizeof(DWORD) * 2;
410 new_one->dwResultClauseOffset = current_offset;
411 *(DWORD*)&newdata[current_offset] = 0;
412 current_offset += sizeof(DWORD);
413 *(DWORD*)&newdata[current_offset] = len;
414 current_offset += sizeof(DWORD);
416 else
417 new_one->dwResultClauseLen = 0;
419 /* ResultStr */
420 new_one->dwResultStrLen = len;
421 if (len > 0)
423 new_one->dwResultStrOffset = current_offset;
424 memcpy(&newdata[current_offset], resultstr, len * sizeof(WCHAR));
426 ImmUnlockIMCC(rc);
427 if (lpcs)
428 ImmUnlockIMCC(old);
430 return rc;
433 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAM lParam)
435 LPINPUTCONTEXT lpIMC;
436 LPTRANSMSG lpTransMsg;
438 lpIMC = LockRealIMC(hIMC);
439 if (lpIMC == NULL)
440 return;
442 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG));
443 if (!lpIMC->hMsgBuf)
444 return;
446 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
447 if (!lpTransMsg)
448 return;
450 lpTransMsg += lpIMC->dwNumMsgBuf;
451 lpTransMsg->message = msg;
452 lpTransMsg->wParam = wParam;
453 lpTransMsg->lParam = lParam;
455 ImmUnlockIMCC(lpIMC->hMsgBuf);
456 lpIMC->dwNumMsgBuf++;
458 ImmGenerateMessage(RealIMC(hIMC));
459 UnlockRealIMC(hIMC);
462 static void GenerateIMECHARMessages(HIMC hIMC, LPWSTR String, DWORD length)
464 LPINPUTCONTEXT lpIMC;
465 LPTRANSMSG lpTransMsg;
466 DWORD i;
468 if (length <= 0)
469 return;
471 lpIMC = LockRealIMC(hIMC);
472 if (lpIMC == NULL)
473 return;
475 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + length) * sizeof(TRANSMSG));
476 if (!lpIMC->hMsgBuf)
477 return;
479 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
480 if (!lpTransMsg)
481 return;
483 lpTransMsg += lpIMC->dwNumMsgBuf;
484 for (i = 0; i < length; i++)
486 lpTransMsg->message = WM_IME_CHAR;
487 lpTransMsg->wParam = String[i];
488 lpTransMsg->lParam = 1;
489 lpTransMsg++;
492 ImmUnlockIMCC(lpIMC->hMsgBuf);
493 lpIMC->dwNumMsgBuf += length;
495 ImmGenerateMessage(RealIMC(hIMC));
496 UnlockRealIMC(hIMC);
499 static BOOL GenerateMessageToTransKey(LPDWORD lpTransBuf, UINT *uNumTranMsgs,
500 UINT msg, WPARAM wParam, LPARAM lParam)
502 LPTRANSMSG ptr;
504 if (*uNumTranMsgs + 1 >= (UINT)*lpTransBuf)
505 return FALSE;
507 ptr = (LPTRANSMSG)(lpTransBuf + 1 + *uNumTranMsgs * 3);
508 ptr->message = msg;
509 ptr->wParam = wParam;
510 ptr->lParam = lParam;
511 (*uNumTranMsgs)++;
513 return TRUE;
517 static BOOL IME_RemoveFromSelected(HIMC hIMC)
519 int i;
520 for (i = 0; i < hSelectedCount; i++)
522 if (hSelectedFrom[i] == hIMC)
524 if (i < hSelectedCount - 1)
525 memmove(&hSelectedFrom[i], &hSelectedFrom[i + 1], (hSelectedCount - i - 1) * sizeof(HIMC));
526 hSelectedCount--;
527 return TRUE;
530 return FALSE;
533 static void IME_AddToSelected(HIMC hIMC)
535 hSelectedCount++;
536 if (hSelectedFrom)
537 hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount * sizeof(HIMC));
538 else
539 hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC));
540 hSelectedFrom[hSelectedCount - 1] = hIMC;
543 static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable)
545 LPCOMPOSITIONSTRING compstr;
546 LPINPUTCONTEXT lpIMC;
548 lpIMC = LockRealIMC(hIMC);
549 if (lpIMC == NULL)
550 return;
552 if (lpIMC->hCompStr)
553 compstr = ImmLockIMCC(lpIMC->hCompStr);
554 else
555 compstr = NULL;
557 if (compstr == NULL || compstr->dwCompStrLen == 0)
558 ShowWindow(hwnd, SW_HIDE);
559 else if (showable)
560 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
562 RedrawWindow(hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE);
564 if (compstr != NULL)
565 ImmUnlockIMCC(lpIMC->hCompStr);
567 UnlockRealIMC(hIMC);
570 BOOL WINAPI ImeConfigure(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
572 FIXME("(%p, %p, %d, %p): stub\n", hKL, hWnd, dwMode, lpData);
573 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
574 return FALSE;
577 DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource, LPCANDIDATELIST lpCandList,
578 DWORD dwBufLen, UINT uFlag)
581 FIXME("(%p, %s, %p, %d, %d): stub\n", hIMC, debugstr_w(lpSource), lpCandList,
582 dwBufLen, uFlag);
583 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
584 return 0;
587 BOOL WINAPI ImeDestroy(UINT uForce)
589 TRACE("\n");
590 HeapFree(GetProcessHeap(), 0, hSelectedFrom);
591 hSelectedFrom = NULL;
592 hSelectedCount = 0;
593 return TRUE;
596 LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
598 TRACE("%x %p\n", uSubFunc, lpData);
599 return 0;
602 BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState)
604 LPINPUTCONTEXT lpIMC;
605 BOOL inIME;
607 TRACE("hIMC %p vKey 0x%04x lKeyData 0x%08lx lpbKeyState %p\n", hIMC, vKey, lKeyData, lpbKeyState);
609 switch (vKey)
611 case VK_SHIFT:
612 case VK_CONTROL:
613 case VK_CAPITAL:
614 case VK_MENU:
615 return FALSE;
618 inIME = macdrv_using_input_method();
619 lpIMC = LockRealIMC(hIMC);
620 if (lpIMC)
622 LPIMEPRIVATE myPrivate;
623 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
625 if (inIME && !myPrivate->bInternalState)
626 ImmSetOpenStatus(RealIMC(FROM_MACDRV), TRUE);
627 else if (!inIME && myPrivate->bInternalState)
629 ShowWindow(myPrivate->hwndDefault, SW_HIDE);
630 ImmDestroyIMCC(lpIMC->hCompStr);
631 lpIMC->hCompStr = ImeCreateBlankCompStr();
632 ImmSetOpenStatus(RealIMC(FROM_MACDRV), FALSE);
635 myPrivate->repeat = (lKeyData >> 30) & 0x1;
637 myPrivate->bInternalState = inIME;
638 ImmUnlockIMCC(lpIMC->hPrivate);
640 UnlockRealIMC(hIMC);
642 return inIME;
645 BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
647 LPINPUTCONTEXT lpIMC;
648 TRACE("%p %s\n", hIMC, fSelect ? "TRUE" : "FALSE");
650 if (hIMC == FROM_MACDRV)
652 ERR("ImeSelect should never be called from Cocoa\n");
653 return FALSE;
656 if (!hIMC)
657 return TRUE;
659 /* not selected */
660 if (!fSelect)
661 return IME_RemoveFromSelected(hIMC);
663 IME_AddToSelected(hIMC);
665 /* Initialize our structures */
666 lpIMC = LockRealIMC(hIMC);
667 if (lpIMC != NULL)
669 LPIMEPRIVATE myPrivate;
670 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
671 myPrivate->bInComposition = FALSE;
672 myPrivate->bInternalState = FALSE;
673 myPrivate->textfont = NULL;
674 myPrivate->hwndDefault = NULL;
675 myPrivate->repeat = 0;
676 ImmUnlockIMCC(lpIMC->hPrivate);
677 UnlockRealIMC(hIMC);
680 return TRUE;
683 BOOL WINAPI ImeSetActiveContext(HIMC hIMC, BOOL fFlag)
685 FIXME("(%p, %x): stub\n", hIMC, fFlag);
686 return TRUE;
689 UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState,
690 LPDWORD lpdwTransKey, UINT fuState, HIMC hIMC)
692 UINT vkey;
693 LPINPUTCONTEXT lpIMC;
694 LPIMEPRIVATE myPrivate;
695 HWND hwndDefault;
696 UINT repeat;
697 int done = 0;
699 TRACE("uVKey 0x%04x uScanCode 0x%04x fuState %u hIMC %p\n", uVKey, uScanCode, fuState, hIMC);
701 vkey = LOWORD(uVKey);
703 if (vkey == VK_KANA || vkey == VK_KANJI || vkey == VK_MENU)
705 TRACE("Skipping metakey\n");
706 return 0;
709 lpIMC = LockRealIMC(hIMC);
710 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
711 if (!myPrivate->bInternalState)
713 ImmUnlockIMCC(lpIMC->hPrivate);
714 UnlockRealIMC(hIMC);
715 return 0;
718 repeat = myPrivate->repeat;
719 hwndDefault = myPrivate->hwndDefault;
720 ImmUnlockIMCC(lpIMC->hPrivate);
721 UnlockRealIMC(hIMC);
723 TRACE("Processing Mac 0x%04x\n", vkey);
724 macdrv_process_text_input(uVKey, uScanCode, repeat, lpbKeyState, hIMC, &done);
726 while (!done)
727 MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_POSTMESSAGE | QS_SENDMESSAGE, 0);
729 if (done < 0)
731 UINT msgs = 0;
732 UINT msg = (uScanCode & 0x8000) ? WM_KEYUP : WM_KEYDOWN;
734 /* KeyStroke not processed by the IME
735 * so we need to rebuild the KeyDown message and pass it on to WINE
737 if (!GenerateMessageToTransKey(lpdwTransKey, &msgs, msg, vkey, MAKELONG(0x0001, uScanCode)))
738 GenerateIMEMessage(hIMC, msg, vkey, MAKELONG(0x0001, uScanCode));
740 return msgs;
742 else
743 UpdateDataInDefaultIMEWindow(hIMC, hwndDefault, FALSE);
744 return 0;
747 BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
749 BOOL bRet = FALSE;
750 LPINPUTCONTEXT lpIMC;
752 TRACE("%p %i %i %i\n", hIMC, dwAction, dwIndex, dwValue);
754 lpIMC = LockRealIMC(hIMC);
755 if (lpIMC == NULL)
756 return FALSE;
758 switch (dwAction)
760 case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break;
761 case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break;
762 case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break;
763 case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break;
764 case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
765 case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
766 case NI_CONTEXTUPDATED:
767 switch (dwValue)
769 case IMC_SETCOMPOSITIONWINDOW: FIXME("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONWINDOW\n"); break;
770 case IMC_SETCONVERSIONMODE: FIXME("NI_CONTEXTUPDATED: IMC_SETCONVERSIONMODE\n"); break;
771 case IMC_SETSENTENCEMODE: FIXME("NI_CONTEXTUPDATED: IMC_SETSENTENCEMODE\n"); break;
772 case IMC_SETCANDIDATEPOS: FIXME("NI_CONTEXTUPDATED: IMC_SETCANDIDATEPOS\n"); break;
773 case IMC_SETCOMPOSITIONFONT:
775 LPIMEPRIVATE myPrivate;
776 TRACE("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONFONT\n");
778 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
779 if (myPrivate->textfont)
781 DeleteObject(myPrivate->textfont);
782 myPrivate->textfont = NULL;
784 myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W);
785 ImmUnlockIMCC(lpIMC->hPrivate);
787 break;
788 case IMC_SETOPENSTATUS:
790 LPIMEPRIVATE myPrivate;
791 TRACE("NI_CONTEXTUPDATED: IMC_SETOPENSTATUS\n");
793 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
794 if (lpIMC->fOpen != myPrivate->bInternalState && myPrivate->bInComposition)
796 if(lpIMC->fOpen == FALSE)
798 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
799 myPrivate->bInComposition = FALSE;
801 else
803 GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
804 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, 0);
807 myPrivate->bInternalState = lpIMC->fOpen;
808 bRet = TRUE;
810 break;
811 default: FIXME("NI_CONTEXTUPDATED: Unknown\n"); break;
813 break;
814 case NI_COMPOSITIONSTR:
815 switch (dwIndex)
817 case CPS_COMPLETE:
819 HIMCC newCompStr;
820 DWORD cplen = 0;
821 LPWSTR cpstr;
822 LPCOMPOSITIONSTRING cs = NULL;
823 LPBYTE cdata = NULL;
824 LPIMEPRIVATE myPrivate;
826 TRACE("NI_COMPOSITIONSTR: CPS_COMPLETE\n");
828 /* clear existing result */
829 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
831 ImmDestroyIMCC(lpIMC->hCompStr);
832 lpIMC->hCompStr = newCompStr;
834 if (lpIMC->hCompStr)
836 cdata = ImmLockIMCC(lpIMC->hCompStr);
837 cs = (LPCOMPOSITIONSTRING)cdata;
838 cplen = cs->dwCompStrLen;
839 cpstr = (LPWSTR)&cdata[cs->dwCompStrOffset];
840 ImmUnlockIMCC(lpIMC->hCompStr);
842 if (cplen > 0)
844 WCHAR param = cpstr[0];
845 DWORD flags = GCS_COMPSTR;
847 newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen);
848 ImmDestroyIMCC(lpIMC->hCompStr);
849 lpIMC->hCompStr = newCompStr;
850 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0, &flags);
851 ImmDestroyIMCC(lpIMC->hCompStr);
852 lpIMC->hCompStr = newCompStr;
854 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, flags);
856 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param,
857 GCS_RESULTSTR | GCS_RESULTCLAUSE);
860 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
862 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
863 myPrivate->bInComposition = FALSE;
864 ImmUnlockIMCC(lpIMC->hPrivate);
866 bRet = TRUE;
868 break;
869 case CPS_CONVERT: FIXME("NI_COMPOSITIONSTR: CPS_CONVERT\n"); break;
870 case CPS_REVERT: FIXME("NI_COMPOSITIONSTR: CPS_REVERT\n"); break;
871 case CPS_CANCEL:
873 LPIMEPRIVATE myPrivate;
875 TRACE("NI_COMPOSITIONSTR: CPS_CANCEL\n");
877 if (lpIMC->hCompStr)
878 ImmDestroyIMCC(lpIMC->hCompStr);
880 lpIMC->hCompStr = ImeCreateBlankCompStr();
882 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
883 if (myPrivate->bInComposition)
885 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
886 myPrivate->bInComposition = FALSE;
888 ImmUnlockIMCC(lpIMC->hPrivate);
889 bRet = TRUE;
891 break;
892 default: FIXME("NI_COMPOSITIONSTR: Unknown\n"); break;
894 break;
895 default: FIXME("Unknown Message\n"); break;
898 UnlockRealIMC(hIMC);
899 return bRet;
902 BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
904 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister));
905 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
906 return FALSE;
909 BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
911 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle, debugstr_w(lpszUnregister));
912 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
913 return FALSE;
916 UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf)
918 FIXME("(%d, %p): stub\n", nItem, lpStyleBuf);
919 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
920 return 0;
923 UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc, LPCWSTR lpszReading,
924 DWORD dwStyle, LPCWSTR lpszRegister, LPVOID lpData)
926 FIXME("(%p, %s, %d, %s, %p): stub\n", lpfnEnumProc, debugstr_w(lpszReading), dwStyle,
927 debugstr_w(lpszRegister), lpData);
928 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
929 return 0;
932 static BOOL IME_SetCompositionString(void* hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, DWORD cursor_pos, BOOL cursor_valid)
934 LPINPUTCONTEXT lpIMC;
935 DWORD flags = 0;
936 WCHAR wParam = 0;
937 LPIMEPRIVATE myPrivate;
939 TRACE("(%p, %d, %p, %d):\n", hIMC, dwIndex, lpComp, dwCompLen);
942 * Explanation:
943 * this sets the composition string in the imm32.dll level
944 * of the composition buffer.
945 * TODO: set the Cocoa window's marked text string and tell text input context
948 lpIMC = LockRealIMC(hIMC);
950 if (lpIMC == NULL)
951 return FALSE;
953 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
955 if (dwIndex == SCS_SETSTR)
957 HIMCC newCompStr;
959 if (!myPrivate->bInComposition)
961 GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
962 myPrivate->bInComposition = TRUE;
965 flags = GCS_COMPSTR;
967 if (dwCompLen && lpComp)
969 newCompStr = updateCompStr(lpIMC->hCompStr, (LPCWSTR)lpComp, dwCompLen / sizeof(WCHAR), &flags);
970 ImmDestroyIMCC(lpIMC->hCompStr);
971 lpIMC->hCompStr = newCompStr;
973 wParam = ((const WCHAR*)lpComp)[0];
974 flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
976 else
978 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0, &flags);
979 ImmDestroyIMCC(lpIMC->hCompStr);
980 lpIMC->hCompStr = newCompStr;
983 if (cursor_valid)
985 LPCOMPOSITIONSTRING compstr;
986 compstr = ImmLockIMCC(lpIMC->hCompStr);
987 compstr->dwCursorPos = cursor_pos;
988 ImmUnlockIMCC(lpIMC->hCompStr);
989 flags |= GCS_CURSORPOS;
994 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
995 ImmUnlockIMCC(lpIMC->hPrivate);
996 UnlockRealIMC(hIMC);
998 return TRUE;
1001 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen,
1002 LPCVOID lpRead, DWORD dwReadLen)
1004 TRACE("(%p, %d, %p, %d, %p, %d):\n", hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1006 if (lpRead && dwReadLen)
1007 FIXME("Reading string unimplemented\n");
1009 return IME_SetCompositionString(hIMC, dwIndex, lpComp, dwCompLen, 0, FALSE);
1012 DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPIMEMENUITEMINFOW lpImeParentMenu,
1013 LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize)
1015 FIXME("(%p, %x %x %p %p %x): stub\n", hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
1016 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1017 return 0;
1020 static void IME_NotifyComplete(void* hIMC)
1022 NotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
1025 /*****
1026 * Internal functions to help with IME window management
1028 static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd)
1030 PAINTSTRUCT ps;
1031 RECT rect;
1032 HDC hdc;
1033 LPCOMPOSITIONSTRING compstr;
1034 LPBYTE compdata = NULL;
1035 HMONITOR monitor;
1036 MONITORINFO mon_info;
1037 INT offX = 0, offY = 0;
1038 LPINPUTCONTEXT lpIMC;
1040 lpIMC = LockRealIMC(hIMC);
1041 if (lpIMC == NULL)
1042 return;
1044 hdc = BeginPaint(hwnd, &ps);
1046 GetClientRect(hwnd, &rect);
1047 FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
1049 compdata = ImmLockIMCC(lpIMC->hCompStr);
1050 compstr = (LPCOMPOSITIONSTRING)compdata;
1052 if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
1054 SIZE size;
1055 POINT pt;
1056 HFONT oldfont = NULL;
1057 LPWSTR CompString;
1058 LPIMEPRIVATE myPrivate;
1060 CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1061 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1063 if (myPrivate->textfont)
1064 oldfont = SelectObject(hdc, myPrivate->textfont);
1066 ImmUnlockIMCC(lpIMC->hPrivate);
1068 GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
1069 pt.x = size.cx;
1070 pt.y = size.cy;
1071 LPtoDP(hdc, &pt, 1);
1074 * How this works based on tests on windows:
1075 * CFS_POINT: then we start our window at the point and grow it as large
1076 * as it needs to be for the string.
1077 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
1078 * window is only as large as we need for the string, but we do not
1079 * grow such that our window exceeds the given rect. Wrapping if
1080 * needed and possible. If our ptCurrentPos is outside of our rect
1081 * then no window is displayed.
1082 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
1083 * maybe because the default MSIME does not do any IME adjusting.
1085 if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT)
1087 POINT cpt = lpIMC->cfCompForm.ptCurrentPos;
1088 ClientToScreen(lpIMC->hWnd, &cpt);
1089 rect.left = cpt.x;
1090 rect.top = cpt.y;
1091 rect.right = rect.left + pt.x;
1092 rect.bottom = rect.top + pt.y;
1093 monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY);
1095 else /* CFS_DEFAULT */
1097 /* Windows places the default IME window in the bottom left */
1098 HWND target = lpIMC->hWnd;
1099 if (!target) target = GetFocus();
1101 GetWindowRect(target, &rect);
1102 rect.top = rect.bottom;
1103 rect.right = rect.left + pt.x + 20;
1104 rect.bottom = rect.top + pt.y + 20;
1105 offX=offY=10;
1106 monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY);
1109 if (lpIMC->cfCompForm.dwStyle == CFS_RECT)
1111 RECT client;
1112 client =lpIMC->cfCompForm.rcArea;
1113 MapWindowPoints(lpIMC->hWnd, 0, (POINT *)&client, 2);
1114 IntersectRect(&rect, &rect, &client);
1115 /* TODO: Wrap the input if needed */
1118 if (lpIMC->cfCompForm.dwStyle == CFS_DEFAULT)
1120 /* make sure we are on the desktop */
1121 mon_info.cbSize = sizeof(mon_info);
1122 GetMonitorInfoW(monitor, &mon_info);
1124 if (rect.bottom > mon_info.rcWork.bottom)
1126 int shift = rect.bottom - mon_info.rcWork.bottom;
1127 rect.top -= shift;
1128 rect.bottom -= shift;
1130 if (rect.left < 0)
1132 rect.right -= rect.left;
1133 rect.left = 0;
1135 if (rect.right > mon_info.rcWork.right)
1137 int shift = rect.right - mon_info.rcWork.right;
1138 rect.left -= shift;
1139 rect.right -= shift;
1143 SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left,
1144 rect.bottom - rect.top, SWP_NOACTIVATE);
1146 TextOutW(hdc, offX, offY, CompString, compstr->dwCompStrLen);
1148 if (oldfont)
1149 SelectObject(hdc, oldfont);
1152 ImmUnlockIMCC(lpIMC->hCompStr);
1154 EndPaint(hwnd, &ps);
1155 UnlockRealIMC(hIMC);
1158 static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam)
1160 TRACE("IME message WM_IME_COMPOSITION 0x%lx\n", lParam);
1161 if (lParam & GCS_RESULTSTR)
1163 LPCOMPOSITIONSTRING compstr;
1164 LPBYTE compdata;
1165 LPWSTR ResultStr;
1166 HIMCC newCompStr;
1167 LPINPUTCONTEXT lpIMC;
1169 lpIMC = LockRealIMC(hIMC);
1170 if (lpIMC == NULL)
1171 return;
1173 TRACE("Posting result as IME_CHAR\n");
1174 compdata = ImmLockIMCC(lpIMC->hCompStr);
1175 compstr = (LPCOMPOSITIONSTRING)compdata;
1176 ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1177 GenerateIMECHARMessages(hIMC, ResultStr, compstr->dwResultStrLen);
1178 ImmUnlockIMCC(lpIMC->hCompStr);
1180 /* clear the buffer */
1181 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
1182 ImmDestroyIMCC(lpIMC->hCompStr);
1183 lpIMC->hCompStr = newCompStr;
1184 UnlockRealIMC(hIMC);
1186 else
1187 UpdateDataInDefaultIMEWindow(hIMC, hwnd, TRUE);
1190 static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd)
1192 LPINPUTCONTEXT lpIMC;
1194 lpIMC = LockRealIMC(hIMC);
1195 if (lpIMC == NULL)
1196 return;
1198 TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1199 lpIMC->hWnd = GetFocus();
1200 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
1201 UnlockRealIMC(hIMC);
1204 static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1206 switch (wParam)
1208 case IMN_OPENSTATUSWINDOW:
1209 FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1210 break;
1211 case IMN_CLOSESTATUSWINDOW:
1212 FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1213 break;
1214 case IMN_OPENCANDIDATE:
1215 FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1216 break;
1217 case IMN_CHANGECANDIDATE:
1218 FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1219 break;
1220 case IMN_CLOSECANDIDATE:
1221 FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1222 break;
1223 case IMN_SETCONVERSIONMODE:
1224 FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1225 break;
1226 case IMN_SETSENTENCEMODE:
1227 FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1228 break;
1229 case IMN_SETOPENSTATUS:
1230 FIXME("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1231 break;
1232 case IMN_SETCANDIDATEPOS:
1233 FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1234 break;
1235 case IMN_SETCOMPOSITIONFONT:
1236 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1237 break;
1238 case IMN_SETCOMPOSITIONWINDOW:
1239 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1240 break;
1241 case IMN_GUIDELINE:
1242 FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1243 break;
1244 case IMN_SETSTATUSWINDOWPOS:
1245 FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1246 break;
1247 default:
1248 FIXME("WM_IME_NOTIFY:<Unknown 0x%lx>\n", wParam);
1249 break;
1251 return 0;
1254 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1256 LRESULT rc = 0;
1257 HIMC hIMC;
1259 TRACE("Incoming Message 0x%x (0x%08lx, 0x%08lx)\n", msg, wParam, lParam);
1262 * Each UI window contains the current Input Context.
1263 * This Input Context can be obtained by calling GetWindowLong
1264 * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message.
1265 * The UI window can refer to this Input Context and handles the
1266 * messages.
1269 hIMC = (HIMC)GetWindowLongPtrW(hwnd, IMMGWL_IMC);
1270 if (!hIMC)
1271 hIMC = RealIMC(FROM_MACDRV);
1273 /* if we have no hIMC there are many messages we cannot process */
1274 if (hIMC == NULL)
1276 switch (msg) {
1277 case WM_IME_STARTCOMPOSITION:
1278 case WM_IME_ENDCOMPOSITION:
1279 case WM_IME_COMPOSITION:
1280 case WM_IME_NOTIFY:
1281 case WM_IME_CONTROL:
1282 case WM_IME_COMPOSITIONFULL:
1283 case WM_IME_SELECT:
1284 case WM_IME_CHAR:
1285 return 0L;
1286 default:
1287 break;
1291 switch (msg)
1293 case WM_CREATE:
1295 LPIMEPRIVATE myPrivate;
1296 LPINPUTCONTEXT lpIMC;
1298 SetWindowTextA(hwnd, "Wine Ime Active");
1300 lpIMC = LockRealIMC(hIMC);
1301 if (lpIMC)
1303 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1304 myPrivate->hwndDefault = hwnd;
1305 ImmUnlockIMCC(lpIMC->hPrivate);
1307 UnlockRealIMC(hIMC);
1309 return TRUE;
1311 case WM_PAINT:
1312 PaintDefaultIMEWnd(hIMC, hwnd);
1313 return FALSE;
1315 case WM_NCCREATE:
1316 return TRUE;
1318 case WM_SETFOCUS:
1319 if (wParam)
1320 SetFocus((HWND)wParam);
1321 else
1322 FIXME("Received focus, should never have focus\n");
1323 break;
1324 case WM_IME_COMPOSITION:
1325 DefaultIMEComposition(hIMC, hwnd, lParam);
1326 break;
1327 case WM_IME_STARTCOMPOSITION:
1328 DefaultIMEStartComposition(hIMC, hwnd);
1329 break;
1330 case WM_IME_ENDCOMPOSITION:
1331 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_IME_ENDCOMPOSITION", wParam, lParam);
1332 ShowWindow(hwnd, SW_HIDE);
1333 break;
1334 case WM_IME_SELECT:
1335 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_IME_SELECT", wParam, lParam);
1336 break;
1337 case WM_IME_CONTROL:
1338 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_IME_CONTROL", wParam, lParam);
1339 rc = 1;
1340 break;
1341 case WM_IME_NOTIFY:
1342 rc = ImeHandleNotify(hIMC, hwnd, msg, wParam, lParam);
1343 break;
1344 default:
1345 TRACE("Non-standard message 0x%x\n", msg);
1347 /* check the MSIME messages */
1348 if (msg == WM_MSIME_SERVICE)
1350 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_SERVICE", wParam, lParam);
1351 rc = FALSE;
1353 else if (msg == WM_MSIME_RECONVERTOPTIONS)
1355 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERTOPTIONS", wParam, lParam);
1357 else if (msg == WM_MSIME_MOUSE)
1359 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_MOUSE", wParam, lParam);
1361 else if (msg == WM_MSIME_RECONVERTREQUEST)
1363 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERTREQUEST", wParam, lParam);
1365 else if (msg == WM_MSIME_RECONVERT)
1367 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERT", wParam, lParam);
1369 else if (msg == WM_MSIME_QUERYPOSITION)
1371 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_QUERYPOSITION", wParam, lParam);
1373 else if (msg == WM_MSIME_DOCUMENTFEED)
1375 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_DOCUMENTFEED", wParam, lParam);
1377 /* DefWndProc if not an IME message */
1378 if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1379 (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
1380 rc = DefWindowProcW(hwnd, msg, wParam, lParam);
1382 return rc;
1385 static BOOL WINAPI register_classes( INIT_ONCE *once, void *param, void **context )
1387 WNDCLASSW wndClass;
1388 ZeroMemory(&wndClass, sizeof(WNDCLASSW));
1389 wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
1390 wndClass.lpfnWndProc = (WNDPROC) IME_WindowProc;
1391 wndClass.cbClsExtra = 0;
1392 wndClass.cbWndExtra = 2 * sizeof(LONG_PTR);
1393 wndClass.hInstance = macdrv_module;
1394 wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
1395 wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
1396 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1397 wndClass.lpszMenuName = 0;
1398 wndClass.lpszClassName = UI_CLASS_NAME;
1400 RegisterClassW(&wndClass);
1402 WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
1403 WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
1404 WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
1405 WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
1406 WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
1407 WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
1408 WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
1409 return TRUE;
1412 BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, LPCWSTR lpszOption)
1414 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
1416 TRACE("\n");
1417 InitOnceExecuteOnce( &init_once, register_classes, NULL, NULL );
1418 lpIMEInfo->dwPrivateDataSize = sizeof(IMEPRIVATE);
1419 lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
1420 lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE;
1421 lpIMEInfo->fdwSentenceCaps = IME_SMODE_AUTOMATIC;
1422 lpIMEInfo->fdwUICaps = UI_CAP_2700;
1423 /* Tell App we cannot accept ImeSetCompositionString calls */
1424 /* FIXME: Can we? */
1425 lpIMEInfo->fdwSCSCaps = 0;
1426 lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
1428 lstrcpyW(lpszUIClass, UI_CLASS_NAME);
1430 return TRUE;
1433 /* Interfaces to other parts of the Mac driver */
1435 /***********************************************************************
1436 * macdrv_im_set_text
1438 void macdrv_im_set_text(const macdrv_event *event)
1440 HWND hwnd = macdrv_get_window_hwnd(event->window);
1441 void *himc = event->im_set_text.data;
1443 TRACE("win %p/%p himc %p text %s complete %u\n", hwnd, event->window, himc,
1444 debugstr_cf(event->im_set_text.text), event->im_set_text.complete);
1446 if (!himc) himc = RealIMC(FROM_MACDRV);
1448 if (event->im_set_text.text)
1450 CFIndex length = CFStringGetLength(event->im_set_text.text);
1451 const UniChar *chars = CFStringGetCharactersPtr(event->im_set_text.text);
1452 UniChar *buffer = NULL;
1454 if (!chars)
1456 buffer = HeapAlloc(GetProcessHeap(), 0, length * sizeof(*buffer));
1457 CFStringGetCharacters(event->im_set_text.text, CFRangeMake(0, length), buffer);
1458 chars = buffer;
1461 if (himc)
1462 IME_SetCompositionString(himc, SCS_SETSTR, chars, length * sizeof(*chars),
1463 event->im_set_text.cursor_pos, !event->im_set_text.complete);
1464 else
1466 INPUT input;
1467 CFIndex i;
1469 input.type = INPUT_KEYBOARD;
1470 input.ki.wVk = 0;
1471 input.ki.time = 0;
1472 input.ki.dwExtraInfo = 0;
1474 for (i = 0; i < length; i++)
1476 input.ki.wScan = chars[i];
1477 input.ki.dwFlags = KEYEVENTF_UNICODE;
1478 __wine_send_input(hwnd, &input);
1480 input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
1481 __wine_send_input(hwnd, &input);
1485 HeapFree(GetProcessHeap(), 0, buffer);
1488 if (event->im_set_text.complete)
1489 IME_NotifyComplete(himc);
1492 /***********************************************************************
1493 * macdrv_sent_text_input
1495 void macdrv_sent_text_input(const macdrv_event *event)
1497 TRACE("handled: %s\n", event->sent_text_input.handled ? "TRUE" : "FALSE");
1498 *event->sent_text_input.done = event->sent_text_input.handled ? 1 : -1;
1502 /**************************************************************************
1503 * query_ime_char_rect
1505 BOOL query_ime_char_rect(macdrv_query* query)
1507 HWND hwnd = macdrv_get_window_hwnd(query->window);
1508 void *himc = query->ime_char_rect.data;
1509 CFRange* range = &query->ime_char_rect.range;
1510 CGRect* rect = &query->ime_char_rect.rect;
1511 IMECHARPOSITION charpos;
1512 BOOL ret = FALSE;
1514 TRACE("win %p/%p himc %p range %ld-%ld\n", hwnd, query->window, himc, range->location,
1515 range->length);
1517 if (!himc) himc = RealIMC(FROM_MACDRV);
1519 charpos.dwSize = sizeof(charpos);
1520 charpos.dwCharPos = range->location;
1521 if (ImmRequestMessageW(himc, IMR_QUERYCHARPOSITION, (ULONG_PTR)&charpos))
1523 int i;
1525 *rect = CGRectMake(charpos.pt.x, charpos.pt.y, 0, charpos.cLineHeight);
1527 /* iterate over rest of length to extend rect */
1528 for (i = 1; i < range->length; i++)
1530 charpos.dwSize = sizeof(charpos);
1531 charpos.dwCharPos = range->location + i;
1532 if (!ImmRequestMessageW(himc, IMR_QUERYCHARPOSITION, (ULONG_PTR)&charpos) ||
1533 charpos.pt.y != rect->origin.y)
1535 range->length = i;
1536 break;
1539 rect->size.width = charpos.pt.x - rect->origin.x;
1542 ret = TRUE;
1545 if (!ret)
1547 LPINPUTCONTEXT ic = ImmLockIMC(himc);
1549 if (ic)
1551 LPIMEPRIVATE private = ImmLockIMCC(ic->hPrivate);
1552 LPBYTE compdata = ImmLockIMCC(ic->hCompStr);
1553 LPCOMPOSITIONSTRING compstr = (LPCOMPOSITIONSTRING)compdata;
1554 LPWSTR str = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1556 if (private->hwndDefault && compstr->dwCompStrOffset &&
1557 IsWindowVisible(private->hwndDefault))
1559 HDC dc = GetDC(private->hwndDefault);
1560 HFONT oldfont = NULL;
1561 SIZE size;
1563 if (private->textfont)
1564 oldfont = SelectObject(dc, private->textfont);
1566 if (range->location > compstr->dwCompStrLen)
1567 range->location = compstr->dwCompStrLen;
1568 if (range->location + range->length > compstr->dwCompStrLen)
1569 range->length = compstr->dwCompStrLen - range->location;
1571 GetTextExtentPoint32W(dc, str, range->location, &size);
1572 charpos.rcDocument.left = size.cx;
1573 charpos.rcDocument.top = 0;
1574 GetTextExtentPoint32W(dc, str, range->location + range->length, &size);
1575 charpos.rcDocument.right = size.cx;
1576 charpos.rcDocument.bottom = size.cy;
1578 if (ic->cfCompForm.dwStyle == CFS_DEFAULT)
1579 OffsetRect(&charpos.rcDocument, 10, 10);
1581 LPtoDP(dc, (POINT*)&charpos.rcDocument, 2);
1582 MapWindowPoints(private->hwndDefault, 0, (POINT*)&charpos.rcDocument, 2);
1583 *rect = cgrect_from_rect(charpos.rcDocument);
1584 ret = TRUE;
1586 if (oldfont)
1587 SelectObject(dc, oldfont);
1588 ReleaseDC(private->hwndDefault, dc);
1591 ImmUnlockIMCC(ic->hCompStr);
1592 ImmUnlockIMCC(ic->hPrivate);
1595 ImmUnlockIMC(himc);
1598 if (!ret)
1600 GUITHREADINFO gti;
1601 gti.cbSize = sizeof(gti);
1602 if (GetGUIThreadInfo(0, &gti))
1604 MapWindowPoints(gti.hwndCaret, 0, (POINT*)&gti.rcCaret, 2);
1605 *rect = cgrect_from_rect(gti.rcCaret);
1606 ret = TRUE;
1610 if (ret && range->length && !rect->size.width)
1611 rect->size.width = 1;
1613 TRACE(" -> %s range %ld-%ld rect %s\n", ret ? "TRUE" : "FALSE", range->location,
1614 range->length, wine_dbgstr_cgrect(*rect));
1616 return ret;