2 * Functions for further XIM control
4 * Copyright 2003 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
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
38 /* this must match with imm32/imm.c */
39 #define FROM_IME 0xcafe1337
41 BOOL ximInComposeMode=FALSE;
43 typedef struct tagInputContextData
54 static HIMC root_context;
55 static XIMStyle ximStyle = 0;
56 static XIMStyle ximStyleRoot = 0;
58 /* moved here from imm32 for dll separation */
59 static DWORD dwCompStringLength = 0;
60 static LPBYTE CompositionString = NULL;
61 static DWORD dwCompStringSize = 0;
62 static LPBYTE ResultString = NULL;
63 static DWORD dwResultStringSize = 0;
64 static DWORD dwPreeditPos = 0;
66 static HMODULE hImmDll = NULL;
67 static HIMC (WINAPI *pImmAssociateContext)(HWND,HIMC);
68 static HIMC (WINAPI *pImmCreateContext)(void);
69 static VOID (WINAPI *pImmSetOpenStatus)(HIMC,BOOL);
70 static BOOL (WINAPI *pImmSetCompositionString)(HIMC, DWORD, LPWSTR,
71 DWORD, LPWSTR, DWORD);
72 static LONG (WINAPI *pImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD);
73 static VOID (WINAPI *pImmNotifyIME)(HIMC, DWORD, DWORD, DWORD);
75 /* WINE specific messages from the xim in x11drv level */
77 #define STYLE_OFFTHESPOT (XIMPreeditArea | XIMStatusArea)
78 #define STYLE_OVERTHESPOT (XIMPreeditPosition | XIMStatusNothing)
79 #define STYLE_ROOT (XIMPreeditNothing | XIMStatusNothing)
80 /* this uses all the callbacks to utilize full IME support */
81 #define STYLE_CALLBACK (XIMPreeditCallbacks | XIMStatusNothing)
82 /* inorder to enable deadkey support */
83 #define STYLE_NONE (XIMPreeditNothing | XIMStatusNothing)
86 * here are the functions that sort of marshall calls into IMM32.DLL
88 static void LoadImmDll(void)
90 hImmDll = LoadLibraryA("imm32.dll");
92 pImmAssociateContext = (void *)GetProcAddress(hImmDll, "ImmAssociateContext");
93 if (!pImmAssociateContext)
94 WARN("IMM: pImmAssociateContext not found in DLL\n");
96 pImmCreateContext = (void *)GetProcAddress(hImmDll, "ImmCreateContext");
97 if (!pImmCreateContext)
98 WARN("IMM: pImmCreateContext not found in DLL\n");
100 pImmSetOpenStatus = (void *)GetProcAddress( hImmDll, "ImmSetOpenStatus");
101 if (!pImmSetOpenStatus)
102 WARN("IMM: pImmSetOpenStatus not found in DLL\n");
104 pImmSetCompositionString =(void *)GetProcAddress(hImmDll, "ImmSetCompositionStringW");
106 if (!pImmSetCompositionString)
107 WARN("IMM: pImmSetCompositionStringW not found in DLL\n");
109 pImmGetCompositionString =(void *)GetProcAddress(hImmDll, "ImmGetCompositionStringW");
111 if (!pImmGetCompositionString)
112 WARN("IMM: pImmGetCompositionStringW not found in DLL\n");
114 pImmNotifyIME = (void *)GetProcAddress( hImmDll, "ImmNotifyIME");
117 WARN("IMM: pImmNotifyIME not found in DLL\n");
120 static BOOL X11DRV_ImmSetInternalString(DWORD dwIndex, DWORD dwOffset,
121 DWORD selLength, LPWSTR lpComp, DWORD dwCompLen)
123 /* Composition strings are edited in chunks */
124 unsigned int byte_length = dwCompLen * sizeof(WCHAR);
125 unsigned int byte_offset = dwOffset * sizeof(WCHAR);
126 unsigned int byte_selection = selLength * sizeof(WCHAR);
129 TRACE("( %i, %i, %d, %p, %d):\n", dwOffset, selLength, dwIndex, lpComp, dwCompLen );
131 if (dwIndex == GCS_COMPSTR)
137 if ((dwCompLen == 0) && (selLength == 0))
141 /* deletion occurred */
142 else if ((dwCompLen== 0) && (selLength != 0))
144 if (dwCompStringLength)
146 for (i = 0; i < byte_selection; i++)
148 if (byte_offset+byte_selection+i <
151 CompositionString[byte_offset + i] =
152 CompositionString[byte_offset + byte_selection + i];
155 CompositionString[byte_offset + i] = 0;
157 /* clean up the end */
158 dwCompStringLength -= byte_selection;
160 i = dwCompStringLength;
161 while (i < dwCompStringSize)
163 CompositionString[i++] = 0;
169 int byte_expansion = byte_length - byte_selection;
171 if (byte_expansion + dwCompStringLength >= dwCompStringSize)
173 if (CompositionString)
175 HeapReAlloc(GetProcessHeap(), 0,
181 HeapAlloc(GetProcessHeap(), 0, dwCompStringSize +
184 memset(&(CompositionString[dwCompStringSize]), 0,
187 dwCompStringSize += byte_expansion;
190 ptr_new = ((LPBYTE)lpComp);
191 ptr_old = CompositionString + byte_offset + byte_selection;
193 dwCompStringLength += byte_expansion;
195 for (j=0,i = byte_offset; i < dwCompStringSize; i++)
199 CompositionString[i] = ptr_new[j++];
203 if (ptr_old < CompositionString + dwCompStringSize)
205 CompositionString[i] = *ptr_old;
209 CompositionString[i] = 0;
214 if (pImmSetCompositionString)
215 rc = pImmSetCompositionString((HIMC)FROM_IME, SCS_SETSTR,
216 (LPWSTR)CompositionString, dwCompStringLength,
219 else if ((dwIndex == GCS_RESULTSTR) && (lpComp) && (dwCompLen))
221 if (dwResultStringSize)
222 HeapFree(GetProcessHeap(),0,ResultString);
223 dwResultStringSize= byte_length;
224 ResultString= HeapAlloc(GetProcessHeap(),0,byte_length);
225 memcpy(ResultString,lpComp,byte_length);
227 if (pImmSetCompositionString)
228 rc = pImmSetCompositionString((HIMC)FROM_IME, SCS_SETSTR,
229 (LPWSTR)ResultString, dwResultStringSize,
233 pImmNotifyIME((HIMC)FROM_IME, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
239 void X11DRV_XIMLookupChars( const char *str, DWORD count )
245 dwOutput = MultiByteToWideChar(CP_UNIXCP, 0, str, count, wcOutput, sizeof(wcOutput)/sizeof(WCHAR));
247 if (pImmAssociateContext && (focus = GetFocus()))
248 pImmAssociateContext(focus,root_context);
250 X11DRV_ImmSetInternalString(GCS_RESULTSTR,0,0,wcOutput,dwOutput);
253 static void X11DRV_ImmSetOpenStatus(BOOL fOpen)
257 if (dwCompStringSize)
258 HeapFree(GetProcessHeap(),0,CompositionString);
260 dwCompStringSize = 0;
261 dwCompStringLength = 0;
262 CompositionString = NULL;
264 if (dwResultStringSize)
265 HeapFree(GetProcessHeap(),0,ResultString);
267 dwResultStringSize = 0;
271 if (pImmSetOpenStatus)
272 pImmSetOpenStatus((HIMC)FROM_IME,fOpen);
275 static int XIMPreEditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
277 TRACE("PreEditStartCallback %p\n",ic);
278 X11DRV_ImmSetOpenStatus(TRUE);
279 ximInComposeMode = TRUE;
280 SendMessageW(((InputContextData*)root_context)->IMC.hWnd,
281 EM_GETSEL, 0, (LPARAM)&dwPreeditPos);
285 static void XIMPreEditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
287 TRACE("PreeditDoneCallback %p\n",ic);
288 ximInComposeMode = FALSE;
289 X11DRV_ImmSetOpenStatus(FALSE);
293 static void XIMPreEditDrawCallback(XIM ic, XPointer client_data,
294 XIMPreeditDrawCallbackStruct *P_DR)
296 TRACE("PreEditDrawCallback %p\n",ic);
300 int sel = P_DR->chg_first;
301 int len = P_DR->chg_length;
304 if (! P_DR->text->encoding_is_wchar)
309 TRACE("multibyte\n");
310 dwOutput = MultiByteToWideChar(CP_UNIXCP, 0,
311 P_DR->text->string.multi_byte, -1,
313 wcOutput = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * dwOutput);
316 dwOutput = MultiByteToWideChar(CP_UNIXCP, 0,
317 P_DR->text->string.multi_byte, -1,
322 X11DRV_ImmSetInternalString (GCS_COMPSTR, sel, len, wcOutput, dwOutput);
323 HeapFree(GetProcessHeap(), 0, wcOutput);
328 FIXME("wchar PROBIBILY WRONG\n");
329 X11DRV_ImmSetInternalString (GCS_COMPSTR, sel, len,
330 (LPWSTR)P_DR->text->string.wide_char,
335 X11DRV_ImmSetInternalString (GCS_COMPSTR, sel, len, NULL, 0);
340 static void XIMPreEditCaretCallback(XIC ic, XPointer client_data,
341 XIMPreeditCaretCallbackStruct *P_C)
343 TRACE("PreeditCaretCallback %p\n",ic);
347 int pos = pImmGetCompositionString(root_context, GCS_CURSORPOS, NULL, 0);
348 TRACE("pos: %d\n", pos);
349 switch(P_C->direction)
355 case XIMBackwardChar:
356 case XIMBackwardWord:
362 case XIMAbsolutePosition:
370 case XIMPreviousLine:
373 FIXME("Not implemented\n");
376 SendMessageW(((InputContextData*)root_context)->IMC.hWnd,
377 EM_SETSEL, dwPreeditPos + pos, dwPreeditPos + pos);
383 void X11DRV_ForceXIMReset(HWND hwnd)
385 XIC ic = X11DRV_get_ic(hwnd);
389 TRACE("Forcing Reset %p\n",ic);
391 leftover = XmbResetIC(ic);
397 /***********************************************************************
398 * X11DRV Ime creation
400 XIM X11DRV_SetupXIM(Display *display, const char *input_style)
402 XIMStyle ximStyleRequest, ximStyleCallback, ximStyleNone;
403 XIMStyles *ximStyles = NULL;
407 ximStyleRequest = STYLE_CALLBACK;
409 if (!strcasecmp(input_style, "offthespot"))
410 ximStyleRequest = STYLE_OFFTHESPOT;
411 else if (!strcasecmp(input_style, "overthespot"))
412 ximStyleRequest = STYLE_OVERTHESPOT;
413 else if (!strcasecmp(input_style, "root"))
414 ximStyleRequest = STYLE_ROOT;
418 if(!XSupportsLocale())
420 WARN("X does not support locale.\n");
423 if(XSetLocaleModifiers("") == NULL)
425 WARN("Could not set locale modifiers.\n");
429 xim = XOpenIM(display, NULL, NULL, NULL);
432 WARN("Could not open input method.\n");
436 TRACE("X display of IM = %p\n", XDisplayOfIM(xim));
437 TRACE("Using %s locale of Input Method\n", XLocaleOfIM(xim));
439 XGetIMValues(xim, XNQueryInputStyle, &ximStyles, NULL);
442 WARN("Could not find supported input style.\n");
446 TRACE("ximStyles->count_styles = %d\n", ximStyles->count_styles);
450 ximStyleCallback = 0;
452 for (i = 0; i < ximStyles->count_styles; ++i)
454 int style = ximStyles->supported_styles[i];
455 TRACE("ximStyles[%d] = %s%s%s%s%s\n", i,
456 (style&XIMPreeditArea)?"XIMPreeditArea ":"",
457 (style&XIMPreeditCallbacks)?"XIMPreeditCallbacks ":"",
458 (style&XIMPreeditPosition)?"XIMPreeditPosition ":"",
459 (style&XIMPreeditNothing)?"XIMPreeditNothing ":"",
460 (style&XIMPreeditNone)?"XIMPreeditNone ":"");
461 if (!ximStyle && (ximStyles->supported_styles[i] ==
464 ximStyle = ximStyleRequest;
465 TRACE("Setting Style: ximStyle = ximStyleRequest\n");
467 else if (!ximStyleRoot &&(ximStyles->supported_styles[i] ==
470 ximStyleRoot = STYLE_ROOT;
471 TRACE("Setting Style: ximStyleRoot = STYLE_ROOT\n");
473 else if (!ximStyleCallback &&(ximStyles->supported_styles[i] ==
476 ximStyleCallback = STYLE_CALLBACK;
477 TRACE("Setting Style: ximStyleCallback = STYLE_CALLBACK\n");
479 else if (!ximStyleNone && (ximStyles->supported_styles[i] ==
482 TRACE("Setting Style: ximStyleNone = STYLE_NONE\n");
483 ximStyleNone = STYLE_NONE;
489 ximStyle = ximStyleRoot;
492 ximStyle = ximStyleNone;
494 if (ximStyleCallback == 0)
496 TRACE("No callback style avalable\n");
497 ximStyleCallback = ximStyle;
508 if (pImmCreateContext)
510 root_context = pImmCreateContext();
511 if (pImmAssociateContext)
512 pImmAssociateContext(0,root_context);
524 XIC X11DRV_CreateIC(XIM xim, Display *display, Window win)
527 XVaNestedList preedit = NULL;
528 XVaNestedList status = NULL;
530 XIMCallback P_StartCB;
531 XIMCallback P_DoneCB;
532 XIMCallback P_DrawCB;
533 XIMCallback P_CaretCB;
534 LANGID langid = PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale()));
538 /* use complex and slow XIC initialization method only for CJK */
539 if (langid != LANG_CHINESE &&
540 langid != LANG_JAPANESE &&
541 langid != LANG_KOREAN)
544 XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
552 /* create callbacks */
553 P_StartCB.client_data = NULL;
554 P_StartCB.callback = (XIMProc)XIMPreEditStartCallback;
555 P_DoneCB.client_data = NULL;
556 P_DoneCB.callback = (XIMProc)XIMPreEditDoneCallback;
557 P_DrawCB.client_data = NULL;
558 P_DrawCB.callback = (XIMProc)XIMPreEditDrawCallback;
559 P_CaretCB.client_data = NULL;
560 P_CaretCB.callback = (XIMProc)XIMPreEditCaretCallback;
562 if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0)
564 preedit = XVaCreateNestedList(0,
565 XNSpotLocation, &spot,
566 XNPreeditStartCallback, &P_StartCB,
567 XNPreeditDoneCallback, &P_DoneCB,
568 XNPreeditDrawCallback, &P_DrawCB,
569 XNPreeditCaretCallback, &P_CaretCB,
571 TRACE("preedit = %p\n", preedit);
575 preedit = XVaCreateNestedList(0,
576 XNPreeditStartCallback, &P_StartCB,
577 XNPreeditDoneCallback, &P_DoneCB,
578 XNPreeditDrawCallback, &P_DrawCB,
579 XNPreeditCaretCallback, &P_CaretCB,
582 TRACE("preedit = %p\n", preedit);
585 if ((ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0)
587 status = XVaCreateNestedList(0,
589 TRACE("status = %p\n", status);
592 if (preedit != NULL && status != NULL)
595 XNInputStyle, ximStyle,
596 XNPreeditAttributes, preedit,
597 XNStatusAttributes, status,
602 else if (preedit != NULL)
605 XNInputStyle, ximStyle,
606 XNPreeditAttributes, preedit,
611 else if (status != NULL)
614 XNInputStyle, ximStyle,
615 XNStatusAttributes, status,
623 XNInputStyle, ximStyle,
629 TRACE("xic = %p\n", xic);