wined3d: Pass the pixel shader input signature to shader_arb_generate_vshader.
[wine.git] / dlls / winemac.drv / ime.c
blobe9f13693fce8c51930f15583b7e7ad32c1cf4a05
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(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;
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);
275 /* CompStr */
276 new_one->dwCompStrLen = len;
277 if (len > 0)
279 new_one->dwCompStrOffset = current_offset;
280 memcpy(&newdata[current_offset], compstr, len * sizeof(WCHAR));
284 ImmUnlockIMCC(rc);
285 if (lpcs)
286 ImmUnlockIMCC(old);
288 return rc;
291 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
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;
303 TRACE("%s, %i\n", debugstr_wn(resultstr, len), len);
305 if (old == NULL && resultstr == NULL && len == 0)
306 return NULL;
308 if (resultstr == NULL && len != 0)
310 ERR("resultstr is NULL however we have a len! Please report\n");
311 len = 0;
314 if (old != NULL)
316 olddata = ImmLockIMCC(old);
317 lpcs = (LPCOMPOSITIONSTRING)olddata;
320 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
321 sizeof(DWORD) * 2;
323 if (lpcs != NULL)
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;
335 rc = ImmCreateIMCC(needed_size);
336 newdata = ImmLockIMCC(rc);
337 new_one = (LPCOMPOSITIONSTRING)newdata;
339 new_one->dwSize = needed_size;
340 current_offset = sizeof(COMPOSITIONSTRING);
341 if (lpcs != NULL)
343 current_offset = updateField(lpcs->dwCompReadAttrLen,
344 lpcs->dwCompReadAttrOffset,
345 current_offset, newdata, olddata,
346 &new_one->dwCompReadAttrLen,
347 &new_one->dwCompReadAttrOffset, FALSE);
349 current_offset = updateField(lpcs->dwCompReadClauseLen,
350 lpcs->dwCompReadClauseOffset,
351 current_offset, newdata, olddata,
352 &new_one->dwCompReadClauseLen,
353 &new_one->dwCompReadClauseOffset, FALSE);
355 current_offset = updateField(lpcs->dwCompReadStrLen,
356 lpcs->dwCompReadStrOffset,
357 current_offset, newdata, olddata,
358 &new_one->dwCompReadStrLen,
359 &new_one->dwCompReadStrOffset, TRUE);
361 current_offset = updateField(lpcs->dwCompAttrLen,
362 lpcs->dwCompAttrOffset,
363 current_offset, newdata, olddata,
364 &new_one->dwCompAttrLen,
365 &new_one->dwCompAttrOffset, FALSE);
367 current_offset = updateField(lpcs->dwCompClauseLen,
368 lpcs->dwCompClauseOffset,
369 current_offset, newdata, olddata,
370 &new_one->dwCompClauseLen,
371 &new_one->dwCompClauseOffset, FALSE);
373 current_offset = updateField(lpcs->dwCompStrLen,
374 lpcs->dwCompStrOffset,
375 current_offset, newdata, olddata,
376 &new_one->dwCompStrLen,
377 &new_one->dwCompStrOffset, TRUE);
379 new_one->dwCursorPos = lpcs->dwCursorPos;
380 new_one->dwDeltaStart = 0;
382 current_offset = updateField(lpcs->dwResultReadClauseLen,
383 lpcs->dwResultReadClauseOffset,
384 current_offset, newdata, olddata,
385 &new_one->dwResultReadClauseLen,
386 &new_one->dwResultReadClauseOffset, FALSE);
388 current_offset = updateField(lpcs->dwResultReadStrLen,
389 lpcs->dwResultReadStrOffset,
390 current_offset, newdata, olddata,
391 &new_one->dwResultReadStrLen,
392 &new_one->dwResultReadStrOffset, TRUE);
394 /* new ResultClause , ResultStr */
396 current_offset = updateField(lpcs->dwPrivateSize,
397 lpcs->dwPrivateOffset,
398 current_offset, newdata, olddata,
399 &new_one->dwPrivateSize,
400 &new_one->dwPrivateOffset, FALSE);
403 /* set new data */
404 /* ResultClause */
405 if (len > 0)
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);
415 /* ResultStr */
416 new_one->dwResultStrLen = len;
417 if (len > 0)
419 new_one->dwResultStrOffset = current_offset;
420 memcpy(&newdata[current_offset], resultstr, len * sizeof(WCHAR));
422 ImmUnlockIMCC(rc);
423 if (lpcs)
424 ImmUnlockIMCC(old);
426 return rc;
429 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAM lParam)
431 LPINPUTCONTEXT lpIMC;
432 LPTRANSMSG lpTransMsg;
434 lpIMC = LockRealIMC(hIMC);
435 if (lpIMC == NULL)
436 return;
438 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG));
439 if (!lpIMC->hMsgBuf)
440 return;
442 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
443 if (!lpTransMsg)
444 return;
446 lpTransMsg += lpIMC->dwNumMsgBuf;
447 lpTransMsg->message = msg;
448 lpTransMsg->wParam = wParam;
449 lpTransMsg->lParam = lParam;
451 ImmUnlockIMCC(lpIMC->hMsgBuf);
452 lpIMC->dwNumMsgBuf++;
454 ImmGenerateMessage(RealIMC(hIMC));
455 UnlockRealIMC(hIMC);
458 static void GenerateIMECHARMessages(HIMC hIMC, LPWSTR String, DWORD length)
460 LPINPUTCONTEXT lpIMC;
461 LPTRANSMSG lpTransMsg;
462 DWORD i;
464 if (length <= 0)
465 return;
467 lpIMC = LockRealIMC(hIMC);
468 if (lpIMC == NULL)
469 return;
471 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + length) * sizeof(TRANSMSG));
472 if (!lpIMC->hMsgBuf)
473 return;
475 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
476 if (!lpTransMsg)
477 return;
479 lpTransMsg += lpIMC->dwNumMsgBuf;
480 for (i = 0; i < length; i++)
482 lpTransMsg->message = WM_IME_CHAR;
483 lpTransMsg->wParam = String[i];
484 lpTransMsg->lParam = 1;
485 lpTransMsg++;
488 ImmUnlockIMCC(lpIMC->hMsgBuf);
489 lpIMC->dwNumMsgBuf += length;
491 ImmGenerateMessage(RealIMC(hIMC));
492 UnlockRealIMC(hIMC);
495 static BOOL GenerateMessageToTransKey(LPDWORD lpTransBuf, UINT *uNumTranMsgs,
496 UINT msg, WPARAM wParam, LPARAM lParam)
498 LPTRANSMSG ptr;
500 if (*uNumTranMsgs + 1 >= (UINT)*lpTransBuf)
501 return FALSE;
503 ptr = (LPTRANSMSG)(lpTransBuf + 1 + *uNumTranMsgs * 3);
504 ptr->message = msg;
505 ptr->wParam = wParam;
506 ptr->lParam = lParam;
507 (*uNumTranMsgs)++;
509 return TRUE;
513 static BOOL IME_RemoveFromSelected(HIMC hIMC)
515 int i;
516 for (i = 0; i < hSelectedCount; i++)
518 if (hSelectedFrom[i] == hIMC)
520 if (i < hSelectedCount - 1)
521 memmove(&hSelectedFrom[i], &hSelectedFrom[i + 1], (hSelectedCount - i - 1) * sizeof(HIMC));
522 hSelectedCount--;
523 return TRUE;
526 return FALSE;
529 static void IME_AddToSelected(HIMC hIMC)
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;
539 static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable)
541 LPCOMPOSITIONSTRING compstr;
542 LPINPUTCONTEXT lpIMC;
544 lpIMC = LockRealIMC(hIMC);
545 if (lpIMC == NULL)
546 return;
548 if (lpIMC->hCompStr)
549 compstr = ImmLockIMCC(lpIMC->hCompStr);
550 else
551 compstr = NULL;
553 if (compstr == NULL || compstr->dwCompStrLen == 0)
554 ShowWindow(hwnd, SW_HIDE);
555 else if (showable)
556 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
558 RedrawWindow(hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE);
560 if (compstr != NULL)
561 ImmUnlockIMCC(lpIMC->hCompStr);
563 UnlockRealIMC(hIMC);
566 BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, LPCWSTR lpszOption)
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;
579 lstrcpyW(lpszUIClass, UI_CLASS_NAME);
581 return TRUE;
584 BOOL WINAPI ImeConfigure(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
586 FIXME("(%p, %p, %d, %p): stub\n", hKL, hWnd, dwMode, lpData);
587 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
588 return FALSE;
591 DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource, LPCANDIDATELIST lpCandList,
592 DWORD dwBufLen, UINT uFlag)
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;
601 BOOL WINAPI ImeDestroy(UINT uForce)
603 TRACE("\n");
604 HeapFree(GetProcessHeap(), 0, hSelectedFrom);
605 hSelectedFrom = NULL;
606 hSelectedCount = 0;
607 return TRUE;
610 LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
612 TRACE("%x %p\n", uSubFunc, lpData);
613 return 0;
616 BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, CONST LPBYTE lpbKeyState)
618 LPINPUTCONTEXT lpIMC;
619 BOOL inIME;
621 TRACE("hIMC %p vKey 0x%04x lKeyData 0x%08lx lpbKeyState %p\n", hIMC, vKey, lKeyData, lpbKeyState);
623 switch (vKey)
625 case VK_SHIFT:
626 case VK_CONTROL:
627 case VK_CAPITAL:
628 case VK_MENU:
629 return FALSE;
632 inIME = macdrv_using_input_method();
633 lpIMC = LockRealIMC(hIMC);
634 if (lpIMC)
636 LPIMEPRIVATE myPrivate;
637 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
639 if (inIME && !myPrivate->bInternalState)
640 ImmSetOpenStatus(RealIMC(FROM_MACDRV), TRUE);
641 else if (!inIME && myPrivate->bInternalState)
643 ShowWindow(myPrivate->hwndDefault, SW_HIDE);
644 ImmDestroyIMCC(lpIMC->hCompStr);
645 lpIMC->hCompStr = ImeCreateBlankCompStr();
646 ImmSetOpenStatus(RealIMC(FROM_MACDRV), FALSE);
649 myPrivate->repeat = (lKeyData >> 30) & 0x1;
651 myPrivate->bInternalState = inIME;
652 ImmUnlockIMCC(lpIMC->hPrivate);
654 UnlockRealIMC(hIMC);
656 return inIME;
659 BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
661 LPINPUTCONTEXT lpIMC;
662 TRACE("%p %s\n", hIMC, fSelect ? "TRUE" : "FALSE");
664 if (hIMC == FROM_MACDRV)
666 ERR("ImeSelect should never be called from Cocoa\n");
667 return FALSE;
670 if (!hIMC)
671 return TRUE;
673 /* not selected */
674 if (!fSelect)
675 return IME_RemoveFromSelected(hIMC);
677 IME_AddToSelected(hIMC);
679 /* Initialize our structures */
680 lpIMC = LockRealIMC(hIMC);
681 if (lpIMC != NULL)
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);
694 return TRUE;
697 BOOL WINAPI ImeSetActiveContext(HIMC hIMC, BOOL fFlag)
699 FIXME("(%p, %x): stub\n", hIMC, fFlag);
700 return TRUE;
703 UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, CONST LPBYTE lpbKeyState,
704 LPDWORD lpdwTransKey, UINT fuState, HIMC hIMC)
706 UINT vkey;
707 LPINPUTCONTEXT lpIMC;
708 LPIMEPRIVATE myPrivate;
709 HWND hwndDefault;
710 UINT repeat;
711 INT rc;
713 TRACE("uVKey 0x%04x uScanCode 0x%04x fuState %u hIMC %p\n", uVKey, uScanCode, fuState, hIMC);
715 vkey = LOWORD(uVKey);
717 if (vkey == VK_KANA || vkey == VK_KANJI || vkey == VK_MENU)
719 TRACE("Skipping metakey\n");
720 return 0;
723 lpIMC = LockRealIMC(hIMC);
724 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
725 if (!myPrivate->bInternalState)
727 ImmUnlockIMCC(lpIMC->hPrivate);
728 UnlockRealIMC(hIMC);
729 return 0;
732 repeat = myPrivate->repeat;
733 hwndDefault = myPrivate->hwndDefault;
734 ImmUnlockIMCC(lpIMC->hPrivate);
735 UnlockRealIMC(hIMC);
737 TRACE("Processing Mac 0x%04x\n", vkey);
738 rc = macdrv_process_text_input(uVKey, uScanCode, repeat, lpbKeyState, hIMC);
740 if (!rc)
742 UINT msgs = 0;
743 UINT msg = (uScanCode & 0x8000) ? WM_KEYUP : WM_KEYDOWN;
745 /* KeyStroke not processed by the IME
746 * so we need to rebuild the KeyDown message and pass it on to WINE
748 if (!GenerateMessageToTransKey(lpdwTransKey, &msgs, msg, vkey, MAKELONG(0x0001, uScanCode)))
749 GenerateIMEMessage(hIMC, msg, vkey, MAKELONG(0x0001, uScanCode));
751 return msgs;
753 else
754 UpdateDataInDefaultIMEWindow(hIMC, hwndDefault, FALSE);
755 return 0;
758 BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
760 BOOL bRet = FALSE;
761 LPINPUTCONTEXT lpIMC;
763 TRACE("%p %i %i %i\n", hIMC, dwAction, dwIndex, dwValue);
765 lpIMC = LockRealIMC(hIMC);
766 if (lpIMC == NULL)
767 return FALSE;
769 switch (dwAction)
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)
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:
786 LPIMEPRIVATE myPrivate;
787 TRACE("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONFONT\n");
789 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
790 if (myPrivate->textfont)
792 DeleteObject(myPrivate->textfont);
793 myPrivate->textfont = NULL;
795 myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W);
796 ImmUnlockIMCC(lpIMC->hPrivate);
798 break;
799 case IMC_SETOPENSTATUS:
801 LPIMEPRIVATE myPrivate;
802 TRACE("NI_CONTEXTUPDATED: IMC_SETOPENSTATUS\n");
804 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
805 if (lpIMC->fOpen != myPrivate->bInternalState && myPrivate->bInComposition)
807 if(lpIMC->fOpen == FALSE)
809 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
810 myPrivate->bInComposition = FALSE;
812 else
814 GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
815 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, 0);
818 myPrivate->bInternalState = lpIMC->fOpen;
819 bRet = TRUE;
821 break;
822 default: FIXME("NI_CONTEXTUPDATED: Unknown\n"); break;
824 break;
825 case NI_COMPOSITIONSTR:
826 switch (dwIndex)
828 case CPS_COMPLETE:
830 HIMCC newCompStr;
831 DWORD cplen = 0;
832 LPWSTR cpstr;
833 LPCOMPOSITIONSTRING cs = NULL;
834 LPBYTE cdata = NULL;
835 LPIMEPRIVATE myPrivate;
837 TRACE("NI_COMPOSITIONSTR: CPS_COMPLETE\n");
839 /* clear existing result */
840 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
842 ImmDestroyIMCC(lpIMC->hCompStr);
843 lpIMC->hCompStr = newCompStr;
845 if (lpIMC->hCompStr)
847 cdata = ImmLockIMCC(lpIMC->hCompStr);
848 cs = (LPCOMPOSITIONSTRING)cdata;
849 cplen = cs->dwCompStrLen;
850 cpstr = (LPWSTR)&cdata[cs->dwCompStrOffset];
851 ImmUnlockIMCC(lpIMC->hCompStr);
853 if (cplen > 0)
855 WCHAR param = cpstr[0];
856 DWORD flags = GCS_COMPSTR;
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;
865 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, flags);
867 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param,
868 GCS_RESULTSTR | GCS_RESULTCLAUSE);
871 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
873 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
874 myPrivate->bInComposition = FALSE;
875 ImmUnlockIMCC(lpIMC->hPrivate);
877 bRet = TRUE;
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:
884 LPIMEPRIVATE myPrivate;
886 TRACE("NI_COMPOSITIONSTR: CPS_CANCEL\n");
888 if (lpIMC->hCompStr)
889 ImmDestroyIMCC(lpIMC->hCompStr);
891 lpIMC->hCompStr = ImeCreateBlankCompStr();
893 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
894 if (myPrivate->bInComposition)
896 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
897 myPrivate->bInComposition = FALSE;
899 ImmUnlockIMCC(lpIMC->hPrivate);
900 bRet = TRUE;
902 break;
903 default: FIXME("NI_COMPOSITIONSTR: Unknown\n"); break;
905 break;
906 default: FIXME("Unknown Message\n"); break;
909 UnlockRealIMC(hIMC);
910 return bRet;
913 BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
915 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister));
916 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
917 return FALSE;
920 BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
922 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle, debugstr_w(lpszUnregister));
923 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
924 return FALSE;
927 UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf)
929 FIXME("(%d, %p): stub\n", nItem, lpStyleBuf);
930 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
931 return 0;
934 UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc, LPCWSTR lpszReading,
935 DWORD dwStyle, LPCWSTR lpszRegister, LPVOID lpData)
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;
943 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen,
944 LPCVOID lpRead, DWORD dwReadLen)
946 LPINPUTCONTEXT lpIMC;
947 DWORD flags = 0;
948 WCHAR wParam = 0;
949 LPIMEPRIVATE myPrivate;
951 TRACE("(%p, %d, %p, %d, %p, %d):\n", hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
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
960 if (lpRead && dwReadLen)
961 FIXME("Reading string unimplemented\n");
963 lpIMC = LockRealIMC(hIMC);
965 if (lpIMC == NULL)
966 return FALSE;
968 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
970 if (dwIndex == SCS_SETSTR)
972 HIMCC newCompStr;
974 if (!myPrivate->bInComposition)
976 GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
977 myPrivate->bInComposition = TRUE;
980 flags = GCS_COMPSTR;
982 if (dwCompLen && lpComp)
984 newCompStr = updateCompStr(lpIMC->hCompStr, (LPCWSTR)lpComp, dwCompLen / sizeof(WCHAR), &flags);
985 ImmDestroyIMCC(lpIMC->hCompStr);
986 lpIMC->hCompStr = newCompStr;
988 wParam = ((const WCHAR*)lpComp)[0];
989 flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
991 else
993 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0, &flags);
994 ImmDestroyIMCC(lpIMC->hCompStr);
995 lpIMC->hCompStr = newCompStr;
999 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
1000 ImmUnlockIMCC(lpIMC->hPrivate);
1001 UnlockRealIMC(hIMC);
1003 return TRUE;
1006 DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPIMEMENUITEMINFOW lpImeParentMenu,
1007 LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize)
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;
1014 static void IME_SetCursorPos(void* hIMC, DWORD pos)
1016 LPINPUTCONTEXT lpIMC;
1017 LPCOMPOSITIONSTRING compstr;
1019 if (!hSelectedFrom)
1020 return;
1022 lpIMC = LockRealIMC(hIMC);
1023 if (!lpIMC)
1024 return;
1026 compstr = ImmLockIMCC(lpIMC->hCompStr);
1027 if (!compstr)
1029 UnlockRealIMC(hIMC);
1030 return;
1033 compstr->dwCursorPos = pos;
1034 ImmUnlockIMCC(lpIMC->hCompStr);
1035 UnlockRealIMC(hIMC);
1036 GenerateIMEMessage(FROM_MACDRV, WM_IME_COMPOSITION, pos, GCS_CURSORPOS);
1037 return;
1041 static void IME_SetCompositionString(void* hIMC, LPCVOID lpComp, DWORD dwCompLen)
1043 ImeSetCompositionString(hIMC, SCS_SETSTR, lpComp, dwCompLen, NULL, 0);
1046 static void IME_NotifyComplete(void* hIMC)
1048 NotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
1051 /*****
1052 * Internal functions to help with IME window management
1054 static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd)
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;
1066 lpIMC = LockRealIMC(hIMC);
1067 if (lpIMC == NULL)
1068 return;
1070 hdc = BeginPaint(hwnd, &ps);
1072 GetClientRect(hwnd, &rect);
1073 FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
1075 compdata = ImmLockIMCC(lpIMC->hCompStr);
1076 compstr = (LPCOMPOSITIONSTRING)compdata;
1078 if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
1080 SIZE size;
1081 POINT pt;
1082 HFONT oldfont = NULL;
1083 LPWSTR CompString;
1084 LPIMEPRIVATE myPrivate;
1086 CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1087 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1089 if (myPrivate->textfont)
1090 oldfont = SelectObject(hdc, myPrivate->textfont);
1092 ImmUnlockIMCC(lpIMC->hPrivate);
1094 GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
1095 pt.x = size.cx;
1096 pt.y = size.cy;
1097 LPtoDP(hdc, &pt, 1);
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.
1111 if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT)
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);
1121 else /* CFS_DEFAULT */
1123 /* Windows places the default IME window in the bottom left */
1124 HWND target = lpIMC->hWnd;
1125 if (!target) target = GetFocus();
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);
1135 if (lpIMC->cfCompForm.dwStyle == CFS_RECT)
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 */
1144 if (lpIMC->cfCompForm.dwStyle == CFS_DEFAULT)
1146 /* make sure we are on the desktop */
1147 mon_info.cbSize = sizeof(mon_info);
1148 GetMonitorInfoW(monitor, &mon_info);
1150 if (rect.bottom > mon_info.rcWork.bottom)
1152 int shift = rect.bottom - mon_info.rcWork.bottom;
1153 rect.top -= shift;
1154 rect.bottom -= shift;
1156 if (rect.left < 0)
1158 rect.right -= rect.left;
1159 rect.left = 0;
1161 if (rect.right > mon_info.rcWork.right)
1163 int shift = rect.right - mon_info.rcWork.right;
1164 rect.left -= shift;
1165 rect.right -= shift;
1169 SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left,
1170 rect.bottom - rect.top, SWP_NOACTIVATE);
1172 TextOutW(hdc, offX, offY, CompString, compstr->dwCompStrLen);
1174 if (oldfont)
1175 SelectObject(hdc, oldfont);
1178 ImmUnlockIMCC(lpIMC->hCompStr);
1180 EndPaint(hwnd, &ps);
1181 UnlockRealIMC(hIMC);
1184 static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam)
1186 TRACE("IME message WM_IME_COMPOSITION 0x%lx\n", lParam);
1187 if (lParam & GCS_RESULTSTR)
1189 LPCOMPOSITIONSTRING compstr;
1190 LPBYTE compdata;
1191 LPWSTR ResultStr;
1192 HIMCC newCompStr;
1193 LPINPUTCONTEXT lpIMC;
1195 lpIMC = LockRealIMC(hIMC);
1196 if (lpIMC == NULL)
1197 return;
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);
1206 /* clear the buffer */
1207 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
1208 ImmDestroyIMCC(lpIMC->hCompStr);
1209 lpIMC->hCompStr = newCompStr;
1210 UnlockRealIMC(hIMC);
1212 else
1213 UpdateDataInDefaultIMEWindow(hIMC, hwnd, TRUE);
1216 static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd)
1218 LPINPUTCONTEXT lpIMC;
1220 lpIMC = LockRealIMC(hIMC);
1221 if (lpIMC == NULL)
1222 return;
1224 TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1225 lpIMC->hWnd = GetFocus();
1226 ShowWindow(hwnd, SW_SHOWNOACTIVATE);
1227 UnlockRealIMC(hIMC);
1230 static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1232 switch (wParam)
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;
1277 return 0;
1280 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1282 LRESULT rc = 0;
1283 HIMC hIMC;
1285 TRACE("Incoming Message 0x%x (0x%08lx, 0x%08lx)\n", msg, wParam, lParam);
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.
1295 hIMC = (HIMC)GetWindowLongPtrW(hwnd, IMMGWL_IMC);
1296 if (!hIMC)
1297 hIMC = RealIMC(FROM_MACDRV);
1299 /* if we have no hIMC there are many messages we cannot process */
1300 if (hIMC == NULL)
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;
1317 switch (msg)
1319 case WM_CREATE:
1321 LPIMEPRIVATE myPrivate;
1322 LPINPUTCONTEXT lpIMC;
1324 SetWindowTextA(hwnd, "Wine Ime Active");
1326 lpIMC = LockRealIMC(hIMC);
1327 if (lpIMC)
1329 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1330 myPrivate->hwndDefault = hwnd;
1331 ImmUnlockIMCC(lpIMC->hPrivate);
1333 UnlockRealIMC(hIMC);
1335 return TRUE;
1337 case WM_PAINT:
1338 PaintDefaultIMEWnd(hIMC, hwnd);
1339 return FALSE;
1341 case WM_NCCREATE:
1342 return TRUE;
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);
1373 /* check the MSIME messages */
1374 if (msg == WM_MSIME_SERVICE)
1376 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_SERVICE", wParam, lParam);
1377 rc = FALSE;
1379 else if (msg == WM_MSIME_RECONVERTOPTIONS)
1381 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERTOPTIONS", wParam, lParam);
1383 else if (msg == WM_MSIME_MOUSE)
1385 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_MOUSE", wParam, lParam);
1387 else if (msg == WM_MSIME_RECONVERTREQUEST)
1389 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERTREQUEST", wParam, lParam);
1391 else if (msg == WM_MSIME_RECONVERT)
1393 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_RECONVERT", wParam, lParam);
1395 else if (msg == WM_MSIME_QUERYPOSITION)
1397 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_QUERYPOSITION", wParam, lParam);
1399 else if (msg == WM_MSIME_DOCUMENTFEED)
1401 TRACE("IME message %s, 0x%lx, 0x%lx\n", "WM_MSIME_DOCUMENTFEED", wParam, lParam);
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);
1408 return rc;
1412 /* Interfaces to other parts of the Mac driver */
1414 void IME_RegisterClasses(HINSTANCE hImeInst)
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;
1429 RegisterClassW(&wndClass);
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");
1441 /***********************************************************************
1442 * macdrv_im_set_cursor_pos
1444 void macdrv_im_set_cursor_pos(const macdrv_event *event)
1446 HWND hwnd = macdrv_get_window_hwnd(event->window);
1447 void *himc = event->im_set_cursor_pos.data;
1449 TRACE("win %p/%p himc %p pos %u\n", hwnd, event->window, himc, event->im_set_cursor_pos.pos);
1451 if (!himc) himc = RealIMC(FROM_MACDRV);
1453 IME_SetCursorPos(himc, event->im_set_cursor_pos.pos);
1457 /***********************************************************************
1458 * macdrv_im_set_text
1460 void macdrv_im_set_text(const macdrv_event *event)
1462 HWND hwnd = macdrv_get_window_hwnd(event->window);
1463 void *himc = event->im_set_text.data;
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);
1468 if (!himc) himc = RealIMC(FROM_MACDRV);
1470 if (event->im_set_text.text)
1472 CFIndex length = CFStringGetLength(event->im_set_text.text);
1473 const UniChar *chars = CFStringGetCharactersPtr(event->im_set_text.text);
1474 UniChar *buffer = NULL;
1476 if (!chars)
1478 buffer = HeapAlloc(GetProcessHeap(), 0, length * sizeof(*buffer));
1479 CFStringGetCharacters(event->im_set_text.text, CFRangeMake(0, length), buffer);
1480 chars = buffer;
1483 if (himc)
1484 IME_SetCompositionString(himc, chars, length * sizeof(*chars));
1485 else
1487 INPUT input;
1488 CFIndex i;
1490 input.type = INPUT_KEYBOARD;
1491 input.ki.wVk = 0;
1492 input.ki.time = 0;
1493 input.ki.dwExtraInfo = 0;
1495 for (i = 0; i < length; i++)
1497 input.ki.wScan = chars[i];
1498 input.ki.dwFlags = KEYEVENTF_UNICODE;
1499 __wine_send_input(hwnd, &input);
1501 input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
1502 __wine_send_input(hwnd, &input);
1506 HeapFree(GetProcessHeap(), 0, buffer);
1509 if (event->im_set_text.complete)
1510 IME_NotifyComplete(himc);