push 9fcdc0d7acf404e32ebbdf911b92222c6b0dee73
[wine/hacks.git] / dlls / winex11.drv / ime.c
blobab94864f41df243962a76cc50cafeba116881cf6
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 implimenetaion.
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 "config.h"
45 #include <stdarg.h>
46 #include "windef.h"
47 #include "winbase.h"
48 #include "wingdi.h"
49 #include "winuser.h"
50 #include "winerror.h"
51 #include "wine/debug.h"
52 #include "imm.h"
53 #include "ddk/imm.h"
54 #include "winnls.h"
55 #include "x11drv.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(imm);
59 #define FROM_X11 ((HIMC)0xcafe1337)
61 typedef struct _IMEPRIVATE {
62 BOOL bInComposition;
63 BOOL bInternalState;
64 HFONT textfont;
65 HWND hwndDefault;
66 } IMEPRIVATE, *LPIMEPRIVATE;
68 typedef struct _tagTRANSMSG {
69 UINT message;
70 WPARAM wParam;
71 LPARAM lParam;
72 } TRANSMSG, *LPTRANSMSG;
74 static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e','X','1','1','I','M','E',0};
76 static HIMC *hSelectedFrom = NULL;
77 static INT hSelectedCount = 0;
79 /* MSIME messages */
80 static UINT WM_MSIME_SERVICE;
81 static UINT WM_MSIME_RECONVERTOPTIONS;
82 static UINT WM_MSIME_MOUSE;
83 static UINT WM_MSIME_RECONVERTREQUEST;
84 static UINT WM_MSIME_RECONVERT;
85 static UINT WM_MSIME_QUERYPOSITION;
86 static UINT WM_MSIME_DOCUMENTFEED;
88 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
89 LPARAM lParam);
90 static void UpdateDataInDefaultIMEWindow(HIMC hHIMC, HWND hwnd, BOOL showable);
92 static HIMC RealIMC(HIMC hIMC)
94 if (hIMC == FROM_X11)
96 INT i;
97 HWND wnd = GetFocus();
98 HIMC winHimc = ImmGetContext(wnd);
99 for (i = 0; i < hSelectedCount; i++)
100 if (winHimc == hSelectedFrom[i])
101 return winHimc;
102 return NULL;
104 else
105 return hIMC;
108 static LPINPUTCONTEXT LockRealIMC(HIMC hIMC)
110 HIMC real_imc = RealIMC(hIMC);
111 if (real_imc)
112 return (LPINPUTCONTEXT)ImmLockIMC(real_imc);
113 else
114 return NULL;
117 static BOOL UnlockRealIMC(HIMC hIMC)
119 HIMC real_imc = RealIMC(hIMC);
120 if (real_imc)
121 return ImmUnlockIMC(real_imc);
122 else
123 return FALSE;
126 static void IME_RegisterClasses(void)
128 static int done;
129 WNDCLASSW wndClass;
131 if (done) return;
132 done = 1;
134 ZeroMemory(&wndClass, sizeof(WNDCLASSW));
135 wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
136 wndClass.lpfnWndProc = IME_WindowProc;
137 wndClass.cbClsExtra = 0;
138 wndClass.cbWndExtra = 2 * sizeof(LONG);
139 wndClass.hInstance = x11drv_module;
140 wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
141 wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
142 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1);
143 wndClass.lpszMenuName = 0;
144 wndClass.lpszClassName = UI_CLASS_NAME;
146 RegisterClassW(&wndClass);
148 WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
149 WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
150 WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
151 WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
152 WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
153 WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
154 WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
157 void IME_UnregisterClasses(void)
159 UnregisterClassW(UI_CLASS_NAME, x11drv_module);
162 static HIMCC ImeCreateBlankCompStr(void)
164 HIMCC rc;
165 LPCOMPOSITIONSTRING ptr;
166 rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
167 ptr = (LPCOMPOSITIONSTRING)ImmLockIMCC(rc);
168 memset(ptr,0,sizeof(COMPOSITIONSTRING));
169 ptr->dwSize = sizeof(COMPOSITIONSTRING);
170 ImmUnlockIMCC(rc);
171 return rc;
174 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
175 LPBYTE target, LPBYTE source, DWORD* lenParam,
176 DWORD* offsetParam, BOOL wchars )
178 if (origLen > 0 && origOffset > 0)
180 int truelen = origLen;
181 if (wchars)
182 truelen *= sizeof(WCHAR);
184 memcpy(&target[currentOffset], &source[origOffset], truelen);
186 *lenParam = origLen;
187 *offsetParam = currentOffset;
188 currentOffset += truelen;
190 return currentOffset;
193 static HIMCC updateCompStr(HIMCC old, LPWSTR compstr, DWORD len)
195 /* we need to make sure the CompStr, CompClaus and CompAttr fields are all
196 * set and correct */
197 int needed_size;
198 HIMCC rc;
199 LPBYTE newdata = NULL;
200 LPBYTE olddata = NULL;
201 LPCOMPOSITIONSTRING new_one;
202 LPCOMPOSITIONSTRING lpcs = NULL;
203 INT current_offset = 0;
205 TRACE("%s, %i\n",debugstr_wn(compstr,len),len);
207 if (old == NULL && compstr == NULL && len == 0)
208 return NULL;
210 if (old != NULL)
212 olddata = ImmLockIMCC(old);
213 lpcs = (LPCOMPOSITIONSTRING)olddata;
216 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
217 len + sizeof(DWORD) * 2;
219 if (lpcs != NULL)
221 needed_size += lpcs->dwCompReadAttrLen;
222 needed_size += lpcs->dwCompReadClauseLen;
223 needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
224 needed_size += lpcs->dwResultReadClauseLen;
225 needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
226 needed_size += lpcs->dwResultClauseLen;
227 needed_size += lpcs->dwResultStrLen * sizeof(DWORD);
228 needed_size += lpcs->dwPrivateSize;
230 rc = ImmCreateIMCC(needed_size);
231 newdata = ImmLockIMCC(rc);
232 new_one = (LPCOMPOSITIONSTRING)newdata;
234 new_one->dwSize = needed_size;
235 current_offset = sizeof(COMPOSITIONSTRING);
236 if (lpcs != NULL)
238 current_offset = updateField(lpcs->dwCompReadAttrLen,
239 lpcs->dwCompReadAttrOffset,
240 current_offset, newdata, olddata,
241 &new_one->dwCompReadAttrLen,
242 &new_one->dwCompReadAttrOffset, FALSE);
244 current_offset = updateField(lpcs->dwCompReadClauseLen,
245 lpcs->dwCompReadClauseOffset,
246 current_offset, newdata, olddata,
247 &new_one->dwCompReadClauseLen,
248 &new_one->dwCompReadClauseOffset, FALSE);
250 current_offset = updateField(lpcs->dwCompReadStrLen,
251 lpcs->dwCompReadStrOffset,
252 current_offset, newdata, olddata,
253 &new_one->dwCompReadStrLen,
254 &new_one->dwCompReadStrOffset, TRUE);
256 /* new CompAttr, CompClause, CompStr, dwCursorPos */
257 new_one->dwDeltaStart = 0;
259 current_offset = updateField(lpcs->dwResultReadClauseLen,
260 lpcs->dwResultReadClauseOffset,
261 current_offset, newdata, olddata,
262 &new_one->dwResultReadClauseLen,
263 &new_one->dwResultReadClauseOffset, FALSE);
265 current_offset = updateField(lpcs->dwResultReadStrLen,
266 lpcs->dwResultReadStrOffset,
267 current_offset, newdata, olddata,
268 &new_one->dwResultReadStrLen,
269 &new_one->dwResultReadStrOffset, TRUE);
271 current_offset = updateField(lpcs->dwResultClauseLen,
272 lpcs->dwResultClauseOffset,
273 current_offset, newdata, olddata,
274 &new_one->dwResultClauseLen,
275 &new_one->dwResultClauseOffset, FALSE);
277 current_offset = updateField(lpcs->dwResultStrLen,
278 lpcs->dwResultStrOffset,
279 current_offset, newdata, olddata,
280 &new_one->dwResultStrLen,
281 &new_one->dwResultStrOffset, TRUE);
283 current_offset = updateField(lpcs->dwPrivateSize,
284 lpcs->dwPrivateOffset,
285 current_offset, newdata, olddata,
286 &new_one->dwPrivateSize,
287 &new_one->dwPrivateOffset, FALSE);
290 /* set new data */
291 /* CompAttr */
292 new_one->dwCompAttrLen = len;
293 if (len > 0)
295 new_one->dwCompAttrOffset = current_offset;
296 memset(&newdata[current_offset],ATTR_INPUT,len);
297 current_offset += len;
300 /* CompClause */
301 if (len > 0)
303 new_one->dwCompClauseLen = sizeof(DWORD) * 2;
304 new_one->dwCompClauseOffset = current_offset;
305 *(DWORD*)(&newdata[current_offset]) = 0;
306 current_offset += sizeof(DWORD);
307 *(DWORD*)(&newdata[current_offset]) = len;
308 current_offset += sizeof(DWORD);
311 /* CompStr */
312 new_one->dwCompStrLen = len;
313 if (len > 0)
315 new_one->dwCompStrOffset = current_offset;
316 memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
319 /* CursorPos */
320 new_one->dwCursorPos = len;
322 ImmUnlockIMCC(rc);
323 if (lpcs)
324 ImmUnlockIMCC(old);
326 return rc;
329 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
331 /* we need to make sure the ResultStr and ResultClause fields are all
332 * set and correct */
333 int needed_size;
334 HIMCC rc;
335 LPBYTE newdata = NULL;
336 LPBYTE olddata = NULL;
337 LPCOMPOSITIONSTRING new_one;
338 LPCOMPOSITIONSTRING lpcs = NULL;
339 INT current_offset = 0;
341 TRACE("%s, %i\n",debugstr_wn(resultstr,len),len);
343 if (old == NULL && resultstr == NULL && len == 0)
344 return NULL;
346 if (old != NULL)
348 olddata = ImmLockIMCC(old);
349 lpcs = (LPCOMPOSITIONSTRING)olddata;
352 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
353 sizeof(DWORD) * 2;
355 if (lpcs != NULL)
357 needed_size += lpcs->dwCompReadAttrLen;
358 needed_size += lpcs->dwCompReadClauseLen;
359 needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
360 needed_size += lpcs->dwCompAttrLen;
361 needed_size += lpcs->dwCompClauseLen;
362 needed_size += lpcs->dwCompStrLen * sizeof(DWORD);
363 needed_size += lpcs->dwResultReadClauseLen;
364 needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
365 needed_size += lpcs->dwPrivateSize;
367 rc = ImmCreateIMCC(needed_size);
368 newdata = ImmLockIMCC(rc);
369 new_one = (LPCOMPOSITIONSTRING)newdata;
371 new_one->dwSize = needed_size;
372 current_offset = sizeof(COMPOSITIONSTRING);
373 if (lpcs != NULL)
375 current_offset = updateField(lpcs->dwCompReadAttrLen,
376 lpcs->dwCompReadAttrOffset,
377 current_offset, newdata, olddata,
378 &new_one->dwCompReadAttrLen,
379 &new_one->dwCompReadAttrOffset, FALSE);
381 current_offset = updateField(lpcs->dwCompReadClauseLen,
382 lpcs->dwCompReadClauseOffset,
383 current_offset, newdata, olddata,
384 &new_one->dwCompReadClauseLen,
385 &new_one->dwCompReadClauseOffset, FALSE);
387 current_offset = updateField(lpcs->dwCompReadStrLen,
388 lpcs->dwCompReadStrOffset,
389 current_offset, newdata, olddata,
390 &new_one->dwCompReadStrLen,
391 &new_one->dwCompReadStrOffset, TRUE);
393 current_offset = updateField(lpcs->dwCompAttrLen,
394 lpcs->dwCompAttrOffset,
395 current_offset, newdata, olddata,
396 &new_one->dwCompAttrLen,
397 &new_one->dwCompAttrOffset, FALSE);
399 current_offset = updateField(lpcs->dwCompClauseLen,
400 lpcs->dwCompClauseOffset,
401 current_offset, newdata, olddata,
402 &new_one->dwCompClauseLen,
403 &new_one->dwCompClauseOffset, FALSE);
405 current_offset = updateField(lpcs->dwCompStrLen,
406 lpcs->dwCompStrOffset,
407 current_offset, newdata, olddata,
408 &new_one->dwCompStrLen,
409 &new_one->dwCompStrOffset, TRUE);
411 new_one->dwCursorPos = lpcs->dwCursorPos;
412 new_one->dwDeltaStart = 0;
414 current_offset = updateField(lpcs->dwResultReadClauseLen,
415 lpcs->dwResultReadClauseOffset,
416 current_offset, newdata, olddata,
417 &new_one->dwResultReadClauseLen,
418 &new_one->dwResultReadClauseOffset, FALSE);
420 current_offset = updateField(lpcs->dwResultReadStrLen,
421 lpcs->dwResultReadStrOffset,
422 current_offset, newdata, olddata,
423 &new_one->dwResultReadStrLen,
424 &new_one->dwResultReadStrOffset, TRUE);
426 /* new ResultClause , ResultStr */
428 current_offset = updateField(lpcs->dwPrivateSize,
429 lpcs->dwPrivateOffset,
430 current_offset, newdata, olddata,
431 &new_one->dwPrivateSize,
432 &new_one->dwPrivateOffset, FALSE);
435 /* set new data */
436 /* ResultClause */
437 if (len > 0)
439 new_one->dwResultClauseLen = sizeof(DWORD) * 2;
440 new_one->dwResultClauseOffset = current_offset;
441 *(DWORD*)(&newdata[current_offset]) = 0;
442 current_offset += sizeof(DWORD);
443 *(DWORD*)(&newdata[current_offset]) = len;
444 current_offset += sizeof(DWORD);
447 /* ResultStr */
448 new_one->dwResultStrLen = len;
449 if (len > 0)
451 new_one->dwResultStrOffset = current_offset;
452 memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
454 ImmUnlockIMCC(rc);
455 if (lpcs)
456 ImmUnlockIMCC(old);
458 return rc;
461 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam,
462 LPARAM lParam)
464 LPINPUTCONTEXT lpIMC;
465 LPTRANSMSG lpTransMsg;
467 lpIMC = LockRealIMC(hIMC);
468 if (lpIMC == NULL)
469 return;
471 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) *
472 sizeof(TRANSMSG));
473 if (!lpIMC->hMsgBuf)
474 return;
476 lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf);
477 if (!lpTransMsg)
478 return;
480 lpTransMsg += lpIMC->dwNumMsgBuf;
481 lpTransMsg->message = msg;
482 lpTransMsg->wParam = wParam;
483 lpTransMsg->lParam = lParam;
485 ImmUnlockIMCC(lpIMC->hMsgBuf);
486 lpIMC->dwNumMsgBuf++;
488 ImmGenerateMessage(RealIMC(hIMC));
489 UnlockRealIMC(hIMC);
492 static void GenerateIMECHARMessages(HIMC hIMC, LPWSTR String, DWORD length)
494 LPINPUTCONTEXT lpIMC;
495 LPTRANSMSG lpTransMsg;
496 INT i;
498 if (length <= 0)
499 return;
501 lpIMC = LockRealIMC(hIMC);
502 if (lpIMC == NULL)
503 return;
505 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf,
506 (lpIMC->dwNumMsgBuf + length) *
507 sizeof(TRANSMSG));
508 if (!lpIMC->hMsgBuf)
509 return;
511 lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf);
512 if (!lpTransMsg)
513 return;
515 lpTransMsg += lpIMC->dwNumMsgBuf;
516 for (i = 0; i < length; i++)
518 lpTransMsg->message = WM_IME_CHAR;
519 lpTransMsg->wParam = String[i];
520 lpTransMsg->lParam = 1;
521 lpTransMsg ++;
524 ImmUnlockIMCC(lpIMC->hMsgBuf);
525 lpIMC->dwNumMsgBuf+=length;
527 ImmGenerateMessage(RealIMC(hIMC));
528 UnlockRealIMC(hIMC);
531 static BOOL IME_RemoveFromSelected(HIMC hIMC)
533 int i;
534 for (i = 0; i < hSelectedCount; i++)
535 if (hSelectedFrom[i] == hIMC)
537 if (i < hSelectedCount - 1)
538 memmove(&hSelectedFrom[i], &hSelectedFrom[i+1], (hSelectedCount - i - 1)*sizeof(HIMC));
539 hSelectedCount --;
540 return TRUE;
542 return FALSE;
545 static void IME_AddToSelected(HIMC hIMC)
547 hSelectedCount++;
548 if (hSelectedFrom)
549 hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount*sizeof(HIMC));
550 else
551 hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC));
552 hSelectedFrom[hSelectedCount-1] = hIMC;
555 BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass,
556 LPCWSTR lpszOption)
558 TRACE("\n");
559 IME_RegisterClasses();
560 lpIMEInfo->dwPrivateDataSize = sizeof (IMEPRIVATE);
561 lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
562 lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE;
563 lpIMEInfo->fdwSentenceCaps = IME_SMODE_AUTOMATIC;
564 lpIMEInfo->fdwUICaps = UI_CAP_2700;
565 /* Tell App we cannot accept ImeSetCompositionString calls */
566 lpIMEInfo->fdwSCSCaps = 0;
567 lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
569 lstrcpyW(lpszUIClass,UI_CLASS_NAME);
571 return TRUE;
574 BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)
576 FIXME("(%p, %p, %d, %p): stub\n", hKL, hWnd, dwMode, lpData);
577 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
578 return FALSE;
581 DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource,
582 LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag)
585 FIXME("(%p, %s, %p, %d, %d): stub\n", hIMC, debugstr_w(lpSource),
586 lpCandList, dwBufLen, uFlag);
587 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
588 return 0;
591 BOOL WINAPI ImeDestroy(UINT uForce)
593 TRACE("\n");
594 HeapFree(GetProcessHeap(),0,hSelectedFrom);
595 hSelectedFrom = NULL;
596 hSelectedCount = 0;
597 return TRUE;
600 LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
602 FIXME("(%p, %d, %p): stub\n", hIMC, uSubFunc, lpData);
603 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
604 return 0;
607 BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData,
608 CONST LPBYTE lpbKeyState)
610 /* See the comment at the head of this file */
611 TRACE("We do no processing via this route\n");
612 return FALSE;
615 BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
617 LPINPUTCONTEXT lpIMC;
618 TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE");
620 if (hIMC == FROM_X11)
622 ERR("ImeSelect should never be called from X11\n");
623 return FALSE;
626 if (!hIMC)
627 return TRUE;
629 /* not selected */
630 if (!fSelect)
631 return IME_RemoveFromSelected(hIMC);
633 IME_AddToSelected(hIMC);
635 /* Initialize our structures */
636 lpIMC = LockRealIMC(hIMC);
637 if (lpIMC != NULL)
639 LPIMEPRIVATE myPrivate;
640 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
641 myPrivate->bInComposition = FALSE;
642 myPrivate->bInternalState = FALSE;
643 myPrivate->textfont = NULL;
644 myPrivate->hwndDefault = NULL;
645 ImmUnlockIMCC(lpIMC->hPrivate);
646 UnlockRealIMC(hIMC);
649 return TRUE;
652 BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag)
654 FIXME("(%p, %x): stub\n", hIMC, fFlag);
655 return TRUE;
658 UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode,
659 CONST LPBYTE lpbKeyState, LPDWORD lpdwTransKey,
660 UINT fuState, HIMC hIMC)
662 /* See the comment at the head of this file */
663 TRACE("We do no processing via this route\n");
664 return 0;
667 BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
669 BOOL bRet = FALSE;
670 LPINPUTCONTEXT lpIMC;
672 TRACE("%p %i %i %i\n",hIMC,dwAction,dwIndex,dwValue);
674 lpIMC = LockRealIMC(hIMC);
675 if (lpIMC == NULL)
676 return FALSE;
678 switch (dwAction)
680 case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break;
681 case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break;
682 case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break;
683 case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break;
684 case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
685 case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
686 case NI_CONTEXTUPDATED:
687 switch (dwValue)
689 case IMC_SETCOMPOSITIONWINDOW: FIXME("IMC_SETCOMPOSITIONWINDOW\n"); break;
690 case IMC_SETCONVERSIONMODE: FIXME("IMC_SETCONVERSIONMODE\n"); break;
691 case IMC_SETSENTENCEMODE: FIXME("IMC_SETSENTENCEMODE\n"); break;
692 case IMC_SETCANDIDATEPOS: FIXME("IMC_SETCANDIDATEPOS\n"); break;
693 case IMC_SETCOMPOSITIONFONT:
695 LPIMEPRIVATE myPrivate;
696 TRACE("IMC_SETCOMPOSITIONFONT\n");
698 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
699 if (myPrivate->textfont)
701 DeleteObject(myPrivate->textfont);
702 myPrivate->textfont = NULL;
704 myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W);
705 ImmUnlockIMCC(lpIMC->hPrivate);
707 break;
708 case IMC_SETOPENSTATUS:
710 LPIMEPRIVATE myPrivate;
711 TRACE("IMC_SETOPENSTATUS\n");
713 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
714 if (lpIMC->fOpen != myPrivate->bInternalState &&
715 myPrivate->bInComposition)
717 if(lpIMC->fOpen == FALSE)
719 X11DRV_ForceXIMReset(lpIMC->hWnd);
720 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION,0,0);
721 myPrivate->bInComposition = FALSE;
723 else
725 GenerateIMEMessage(hIMC,WM_IME_STARTCOMPOSITION,0,0);
726 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, 0);
729 myPrivate->bInternalState = lpIMC->fOpen;
730 bRet = TRUE;
732 break;
733 default: FIXME("Unknown\n"); break;
735 break;
736 case NI_COMPOSITIONSTR:
737 switch (dwIndex)
739 case CPS_COMPLETE:
741 HIMCC newCompStr;
742 DWORD cplen = 0;
743 LPWSTR cpstr;
744 LPCOMPOSITIONSTRING cs = NULL;
745 LPBYTE cdata = NULL;
746 LPIMEPRIVATE myPrivate;
748 TRACE("CPS_COMPLETE\n");
750 /* clear existing result */
751 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
753 ImmDestroyIMCC(lpIMC->hCompStr);
754 lpIMC->hCompStr = newCompStr;
756 if (lpIMC->hCompStr)
758 cdata = ImmLockIMCC(lpIMC->hCompStr);
759 cs = (LPCOMPOSITIONSTRING)cdata;
760 cplen = cs->dwCompStrLen;
761 cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]);
762 ImmUnlockIMCC(lpIMC->hCompStr);
764 if (cplen > 0)
766 WCHAR param = cpstr[0];
768 newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen);
769 ImmDestroyIMCC(lpIMC->hCompStr);
770 lpIMC->hCompStr = newCompStr;
771 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
772 ImmDestroyIMCC(lpIMC->hCompStr);
773 lpIMC->hCompStr = newCompStr;
775 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0,
776 GCS_COMPSTR);
778 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param,
779 GCS_RESULTSTR|GCS_RESULTCLAUSE);
782 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
784 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
785 myPrivate->bInComposition = FALSE;
786 ImmUnlockIMCC(lpIMC->hPrivate);
788 bRet = TRUE;
790 break;
791 case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break;
792 case CPS_REVERT: FIXME("CPS_REVERT\n"); break;
793 case CPS_CANCEL:
795 LPIMEPRIVATE myPrivate;
797 TRACE("CPS_CANCEL\n");
799 X11DRV_ForceXIMReset(lpIMC->hWnd);
801 if (lpIMC->hCompStr)
802 ImmDestroyIMCC(lpIMC->hCompStr);
803 lpIMC->hCompStr = ImeCreateBlankCompStr();
805 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
806 if (myPrivate->bInComposition)
808 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
809 myPrivate->bInComposition = FALSE;
811 ImmUnlockIMCC(lpIMC->hPrivate);
812 bRet = TRUE;
814 break;
815 default: FIXME("Unknown\n"); break;
817 break;
818 default: FIXME("Unknown Message\n"); break;
821 UnlockRealIMC(hIMC);
822 return bRet;
825 BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle,
826 LPCWSTR lpszRegister)
828 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
829 debugstr_w(lpszRegister));
830 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
831 return FALSE;
834 BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle,
835 LPCWSTR lpszUnregister)
837 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
838 debugstr_w(lpszUnregister));
839 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
840 return FALSE;
843 UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf)
845 FIXME("(%d, %p): stub\n", nItem, lpStyleBuf);
846 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
847 return 0;
850 UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc,
851 LPCWSTR lpszReading, DWORD dwStyle,
852 LPCWSTR lpszRegister, LPVOID lpData)
854 FIXME("(%p, %s, %d, %s, %p): stub\n", lpfnEnumProc,
855 debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister),
856 lpData);
857 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
858 return 0;
861 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp,
862 DWORD dwCompLen, LPCVOID lpRead,
863 DWORD dwReadLen)
865 LPINPUTCONTEXT lpIMC;
866 DWORD flags = 0;
867 WCHAR wParam = 0;
868 LPIMEPRIVATE myPrivate;
870 TRACE("(%p, %d, %p, %d, %p, %d):\n",
871 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
874 if (hIMC != FROM_X11)
875 FIXME("PROBLEM: This only sets the wine level string\n");
878 * Explanation:
879 * this sets the composition string in the imm32.dll level
880 * of the composition buffer. we cannot manipulate the xim level
881 * buffer, which means that once the xim level buffer changes again
882 * any call to this function from the application will be lost
885 if (lpRead && dwReadLen)
886 FIXME("Reading string unimplemented\n");
888 lpIMC = LockRealIMC(hIMC);
890 if (lpIMC == NULL)
891 return FALSE;
893 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
895 if (dwIndex == SCS_SETSTR)
897 HIMCC newCompStr;
899 if (!myPrivate->bInComposition)
901 GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
902 myPrivate->bInComposition = TRUE;
905 flags = GCS_COMPSTR;
907 if (dwCompLen && lpComp)
909 newCompStr = updateCompStr(lpIMC->hCompStr, (LPWSTR)lpComp, dwCompLen / sizeof(WCHAR));
910 ImmDestroyIMCC(lpIMC->hCompStr);
911 lpIMC->hCompStr = newCompStr;
913 wParam = ((const WCHAR*)lpComp)[0];
914 flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
916 else
918 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
919 ImmDestroyIMCC(lpIMC->hCompStr);
920 lpIMC->hCompStr = newCompStr;
924 UpdateDataInDefaultIMEWindow(hIMC, myPrivate->hwndDefault,FALSE);
926 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
927 ImmUnlockIMCC(lpIMC->hPrivate);
928 UnlockRealIMC(hIMC);
930 return TRUE;
933 DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType,
934 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
935 DWORD dwSize)
937 FIXME("(%p, %x %x %p %p %x): stub\n", hIMC, dwFlags, dwType,
938 lpImeParentMenu, lpImeMenu, dwSize);
939 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
940 return 0;
943 /* Interfaces to XIM and other parts of winex11drv */
945 void IME_SetOpenStatus(BOOL fOpen)
947 LPINPUTCONTEXT lpIMC;
948 LPIMEPRIVATE myPrivate;
950 lpIMC = LockRealIMC(FROM_X11);
951 if (lpIMC == NULL)
952 return;
954 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
956 if (myPrivate->bInternalState && fOpen == FALSE)
958 ShowWindow(myPrivate->hwndDefault, SW_HIDE);
959 ImmDestroyIMCC(lpIMC->hCompStr);
960 lpIMC->hCompStr = ImeCreateBlankCompStr();
963 ImmUnlockIMCC(lpIMC->hPrivate);
964 UnlockRealIMC(FROM_X11);
966 if (myPrivate->bInComposition && fOpen == FALSE)
968 GenerateIMEMessage(FROM_X11, WM_IME_ENDCOMPOSITION, 0, 0);
969 myPrivate->bInComposition = FALSE;
972 if (!myPrivate->bInternalState && fOpen == TRUE)
973 ImmSetOpenStatus(RealIMC(FROM_X11), fOpen);
976 LRESULT IME_SendMessageToSelectedHWND(UINT msg, WPARAM wParam, LPARAM lParam)
978 LPINPUTCONTEXT lpIMC;
979 LRESULT rc = 0;
981 if (!hSelectedFrom)
982 return rc;
984 lpIMC = LockRealIMC(FROM_X11);
985 if (lpIMC)
986 rc = SendMessageW(lpIMC->hWnd,msg,wParam,lParam);
988 UnlockRealIMC(FROM_X11);
989 return rc;
992 INT IME_GetCursorPos(void)
994 LPINPUTCONTEXT lpIMC;
995 INT rc = 0;
996 LPCOMPOSITIONSTRING compstr;
998 if (!hSelectedFrom)
999 return rc;
1001 lpIMC = LockRealIMC(FROM_X11);
1002 if (lpIMC)
1004 compstr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
1005 rc = compstr->dwCursorPos;
1006 ImmUnlockIMCC(lpIMC->hCompStr);
1008 UnlockRealIMC(FROM_X11);
1009 return rc;
1012 void IME_SetCursorPos(DWORD pos)
1014 LPINPUTCONTEXT lpIMC;
1015 LPCOMPOSITIONSTRING compstr;
1017 if (!hSelectedFrom)
1018 return;
1020 lpIMC = LockRealIMC(FROM_X11);
1021 if (!lpIMC)
1022 return;
1024 compstr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
1025 if (!compstr)
1027 UnlockRealIMC(FROM_X11);
1028 return;
1031 compstr->dwCursorPos = pos;
1032 ImmUnlockIMCC(lpIMC->hCompStr);
1033 UnlockRealIMC(FROM_X11);
1034 GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS);
1035 return;
1038 void IME_UpdateAssociation(HWND focus)
1040 ImmGetContext(focus);
1042 if (!focus || !hSelectedFrom)
1043 return;
1045 ImmAssociateContext(focus,RealIMC(FROM_X11));
1049 BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen,
1050 LPCVOID lpRead, DWORD dwReadLen)
1052 return ImeSetCompositionString(FROM_X11, dwIndex, lpComp, dwCompLen,
1053 lpRead, dwReadLen);
1056 BOOL IME_NotifyIME(DWORD dwAction, DWORD dwIndex, DWORD dwValue)
1058 return NotifyIME(FROM_X11, dwAction, dwIndex, dwValue);
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 = (LPIMEPRIVATE)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 becase 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 UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable)
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 if (showable)
1210 ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1212 RedrawWindow(hwnd,NULL,NULL,RDW_ERASENOW|RDW_INVALIDATE);
1214 if (compstr != NULL)
1215 ImmUnlockIMCC(lpIMC->hCompStr);
1217 UnlockRealIMC(hIMC);
1220 static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam)
1222 TRACE("IME message WM_IME_COMPOSITION 0x%lx\n", lParam);
1223 if (lParam & GCS_RESULTSTR)
1225 LPCOMPOSITIONSTRING compstr;
1226 LPBYTE compdata;
1227 LPWSTR ResultStr;
1228 HIMCC newCompStr;
1229 LPINPUTCONTEXT lpIMC;
1231 lpIMC = LockRealIMC(hIMC);
1232 if (lpIMC == NULL)
1233 return;
1235 TRACE("Posting result as IME_CHAR\n");
1236 compdata = ImmLockIMCC(lpIMC->hCompStr);
1237 compstr = (LPCOMPOSITIONSTRING)compdata;
1238 ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1239 GenerateIMECHARMessages(hIMC, ResultStr, compstr->dwResultStrLen);
1240 ImmUnlockIMCC(lpIMC->hCompStr);
1242 /* clear the buffer */
1243 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
1244 ImmDestroyIMCC(lpIMC->hCompStr);
1245 lpIMC->hCompStr = newCompStr;
1246 UnlockRealIMC(hIMC);
1248 else
1249 UpdateDataInDefaultIMEWindow(hIMC,hwnd,TRUE);
1252 static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd )
1254 LPINPUTCONTEXT lpIMC;
1256 lpIMC = LockRealIMC(hIMC);
1257 if (lpIMC == NULL)
1258 return;
1260 TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1261 lpIMC->hWnd = GetFocus();
1262 ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1263 UnlockRealIMC(hIMC);
1266 static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam,
1267 LPARAM lParam)
1269 switch (wParam)
1271 case IMN_OPENSTATUSWINDOW:
1272 FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1273 break;
1274 case IMN_CLOSESTATUSWINDOW:
1275 FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1276 break;
1277 case IMN_OPENCANDIDATE:
1278 FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1279 break;
1280 case IMN_CHANGECANDIDATE:
1281 FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1282 break;
1283 case IMN_CLOSECANDIDATE:
1284 FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1285 break;
1286 case IMN_SETCONVERSIONMODE:
1287 FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1288 break;
1289 case IMN_SETSENTENCEMODE:
1290 FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1291 break;
1292 case IMN_SETOPENSTATUS:
1293 FIXME("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1294 break;
1295 case IMN_SETCANDIDATEPOS:
1296 FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1297 break;
1298 case IMN_SETCOMPOSITIONFONT:
1299 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1300 break;
1301 case IMN_SETCOMPOSITIONWINDOW:
1302 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1303 break;
1304 case IMN_GUIDELINE:
1305 FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1306 break;
1307 case IMN_SETSTATUSWINDOWPOS:
1308 FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1309 break;
1310 default:
1311 FIXME("WM_IME_NOTIFY:<Unknown 0x%lx>\n",wParam);
1312 break;
1314 return 0;
1317 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
1318 LPARAM lParam)
1320 LRESULT rc = 0;
1321 HIMC hIMC;
1323 TRACE("Incoming Message 0x%x (0x%08lx, 0x%08lx)\n", msg, wParam, lParam);
1326 * Each UI window contains the current Input Context.
1327 * This Input Context can be obtained by calling GetWindowLong
1328 * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message.
1329 * The UI window can refer to this Input Context and handles the
1330 * messages.
1333 hIMC = (HIMC)GetWindowLongW(hwnd,IMMGWL_IMC);
1334 if (!hIMC)
1335 hIMC = RealIMC(FROM_X11);
1337 /* if we have no hIMC there are many messages we cannot process */
1338 if (hIMC == NULL)
1340 switch (msg) {
1341 case WM_IME_STARTCOMPOSITION:
1342 case WM_IME_ENDCOMPOSITION:
1343 case WM_IME_COMPOSITION:
1344 case WM_IME_NOTIFY:
1345 case WM_IME_CONTROL:
1346 case WM_IME_COMPOSITIONFULL:
1347 case WM_IME_SELECT:
1348 case WM_IME_CHAR:
1349 return 0L;
1350 default:
1351 break;
1355 switch(msg)
1357 case WM_CREATE:
1359 LPIMEPRIVATE myPrivate;
1360 LPINPUTCONTEXT lpIMC;
1362 SetWindowTextA(hwnd,"Wine Ime Active");
1364 lpIMC = LockRealIMC(hIMC);
1365 if (lpIMC)
1367 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
1368 myPrivate->hwndDefault = hwnd;
1369 ImmUnlockIMCC(lpIMC->hPrivate);
1371 UnlockRealIMC(hIMC);
1373 return TRUE;
1375 case WM_PAINT:
1376 PaintDefaultIMEWnd(hIMC, hwnd);
1377 return FALSE;
1379 case WM_NCCREATE:
1380 return TRUE;
1382 case WM_SETFOCUS:
1383 if (wParam)
1384 SetFocus((HWND)wParam);
1385 else
1386 FIXME("Received focus, should never have focus\n");
1387 break;
1388 case WM_IME_COMPOSITION:
1389 DefaultIMEComposition(hIMC, hwnd, lParam);
1390 break;
1391 case WM_IME_STARTCOMPOSITION:
1392 DefaultIMEStartComposition(hIMC, hwnd);
1393 break;
1394 case WM_IME_ENDCOMPOSITION:
1395 TRACE("IME message %s, 0x%lx, 0x%lx\n",
1396 "WM_IME_ENDCOMPOSITION", wParam, lParam);
1397 ShowWindow(hwnd,SW_HIDE);
1398 break;
1399 case WM_IME_SELECT:
1400 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_SELECT", wParam, lParam);
1401 break;
1402 case WM_IME_CONTROL:
1403 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_CONTROL", wParam, lParam);
1404 rc = 1;
1405 break;
1406 case WM_IME_NOTIFY:
1407 rc = ImeHandleNotify(hIMC,hwnd,msg,wParam,lParam);
1408 break;
1409 default:
1410 TRACE("Non-standard message 0x%x\n",msg);
1412 /* check the MSIME messages */
1413 if (msg == WM_MSIME_SERVICE)
1415 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_SERVICE", wParam, lParam);
1416 rc = FALSE;
1418 else if (msg == WM_MSIME_RECONVERTOPTIONS)
1420 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTOPTIONS", wParam, lParam);
1422 else if (msg == WM_MSIME_MOUSE)
1424 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_MOUSE", wParam, lParam);
1426 else if (msg == WM_MSIME_RECONVERTREQUEST)
1428 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTREQUEST", wParam, lParam);
1430 else if (msg == WM_MSIME_RECONVERT)
1432 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERT", wParam, lParam);
1434 else if (msg == WM_MSIME_QUERYPOSITION)
1436 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_QUERYPOSITION", wParam, lParam);
1438 else if (msg == WM_MSIME_DOCUMENTFEED)
1440 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_DOCUMENTFEED", wParam, lParam);
1442 /* DefWndProc if not an IME message */
1443 if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1444 (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
1445 rc = DefWindowProcW(hwnd,msg,wParam,lParam);
1447 return rc;