d3d11: Make extracting input signature more robust.
[wine.git] / dlls / winex11.drv / ime.c
blob0f4d2b29ee0887b9f12d221338f5a5819130a98e
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 "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);
91 static HIMC RealIMC(HIMC hIMC)
93 if (hIMC == FROM_X11)
95 INT i;
96 HWND wnd = GetFocus();
97 HIMC winHimc = ImmGetContext(wnd);
98 for (i = 0; i < hSelectedCount; i++)
99 if (winHimc == hSelectedFrom[i])
100 return winHimc;
101 return NULL;
103 else
104 return hIMC;
107 static LPINPUTCONTEXT LockRealIMC(HIMC hIMC)
109 HIMC real_imc = RealIMC(hIMC);
110 if (real_imc)
111 return ImmLockIMC(real_imc);
112 else
113 return NULL;
116 static BOOL UnlockRealIMC(HIMC hIMC)
118 HIMC real_imc = RealIMC(hIMC);
119 if (real_imc)
120 return ImmUnlockIMC(real_imc);
121 else
122 return FALSE;
125 static BOOL WINAPI register_classes( INIT_ONCE *once, void *param, void **context )
127 WNDCLASSW wndClass;
129 ZeroMemory(&wndClass, sizeof(WNDCLASSW));
130 wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
131 wndClass.lpfnWndProc = IME_WindowProc;
132 wndClass.cbClsExtra = 0;
133 wndClass.cbWndExtra = 2 * sizeof(LONG_PTR);
134 wndClass.hInstance = x11drv_module;
135 wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
136 wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
137 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1);
138 wndClass.lpszMenuName = 0;
139 wndClass.lpszClassName = UI_CLASS_NAME;
141 RegisterClassW(&wndClass);
143 WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
144 WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
145 WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
146 WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
147 WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
148 WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
149 WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
150 return TRUE;
153 static HIMCC ImeCreateBlankCompStr(void)
155 HIMCC rc;
156 LPCOMPOSITIONSTRING ptr;
157 rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
158 ptr = ImmLockIMCC(rc);
159 memset(ptr,0,sizeof(COMPOSITIONSTRING));
160 ptr->dwSize = sizeof(COMPOSITIONSTRING);
161 ImmUnlockIMCC(rc);
162 return rc;
165 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
166 LPBYTE target, LPBYTE source, DWORD* lenParam,
167 DWORD* offsetParam, BOOL wchars )
169 if (origLen > 0 && origOffset > 0)
171 int truelen = origLen;
172 if (wchars)
173 truelen *= sizeof(WCHAR);
175 memcpy(&target[currentOffset], &source[origOffset], truelen);
177 *lenParam = origLen;
178 *offsetParam = currentOffset;
179 currentOffset += truelen;
181 return currentOffset;
184 static HIMCC updateCompStr(HIMCC old, LPCWSTR compstr, DWORD len)
186 /* we need to make sure the CompStr, CompClaus and CompAttr fields are all
187 * set and correct */
188 int needed_size;
189 HIMCC rc;
190 LPBYTE newdata = NULL;
191 LPBYTE olddata = NULL;
192 LPCOMPOSITIONSTRING new_one;
193 LPCOMPOSITIONSTRING lpcs = NULL;
194 INT current_offset = 0;
196 TRACE("%s, %i\n",debugstr_wn(compstr,len),len);
198 if (old == NULL && compstr == NULL && len == 0)
199 return NULL;
201 if (compstr == NULL && len != 0)
203 ERR("compstr is NULL however we have a len! Please report\n");
204 len = 0;
207 if (old != NULL)
209 olddata = ImmLockIMCC(old);
210 lpcs = (LPCOMPOSITIONSTRING)olddata;
213 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
214 len + sizeof(DWORD) * 2;
216 if (lpcs != NULL)
218 needed_size += lpcs->dwCompReadAttrLen;
219 needed_size += lpcs->dwCompReadClauseLen;
220 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
221 needed_size += lpcs->dwResultReadClauseLen;
222 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
223 needed_size += lpcs->dwResultClauseLen;
224 needed_size += lpcs->dwResultStrLen * sizeof(WCHAR);
225 needed_size += lpcs->dwPrivateSize;
227 rc = ImmCreateIMCC(needed_size);
228 newdata = ImmLockIMCC(rc);
229 new_one = (LPCOMPOSITIONSTRING)newdata;
231 new_one->dwSize = needed_size;
232 current_offset = sizeof(COMPOSITIONSTRING);
233 if (lpcs != NULL)
235 current_offset = updateField(lpcs->dwCompReadAttrLen,
236 lpcs->dwCompReadAttrOffset,
237 current_offset, newdata, olddata,
238 &new_one->dwCompReadAttrLen,
239 &new_one->dwCompReadAttrOffset, FALSE);
241 current_offset = updateField(lpcs->dwCompReadClauseLen,
242 lpcs->dwCompReadClauseOffset,
243 current_offset, newdata, olddata,
244 &new_one->dwCompReadClauseLen,
245 &new_one->dwCompReadClauseOffset, FALSE);
247 current_offset = updateField(lpcs->dwCompReadStrLen,
248 lpcs->dwCompReadStrOffset,
249 current_offset, newdata, olddata,
250 &new_one->dwCompReadStrLen,
251 &new_one->dwCompReadStrOffset, TRUE);
253 /* new CompAttr, CompClause, CompStr, dwCursorPos */
254 new_one->dwDeltaStart = 0;
256 current_offset = updateField(lpcs->dwResultReadClauseLen,
257 lpcs->dwResultReadClauseOffset,
258 current_offset, newdata, olddata,
259 &new_one->dwResultReadClauseLen,
260 &new_one->dwResultReadClauseOffset, FALSE);
262 current_offset = updateField(lpcs->dwResultReadStrLen,
263 lpcs->dwResultReadStrOffset,
264 current_offset, newdata, olddata,
265 &new_one->dwResultReadStrLen,
266 &new_one->dwResultReadStrOffset, TRUE);
268 current_offset = updateField(lpcs->dwResultClauseLen,
269 lpcs->dwResultClauseOffset,
270 current_offset, newdata, olddata,
271 &new_one->dwResultClauseLen,
272 &new_one->dwResultClauseOffset, FALSE);
274 current_offset = updateField(lpcs->dwResultStrLen,
275 lpcs->dwResultStrOffset,
276 current_offset, newdata, olddata,
277 &new_one->dwResultStrLen,
278 &new_one->dwResultStrOffset, TRUE);
280 current_offset = updateField(lpcs->dwPrivateSize,
281 lpcs->dwPrivateOffset,
282 current_offset, newdata, olddata,
283 &new_one->dwPrivateSize,
284 &new_one->dwPrivateOffset, FALSE);
287 /* set new data */
288 /* CompAttr */
289 new_one->dwCompAttrLen = len;
290 if (len > 0)
292 new_one->dwCompAttrOffset = current_offset;
293 memset(&newdata[current_offset],ATTR_INPUT,len);
294 current_offset += len;
297 /* CompClause */
298 if (len > 0)
300 new_one->dwCompClauseLen = sizeof(DWORD) * 2;
301 new_one->dwCompClauseOffset = current_offset;
302 *(DWORD*)(&newdata[current_offset]) = 0;
303 current_offset += sizeof(DWORD);
304 *(DWORD*)(&newdata[current_offset]) = len;
305 current_offset += sizeof(DWORD);
307 else
308 new_one->dwCompClauseLen = 0;
310 /* CompStr */
311 new_one->dwCompStrLen = len;
312 if (len > 0)
314 new_one->dwCompStrOffset = current_offset;
315 memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
318 /* CursorPos */
319 new_one->dwCursorPos = len;
321 ImmUnlockIMCC(rc);
322 if (lpcs)
323 ImmUnlockIMCC(old);
325 return rc;
328 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
330 /* we need to make sure the ResultStr and ResultClause fields are all
331 * set and correct */
332 int needed_size;
333 HIMCC rc;
334 LPBYTE newdata = NULL;
335 LPBYTE olddata = NULL;
336 LPCOMPOSITIONSTRING new_one;
337 LPCOMPOSITIONSTRING lpcs = NULL;
338 INT current_offset = 0;
340 TRACE("%s, %i\n",debugstr_wn(resultstr,len),len);
342 if (old == NULL && resultstr == NULL && len == 0)
343 return NULL;
345 if (resultstr == NULL && len != 0)
347 ERR("resultstr is NULL however we have a len! Please report\n");
348 len = 0;
351 if (old != NULL)
353 olddata = ImmLockIMCC(old);
354 lpcs = (LPCOMPOSITIONSTRING)olddata;
357 needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
358 sizeof(DWORD) * 2;
360 if (lpcs != NULL)
362 needed_size += lpcs->dwCompReadAttrLen;
363 needed_size += lpcs->dwCompReadClauseLen;
364 needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR);
365 needed_size += lpcs->dwCompAttrLen;
366 needed_size += lpcs->dwCompClauseLen;
367 needed_size += lpcs->dwCompStrLen * sizeof(WCHAR);
368 needed_size += lpcs->dwResultReadClauseLen;
369 needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR);
370 needed_size += lpcs->dwPrivateSize;
372 rc = ImmCreateIMCC(needed_size);
373 newdata = ImmLockIMCC(rc);
374 new_one = (LPCOMPOSITIONSTRING)newdata;
376 new_one->dwSize = needed_size;
377 current_offset = sizeof(COMPOSITIONSTRING);
378 if (lpcs != NULL)
380 current_offset = updateField(lpcs->dwCompReadAttrLen,
381 lpcs->dwCompReadAttrOffset,
382 current_offset, newdata, olddata,
383 &new_one->dwCompReadAttrLen,
384 &new_one->dwCompReadAttrOffset, FALSE);
386 current_offset = updateField(lpcs->dwCompReadClauseLen,
387 lpcs->dwCompReadClauseOffset,
388 current_offset, newdata, olddata,
389 &new_one->dwCompReadClauseLen,
390 &new_one->dwCompReadClauseOffset, FALSE);
392 current_offset = updateField(lpcs->dwCompReadStrLen,
393 lpcs->dwCompReadStrOffset,
394 current_offset, newdata, olddata,
395 &new_one->dwCompReadStrLen,
396 &new_one->dwCompReadStrOffset, TRUE);
398 current_offset = updateField(lpcs->dwCompAttrLen,
399 lpcs->dwCompAttrOffset,
400 current_offset, newdata, olddata,
401 &new_one->dwCompAttrLen,
402 &new_one->dwCompAttrOffset, FALSE);
404 current_offset = updateField(lpcs->dwCompClauseLen,
405 lpcs->dwCompClauseOffset,
406 current_offset, newdata, olddata,
407 &new_one->dwCompClauseLen,
408 &new_one->dwCompClauseOffset, FALSE);
410 current_offset = updateField(lpcs->dwCompStrLen,
411 lpcs->dwCompStrOffset,
412 current_offset, newdata, olddata,
413 &new_one->dwCompStrLen,
414 &new_one->dwCompStrOffset, TRUE);
416 new_one->dwCursorPos = lpcs->dwCursorPos;
417 new_one->dwDeltaStart = 0;
419 current_offset = updateField(lpcs->dwResultReadClauseLen,
420 lpcs->dwResultReadClauseOffset,
421 current_offset, newdata, olddata,
422 &new_one->dwResultReadClauseLen,
423 &new_one->dwResultReadClauseOffset, FALSE);
425 current_offset = updateField(lpcs->dwResultReadStrLen,
426 lpcs->dwResultReadStrOffset,
427 current_offset, newdata, olddata,
428 &new_one->dwResultReadStrLen,
429 &new_one->dwResultReadStrOffset, TRUE);
431 /* new ResultClause , ResultStr */
433 current_offset = updateField(lpcs->dwPrivateSize,
434 lpcs->dwPrivateOffset,
435 current_offset, newdata, olddata,
436 &new_one->dwPrivateSize,
437 &new_one->dwPrivateOffset, FALSE);
440 /* set new data */
441 /* ResultClause */
442 if (len > 0)
444 new_one->dwResultClauseLen = sizeof(DWORD) * 2;
445 new_one->dwResultClauseOffset = current_offset;
446 *(DWORD*)(&newdata[current_offset]) = 0;
447 current_offset += sizeof(DWORD);
448 *(DWORD*)(&newdata[current_offset]) = len;
449 current_offset += sizeof(DWORD);
451 else
452 new_one->dwResultClauseLen = 0;
454 /* ResultStr */
455 new_one->dwResultStrLen = len;
456 if (len > 0)
458 new_one->dwResultStrOffset = current_offset;
459 memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
461 ImmUnlockIMCC(rc);
462 if (lpcs)
463 ImmUnlockIMCC(old);
465 return rc;
468 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam,
469 LPARAM lParam)
471 LPINPUTCONTEXT lpIMC;
472 LPTRANSMSG lpTransMsg;
474 lpIMC = LockRealIMC(hIMC);
475 if (lpIMC == NULL)
476 return;
478 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) *
479 sizeof(TRANSMSG));
480 if (!lpIMC->hMsgBuf)
481 return;
483 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
484 if (!lpTransMsg)
485 return;
487 lpTransMsg += lpIMC->dwNumMsgBuf;
488 lpTransMsg->message = msg;
489 lpTransMsg->wParam = wParam;
490 lpTransMsg->lParam = lParam;
492 ImmUnlockIMCC(lpIMC->hMsgBuf);
493 lpIMC->dwNumMsgBuf++;
495 ImmGenerateMessage(RealIMC(hIMC));
496 UnlockRealIMC(hIMC);
499 static void GenerateIMECHARMessages(HIMC hIMC, LPWSTR String, DWORD length)
501 LPINPUTCONTEXT lpIMC;
502 LPTRANSMSG lpTransMsg;
503 DWORD i;
505 if (length <= 0)
506 return;
508 lpIMC = LockRealIMC(hIMC);
509 if (lpIMC == NULL)
510 return;
512 lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf,
513 (lpIMC->dwNumMsgBuf + length) *
514 sizeof(TRANSMSG));
515 if (!lpIMC->hMsgBuf)
516 return;
518 lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf);
519 if (!lpTransMsg)
520 return;
522 lpTransMsg += lpIMC->dwNumMsgBuf;
523 for (i = 0; i < length; i++)
525 lpTransMsg->message = WM_IME_CHAR;
526 lpTransMsg->wParam = String[i];
527 lpTransMsg->lParam = 1;
528 lpTransMsg ++;
531 ImmUnlockIMCC(lpIMC->hMsgBuf);
532 lpIMC->dwNumMsgBuf+=length;
534 ImmGenerateMessage(RealIMC(hIMC));
535 UnlockRealIMC(hIMC);
538 static BOOL IME_RemoveFromSelected(HIMC hIMC)
540 int i;
541 for (i = 0; i < hSelectedCount; i++)
542 if (hSelectedFrom[i] == hIMC)
544 if (i < hSelectedCount - 1)
545 memmove(&hSelectedFrom[i], &hSelectedFrom[i+1], (hSelectedCount - i - 1)*sizeof(HIMC));
546 hSelectedCount --;
547 return TRUE;
549 return FALSE;
552 static void IME_AddToSelected(HIMC hIMC)
554 hSelectedCount++;
555 if (hSelectedFrom)
556 hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount*sizeof(HIMC));
557 else
558 hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC));
559 hSelectedFrom[hSelectedCount-1] = hIMC;
562 BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass,
563 LPCWSTR lpszOption)
565 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
567 TRACE("\n");
568 InitOnceExecuteOnce( &init_once, register_classes, NULL, NULL );
569 lpIMEInfo->dwPrivateDataSize = sizeof (IMEPRIVATE);
570 lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
571 lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE;
572 lpIMEInfo->fdwSentenceCaps = IME_SMODE_AUTOMATIC;
573 lpIMEInfo->fdwUICaps = UI_CAP_2700;
574 /* Tell App we cannot accept ImeSetCompositionString calls */
575 lpIMEInfo->fdwSCSCaps = 0;
576 lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
578 lstrcpyW(lpszUIClass,UI_CLASS_NAME);
580 return TRUE;
583 BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)
585 FIXME("(%p, %p, %d, %p): stub\n", hKL, hWnd, dwMode, lpData);
586 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
587 return FALSE;
590 DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource,
591 LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag)
594 FIXME("(%p, %s, %p, %d, %d): stub\n", hIMC, debugstr_w(lpSource),
595 lpCandList, dwBufLen, uFlag);
596 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
597 return 0;
600 BOOL WINAPI ImeDestroy(UINT uForce)
602 TRACE("\n");
603 HeapFree(GetProcessHeap(),0,hSelectedFrom);
604 hSelectedFrom = NULL;
605 hSelectedCount = 0;
606 return TRUE;
609 LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
611 FIXME("(%p, %d, %p): stub\n", hIMC, uSubFunc, lpData);
612 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
613 return 0;
616 BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState)
618 /* See the comment at the head of this file */
619 TRACE("We do no processing via this route\n");
620 return FALSE;
623 BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
625 LPINPUTCONTEXT lpIMC;
626 TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE");
628 if (hIMC == FROM_X11)
630 ERR("ImeSelect should never be called from X11\n");
631 return FALSE;
634 if (!hIMC)
635 return TRUE;
637 /* not selected */
638 if (!fSelect)
639 return IME_RemoveFromSelected(hIMC);
641 IME_AddToSelected(hIMC);
643 /* Initialize our structures */
644 lpIMC = LockRealIMC(hIMC);
645 if (lpIMC != NULL)
647 LPIMEPRIVATE myPrivate;
648 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
649 myPrivate->bInComposition = FALSE;
650 myPrivate->bInternalState = FALSE;
651 myPrivate->textfont = NULL;
652 myPrivate->hwndDefault = NULL;
653 ImmUnlockIMCC(lpIMC->hPrivate);
654 UnlockRealIMC(hIMC);
657 return TRUE;
660 BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag)
662 FIXME("(%p, %x): stub\n", hIMC, fFlag);
663 return TRUE;
666 UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState,
667 LPDWORD lpdwTransKey, UINT fuState, HIMC hIMC)
669 /* See the comment at the head of this file */
670 TRACE("We do no processing via this route\n");
671 return 0;
674 BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
676 BOOL bRet = FALSE;
677 LPINPUTCONTEXT lpIMC;
679 TRACE("%p %i %i %i\n",hIMC,dwAction,dwIndex,dwValue);
681 lpIMC = LockRealIMC(hIMC);
682 if (lpIMC == NULL)
683 return FALSE;
685 switch (dwAction)
687 case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break;
688 case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break;
689 case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break;
690 case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break;
691 case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
692 case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
693 case NI_CONTEXTUPDATED:
694 switch (dwValue)
696 case IMC_SETCOMPOSITIONWINDOW: FIXME("IMC_SETCOMPOSITIONWINDOW\n"); break;
697 case IMC_SETCONVERSIONMODE: FIXME("IMC_SETCONVERSIONMODE\n"); break;
698 case IMC_SETSENTENCEMODE: FIXME("IMC_SETSENTENCEMODE\n"); break;
699 case IMC_SETCANDIDATEPOS: FIXME("IMC_SETCANDIDATEPOS\n"); break;
700 case IMC_SETCOMPOSITIONFONT:
702 LPIMEPRIVATE myPrivate;
703 TRACE("IMC_SETCOMPOSITIONFONT\n");
705 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
706 if (myPrivate->textfont)
708 DeleteObject(myPrivate->textfont);
709 myPrivate->textfont = NULL;
711 myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W);
712 ImmUnlockIMCC(lpIMC->hPrivate);
714 break;
715 case IMC_SETOPENSTATUS:
716 TRACE("IMC_SETOPENSTATUS\n");
718 bRet = TRUE;
719 X11DRV_SetPreeditState(lpIMC->hWnd, lpIMC->fOpen);
720 if (!lpIMC->fOpen)
722 LPIMEPRIVATE myPrivate;
724 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
725 if (myPrivate->bInComposition)
727 X11DRV_ForceXIMReset(lpIMC->hWnd);
728 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
729 myPrivate->bInComposition = FALSE;
731 ImmUnlockIMCC(lpIMC->hPrivate);
734 break;
735 default: FIXME("Unknown\n"); break;
737 break;
738 case NI_COMPOSITIONSTR:
739 switch (dwIndex)
741 case CPS_COMPLETE:
743 HIMCC newCompStr;
744 DWORD cplen = 0;
745 LPWSTR cpstr;
746 LPCOMPOSITIONSTRING cs = NULL;
747 LPBYTE cdata = NULL;
748 LPIMEPRIVATE myPrivate;
750 TRACE("CPS_COMPLETE\n");
752 /* clear existing result */
753 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
755 ImmDestroyIMCC(lpIMC->hCompStr);
756 lpIMC->hCompStr = newCompStr;
758 if (lpIMC->hCompStr)
760 cdata = ImmLockIMCC(lpIMC->hCompStr);
761 cs = (LPCOMPOSITIONSTRING)cdata;
762 cplen = cs->dwCompStrLen;
763 cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]);
764 ImmUnlockIMCC(lpIMC->hCompStr);
766 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
767 if (cplen > 0)
769 WCHAR param = cpstr[0];
771 newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen);
772 ImmDestroyIMCC(lpIMC->hCompStr);
773 lpIMC->hCompStr = newCompStr;
774 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
775 ImmDestroyIMCC(lpIMC->hCompStr);
776 lpIMC->hCompStr = newCompStr;
778 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0,
779 GCS_COMPSTR);
781 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param,
782 GCS_RESULTSTR|GCS_RESULTCLAUSE);
784 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
786 else if (myPrivate->bInComposition)
787 GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
789 myPrivate->bInComposition = FALSE;
790 ImmUnlockIMCC(lpIMC->hPrivate);
792 bRet = TRUE;
794 break;
795 case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break;
796 case CPS_REVERT: FIXME("CPS_REVERT\n"); break;
797 case CPS_CANCEL:
799 LPIMEPRIVATE myPrivate;
801 TRACE("CPS_CANCEL\n");
803 X11DRV_ForceXIMReset(lpIMC->hWnd);
805 if (lpIMC->hCompStr)
806 ImmDestroyIMCC(lpIMC->hCompStr);
807 lpIMC->hCompStr = ImeCreateBlankCompStr();
809 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
810 if (myPrivate->bInComposition)
812 GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
813 myPrivate->bInComposition = FALSE;
815 ImmUnlockIMCC(lpIMC->hPrivate);
816 bRet = TRUE;
818 break;
819 default: FIXME("Unknown\n"); break;
821 break;
822 default: FIXME("Unknown Message\n"); break;
825 UnlockRealIMC(hIMC);
826 return bRet;
829 BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle,
830 LPCWSTR lpszRegister)
832 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
833 debugstr_w(lpszRegister));
834 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
835 return FALSE;
838 BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle,
839 LPCWSTR lpszUnregister)
841 FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
842 debugstr_w(lpszUnregister));
843 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
844 return FALSE;
847 UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf)
849 FIXME("(%d, %p): stub\n", nItem, lpStyleBuf);
850 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
851 return 0;
854 UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc,
855 LPCWSTR lpszReading, DWORD dwStyle,
856 LPCWSTR lpszRegister, LPVOID lpData)
858 FIXME("(%p, %s, %d, %s, %p): stub\n", lpfnEnumProc,
859 debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister),
860 lpData);
861 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
862 return 0;
865 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp,
866 DWORD dwCompLen, LPCVOID lpRead,
867 DWORD dwReadLen)
869 LPINPUTCONTEXT lpIMC;
870 DWORD flags = 0;
871 WCHAR wParam = 0;
872 LPIMEPRIVATE myPrivate;
874 TRACE("(%p, %d, %p, %d, %p, %d):\n",
875 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
878 if (hIMC != FROM_X11)
879 FIXME("PROBLEM: This only sets the wine level string\n");
882 * Explanation:
883 * this sets the composition string in the imm32.dll level
884 * of the composition buffer. we cannot manipulate the xim level
885 * buffer, which means that once the xim level buffer changes again
886 * any call to this function from the application will be lost
889 if (lpRead && dwReadLen)
890 FIXME("Reading string unimplemented\n");
892 lpIMC = LockRealIMC(hIMC);
894 if (lpIMC == NULL)
895 return FALSE;
897 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
899 if (dwIndex == SCS_SETSTR)
901 HIMCC newCompStr;
903 if (!myPrivate->bInComposition)
905 GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
906 myPrivate->bInComposition = TRUE;
909 flags = GCS_COMPSTR;
911 if (dwCompLen && lpComp)
913 newCompStr = updateCompStr(lpIMC->hCompStr, (LPCWSTR)lpComp, dwCompLen / sizeof(WCHAR));
914 ImmDestroyIMCC(lpIMC->hCompStr);
915 lpIMC->hCompStr = newCompStr;
917 wParam = ((const WCHAR*)lpComp)[0];
918 flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
920 else
922 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
923 ImmDestroyIMCC(lpIMC->hCompStr);
924 lpIMC->hCompStr = newCompStr;
928 GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
929 ImmUnlockIMCC(lpIMC->hPrivate);
930 UnlockRealIMC(hIMC);
932 return TRUE;
935 DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType,
936 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
937 DWORD dwSize)
939 FIXME("(%p, %x %x %p %p %x): stub\n", hIMC, dwFlags, dwType,
940 lpImeParentMenu, lpImeMenu, dwSize);
941 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
942 return 0;
945 /* Interfaces to XIM and other parts of winex11drv */
947 void IME_SetOpenStatus(BOOL fOpen)
949 HIMC imc;
951 imc = RealIMC(FROM_X11);
952 ImmSetOpenStatus(imc, fOpen);
955 void IME_SetCompositionStatus(BOOL fOpen)
957 HIMC imc;
958 LPINPUTCONTEXT lpIMC;
959 LPIMEPRIVATE myPrivate;
961 imc = RealIMC(FROM_X11);
962 lpIMC = ImmLockIMC(imc);
963 if (lpIMC == NULL)
964 return;
966 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
968 if (fOpen && !myPrivate->bInComposition)
970 GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0);
972 else if (!fOpen && myPrivate->bInComposition)
974 ShowWindow(myPrivate->hwndDefault, SW_HIDE);
975 ImmDestroyIMCC(lpIMC->hCompStr);
976 lpIMC->hCompStr = ImeCreateBlankCompStr();
977 GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0);
979 myPrivate->bInComposition = fOpen;
981 ImmUnlockIMCC(lpIMC->hPrivate);
982 ImmUnlockIMC(imc);
985 INT IME_GetCursorPos(void)
987 LPINPUTCONTEXT lpIMC;
988 INT rc = 0;
989 LPCOMPOSITIONSTRING compstr;
991 if (!hSelectedFrom)
992 return rc;
994 lpIMC = LockRealIMC(FROM_X11);
995 if (lpIMC)
997 compstr = ImmLockIMCC(lpIMC->hCompStr);
998 rc = compstr->dwCursorPos;
999 ImmUnlockIMCC(lpIMC->hCompStr);
1001 UnlockRealIMC(FROM_X11);
1002 return rc;
1005 void IME_SetCursorPos(DWORD pos)
1007 LPINPUTCONTEXT lpIMC;
1008 LPCOMPOSITIONSTRING compstr;
1010 if (!hSelectedFrom)
1011 return;
1013 lpIMC = LockRealIMC(FROM_X11);
1014 if (!lpIMC)
1015 return;
1017 compstr = ImmLockIMCC(lpIMC->hCompStr);
1018 if (!compstr)
1020 UnlockRealIMC(FROM_X11);
1021 return;
1024 compstr->dwCursorPos = pos;
1025 ImmUnlockIMCC(lpIMC->hCompStr);
1026 UnlockRealIMC(FROM_X11);
1027 GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS);
1028 return;
1031 void IME_UpdateAssociation(HWND focus)
1033 ImmGetContext(focus);
1035 if (!focus || !hSelectedFrom)
1036 return;
1038 ImmAssociateContext(focus,RealIMC(FROM_X11));
1042 BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen,
1043 LPCVOID lpRead, DWORD dwReadLen)
1045 return ImeSetCompositionString(FROM_X11, dwIndex, lpComp, dwCompLen,
1046 lpRead, dwReadLen);
1049 void IME_SetResultString(LPWSTR lpResult, DWORD dwResultLen)
1051 HIMC imc;
1052 LPINPUTCONTEXT lpIMC;
1053 HIMCC newCompStr;
1054 LPIMEPRIVATE myPrivate;
1055 BOOL inComp;
1057 imc = RealIMC(FROM_X11);
1058 lpIMC = ImmLockIMC(imc);
1059 if (lpIMC == NULL)
1060 return;
1062 newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
1063 ImmDestroyIMCC(lpIMC->hCompStr);
1064 lpIMC->hCompStr = newCompStr;
1066 newCompStr = updateResultStr(lpIMC->hCompStr, lpResult, dwResultLen);
1067 ImmDestroyIMCC(lpIMC->hCompStr);
1068 lpIMC->hCompStr = newCompStr;
1070 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1071 inComp = myPrivate->bInComposition;
1072 ImmUnlockIMCC(lpIMC->hPrivate);
1074 if (!inComp)
1076 ImmSetOpenStatus(imc, TRUE);
1077 GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0);
1080 GenerateIMEMessage(imc, WM_IME_COMPOSITION, 0, GCS_COMPSTR);
1081 GenerateIMEMessage(imc, WM_IME_COMPOSITION, lpResult[0], GCS_RESULTSTR|GCS_RESULTCLAUSE);
1082 GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0);
1084 if (!inComp)
1085 ImmSetOpenStatus(imc, FALSE);
1087 ImmUnlockIMC(imc);
1090 /*****
1091 * Internal functions to help with IME window management
1093 static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd)
1095 PAINTSTRUCT ps;
1096 RECT rect;
1097 HDC hdc;
1098 LPCOMPOSITIONSTRING compstr;
1099 LPBYTE compdata = NULL;
1100 HMONITOR monitor;
1101 MONITORINFO mon_info;
1102 INT offX=0, offY=0;
1103 LPINPUTCONTEXT lpIMC;
1105 lpIMC = LockRealIMC(hIMC);
1106 if (lpIMC == NULL)
1107 return;
1109 hdc = BeginPaint(hwnd,&ps);
1111 GetClientRect(hwnd,&rect);
1112 FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
1114 compdata = ImmLockIMCC(lpIMC->hCompStr);
1115 compstr = (LPCOMPOSITIONSTRING)compdata;
1117 if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
1119 SIZE size;
1120 POINT pt;
1121 HFONT oldfont = NULL;
1122 LPWSTR CompString;
1123 LPIMEPRIVATE myPrivate;
1125 CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1126 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1128 if (myPrivate->textfont)
1129 oldfont = SelectObject(hdc,myPrivate->textfont);
1131 ImmUnlockIMCC(lpIMC->hPrivate);
1133 GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
1134 pt.x = size.cx;
1135 pt.y = size.cy;
1136 LPtoDP(hdc,&pt,1);
1139 * How this works based on tests on windows:
1140 * CFS_POINT: then we start our window at the point and grow it as large
1141 * as it needs to be for the string.
1142 * CFS_RECT: we still use the ptCurrentPos as a starting point and our
1143 * window is only as large as we need for the string, but we do not
1144 * grow such that our window exceeds the given rect. Wrapping if
1145 * needed and possible. If our ptCurrentPos is outside of our rect
1146 * then no window is displayed.
1147 * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
1148 * maybe because the default MSIME does not do any IME adjusting.
1150 if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT)
1152 POINT cpt = lpIMC->cfCompForm.ptCurrentPos;
1153 ClientToScreen(lpIMC->hWnd,&cpt);
1154 rect.left = cpt.x;
1155 rect.top = cpt.y;
1156 rect.right = rect.left + pt.x;
1157 rect.bottom = rect.top + pt.y;
1158 monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY);
1160 else /* CFS_DEFAULT */
1162 /* Windows places the default IME window in the bottom left */
1163 HWND target = lpIMC->hWnd;
1164 if (!target) target = GetFocus();
1166 GetWindowRect(target,&rect);
1167 rect.top = rect.bottom;
1168 rect.right = rect.left + pt.x + 20;
1169 rect.bottom = rect.top + pt.y + 20;
1170 offX=offY=10;
1171 monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY);
1174 if (lpIMC->cfCompForm.dwStyle == CFS_RECT)
1176 RECT client;
1177 client =lpIMC->cfCompForm.rcArea;
1178 MapWindowPoints( lpIMC->hWnd, 0, (POINT *)&client, 2 );
1179 IntersectRect(&rect,&rect,&client);
1180 /* TODO: Wrap the input if needed */
1183 if (lpIMC->cfCompForm.dwStyle == CFS_DEFAULT)
1185 /* make sure we are on the desktop */
1186 mon_info.cbSize = sizeof(mon_info);
1187 GetMonitorInfoW(monitor, &mon_info);
1189 if (rect.bottom > mon_info.rcWork.bottom)
1191 int shift = rect.bottom - mon_info.rcWork.bottom;
1192 rect.top -= shift;
1193 rect.bottom -= shift;
1195 if (rect.left < 0)
1197 rect.right -= rect.left;
1198 rect.left = 0;
1200 if (rect.right > mon_info.rcWork.right)
1202 int shift = rect.right - mon_info.rcWork.right;
1203 rect.left -= shift;
1204 rect.right -= shift;
1208 SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);
1210 TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen);
1212 if (oldfont)
1213 SelectObject(hdc,oldfont);
1216 ImmUnlockIMCC(lpIMC->hCompStr);
1218 EndPaint(hwnd,&ps);
1219 UnlockRealIMC(hIMC);
1222 static void UpdateDefaultIMEWindow(HIMC hIMC, HWND hwnd)
1224 LPCOMPOSITIONSTRING compstr;
1225 LPINPUTCONTEXT lpIMC;
1227 lpIMC = LockRealIMC(hIMC);
1228 if (lpIMC == NULL)
1229 return;
1231 if (lpIMC->hCompStr)
1232 compstr = ImmLockIMCC(lpIMC->hCompStr);
1233 else
1234 compstr = NULL;
1236 if (compstr == NULL || compstr->dwCompStrLen == 0)
1237 ShowWindow(hwnd,SW_HIDE);
1238 else
1240 ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1241 RedrawWindow(hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE);
1244 if (compstr != NULL)
1245 ImmUnlockIMCC(lpIMC->hCompStr);
1247 lpIMC->hWnd = GetFocus();
1248 UnlockRealIMC(hIMC);
1251 static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam)
1253 TRACE("IME message WM_IME_COMPOSITION 0x%lx\n", lParam);
1254 if (lParam & GCS_RESULTSTR)
1256 LPCOMPOSITIONSTRING compstr;
1257 LPBYTE compdata;
1258 LPWSTR ResultStr;
1259 HIMCC newCompStr;
1260 LPINPUTCONTEXT lpIMC;
1262 lpIMC = LockRealIMC(hIMC);
1263 if (lpIMC == NULL)
1264 return;
1266 TRACE("Posting result as IME_CHAR\n");
1267 compdata = ImmLockIMCC(lpIMC->hCompStr);
1268 compstr = (LPCOMPOSITIONSTRING)compdata;
1269 ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1270 GenerateIMECHARMessages(hIMC, ResultStr, compstr->dwResultStrLen);
1271 ImmUnlockIMCC(lpIMC->hCompStr);
1273 /* clear the buffer */
1274 newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
1275 ImmDestroyIMCC(lpIMC->hCompStr);
1276 lpIMC->hCompStr = newCompStr;
1277 UnlockRealIMC(hIMC);
1279 else
1280 UpdateDefaultIMEWindow(hIMC, hwnd);
1283 static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd )
1285 TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1286 UpdateDefaultIMEWindow(hIMC, hwnd);
1289 static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam,
1290 LPARAM lParam)
1292 switch (wParam)
1294 case IMN_OPENSTATUSWINDOW:
1295 FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1296 break;
1297 case IMN_CLOSESTATUSWINDOW:
1298 FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1299 break;
1300 case IMN_OPENCANDIDATE:
1301 FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1302 break;
1303 case IMN_CHANGECANDIDATE:
1304 FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1305 break;
1306 case IMN_CLOSECANDIDATE:
1307 FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1308 break;
1309 case IMN_SETCONVERSIONMODE:
1310 FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1311 break;
1312 case IMN_SETSENTENCEMODE:
1313 FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1314 break;
1315 case IMN_SETOPENSTATUS:
1316 TRACE("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1317 break;
1318 case IMN_SETCANDIDATEPOS:
1319 FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1320 break;
1321 case IMN_SETCOMPOSITIONFONT:
1322 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1323 break;
1324 case IMN_SETCOMPOSITIONWINDOW:
1325 FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1326 break;
1327 case IMN_GUIDELINE:
1328 FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1329 break;
1330 case IMN_SETSTATUSWINDOWPOS:
1331 FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1332 break;
1333 default:
1334 FIXME("WM_IME_NOTIFY:<Unknown 0x%lx>\n",wParam);
1335 break;
1337 return 0;
1340 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
1341 LPARAM lParam)
1343 LRESULT rc = 0;
1344 HIMC hIMC;
1346 TRACE("Incoming Message 0x%x (0x%08lx, 0x%08lx)\n", msg, wParam, lParam);
1349 * Each UI window contains the current Input Context.
1350 * This Input Context can be obtained by calling GetWindowLong
1351 * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message.
1352 * The UI window can refer to this Input Context and handles the
1353 * messages.
1356 hIMC = (HIMC)GetWindowLongPtrW(hwnd,IMMGWL_IMC);
1357 if (!hIMC)
1358 hIMC = RealIMC(FROM_X11);
1360 /* if we have no hIMC there are many messages we cannot process */
1361 if (hIMC == NULL)
1363 switch (msg) {
1364 case WM_IME_STARTCOMPOSITION:
1365 case WM_IME_ENDCOMPOSITION:
1366 case WM_IME_COMPOSITION:
1367 case WM_IME_NOTIFY:
1368 case WM_IME_CONTROL:
1369 case WM_IME_COMPOSITIONFULL:
1370 case WM_IME_SELECT:
1371 case WM_IME_CHAR:
1372 return 0L;
1373 default:
1374 break;
1378 switch(msg)
1380 case WM_CREATE:
1382 LPIMEPRIVATE myPrivate;
1383 LPINPUTCONTEXT lpIMC;
1385 SetWindowTextA(hwnd,"Wine Ime Active");
1387 lpIMC = LockRealIMC(hIMC);
1388 if (lpIMC)
1390 myPrivate = ImmLockIMCC(lpIMC->hPrivate);
1391 myPrivate->hwndDefault = hwnd;
1392 ImmUnlockIMCC(lpIMC->hPrivate);
1394 UnlockRealIMC(hIMC);
1396 return TRUE;
1398 case WM_PAINT:
1399 PaintDefaultIMEWnd(hIMC, hwnd);
1400 return FALSE;
1402 case WM_NCCREATE:
1403 return TRUE;
1405 case WM_SETFOCUS:
1406 if (wParam)
1407 SetFocus((HWND)wParam);
1408 else
1409 FIXME("Received focus, should never have focus\n");
1410 break;
1411 case WM_IME_COMPOSITION:
1412 DefaultIMEComposition(hIMC, hwnd, lParam);
1413 break;
1414 case WM_IME_STARTCOMPOSITION:
1415 DefaultIMEStartComposition(hIMC, hwnd);
1416 break;
1417 case WM_IME_ENDCOMPOSITION:
1418 TRACE("IME message %s, 0x%lx, 0x%lx\n",
1419 "WM_IME_ENDCOMPOSITION", wParam, lParam);
1420 ShowWindow(hwnd,SW_HIDE);
1421 break;
1422 case WM_IME_SELECT:
1423 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_SELECT", wParam, lParam);
1424 break;
1425 case WM_IME_CONTROL:
1426 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_CONTROL", wParam, lParam);
1427 rc = 1;
1428 break;
1429 case WM_IME_NOTIFY:
1430 rc = ImeHandleNotify(hIMC,hwnd,msg,wParam,lParam);
1431 break;
1432 default:
1433 TRACE("Non-standard message 0x%x\n",msg);
1435 /* check the MSIME messages */
1436 if (msg == WM_MSIME_SERVICE)
1438 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_SERVICE", wParam, lParam);
1439 rc = FALSE;
1441 else if (msg == WM_MSIME_RECONVERTOPTIONS)
1443 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTOPTIONS", wParam, lParam);
1445 else if (msg == WM_MSIME_MOUSE)
1447 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_MOUSE", wParam, lParam);
1449 else if (msg == WM_MSIME_RECONVERTREQUEST)
1451 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTREQUEST", wParam, lParam);
1453 else if (msg == WM_MSIME_RECONVERT)
1455 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERT", wParam, lParam);
1457 else if (msg == WM_MSIME_QUERYPOSITION)
1459 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_QUERYPOSITION", wParam, lParam);
1461 else if (msg == WM_MSIME_DOCUMENTFEED)
1463 TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_DOCUMENTFEED", wParam, lParam);
1465 /* DefWndProc if not an IME message */
1466 if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1467 (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
1468 rc = DefWindowProcW(hwnd,msg,wParam,lParam);
1470 return rc;