include: Fix ImeToAsciiEx declaration.
[wine.git] / dlls / winex11.drv / ime.c
bloba293daa6ad94038bb494dd707af946bcc30f23ab
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 "immdev.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 static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e','X','1','1','I','M','E',0};
61 static HIMC *hSelectedFrom = NULL;
62 static INT hSelectedCount = 0;
64 /* MSIME messages */
65 static UINT WM_MSIME_SERVICE;
66 static UINT WM_MSIME_RECONVERTOPTIONS;
67 static UINT WM_MSIME_MOUSE;
68 static UINT WM_MSIME_RECONVERTREQUEST;
69 static UINT WM_MSIME_RECONVERT;
70 static UINT WM_MSIME_QUERYPOSITION;
71 static UINT WM_MSIME_DOCUMENTFEED;
73 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
74 LPARAM lParam);
76 static HIMC RealIMC(HIMC hIMC)
78 if (hIMC == FROM_X11)
80 INT i;
81 HWND wnd = GetFocus();
82 HIMC winHimc = ImmGetContext(wnd);
83 for (i = 0; i < hSelectedCount; i++)
84 if (winHimc == hSelectedFrom[i])
85 return winHimc;
86 return NULL;
88 else
89 return hIMC;
92 static LPINPUTCONTEXT LockRealIMC(HIMC hIMC)
94 HIMC real_imc = RealIMC(hIMC);
95 if (real_imc)
96 return ImmLockIMC(real_imc);
97 else
98 return NULL;
101 static BOOL UnlockRealIMC(HIMC hIMC)
103 HIMC real_imc = RealIMC(hIMC);
104 if (real_imc)
105 return ImmUnlockIMC(real_imc);
106 else
107 return FALSE;
110 static BOOL WINAPI register_classes( INIT_ONCE *once, void *param, void **context )
112 WNDCLASSW wndClass;
114 ZeroMemory(&wndClass, sizeof(WNDCLASSW));
115 wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
116 wndClass.lpfnWndProc = IME_WindowProc;
117 wndClass.cbClsExtra = 0;
118 wndClass.cbWndExtra = 2 * sizeof(LONG_PTR);
119 wndClass.hInstance = x11drv_module;
120 wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
121 wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
122 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1);
123 wndClass.lpszMenuName = 0;
124 wndClass.lpszClassName = UI_CLASS_NAME;
126 RegisterClassW(&wndClass);
128 WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
129 WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
130 WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
131 WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
132 WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
133 WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
134 WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
135 return TRUE;
138 static HIMCC ImeCreateBlankCompStr(void)
140 HIMCC rc;
141 LPCOMPOSITIONSTRING ptr;
142 rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
143 ptr = ImmLockIMCC(rc);
144 memset(ptr,0,sizeof(COMPOSITIONSTRING));
145 ptr->dwSize = sizeof(COMPOSITIONSTRING);
146 ImmUnlockIMCC(rc);
147 return rc;
150 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
151 LPBYTE target, LPBYTE source, DWORD* lenParam,
152 DWORD* offsetParam, BOOL wchars )
154 if (origLen > 0 && origOffset > 0)
156 int truelen = origLen;
157 if (wchars)
158 truelen *= sizeof(WCHAR);
160 memcpy(&target[currentOffset], &source[origOffset], truelen);
162 *lenParam = origLen;
163 *offsetParam = currentOffset;
164 currentOffset += truelen;
166 return currentOffset;
169 static HIMCC updateCompStr(HIMCC old, LPCWSTR compstr, DWORD len)
171 /* We need to make sure the CompStr, CompClause and CompAttr fields are all
172 * set and correct. */
173 int needed_size;
174 HIMCC rc;
175 LPBYTE newdata = NULL;
176 LPBYTE olddata = NULL;
177 LPCOMPOSITIONSTRING new_one;
178 LPCOMPOSITIONSTRING lpcs = NULL;
179 INT current_offset = 0;
181 TRACE("%s, %li\n",debugstr_wn(compstr,len),len);
183 if (old == NULL && compstr == NULL && len == 0)
184 return NULL;
186 if (compstr == NULL && len != 0)
188 ERR("compstr is NULL however we have a len! Please report\n");
189 len = 0;
192 if (old != NULL)
194 olddata = ImmLockIMCC(old);
195 lpcs = (LPCOMPOSITIONSTRING)olddata;
198 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
199 len + sizeof(DWORD) * 2;
201 if (lpcs != NULL)
203 needed_size += lpcs->dwCompReadAttrLen;
204 needed_size += lpcs->dwCompReadClauseLen;
205 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
206 needed_size += lpcs->dwResultReadClauseLen;
207 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
208 needed_size += lpcs->dwResultClauseLen;
209 needed_size += lpcs->dwResultStrLen * sizeof(WCHAR);
210 needed_size += lpcs->dwPrivateSize;
212 rc = ImmCreateIMCC(needed_size);
213 newdata = ImmLockIMCC(rc);
214 new_one = (LPCOMPOSITIONSTRING)newdata;
216 new_one->dwSize = needed_size;
217 current_offset = sizeof(COMPOSITIONSTRING);
218 if (lpcs != NULL)
220 current_offset = updateField(lpcs->dwCompReadAttrLen,
221 lpcs->dwCompReadAttrOffset,
222 current_offset, newdata, olddata,
223 &new_one->dwCompReadAttrLen,
224 &new_one->dwCompReadAttrOffset, FALSE);
226 current_offset = updateField(lpcs->dwCompReadClauseLen,
227 lpcs->dwCompReadClauseOffset,
228 current_offset, newdata, olddata,
229 &new_one->dwCompReadClauseLen,
230 &new_one->dwCompReadClauseOffset, FALSE);
232 current_offset = updateField(lpcs->dwCompReadStrLen,
233 lpcs->dwCompReadStrOffset,
234 current_offset, newdata, olddata,
235 &new_one->dwCompReadStrLen,
236 &new_one->dwCompReadStrOffset, TRUE);
238 /* new CompAttr, CompClause, CompStr, dwCursorPos */
239 new_one->dwDeltaStart = 0;
241 current_offset = updateField(lpcs->dwResultReadClauseLen,
242 lpcs->dwResultReadClauseOffset,
243 current_offset, newdata, olddata,
244 &new_one->dwResultReadClauseLen,
245 &new_one->dwResultReadClauseOffset, FALSE);
247 current_offset = updateField(lpcs->dwResultReadStrLen,
248 lpcs->dwResultReadStrOffset,
249 current_offset, newdata, olddata,
250 &new_one->dwResultReadStrLen,
251 &new_one->dwResultReadStrOffset, TRUE);
253 current_offset = updateField(lpcs->dwResultClauseLen,
254 lpcs->dwResultClauseOffset,
255 current_offset, newdata, olddata,
256 &new_one->dwResultClauseLen,
257 &new_one->dwResultClauseOffset, FALSE);
259 current_offset = updateField(lpcs->dwResultStrLen,
260 lpcs->dwResultStrOffset,
261 current_offset, newdata, olddata,
262 &new_one->dwResultStrLen,
263 &new_one->dwResultStrOffset, TRUE);
265 current_offset = updateField(lpcs->dwPrivateSize,
266 lpcs->dwPrivateOffset,
267 current_offset, newdata, olddata,
268 &new_one->dwPrivateSize,
269 &new_one->dwPrivateOffset, FALSE);
272 /* set new data */
273 /* CompAttr */
274 new_one->dwCompAttrLen = len;
275 if (len > 0)
277 new_one->dwCompAttrOffset = current_offset;
278 memset(&newdata[current_offset],ATTR_INPUT,len);
279 current_offset += len;
282 /* CompClause */
283 if (len > 0)
285 new_one->dwCompClauseLen = sizeof(DWORD) * 2;
286 new_one->dwCompClauseOffset = current_offset;
287 *(DWORD*)(&newdata[current_offset]) = 0;
288 current_offset += sizeof(DWORD);
289 *(DWORD*)(&newdata[current_offset]) = len;
290 current_offset += sizeof(DWORD);
292 else
293 new_one->dwCompClauseLen = 0;
295 /* CompStr */
296 new_one->dwCompStrLen = len;
297 if (len > 0)
299 new_one->dwCompStrOffset = current_offset;
300 memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
303 /* CursorPos */
304 new_one->dwCursorPos = len;
306 ImmUnlockIMCC(rc);
307 if (lpcs)
308 ImmUnlockIMCC(old);
310 return rc;
313 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
315 /* we need to make sure the ResultStr and ResultClause fields are all
316 * set and correct */
317 int needed_size;
318 HIMCC rc;
319 LPBYTE newdata = NULL;
320 LPBYTE olddata = NULL;
321 LPCOMPOSITIONSTRING new_one;
322 LPCOMPOSITIONSTRING lpcs = NULL;
323 INT current_offset = 0;
325 TRACE("%s, %li\n",debugstr_wn(resultstr,len),len);
327 if (old == NULL && resultstr == NULL && len == 0)
328 return NULL;
330 if (resultstr == NULL && len != 0)
332 ERR("resultstr is NULL however we have a len! Please report\n");
333 len = 0;
336 if (old != NULL)
338 olddata = ImmLockIMCC(old);
339 lpcs = (LPCOMPOSITIONSTRING)olddata;
342 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
343 sizeof(DWORD) * 2;
345 if (lpcs != NULL)
347 needed_size += lpcs->dwCompReadAttrLen;
348 needed_size += lpcs->dwCompReadClauseLen;
349 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
350 needed_size += lpcs->dwCompAttrLen;
351 needed_size += lpcs->dwCompClauseLen;
352 needed_size += lpcs->dwCompStrLen * sizeof(WCHAR);
353 needed_size += lpcs->dwResultReadClauseLen;
354 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
355 needed_size += lpcs->dwPrivateSize;
357 rc = ImmCreateIMCC(needed_size);
358 newdata = ImmLockIMCC(rc);
359 new_one = (LPCOMPOSITIONSTRING)newdata;
361 new_one->dwSize = needed_size;
362 current_offset = sizeof(COMPOSITIONSTRING);
363 if (lpcs != NULL)
365 current_offset = updateField(lpcs->dwCompReadAttrLen,
366 lpcs->dwCompReadAttrOffset,
367 current_offset, newdata, olddata,
368 &new_one->dwCompReadAttrLen,
369 &new_one->dwCompReadAttrOffset, FALSE);
371 current_offset = updateField(lpcs->dwCompReadClauseLen,
372 lpcs->dwCompReadClauseOffset,
373 current_offset, newdata, olddata,
374 &new_one->dwCompReadClauseLen,
375 &new_one->dwCompReadClauseOffset, FALSE);
377 current_offset = updateField(lpcs->dwCompReadStrLen,
378 lpcs->dwCompReadStrOffset,
379 current_offset, newdata, olddata,
380 &new_one->dwCompReadStrLen,
381 &new_one->dwCompReadStrOffset, TRUE);
383 current_offset = updateField(lpcs->dwCompAttrLen,
384 lpcs->dwCompAttrOffset,
385 current_offset, newdata, olddata,
386 &new_one->dwCompAttrLen,
387 &new_one->dwCompAttrOffset, FALSE);
389 current_offset = updateField(lpcs->dwCompClauseLen,
390 lpcs->dwCompClauseOffset,
391 current_offset, newdata, olddata,
392 &new_one->dwCompClauseLen,
393 &new_one->dwCompClauseOffset, FALSE);
395 current_offset = updateField(lpcs->dwCompStrLen,
396 lpcs->dwCompStrOffset,
397 current_offset, newdata, olddata,
398 &new_one->dwCompStrLen,
399 &new_one->dwCompStrOffset, TRUE);
401 new_one->dwCursorPos = lpcs->dwCursorPos;
402 new_one->dwDeltaStart = 0;
404 current_offset = updateField(lpcs->dwResultReadClauseLen,
405 lpcs->dwResultReadClauseOffset,
406 current_offset, newdata, olddata,
407 &new_one->dwResultReadClauseLen,
408 &new_one->dwResultReadClauseOffset, FALSE);
410 current_offset = updateField(lpcs->dwResultReadStrLen,
411 lpcs->dwResultReadStrOffset,
412 current_offset, newdata, olddata,
413 &new_one->dwResultReadStrLen,
414 &new_one->dwResultReadStrOffset, TRUE);
416 /* new ResultClause , ResultStr */
418 current_offset = updateField(lpcs->dwPrivateSize,
419 lpcs->dwPrivateOffset,
420 current_offset, newdata, olddata,
421 &new_one->dwPrivateSize,
422 &new_one->dwPrivateOffset, FALSE);
425 /* set new data */
426 /* ResultClause */
427 if (len > 0)
429 new_one->dwResultClauseLen = sizeof(DWORD) * 2;
430 new_one->dwResultClauseOffset = current_offset;
431 *(DWORD*)(&newdata[current_offset]) = 0;
432 current_offset += sizeof(DWORD);
433 *(DWORD*)(&newdata[current_offset]) = len;
434 current_offset += sizeof(DWORD);
436 else
437 new_one->dwResultClauseLen = 0;
439 /* ResultStr */
440 new_one->dwResultStrLen = len;
441 if (len > 0)
443 new_one->dwResultStrOffset = current_offset;
444 memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
446 ImmUnlockIMCC(rc);
447 if (lpcs)
448 ImmUnlockIMCC(old);
450 return rc;
453 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam,
454 LPARAM lParam)
456 LPINPUTCONTEXT lpIMC;
457 LPTRANSMSG lpTransMsg;
459 lpIMC = LockRealIMC(hIMC);
460 if (lpIMC == NULL)
461 return;
463 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) *
464 sizeof(TRANSMSG));
465 if (!lpIMC->hMsgBuf)
466 return;
468 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
469 if (!lpTransMsg)
470 return;
472 lpTransMsg += lpIMC->dwNumMsgBuf;
473 lpTransMsg->message = msg;
474 lpTransMsg->wParam = wParam;
475 lpTransMsg->lParam = lParam;
477 ImmUnlockIMCC(lpIMC->hMsgBuf);
478 lpIMC->dwNumMsgBuf++;
480 ImmGenerateMessage(RealIMC(hIMC));
481 UnlockRealIMC(hIMC);
484 static BOOL IME_RemoveFromSelected(HIMC hIMC)
486 int i;
487 for (i = 0; i < hSelectedCount; i++)
488 if (hSelectedFrom[i] == hIMC)
490 if (i < hSelectedCount - 1)
491 memmove(&hSelectedFrom[i], &hSelectedFrom[i+1], (hSelectedCount - i - 1)*sizeof(HIMC));
492 hSelectedCount --;
493 return TRUE;
495 return FALSE;
498 static void IME_AddToSelected(HIMC hIMC)
500 hSelectedCount++;
501 if (hSelectedFrom)
502 hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount*sizeof(HIMC));
503 else
504 hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC));
505 hSelectedFrom[hSelectedCount-1] = hIMC;
508 BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, DWORD flags)
510 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
512 TRACE("\n");
513 InitOnceExecuteOnce( &init_once, register_classes, NULL, NULL );
514 lpIMEInfo->dwPrivateDataSize = sizeof (IMEPRIVATE);
515 lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
516 lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE;
517 lpIMEInfo->fdwSentenceCaps = IME_SMODE_AUTOMATIC;
518 lpIMEInfo->fdwUICaps = UI_CAP_2700;
519 /* Tell App we cannot accept ImeSetCompositionString calls */
520 lpIMEInfo->fdwSCSCaps = 0;
521 lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
523 lstrcpyW(lpszUIClass,UI_CLASS_NAME);
525 return TRUE;
528 BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)
530 FIXME("(%p, %p, %ld, %p): stub\n", hKL, hWnd, dwMode, lpData);
531 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
532 return FALSE;
535 DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource,
536 LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag)
539 FIXME("(%p, %s, %p, %ld, %d): stub\n", hIMC, debugstr_w(lpSource),
540 lpCandList, dwBufLen, uFlag);
541 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
542 return 0;
545 BOOL WINAPI ImeDestroy(UINT uForce)
547 TRACE("\n");
548 HeapFree(GetProcessHeap(),0,hSelectedFrom);
549 hSelectedFrom = NULL;
550 hSelectedCount = 0;
551 return TRUE;
554 LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
556 FIXME("(%p, %d, %p): stub\n", hIMC, uSubFunc, lpData);
557 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
558 return 0;
561 BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState)
563 /* See the comment at the head of this file */
564 TRACE("We do no processing via this route\n");
565 return FALSE;
568 BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
570 LPINPUTCONTEXT lpIMC;
571 TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE");
573 if (hIMC == FROM_X11)
575 ERR("ImeSelect should never be called from X11\n");
576 return FALSE;
579 if (!hIMC)
580 return TRUE;
582 /* not selected */
583 if (!fSelect)
584 return IME_RemoveFromSelected(hIMC);
586 IME_AddToSelected(hIMC);
588 /* Initialize our structures */
589 lpIMC = LockRealIMC(hIMC);
590 if (lpIMC != NULL)
592 LPIMEPRIVATE myPrivate;
593 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
594 myPrivate->bInComposition = FALSE;
595 myPrivate->bInternalState = FALSE;
596 myPrivate->textfont = NULL;
597 myPrivate->hwndDefault = NULL;
598 ImmUnlockIMCC(lpIMC->hPrivate);
599 UnlockRealIMC(hIMC);
602 return TRUE;
605 BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag)
607 static int once;
609 if (!once++)
610 FIXME("(%p, %x): stub\n", hIMC, fFlag);
611 return TRUE;
614 UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState,
615 TRANSMSGLIST *lpdwTransKey, UINT fuState, HIMC hIMC)
617 /* See the comment at the head of this file */
618 TRACE("We do no processing via this route\n");
619 return 0;
622 BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
624 struct xim_preedit_state_params preedit_params;
625 BOOL bRet = FALSE;
626 LPINPUTCONTEXT lpIMC;
628 TRACE("%p %li %li %li\n",hIMC,dwAction,dwIndex,dwValue);
630 lpIMC = LockRealIMC(hIMC);
631 if (lpIMC == NULL)
632 return FALSE;
634 switch (dwAction)
636 case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break;
637 case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break;
638 case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break;
639 case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break;
640 case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
641 case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
642 case NI_CONTEXTUPDATED:
643 switch (dwValue)
645 case IMC_SETCOMPOSITIONWINDOW: FIXME("IMC_SETCOMPOSITIONWINDOW\n"); break;
646 case IMC_SETCONVERSIONMODE: FIXME("IMC_SETCONVERSIONMODE\n"); break;
647 case IMC_SETSENTENCEMODE: FIXME("IMC_SETSENTENCEMODE\n"); break;
648 case IMC_SETCANDIDATEPOS: FIXME("IMC_SETCANDIDATEPOS\n"); break;
649 case IMC_SETCOMPOSITIONFONT:
651 LPIMEPRIVATE myPrivate;
652 TRACE("IMC_SETCOMPOSITIONFONT\n");
654 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
655 if (myPrivate->textfont)
657 DeleteObject(myPrivate->textfont);
658 myPrivate->textfont = NULL;
660 myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W);
661 ImmUnlockIMCC(lpIMC->hPrivate);
663 break;
664 case IMC_SETOPENSTATUS:
665 TRACE("IMC_SETOPENSTATUS\n");
667 bRet = TRUE;
668 preedit_params.hwnd = lpIMC->hWnd;
669 preedit_params.open = lpIMC->fOpen;
670 X11DRV_CALL( xim_preedit_state, &preedit_params );
671 if (!lpIMC->fOpen)
673 LPIMEPRIVATE myPrivate;
675 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
676 if (myPrivate->bInComposition)
678 X11DRV_CALL( xim_reset, lpIMC->hWnd );
679 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
680 myPrivate->bInComposition = FALSE;
682 ImmUnlockIMCC(lpIMC->hPrivate);
685 break;
686 default: FIXME("Unknown\n"); break;
688 break;
689 case NI_COMPOSITIONSTR:
690 switch (dwIndex)
692 case CPS_COMPLETE:
694 HIMCC newCompStr;
695 DWORD cplen = 0;
696 LPWSTR cpstr;
697 LPCOMPOSITIONSTRING cs = NULL;
698 LPBYTE cdata = NULL;
699 LPIMEPRIVATE myPrivate;
701 TRACE("CPS_COMPLETE\n");
703 /* clear existing result */
704 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
706 ImmDestroyIMCC(lpIMC->hCompStr);
707 lpIMC->hCompStr = newCompStr;
709 if (lpIMC->hCompStr)
711 cdata = ImmLockIMCC(lpIMC->hCompStr);
712 cs = (LPCOMPOSITIONSTRING)cdata;
713 cplen = cs->dwCompStrLen;
714 cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]);
715 ImmUnlockIMCC(lpIMC->hCompStr);
717 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
718 if (cplen > 0)
720 WCHAR param = cpstr[0];
722 newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen);
723 ImmDestroyIMCC(lpIMC->hCompStr);
724 lpIMC->hCompStr = newCompStr;
725 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
726 ImmDestroyIMCC(lpIMC->hCompStr);
727 lpIMC->hCompStr = newCompStr;
729 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0,
730 GCS_COMPSTR);
732 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param,
733 GCS_RESULTSTR|GCS_RESULTCLAUSE);
735 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
737 else if (myPrivate->bInComposition)
738 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
740 myPrivate->bInComposition = FALSE;
741 ImmUnlockIMCC(lpIMC->hPrivate);
743 bRet = TRUE;
745 break;
746 case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break;
747 case CPS_REVERT: FIXME("CPS_REVERT\n"); break;
748 case CPS_CANCEL:
750 LPIMEPRIVATE myPrivate;
752 TRACE("CPS_CANCEL\n");
754 X11DRV_CALL( xim_reset, lpIMC->hWnd );
756 if (lpIMC->hCompStr)
757 ImmDestroyIMCC(lpIMC->hCompStr);
758 lpIMC->hCompStr = ImeCreateBlankCompStr();
760 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
761 if (myPrivate->bInComposition)
763 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
764 myPrivate->bInComposition = FALSE;
766 ImmUnlockIMCC(lpIMC->hPrivate);
767 bRet = TRUE;
769 break;
770 default: FIXME("Unknown\n"); break;
772 break;
773 default: FIXME("Unknown Message\n"); break;
776 UnlockRealIMC(hIMC);
777 return bRet;
780 BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle,
781 LPCWSTR lpszRegister)
783 FIXME("(%s, %ld, %s): stub\n", debugstr_w(lpszReading), dwStyle,
784 debugstr_w(lpszRegister));
785 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
786 return FALSE;
789 BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle,
790 LPCWSTR lpszUnregister)
792 FIXME("(%s, %ld, %s): stub\n", debugstr_w(lpszReading), dwStyle,
793 debugstr_w(lpszUnregister));
794 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
795 return FALSE;
798 UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf)
800 FIXME("(%d, %p): stub\n", nItem, lpStyleBuf);
801 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
802 return 0;
805 UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc,
806 LPCWSTR lpszReading, DWORD dwStyle,
807 LPCWSTR lpszRegister, LPVOID lpData)
809 FIXME("(%p, %s, %ld, %s, %p): stub\n", lpfnEnumProc,
810 debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister),
811 lpData);
812 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
813 return 0;
816 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp,
817 DWORD dwCompLen, LPCVOID lpRead,
818 DWORD dwReadLen)
820 LPINPUTCONTEXT lpIMC;
821 DWORD flags = 0;
822 WCHAR wParam = 0;
823 LPIMEPRIVATE myPrivate;
825 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
826 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
829 if (hIMC != FROM_X11)
830 FIXME("PROBLEM: This only sets the wine level string\n");
833 * Explanation:
834 * this sets the composition string in the imm32.dll level
835 * of the composition buffer. we cannot manipulate the xim level
836 * buffer, which means that once the xim level buffer changes again
837 * any call to this function from the application will be lost
840 if (lpRead && dwReadLen)
841 FIXME("Reading string unimplemented\n");
843 lpIMC = LockRealIMC(hIMC);
845 if (lpIMC == NULL)
846 return FALSE;
848 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
850 if (dwIndex == SCS_SETSTR)
852 HIMCC newCompStr;
854 if (!myPrivate->bInComposition)
856 GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
857 myPrivate->bInComposition = TRUE;
860 /* clear existing result */
861 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
862 ImmDestroyIMCC(lpIMC->hCompStr);
863 lpIMC->hCompStr = newCompStr;
865 flags = GCS_COMPSTR;
867 if (dwCompLen && lpComp)
869 newCompStr = updateCompStr(lpIMC->hCompStr, (LPCWSTR)lpComp, dwCompLen / sizeof(WCHAR));
870 ImmDestroyIMCC(lpIMC->hCompStr);
871 lpIMC->hCompStr = newCompStr;
873 wParam = ((const WCHAR*)lpComp)[0];
874 flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
876 else
878 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
879 ImmDestroyIMCC(lpIMC->hCompStr);
880 lpIMC->hCompStr = newCompStr;
884 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
885 ImmUnlockIMCC(lpIMC->hPrivate);
886 UnlockRealIMC(hIMC);
888 return TRUE;
891 DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType,
892 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
893 DWORD dwSize)
895 FIXME("(%p, %lx %lx %p %p %lx): stub\n", hIMC, dwFlags, dwType,
896 lpImeParentMenu, lpImeMenu, dwSize);
897 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
898 return 0;
901 /* Interfaces to XIM and other parts of winex11drv */
903 NTSTATUS x11drv_ime_set_open_status( UINT open )
905 HIMC imc;
907 imc = RealIMC(FROM_X11);
908 ImmSetOpenStatus(imc, open);
909 return 0;
912 NTSTATUS x11drv_ime_set_composition_status( UINT open )
914 HIMC imc;
915 LPINPUTCONTEXT lpIMC;
916 LPIMEPRIVATE myPrivate;
918 imc = RealIMC(FROM_X11);
919 lpIMC = ImmLockIMC(imc);
920 if (lpIMC == NULL)
921 return 0;
923 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
925 if (open && !myPrivate->bInComposition)
927 GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0);
929 else if (!open && myPrivate->bInComposition)
931 ShowWindow(myPrivate->hwndDefault, SW_HIDE);
932 ImmDestroyIMCC(lpIMC->hCompStr);
933 lpIMC->hCompStr = ImeCreateBlankCompStr();
934 GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0);
936 myPrivate->bInComposition = open;
938 ImmUnlockIMCC(lpIMC->hPrivate);
939 ImmUnlockIMC(imc);
940 return 0;
943 NTSTATUS x11drv_ime_get_cursor_pos( UINT arg )
945 LPINPUTCONTEXT lpIMC;
946 INT rc = 0;
947 LPCOMPOSITIONSTRING compstr;
949 if (!hSelectedFrom)
950 return rc;
952 lpIMC = LockRealIMC(FROM_X11);
953 if (lpIMC)
955 compstr = ImmLockIMCC(lpIMC->hCompStr);
956 rc = compstr->dwCursorPos;
957 ImmUnlockIMCC(lpIMC->hCompStr);
959 UnlockRealIMC(FROM_X11);
960 return rc;
963 NTSTATUS x11drv_ime_set_cursor_pos( UINT pos )
965 LPINPUTCONTEXT lpIMC;
966 LPCOMPOSITIONSTRING compstr;
968 if (!hSelectedFrom)
969 return 0;
971 lpIMC = LockRealIMC(FROM_X11);
972 if (!lpIMC)
973 return 0;
975 compstr = ImmLockIMCC(lpIMC->hCompStr);
976 if (!compstr)
978 UnlockRealIMC(FROM_X11);
979 return 0;
982 compstr->dwCursorPos = pos;
983 ImmUnlockIMCC(lpIMC->hCompStr);
984 UnlockRealIMC(FROM_X11);
985 GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS);
986 return 0;
989 NTSTATUS x11drv_ime_update_association( UINT arg )
991 HWND focus = UlongToHandle( arg );
993 ImmGetContext(focus);
995 if (focus && hSelectedFrom)
996 ImmAssociateContext(focus,RealIMC(FROM_X11));
997 return 0;
1001 NTSTATUS WINAPI x11drv_ime_set_composition_string( void *param, ULONG size )
1003 return ImeSetCompositionString(FROM_X11, SCS_SETSTR, param, size, NULL, 0);
1006 NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG len )
1008 WCHAR *lpResult = params;
1009 HIMC imc;
1010 LPINPUTCONTEXT lpIMC;
1011 HIMCC newCompStr;
1012 LPIMEPRIVATE myPrivate;
1013 BOOL inComp;
1014 HWND focus;
1016 len /= sizeof(WCHAR);
1017 if ((focus = GetFocus()))
1018 x11drv_ime_update_association( HandleToUlong( focus ));
1020 imc = RealIMC(FROM_X11);
1021 lpIMC = ImmLockIMC(imc);
1022 if (lpIMC == NULL)
1023 return 0;
1025 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
1026 ImmDestroyIMCC(lpIMC->hCompStr);
1027 lpIMC->hCompStr = newCompStr;
1029 newCompStr = updateResultStr(lpIMC->hCompStr, lpResult, len);
1030 ImmDestroyIMCC(lpIMC->hCompStr);
1031 lpIMC->hCompStr = newCompStr;
1033 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1034 inComp = myPrivate->bInComposition;
1035 ImmUnlockIMCC(lpIMC->hPrivate);
1037 if (!inComp)
1039 ImmSetOpenStatus(imc, TRUE);
1040 GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0);
1043 GenerateIMEMessage(imc, WM_IME_COMPOSITION, 0, GCS_COMPSTR);
1044 GenerateIMEMessage(imc, WM_IME_COMPOSITION, lpResult[0], GCS_RESULTSTR|GCS_RESULTCLAUSE);
1045 GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0);
1047 if (!inComp)
1048 ImmSetOpenStatus(imc, FALSE);
1050 ImmUnlockIMC(imc);
1051 return 0;
1054 /*****
1055 * Internal functions to help with IME window management
1057 static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd)
1059 PAINTSTRUCT ps;
1060 RECT rect;
1061 HDC hdc;
1062 LPCOMPOSITIONSTRING compstr;
1063 LPBYTE compdata = NULL;
1064 HMONITOR monitor;
1065 MONITORINFO mon_info;
1066 INT offX=0, offY=0;
1067 LPINPUTCONTEXT lpIMC;
1069 lpIMC = LockRealIMC(hIMC);
1070 if (lpIMC == NULL)
1071 return;
1073 hdc = BeginPaint(hwnd,&ps);
1075 GetClientRect(hwnd,&rect);
1076 FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
1078 compdata = ImmLockIMCC(lpIMC->hCompStr);
1079 compstr = (LPCOMPOSITIONSTRING)compdata;
1081 if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
1083 SIZE size;
1084 POINT pt;
1085 HFONT oldfont = NULL;
1086 LPWSTR CompString;
1087 LPIMEPRIVATE myPrivate;
1089 CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1090 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1092 if (myPrivate->textfont)
1093 oldfont = SelectObject(hdc,myPrivate->textfont);
1095 ImmUnlockIMCC(lpIMC->hPrivate);
1097 GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
1098 pt.x = size.cx;
1099 pt.y = size.cy;
1100 LPtoDP(hdc,&pt,1);
1103 * How this works based on tests on windows:
1104 * CFS_POINT: then we start our window at the point and grow it as large
1105 * as it needs to be for the string.
1106 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
1107 * window is only as large as we need for the string, but we do not
1108 * grow such that our window exceeds the given rect. Wrapping if
1109 * needed and possible. If our ptCurrentPos is outside of our rect
1110 * then no window is displayed.
1111 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
1112 * maybe because the default MSIME does not do any IME adjusting.
1114 if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT)
1116 POINT cpt = lpIMC->cfCompForm.ptCurrentPos;
1117 ClientToScreen(lpIMC->hWnd,&cpt);
1118 rect.left = cpt.x;
1119 rect.top = cpt.y;
1120 rect.right = rect.left + pt.x;
1121 rect.bottom = rect.top + pt.y;
1122 monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY);
1124 else /* CFS_DEFAULT */
1126 /* Windows places the default IME window in the bottom left */
1127 HWND target = lpIMC->hWnd;
1128 if (!target) target = GetFocus();
1130 GetWindowRect(target,&rect);
1131 rect.top = rect.bottom;
1132 rect.right = rect.left + pt.x + 20;
1133 rect.bottom = rect.top + pt.y + 20;
1134 offX=offY=10;
1135 monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY);
1138 if (lpIMC->cfCompForm.dwStyle == CFS_RECT)
1140 RECT client;
1141 client =lpIMC->cfCompForm.rcArea;
1142 MapWindowPoints( lpIMC->hWnd, 0, (POINT *)&client, 2 );
1143 IntersectRect(&rect,&rect,&client);
1144 /* TODO: Wrap the input if needed */
1147 if (lpIMC->cfCompForm.dwStyle == CFS_DEFAULT)
1149 /* make sure we are on the desktop */
1150 mon_info.cbSize = sizeof(mon_info);
1151 GetMonitorInfoW(monitor, &mon_info);
1153 if (rect.bottom > mon_info.rcWork.bottom)
1155 int shift = rect.bottom - mon_info.rcWork.bottom;
1156 rect.top -= shift;
1157 rect.bottom -= shift;
1159 if (rect.left < 0)
1161 rect.right -= rect.left;
1162 rect.left = 0;
1164 if (rect.right > mon_info.rcWork.right)
1166 int shift = rect.right - mon_info.rcWork.right;
1167 rect.left -= shift;
1168 rect.right -= shift;
1172 SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);
1174 TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen);
1176 if (oldfont)
1177 SelectObject(hdc,oldfont);
1180 ImmUnlockIMCC(lpIMC->hCompStr);
1182 EndPaint(hwnd,&ps);
1183 UnlockRealIMC(hIMC);
1186 static void UpdateDefaultIMEWindow(HIMC hIMC, HWND hwnd)
1188 LPCOMPOSITIONSTRING compstr;
1189 LPINPUTCONTEXT lpIMC;
1191 lpIMC = LockRealIMC(hIMC);
1192 if (lpIMC == NULL)
1193 return;
1195 if (lpIMC->hCompStr)
1196 compstr = ImmLockIMCC(lpIMC->hCompStr);
1197 else
1198 compstr = NULL;
1200 if (compstr == NULL || compstr->dwCompStrLen == 0)
1201 ShowWindow(hwnd,SW_HIDE);
1202 else
1204 ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1205 RedrawWindow(hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE);
1208 if (compstr != NULL)
1209 ImmUnlockIMCC(lpIMC->hCompStr);
1211 lpIMC->hWnd = GetFocus();
1212 UnlockRealIMC(hIMC);
1215 static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam)
1217 TRACE("IME message WM_IME_COMPOSITION 0x%Ix\n", lParam);
1218 if (!(lParam & GCS_RESULTSTR))
1219 UpdateDefaultIMEWindow(hIMC, hwnd);
1222 static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd )
1224 TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1225 UpdateDefaultIMEWindow(hIMC, hwnd);
1228 static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam,
1229 LPARAM lParam)
1231 switch (wParam)
1233 case IMN_OPENSTATUSWINDOW:
1234 FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1235 break;
1236 case IMN_CLOSESTATUSWINDOW:
1237 FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1238 break;
1239 case IMN_OPENCANDIDATE:
1240 FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1241 break;
1242 case IMN_CHANGECANDIDATE:
1243 FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1244 break;
1245 case IMN_CLOSECANDIDATE:
1246 FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1247 break;
1248 case IMN_SETCONVERSIONMODE:
1249 FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1250 break;
1251 case IMN_SETSENTENCEMODE:
1252 FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1253 break;
1254 case IMN_SETOPENSTATUS:
1255 TRACE("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1256 break;
1257 case IMN_SETCANDIDATEPOS:
1258 FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1259 break;
1260 case IMN_SETCOMPOSITIONFONT:
1261 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1262 break;
1263 case IMN_SETCOMPOSITIONWINDOW:
1264 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1265 break;
1266 case IMN_GUIDELINE:
1267 FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1268 break;
1269 case IMN_SETSTATUSWINDOWPOS:
1270 FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1271 break;
1272 default:
1273 FIXME("WM_IME_NOTIFY:<Unknown 0x%Ix>\n",wParam);
1274 break;
1276 return 0;
1279 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
1280 LPARAM lParam)
1282 LRESULT rc = 0;
1283 HIMC hIMC;
1285 TRACE("Incoming Message 0x%x (0x%08Ix, 0x%08Ix)\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_X11);
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%Ix, 0x%Ix\n",
1358 "WM_IME_ENDCOMPOSITION", wParam, lParam);
1359 ShowWindow(hwnd,SW_HIDE);
1360 break;
1361 case WM_IME_SELECT:
1362 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_IME_SELECT", wParam, lParam);
1363 break;
1364 case WM_IME_CONTROL:
1365 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_IME_CONTROL", wParam, lParam);
1366 rc = 1;
1367 break;
1368 case WM_IME_NOTIFY:
1369 rc = ImeHandleNotify(hIMC,hwnd,msg,wParam,lParam);
1370 break;
1371 default:
1372 TRACE("Non-standard message 0x%x\n",msg);
1374 /* check the MSIME messages */
1375 if (msg == WM_MSIME_SERVICE)
1377 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_SERVICE", wParam, lParam);
1378 rc = FALSE;
1380 else if (msg == WM_MSIME_RECONVERTOPTIONS)
1382 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_RECONVERTOPTIONS", wParam, lParam);
1384 else if (msg == WM_MSIME_MOUSE)
1386 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_MOUSE", wParam, lParam);
1388 else if (msg == WM_MSIME_RECONVERTREQUEST)
1390 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_RECONVERTREQUEST", wParam, lParam);
1392 else if (msg == WM_MSIME_RECONVERT)
1394 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_RECONVERT", wParam, lParam);
1396 else if (msg == WM_MSIME_QUERYPOSITION)
1398 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_QUERYPOSITION", wParam, lParam);
1400 else if (msg == WM_MSIME_DOCUMENTFEED)
1402 TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_DOCUMENTFEED", wParam, lParam);
1404 /* DefWndProc if not an IME message */
1405 if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1406 (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
1407 rc = DefWindowProcW(hwnd,msg,wParam,lParam);
1409 return rc;