vbscript: Fix memory leak in owned safearray iterator.
[wine.git] / dlls / winex11.drv / ime.c
blob0599159646fc9023e26481d9cce449560a8cffa2
1 /*
2 * The IME for interfacing with XIM
4 * Copyright 2008 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Notes:
23 * The normal flow for IMM/IME Processing is as follows.
24 * 1) The Keyboard Driver generates key messages which are first passed to
25 * the IMM and then to IME via ImeProcessKey. If the IME returns 0 then
26 * it does not want the key and the keyboard driver then generates the
27 * WM_KEYUP/WM_KEYDOWN messages. However if the IME is going to process the
28 * key it returns non-zero.
29 * 2) If the IME is going to process the key then the IMM calls ImeToAsciiEx to
30 * process the key. the IME modifies the HIMC structure to reflect the
31 * current state and generates any messages it needs the IMM to process.
32 * 3) IMM checks the messages and send them to the application in question. From
33 * here the IMM level deals with if the application is IME aware or not.
35 * This flow does not work well for the X11 driver and XIM.
36 * (It works fine for Mac)
37 * As such we will have to reroute step 1. Instead the x11drv driver will
38 * generate an XIM events and call directly into this IME implementation.
39 * As such we will have to use the alternative ImmGenerateMessage path to be
40 * generate the messages that we want the IMM layer to send to the application.
43 #include "x11drv_dll.h"
44 #include "wine/debug.h"
45 #include "imm.h"
46 #include "ddk/imm.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(imm);
50 #define FROM_X11 ((HIMC)0xcafe1337)
52 typedef struct _IMEPRIVATE {
53 BOOL bInComposition;
54 BOOL bInternalState;
55 HFONT textfont;
56 HWND hwndDefault;
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','X','1','1','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;
79 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
80 LPARAM lParam);
82 static HIMC RealIMC(HIMC hIMC)
84 if (hIMC == FROM_X11)
86 INT i;
87 HWND wnd = GetFocus();
88 HIMC winHimc = ImmGetContext(wnd);
89 for (i = 0; i < hSelectedCount; i++)
90 if (winHimc == hSelectedFrom[i])
91 return winHimc;
92 return NULL;
94 else
95 return hIMC;
98 static LPINPUTCONTEXT LockRealIMC(HIMC hIMC)
100 HIMC real_imc = RealIMC(hIMC);
101 if (real_imc)
102 return ImmLockIMC(real_imc);
103 else
104 return NULL;
107 static BOOL UnlockRealIMC(HIMC hIMC)
109 HIMC real_imc = RealIMC(hIMC);
110 if (real_imc)
111 return ImmUnlockIMC(real_imc);
112 else
113 return FALSE;
116 static BOOL WINAPI register_classes( INIT_ONCE *once, void *param, void **context )
118 WNDCLASSW wndClass;
120 ZeroMemory(&wndClass, sizeof(WNDCLASSW));
121 wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
122 wndClass.lpfnWndProc = IME_WindowProc;
123 wndClass.cbClsExtra = 0;
124 wndClass.cbWndExtra = 2 * sizeof(LONG_PTR);
125 wndClass.hInstance = x11drv_module;
126 wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
127 wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
128 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1);
129 wndClass.lpszMenuName = 0;
130 wndClass.lpszClassName = UI_CLASS_NAME;
132 RegisterClassW(&wndClass);
134 WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
135 WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
136 WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
137 WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
138 WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
139 WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
140 WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
141 return TRUE;
144 static HIMCC ImeCreateBlankCompStr(void)
146 HIMCC rc;
147 LPCOMPOSITIONSTRING ptr;
148 rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
149 ptr = ImmLockIMCC(rc);
150 memset(ptr,0,sizeof(COMPOSITIONSTRING));
151 ptr->dwSize = sizeof(COMPOSITIONSTRING);
152 ImmUnlockIMCC(rc);
153 return rc;
156 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
157 LPBYTE target, LPBYTE source, DWORD* lenParam,
158 DWORD* offsetParam, BOOL wchars )
160 if (origLen > 0 && origOffset > 0)
162 int truelen = origLen;
163 if (wchars)
164 truelen *= sizeof(WCHAR);
166 memcpy(&target[currentOffset], &source[origOffset], truelen);
168 *lenParam = origLen;
169 *offsetParam = currentOffset;
170 currentOffset += truelen;
172 return currentOffset;
175 static HIMCC updateCompStr(HIMCC old, LPCWSTR compstr, DWORD len)
177 /* We need to make sure the CompStr, CompClause and CompAttr fields are all
178 * set and correct. */
179 int needed_size;
180 HIMCC rc;
181 LPBYTE newdata = NULL;
182 LPBYTE olddata = NULL;
183 LPCOMPOSITIONSTRING new_one;
184 LPCOMPOSITIONSTRING lpcs = NULL;
185 INT current_offset = 0;
187 TRACE("%s, %li\n",debugstr_wn(compstr,len),len);
189 if (old == NULL && compstr == NULL && len == 0)
190 return NULL;
192 if (compstr == NULL && len != 0)
194 ERR("compstr is NULL however we have a len! Please report\n");
195 len = 0;
198 if (old != NULL)
200 olddata = ImmLockIMCC(old);
201 lpcs = (LPCOMPOSITIONSTRING)olddata;
204 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
205 len + sizeof(DWORD) * 2;
207 if (lpcs != NULL)
209 needed_size += lpcs->dwCompReadAttrLen;
210 needed_size += lpcs->dwCompReadClauseLen;
211 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
212 needed_size += lpcs->dwResultReadClauseLen;
213 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
214 needed_size += lpcs->dwResultClauseLen;
215 needed_size += lpcs->dwResultStrLen * sizeof(WCHAR);
216 needed_size += lpcs->dwPrivateSize;
218 rc = ImmCreateIMCC(needed_size);
219 newdata = ImmLockIMCC(rc);
220 new_one = (LPCOMPOSITIONSTRING)newdata;
222 new_one->dwSize = needed_size;
223 current_offset = sizeof(COMPOSITIONSTRING);
224 if (lpcs != NULL)
226 current_offset = updateField(lpcs->dwCompReadAttrLen,
227 lpcs->dwCompReadAttrOffset,
228 current_offset, newdata, olddata,
229 &new_one->dwCompReadAttrLen,
230 &new_one->dwCompReadAttrOffset, FALSE);
232 current_offset = updateField(lpcs->dwCompReadClauseLen,
233 lpcs->dwCompReadClauseOffset,
234 current_offset, newdata, olddata,
235 &new_one->dwCompReadClauseLen,
236 &new_one->dwCompReadClauseOffset, FALSE);
238 current_offset = updateField(lpcs->dwCompReadStrLen,
239 lpcs->dwCompReadStrOffset,
240 current_offset, newdata, olddata,
241 &new_one->dwCompReadStrLen,
242 &new_one->dwCompReadStrOffset, TRUE);
244 /* new CompAttr, CompClause, CompStr, dwCursorPos */
245 new_one->dwDeltaStart = 0;
247 current_offset = updateField(lpcs->dwResultReadClauseLen,
248 lpcs->dwResultReadClauseOffset,
249 current_offset, newdata, olddata,
250 &new_one->dwResultReadClauseLen,
251 &new_one->dwResultReadClauseOffset, FALSE);
253 current_offset = updateField(lpcs->dwResultReadStrLen,
254 lpcs->dwResultReadStrOffset,
255 current_offset, newdata, olddata,
256 &new_one->dwResultReadStrLen,
257 &new_one->dwResultReadStrOffset, TRUE);
259 current_offset = updateField(lpcs->dwResultClauseLen,
260 lpcs->dwResultClauseOffset,
261 current_offset, newdata, olddata,
262 &new_one->dwResultClauseLen,
263 &new_one->dwResultClauseOffset, FALSE);
265 current_offset = updateField(lpcs->dwResultStrLen,
266 lpcs->dwResultStrOffset,
267 current_offset, newdata, olddata,
268 &new_one->dwResultStrLen,
269 &new_one->dwResultStrOffset, TRUE);
271 current_offset = updateField(lpcs->dwPrivateSize,
272 lpcs->dwPrivateOffset,
273 current_offset, newdata, olddata,
274 &new_one->dwPrivateSize,
275 &new_one->dwPrivateOffset, FALSE);
278 /* set new data */
279 /* CompAttr */
280 new_one->dwCompAttrLen = len;
281 if (len > 0)
283 new_one->dwCompAttrOffset = current_offset;
284 memset(&newdata[current_offset],ATTR_INPUT,len);
285 current_offset += len;
288 /* CompClause */
289 if (len > 0)
291 new_one->dwCompClauseLen = sizeof(DWORD) * 2;
292 new_one->dwCompClauseOffset = current_offset;
293 *(DWORD*)(&newdata[current_offset]) = 0;
294 current_offset += sizeof(DWORD);
295 *(DWORD*)(&newdata[current_offset]) = len;
296 current_offset += sizeof(DWORD);
298 else
299 new_one->dwCompClauseLen = 0;
301 /* CompStr */
302 new_one->dwCompStrLen = len;
303 if (len > 0)
305 new_one->dwCompStrOffset = current_offset;
306 memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
309 /* CursorPos */
310 new_one->dwCursorPos = len;
312 ImmUnlockIMCC(rc);
313 if (lpcs)
314 ImmUnlockIMCC(old);
316 return rc;
319 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
321 /* we need to make sure the ResultStr and ResultClause fields are all
322 * set and correct */
323 int needed_size;
324 HIMCC rc;
325 LPBYTE newdata = NULL;
326 LPBYTE olddata = NULL;
327 LPCOMPOSITIONSTRING new_one;
328 LPCOMPOSITIONSTRING lpcs = NULL;
329 INT current_offset = 0;
331 TRACE("%s, %li\n",debugstr_wn(resultstr,len),len);
333 if (old == NULL && resultstr == NULL && len == 0)
334 return NULL;
336 if (resultstr == NULL && len != 0)
338 ERR("resultstr is NULL however we have a len! Please report\n");
339 len = 0;
342 if (old != NULL)
344 olddata = ImmLockIMCC(old);
345 lpcs = (LPCOMPOSITIONSTRING)olddata;
348 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
349 sizeof(DWORD) * 2;
351 if (lpcs != NULL)
353 needed_size += lpcs->dwCompReadAttrLen;
354 needed_size += lpcs->dwCompReadClauseLen;
355 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
356 needed_size += lpcs->dwCompAttrLen;
357 needed_size += lpcs->dwCompClauseLen;
358 needed_size += lpcs->dwCompStrLen * sizeof(WCHAR);
359 needed_size += lpcs->dwResultReadClauseLen;
360 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
361 needed_size += lpcs->dwPrivateSize;
363 rc = ImmCreateIMCC(needed_size);
364 newdata = ImmLockIMCC(rc);
365 new_one = (LPCOMPOSITIONSTRING)newdata;
367 new_one->dwSize = needed_size;
368 current_offset = sizeof(COMPOSITIONSTRING);
369 if (lpcs != NULL)
371 current_offset = updateField(lpcs->dwCompReadAttrLen,
372 lpcs->dwCompReadAttrOffset,
373 current_offset, newdata, olddata,
374 &new_one->dwCompReadAttrLen,
375 &new_one->dwCompReadAttrOffset, FALSE);
377 current_offset = updateField(lpcs->dwCompReadClauseLen,
378 lpcs->dwCompReadClauseOffset,
379 current_offset, newdata, olddata,
380 &new_one->dwCompReadClauseLen,
381 &new_one->dwCompReadClauseOffset, FALSE);
383 current_offset = updateField(lpcs->dwCompReadStrLen,
384 lpcs->dwCompReadStrOffset,
385 current_offset, newdata, olddata,
386 &new_one->dwCompReadStrLen,
387 &new_one->dwCompReadStrOffset, TRUE);
389 current_offset = updateField(lpcs->dwCompAttrLen,
390 lpcs->dwCompAttrOffset,
391 current_offset, newdata, olddata,
392 &new_one->dwCompAttrLen,
393 &new_one->dwCompAttrOffset, FALSE);
395 current_offset = updateField(lpcs->dwCompClauseLen,
396 lpcs->dwCompClauseOffset,
397 current_offset, newdata, olddata,
398 &new_one->dwCompClauseLen,
399 &new_one->dwCompClauseOffset, FALSE);
401 current_offset = updateField(lpcs->dwCompStrLen,
402 lpcs->dwCompStrOffset,
403 current_offset, newdata, olddata,
404 &new_one->dwCompStrLen,
405 &new_one->dwCompStrOffset, TRUE);
407 new_one->dwCursorPos = lpcs->dwCursorPos;
408 new_one->dwDeltaStart = 0;
410 current_offset = updateField(lpcs->dwResultReadClauseLen,
411 lpcs->dwResultReadClauseOffset,
412 current_offset, newdata, olddata,
413 &new_one->dwResultReadClauseLen,
414 &new_one->dwResultReadClauseOffset, FALSE);
416 current_offset = updateField(lpcs->dwResultReadStrLen,
417 lpcs->dwResultReadStrOffset,
418 current_offset, newdata, olddata,
419 &new_one->dwResultReadStrLen,
420 &new_one->dwResultReadStrOffset, TRUE);
422 /* new ResultClause , ResultStr */
424 current_offset = updateField(lpcs->dwPrivateSize,
425 lpcs->dwPrivateOffset,
426 current_offset, newdata, olddata,
427 &new_one->dwPrivateSize,
428 &new_one->dwPrivateOffset, FALSE);
431 /* set new data */
432 /* ResultClause */
433 if (len > 0)
435 new_one->dwResultClauseLen = sizeof(DWORD) * 2;
436 new_one->dwResultClauseOffset = current_offset;
437 *(DWORD*)(&newdata[current_offset]) = 0;
438 current_offset += sizeof(DWORD);
439 *(DWORD*)(&newdata[current_offset]) = len;
440 current_offset += sizeof(DWORD);
442 else
443 new_one->dwResultClauseLen = 0;
445 /* ResultStr */
446 new_one->dwResultStrLen = len;
447 if (len > 0)
449 new_one->dwResultStrOffset = current_offset;
450 memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
452 ImmUnlockIMCC(rc);
453 if (lpcs)
454 ImmUnlockIMCC(old);
456 return rc;
459 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam,
460 LPARAM lParam)
462 LPINPUTCONTEXT lpIMC;
463 LPTRANSMSG lpTransMsg;
465 lpIMC = LockRealIMC(hIMC);
466 if (lpIMC == NULL)
467 return;
469 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) *
470 sizeof(TRANSMSG));
471 if (!lpIMC->hMsgBuf)
472 return;
474 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
475 if (!lpTransMsg)
476 return;
478 lpTransMsg += lpIMC->dwNumMsgBuf;
479 lpTransMsg->message = msg;
480 lpTransMsg->wParam = wParam;
481 lpTransMsg->lParam = lParam;
483 ImmUnlockIMCC(lpIMC->hMsgBuf);
484 lpIMC->dwNumMsgBuf++;
486 ImmGenerateMessage(RealIMC(hIMC));
487 UnlockRealIMC(hIMC);
490 static BOOL IME_RemoveFromSelected(HIMC hIMC)
492 int i;
493 for (i = 0; i < hSelectedCount; i++)
494 if (hSelectedFrom[i] == hIMC)
496 if (i < hSelectedCount - 1)
497 memmove(&hSelectedFrom[i], &hSelectedFrom[i+1], (hSelectedCount - i - 1)*sizeof(HIMC));
498 hSelectedCount --;
499 return TRUE;
501 return FALSE;
504 static void IME_AddToSelected(HIMC hIMC)
506 hSelectedCount++;
507 if (hSelectedFrom)
508 hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount*sizeof(HIMC));
509 else
510 hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC));
511 hSelectedFrom[hSelectedCount-1] = hIMC;
514 BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass,
515 LPCWSTR lpszOption)
517 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
519 TRACE("\n");
520 InitOnceExecuteOnce( &init_once, register_classes, NULL, NULL );
521 lpIMEInfo->dwPrivateDataSize = sizeof (IMEPRIVATE);
522 lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
523 lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE;
524 lpIMEInfo->fdwSentenceCaps = IME_SMODE_AUTOMATIC;
525 lpIMEInfo->fdwUICaps = UI_CAP_2700;
526 /* Tell App we cannot accept ImeSetCompositionString calls */
527 lpIMEInfo->fdwSCSCaps = 0;
528 lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
530 lstrcpyW(lpszUIClass,UI_CLASS_NAME);
532 return TRUE;
535 BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)
537 FIXME("(%p, %p, %ld, %p): stub\n", hKL, hWnd, dwMode, lpData);
538 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
539 return FALSE;
542 DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource,
543 LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag)
546 FIXME("(%p, %s, %p, %ld, %d): stub\n", hIMC, debugstr_w(lpSource),
547 lpCandList, dwBufLen, uFlag);
548 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
549 return 0;
552 BOOL WINAPI ImeDestroy(UINT uForce)
554 TRACE("\n");
555 HeapFree(GetProcessHeap(),0,hSelectedFrom);
556 hSelectedFrom = NULL;
557 hSelectedCount = 0;
558 return TRUE;
561 LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
563 FIXME("(%p, %d, %p): stub\n", hIMC, uSubFunc, lpData);
564 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
565 return 0;
568 BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState)
570 /* See the comment at the head of this file */
571 TRACE("We do no processing via this route\n");
572 return FALSE;
575 BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
577 LPINPUTCONTEXT lpIMC;
578 TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE");
580 if (hIMC == FROM_X11)
582 ERR("ImeSelect should never be called from X11\n");
583 return FALSE;
586 if (!hIMC)
587 return TRUE;
589 /* not selected */
590 if (!fSelect)
591 return IME_RemoveFromSelected(hIMC);
593 IME_AddToSelected(hIMC);
595 /* Initialize our structures */
596 lpIMC = LockRealIMC(hIMC);
597 if (lpIMC != NULL)
599 LPIMEPRIVATE myPrivate;
600 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
601 myPrivate->bInComposition = FALSE;
602 myPrivate->bInternalState = FALSE;
603 myPrivate->textfont = NULL;
604 myPrivate->hwndDefault = NULL;
605 ImmUnlockIMCC(lpIMC->hPrivate);
606 UnlockRealIMC(hIMC);
609 return TRUE;
612 BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag)
614 static int once;
616 if (!once++)
617 FIXME("(%p, %x): stub\n", hIMC, fFlag);
618 return TRUE;
621 UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState,
622 LPDWORD lpdwTransKey, UINT fuState, HIMC hIMC)
624 /* See the comment at the head of this file */
625 TRACE("We do no processing via this route\n");
626 return 0;
629 BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
631 struct xim_preedit_state_params preedit_params;
632 BOOL bRet = FALSE;
633 LPINPUTCONTEXT lpIMC;
635 TRACE("%p %li %li %li\n",hIMC,dwAction,dwIndex,dwValue);
637 lpIMC = LockRealIMC(hIMC);
638 if (lpIMC == NULL)
639 return FALSE;
641 switch (dwAction)
643 case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break;
644 case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break;
645 case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break;
646 case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break;
647 case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
648 case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
649 case NI_CONTEXTUPDATED:
650 switch (dwValue)
652 case IMC_SETCOMPOSITIONWINDOW: FIXME("IMC_SETCOMPOSITIONWINDOW\n"); break;
653 case IMC_SETCONVERSIONMODE: FIXME("IMC_SETCONVERSIONMODE\n"); break;
654 case IMC_SETSENTENCEMODE: FIXME("IMC_SETSENTENCEMODE\n"); break;
655 case IMC_SETCANDIDATEPOS: FIXME("IMC_SETCANDIDATEPOS\n"); break;
656 case IMC_SETCOMPOSITIONFONT:
658 LPIMEPRIVATE myPrivate;
659 TRACE("IMC_SETCOMPOSITIONFONT\n");
661 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
662 if (myPrivate->textfont)
664 DeleteObject(myPrivate->textfont);
665 myPrivate->textfont = NULL;
667 myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W);
668 ImmUnlockIMCC(lpIMC->hPrivate);
670 break;
671 case IMC_SETOPENSTATUS:
672 TRACE("IMC_SETOPENSTATUS\n");
674 bRet = TRUE;
675 preedit_params.hwnd = lpIMC->hWnd;
676 preedit_params.open = lpIMC->fOpen;
677 X11DRV_CALL( xim_preedit_state, &preedit_params );
678 if (!lpIMC->fOpen)
680 LPIMEPRIVATE myPrivate;
682 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
683 if (myPrivate->bInComposition)
685 X11DRV_CALL( xim_reset, lpIMC->hWnd );
686 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
687 myPrivate->bInComposition = FALSE;
689 ImmUnlockIMCC(lpIMC->hPrivate);
692 break;
693 default: FIXME("Unknown\n"); break;
695 break;
696 case NI_COMPOSITIONSTR:
697 switch (dwIndex)
699 case CPS_COMPLETE:
701 HIMCC newCompStr;
702 DWORD cplen = 0;
703 LPWSTR cpstr;
704 LPCOMPOSITIONSTRING cs = NULL;
705 LPBYTE cdata = NULL;
706 LPIMEPRIVATE myPrivate;
708 TRACE("CPS_COMPLETE\n");
710 /* clear existing result */
711 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
713 ImmDestroyIMCC(lpIMC->hCompStr);
714 lpIMC->hCompStr = newCompStr;
716 if (lpIMC->hCompStr)
718 cdata = ImmLockIMCC(lpIMC->hCompStr);
719 cs = (LPCOMPOSITIONSTRING)cdata;
720 cplen = cs->dwCompStrLen;
721 cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]);
722 ImmUnlockIMCC(lpIMC->hCompStr);
724 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
725 if (cplen > 0)
727 WCHAR param = cpstr[0];
729 newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen);
730 ImmDestroyIMCC(lpIMC->hCompStr);
731 lpIMC->hCompStr = newCompStr;
732 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
733 ImmDestroyIMCC(lpIMC->hCompStr);
734 lpIMC->hCompStr = newCompStr;
736 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0,
737 GCS_COMPSTR);
739 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param,
740 GCS_RESULTSTR|GCS_RESULTCLAUSE);
742 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
744 else if (myPrivate->bInComposition)
745 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
747 myPrivate->bInComposition = FALSE;
748 ImmUnlockIMCC(lpIMC->hPrivate);
750 bRet = TRUE;
752 break;
753 case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break;
754 case CPS_REVERT: FIXME("CPS_REVERT\n"); break;
755 case CPS_CANCEL:
757 LPIMEPRIVATE myPrivate;
759 TRACE("CPS_CANCEL\n");
761 X11DRV_CALL( xim_reset, lpIMC->hWnd );
763 if (lpIMC->hCompStr)
764 ImmDestroyIMCC(lpIMC->hCompStr);
765 lpIMC->hCompStr = ImeCreateBlankCompStr();
767 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
768 if (myPrivate->bInComposition)
770 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
771 myPrivate->bInComposition = FALSE;
773 ImmUnlockIMCC(lpIMC->hPrivate);
774 bRet = TRUE;
776 break;
777 default: FIXME("Unknown\n"); break;
779 break;
780 default: FIXME("Unknown Message\n"); break;
783 UnlockRealIMC(hIMC);
784 return bRet;
787 BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle,
788 LPCWSTR lpszRegister)
790 FIXME("(%s, %ld, %s): stub\n", debugstr_w(lpszReading), dwStyle,
791 debugstr_w(lpszRegister));
792 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
793 return FALSE;
796 BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle,
797 LPCWSTR lpszUnregister)
799 FIXME("(%s, %ld, %s): stub\n", debugstr_w(lpszReading), dwStyle,
800 debugstr_w(lpszUnregister));
801 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
802 return FALSE;
805 UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf)
807 FIXME("(%d, %p): stub\n", nItem, lpStyleBuf);
808 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
809 return 0;
812 UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc,
813 LPCWSTR lpszReading, DWORD dwStyle,
814 LPCWSTR lpszRegister, LPVOID lpData)
816 FIXME("(%p, %s, %ld, %s, %p): stub\n", lpfnEnumProc,
817 debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister),
818 lpData);
819 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
820 return 0;
823 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp,
824 DWORD dwCompLen, LPCVOID lpRead,
825 DWORD dwReadLen)
827 LPINPUTCONTEXT lpIMC;
828 DWORD flags = 0;
829 WCHAR wParam = 0;
830 LPIMEPRIVATE myPrivate;
832 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
833 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
836 if (hIMC != FROM_X11)
837 FIXME("PROBLEM: This only sets the wine level string\n");
840 * Explanation:
841 * this sets the composition string in the imm32.dll level
842 * of the composition buffer. we cannot manipulate the xim level
843 * buffer, which means that once the xim level buffer changes again
844 * any call to this function from the application will be lost
847 if (lpRead && dwReadLen)
848 FIXME("Reading string unimplemented\n");
850 lpIMC = LockRealIMC(hIMC);
852 if (lpIMC == NULL)
853 return FALSE;
855 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
857 if (dwIndex == SCS_SETSTR)
859 HIMCC newCompStr;
861 if (!myPrivate->bInComposition)
863 GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
864 myPrivate->bInComposition = TRUE;
867 /* clear existing result */
868 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
869 ImmDestroyIMCC(lpIMC->hCompStr);
870 lpIMC->hCompStr = newCompStr;
872 flags = GCS_COMPSTR;
874 if (dwCompLen && lpComp)
876 newCompStr = updateCompStr(lpIMC->hCompStr, (LPCWSTR)lpComp, dwCompLen / sizeof(WCHAR));
877 ImmDestroyIMCC(lpIMC->hCompStr);
878 lpIMC->hCompStr = newCompStr;
880 wParam = ((const WCHAR*)lpComp)[0];
881 flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
883 else
885 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
886 ImmDestroyIMCC(lpIMC->hCompStr);
887 lpIMC->hCompStr = newCompStr;
891 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
892 ImmUnlockIMCC(lpIMC->hPrivate);
893 UnlockRealIMC(hIMC);
895 return TRUE;
898 DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType,
899 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
900 DWORD dwSize)
902 FIXME("(%p, %lx %lx %p %p %lx): stub\n", hIMC, dwFlags, dwType,
903 lpImeParentMenu, lpImeMenu, dwSize);
904 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
905 return 0;
908 /* Interfaces to XIM and other parts of winex11drv */
910 NTSTATUS x11drv_ime_set_open_status( UINT open )
912 HIMC imc;
914 imc = RealIMC(FROM_X11);
915 ImmSetOpenStatus(imc, open);
916 return 0;
919 NTSTATUS x11drv_ime_set_composition_status( UINT open )
921 HIMC imc;
922 LPINPUTCONTEXT lpIMC;
923 LPIMEPRIVATE myPrivate;
925 imc = RealIMC(FROM_X11);
926 lpIMC = ImmLockIMC(imc);
927 if (lpIMC == NULL)
928 return 0;
930 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
932 if (open && !myPrivate->bInComposition)
934 GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0);
936 else if (!open && myPrivate->bInComposition)
938 ShowWindow(myPrivate->hwndDefault, SW_HIDE);
939 ImmDestroyIMCC(lpIMC->hCompStr);
940 lpIMC->hCompStr = ImeCreateBlankCompStr();
941 GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0);
943 myPrivate->bInComposition = open;
945 ImmUnlockIMCC(lpIMC->hPrivate);
946 ImmUnlockIMC(imc);
947 return 0;
950 NTSTATUS x11drv_ime_get_cursor_pos( UINT arg )
952 LPINPUTCONTEXT lpIMC;
953 INT rc = 0;
954 LPCOMPOSITIONSTRING compstr;
956 if (!hSelectedFrom)
957 return rc;
959 lpIMC = LockRealIMC(FROM_X11);
960 if (lpIMC)
962 compstr = ImmLockIMCC(lpIMC->hCompStr);
963 rc = compstr->dwCursorPos;
964 ImmUnlockIMCC(lpIMC->hCompStr);
966 UnlockRealIMC(FROM_X11);
967 return rc;
970 NTSTATUS x11drv_ime_set_cursor_pos( UINT pos )
972 LPINPUTCONTEXT lpIMC;
973 LPCOMPOSITIONSTRING compstr;
975 if (!hSelectedFrom)
976 return 0;
978 lpIMC = LockRealIMC(FROM_X11);
979 if (!lpIMC)
980 return 0;
982 compstr = ImmLockIMCC(lpIMC->hCompStr);
983 if (!compstr)
985 UnlockRealIMC(FROM_X11);
986 return 0;
989 compstr->dwCursorPos = pos;
990 ImmUnlockIMCC(lpIMC->hCompStr);
991 UnlockRealIMC(FROM_X11);
992 GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS);
993 return 0;
996 NTSTATUS x11drv_ime_update_association( UINT arg )
998 HWND focus = UlongToHandle( arg );
1000 ImmGetContext(focus);
1002 if (focus && hSelectedFrom)
1003 ImmAssociateContext(focus,RealIMC(FROM_X11));
1004 return 0;
1008 NTSTATUS WINAPI x11drv_ime_set_composition_string( void *param, ULONG size )
1010 return ImeSetCompositionString(FROM_X11, SCS_SETSTR, param, size, NULL, 0);
1013 NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG len )
1015 WCHAR *lpResult = params;
1016 HIMC imc;
1017 LPINPUTCONTEXT lpIMC;
1018 HIMCC newCompStr;
1019 LPIMEPRIVATE myPrivate;
1020 BOOL inComp;
1021 HWND focus;
1023 len /= sizeof(WCHAR);
1024 if ((focus = GetFocus()))
1025 x11drv_ime_update_association( HandleToUlong( focus ));
1027 imc = RealIMC(FROM_X11);
1028 lpIMC = ImmLockIMC(imc);
1029 if (lpIMC == NULL)
1030 return 0;
1032 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
1033 ImmDestroyIMCC(lpIMC->hCompStr);
1034 lpIMC->hCompStr = newCompStr;
1036 newCompStr = updateResultStr(lpIMC->hCompStr, lpResult, len);
1037 ImmDestroyIMCC(lpIMC->hCompStr);
1038 lpIMC->hCompStr = newCompStr;
1040 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1041 inComp = myPrivate->bInComposition;
1042 ImmUnlockIMCC(lpIMC->hPrivate);
1044 if (!inComp)
1046 ImmSetOpenStatus(imc, TRUE);
1047 GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0);
1050 GenerateIMEMessage(imc, WM_IME_COMPOSITION, 0, GCS_COMPSTR);
1051 GenerateIMEMessage(imc, WM_IME_COMPOSITION, lpResult[0], GCS_RESULTSTR|GCS_RESULTCLAUSE);
1052 GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0);
1054 if (!inComp)
1055 ImmSetOpenStatus(imc, FALSE);
1057 ImmUnlockIMC(imc);
1058 return 0;
1061 /*****
1062 * Internal functions to help with IME window management
1064 static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd)
1066 PAINTSTRUCT ps;
1067 RECT rect;
1068 HDC hdc;
1069 LPCOMPOSITIONSTRING compstr;
1070 LPBYTE compdata = NULL;
1071 HMONITOR monitor;
1072 MONITORINFO mon_info;
1073 INT offX=0, offY=0;
1074 LPINPUTCONTEXT lpIMC;
1076 lpIMC = LockRealIMC(hIMC);
1077 if (lpIMC == NULL)
1078 return;
1080 hdc = BeginPaint(hwnd,&ps);
1082 GetClientRect(hwnd,&rect);
1083 FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
1085 compdata = ImmLockIMCC(lpIMC->hCompStr);
1086 compstr = (LPCOMPOSITIONSTRING)compdata;
1088 if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
1090 SIZE size;
1091 POINT pt;
1092 HFONT oldfont = NULL;
1093 LPWSTR CompString;
1094 LPIMEPRIVATE myPrivate;
1096 CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1097 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1099 if (myPrivate->textfont)
1100 oldfont = SelectObject(hdc,myPrivate->textfont);
1102 ImmUnlockIMCC(lpIMC->hPrivate);
1104 GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
1105 pt.x = size.cx;
1106 pt.y = size.cy;
1107 LPtoDP(hdc,&pt,1);
1110 * How this works based on tests on windows:
1111 * CFS_POINT: then we start our window at the point and grow it as large
1112 * as it needs to be for the string.
1113 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
1114 * window is only as large as we need for the string, but we do not
1115 * grow such that our window exceeds the given rect. Wrapping if
1116 * needed and possible. If our ptCurrentPos is outside of our rect
1117 * then no window is displayed.
1118 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
1119 * maybe because the default MSIME does not do any IME adjusting.
1121 if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT)
1123 POINT cpt = lpIMC->cfCompForm.ptCurrentPos;
1124 ClientToScreen(lpIMC->hWnd,&cpt);
1125 rect.left = cpt.x;
1126 rect.top = cpt.y;
1127 rect.right = rect.left + pt.x;
1128 rect.bottom = rect.top + pt.y;
1129 monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY);
1131 else /* CFS_DEFAULT */
1133 /* Windows places the default IME window in the bottom left */
1134 HWND target = lpIMC->hWnd;
1135 if (!target) target = GetFocus();
1137 GetWindowRect(target,&rect);
1138 rect.top = rect.bottom;
1139 rect.right = rect.left + pt.x + 20;
1140 rect.bottom = rect.top + pt.y + 20;
1141 offX=offY=10;
1142 monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY);
1145 if (lpIMC->cfCompForm.dwStyle == CFS_RECT)
1147 RECT client;
1148 client =lpIMC->cfCompForm.rcArea;
1149 MapWindowPoints( lpIMC->hWnd, 0, (POINT *)&client, 2 );
1150 IntersectRect(&rect,&rect,&client);
1151 /* TODO: Wrap the input if needed */
1154 if (lpIMC->cfCompForm.dwStyle == CFS_DEFAULT)
1156 /* make sure we are on the desktop */
1157 mon_info.cbSize = sizeof(mon_info);
1158 GetMonitorInfoW(monitor, &mon_info);
1160 if (rect.bottom > mon_info.rcWork.bottom)
1162 int shift = rect.bottom - mon_info.rcWork.bottom;
1163 rect.top -= shift;
1164 rect.bottom -= shift;
1166 if (rect.left < 0)
1168 rect.right -= rect.left;
1169 rect.left = 0;
1171 if (rect.right > mon_info.rcWork.right)
1173 int shift = rect.right - mon_info.rcWork.right;
1174 rect.left -= shift;
1175 rect.right -= shift;
1179 SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);
1181 TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen);
1183 if (oldfont)
1184 SelectObject(hdc,oldfont);
1187 ImmUnlockIMCC(lpIMC->hCompStr);
1189 EndPaint(hwnd,&ps);
1190 UnlockRealIMC(hIMC);
1193 static void UpdateDefaultIMEWindow(HIMC hIMC, HWND hwnd)
1195 LPCOMPOSITIONSTRING compstr;
1196 LPINPUTCONTEXT lpIMC;
1198 lpIMC = LockRealIMC(hIMC);
1199 if (lpIMC == NULL)
1200 return;
1202 if (lpIMC->hCompStr)
1203 compstr = ImmLockIMCC(lpIMC->hCompStr);
1204 else
1205 compstr = NULL;
1207 if (compstr == NULL || compstr->dwCompStrLen == 0)
1208 ShowWindow(hwnd,SW_HIDE);
1209 else
1211 ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1212 RedrawWindow(hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE);
1215 if (compstr != NULL)
1216 ImmUnlockIMCC(lpIMC->hCompStr);
1218 lpIMC->hWnd = GetFocus();
1219 UnlockRealIMC(hIMC);
1222 static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam)
1224 TRACE("IME message WM_IME_COMPOSITION 0x%Ix\n", lParam);
1225 if (!(lParam & GCS_RESULTSTR))
1226 UpdateDefaultIMEWindow(hIMC, hwnd);
1229 static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd )
1231 TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1232 UpdateDefaultIMEWindow(hIMC, hwnd);
1235 static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam,
1236 LPARAM lParam)
1238 switch (wParam)
1240 case IMN_OPENSTATUSWINDOW:
1241 FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1242 break;
1243 case IMN_CLOSESTATUSWINDOW:
1244 FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1245 break;
1246 case IMN_OPENCANDIDATE:
1247 FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1248 break;
1249 case IMN_CHANGECANDIDATE:
1250 FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1251 break;
1252 case IMN_CLOSECANDIDATE:
1253 FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1254 break;
1255 case IMN_SETCONVERSIONMODE:
1256 FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1257 break;
1258 case IMN_SETSENTENCEMODE:
1259 FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1260 break;
1261 case IMN_SETOPENSTATUS:
1262 TRACE("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1263 break;
1264 case IMN_SETCANDIDATEPOS:
1265 FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1266 break;
1267 case IMN_SETCOMPOSITIONFONT:
1268 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1269 break;
1270 case IMN_SETCOMPOSITIONWINDOW:
1271 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1272 break;
1273 case IMN_GUIDELINE:
1274 FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1275 break;
1276 case IMN_SETSTATUSWINDOWPOS:
1277 FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1278 break;
1279 default:
1280 FIXME("WM_IME_NOTIFY:<Unknown 0x%Ix>\n",wParam);
1281 break;
1283 return 0;
1286 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
1287 LPARAM lParam)
1289 LRESULT rc = 0;
1290 HIMC hIMC;
1292 TRACE("Incoming Message 0x%x (0x%08Ix, 0x%08Ix)\n", msg, wParam, lParam);
1295 * Each UI window contains the current Input Context.
1296 * This Input Context can be obtained by calling GetWindowLong
1297 * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message.
1298 * The UI window can refer to this Input Context and handles the
1299 * messages.
1302 hIMC = (HIMC)GetWindowLongPtrW(hwnd,IMMGWL_IMC);
1303 if (!hIMC)
1304 hIMC = RealIMC(FROM_X11);
1306 /* if we have no hIMC there are many messages we cannot process */
1307 if (hIMC == NULL)
1309 switch (msg) {
1310 case WM_IME_STARTCOMPOSITION:
1311 case WM_IME_ENDCOMPOSITION:
1312 case WM_IME_COMPOSITION:
1313 case WM_IME_NOTIFY:
1314 case WM_IME_CONTROL:
1315 case WM_IME_COMPOSITIONFULL:
1316 case WM_IME_SELECT:
1317 case WM_IME_CHAR:
1318 return 0L;
1319 default:
1320 break;
1324 switch(msg)
1326 case WM_CREATE:
1328 LPIMEPRIVATE myPrivate;
1329 LPINPUTCONTEXT lpIMC;
1331 SetWindowTextA(hwnd,"Wine Ime Active");
1333 lpIMC = LockRealIMC(hIMC);
1334 if (lpIMC)
1336 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1337 myPrivate->hwndDefault = hwnd;
1338 ImmUnlockIMCC(lpIMC->hPrivate);
1340 UnlockRealIMC(hIMC);
1342 return TRUE;
1344 case WM_PAINT:
1345 PaintDefaultIMEWnd(hIMC, hwnd);
1346 return FALSE;
1348 case WM_NCCREATE:
1349 return TRUE;
1351 case WM_SETFOCUS:
1352 if (wParam)
1353 SetFocus((HWND)wParam);
1354 else
1355 FIXME("Received focus, should never have focus\n");
1356 break;
1357 case WM_IME_COMPOSITION:
1358 DefaultIMEComposition(hIMC, hwnd, lParam);
1359 break;
1360 case WM_IME_STARTCOMPOSITION:
1361 DefaultIMEStartComposition(hIMC, hwnd);
1362 break;
1363 case WM_IME_ENDCOMPOSITION:
1364 TRACE("IME message %s, 0x%Ix, 0x%Ix\n",
1365 "WM_IME_ENDCOMPOSITION", wParam, lParam);
1366 ShowWindow(hwnd,SW_HIDE);
1367 break;
1368 case WM_IME_SELECT:
1369 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_IME_SELECT", wParam, lParam);
1370 break;
1371 case WM_IME_CONTROL:
1372 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_IME_CONTROL", wParam, lParam);
1373 rc = 1;
1374 break;
1375 case WM_IME_NOTIFY:
1376 rc = ImeHandleNotify(hIMC,hwnd,msg,wParam,lParam);
1377 break;
1378 default:
1379 TRACE("Non-standard message 0x%x\n",msg);
1381 /* check the MSIME messages */
1382 if (msg == WM_MSIME_SERVICE)
1384 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_SERVICE", wParam, lParam);
1385 rc = FALSE;
1387 else if (msg == WM_MSIME_RECONVERTOPTIONS)
1389 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_RECONVERTOPTIONS", wParam, lParam);
1391 else if (msg == WM_MSIME_MOUSE)
1393 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_MOUSE", wParam, lParam);
1395 else if (msg == WM_MSIME_RECONVERTREQUEST)
1397 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_RECONVERTREQUEST", wParam, lParam);
1399 else if (msg == WM_MSIME_RECONVERT)
1401 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_RECONVERT", wParam, lParam);
1403 else if (msg == WM_MSIME_QUERYPOSITION)
1405 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_QUERYPOSITION", wParam, lParam);
1407 else if (msg == WM_MSIME_DOCUMENTFEED)
1409 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_DOCUMENTFEED", wParam, lParam);
1411 /* DefWndProc if not an IME message */
1412 if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1413 (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
1414 rc = DefWindowProcW(hwnd,msg,wParam,lParam);
1416 return rc;