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;
65 static HMODULE hImmDll = NULL;
66 static HIMC (WINAPI *pImmAssociateContext)(HWND,HIMC);
67 static HIMC (WINAPI *pImmCreateContext)(void);
68 static VOID (WINAPI *pImmSetOpenStatus)(HIMC,BOOL);
69 static BOOL (WINAPI *pImmSetCompositionString)(HIMC, DWORD, LPWSTR,
70 DWORD, LPWSTR, DWORD);
71 static LONG (WINAPI *pImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD);
72 static VOID (WINAPI *pImmNotifyIME)(HIMC, DWORD, DWORD, DWORD);
74 /* WINE specific messages from the xim in x11drv level */
76 #define STYLE_OFFTHESPOT (XIMPreeditArea | XIMStatusArea)
77 #define STYLE_OVERTHESPOT (XIMPreeditPosition | XIMStatusNothing)
78 #define STYLE_ROOT (XIMPreeditNothing | XIMStatusNothing)
79 /* this uses all the callbacks to utilize full IME support */
80 #define STYLE_CALLBACK (XIMPreeditCallbacks | XIMStatusNothing)
81 /* inorder to enable deadkey support */
82 #define STYLE_NONE (XIMPreeditNothing | XIMStatusNothing)
85 * here are the functions that sort of marshall calls into IMM32.DLL
87 static void LoadImmDll(void)
89 hImmDll = LoadLibraryA("imm32.dll");
91 pImmAssociateContext = (void *)GetProcAddress(hImmDll, "ImmAssociateContext");
92 if (!pImmAssociateContext)
93 WARN("IMM: pImmAssociateContext not found in DLL\n");
95 pImmCreateContext = (void *)GetProcAddress(hImmDll, "ImmCreateContext");
96 if (!pImmCreateContext)
97 WARN("IMM: pImmCreateContext not found in DLL\n");
99 pImmSetOpenStatus = (void *)GetProcAddress( hImmDll, "ImmSetOpenStatus");
100 if (!pImmSetOpenStatus)
101 WARN("IMM: pImmSetOpenStatus not found in DLL\n");
103 pImmSetCompositionString =(void *)GetProcAddress(hImmDll, "ImmSetCompositionStringW");
105 if (!pImmSetCompositionString)
106 WARN("IMM: pImmSetCompositionStringW not found in DLL\n");
108 pImmGetCompositionString =(void *)GetProcAddress(hImmDll, "ImmGetCompositionStringW");
110 if (!pImmGetCompositionString)
111 WARN("IMM: pImmGetCompositionStringW not found in DLL\n");
113 pImmNotifyIME = (void *)GetProcAddress( hImmDll, "ImmNotifyIME");
116 WARN("IMM: pImmNotifyIME not found in DLL\n");
119 static BOOL X11DRV_ImmSetInternalString(DWORD dwIndex, DWORD dwOffset,
120 DWORD selLength, LPWSTR lpComp, DWORD dwCompLen)
122 /* Composition strings are edited in chunks */
123 unsigned int byte_length = dwCompLen * sizeof(WCHAR);
124 unsigned int byte_offset = dwOffset * sizeof(WCHAR);
125 unsigned int byte_selection = selLength * sizeof(WCHAR);
128 TRACE("( %i, %i, %d, %p, %d):\n", dwOffset, selLength, dwIndex, lpComp, dwCompLen );
130 if (dwIndex == GCS_COMPSTR)
136 if ((dwCompLen == 0) && (selLength == 0))
140 /* deletion occurred */
141 else if ((dwCompLen== 0) && (selLength != 0))
143 if (dwCompStringLength)
145 for (i = 0; i < byte_selection; i++)
147 if (byte_offset+byte_selection+i <
150 CompositionString[byte_offset + i] =
151 CompositionString[byte_offset + byte_selection + i];
154 CompositionString[byte_offset + i] = 0;
156 /* clean up the end */
157 dwCompStringLength -= byte_selection;
159 i = dwCompStringLength;
160 while (i < dwCompStringSize)
162 CompositionString[i++] = 0;
168 int byte_expansion = byte_length - byte_selection;
170 if (byte_expansion + dwCompStringLength >= dwCompStringSize)
172 if (CompositionString)
174 HeapReAlloc(GetProcessHeap(), 0,
180 HeapAlloc(GetProcessHeap(), 0, dwCompStringSize +
183 memset(&(CompositionString[dwCompStringSize]), 0,
186 dwCompStringSize += byte_expansion;
189 ptr_new = ((LPBYTE)lpComp);
190 ptr_old = CompositionString + byte_offset + byte_selection;
192 dwCompStringLength += byte_expansion;
194 for (j=0,i = byte_offset; i < dwCompStringSize; i++)
198 CompositionString[i] = ptr_new[j++];
202 if (ptr_old < CompositionString + dwCompStringSize)
204 CompositionString[i] = *ptr_old;
208 CompositionString[i] = 0;
213 if (pImmSetCompositionString)
214 rc = pImmSetCompositionString((HIMC)FROM_IME, SCS_SETSTR,
215 (LPWSTR)CompositionString, dwCompStringLength,
218 else if ((dwIndex == GCS_RESULTSTR) && (lpComp) && (dwCompLen))
220 if (dwResultStringSize)
221 HeapFree(GetProcessHeap(),0,ResultString);
222 dwResultStringSize= byte_length;
223 ResultString= HeapAlloc(GetProcessHeap(),0,byte_length);
224 memcpy(ResultString,lpComp,byte_length);
226 if (pImmSetCompositionString)
227 rc = pImmSetCompositionString((HIMC)FROM_IME, SCS_SETSTR,
228 (LPWSTR)ResultString, dwResultStringSize,
232 pImmNotifyIME((HIMC)FROM_IME, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
238 void X11DRV_XIMLookupChars( const char *str, DWORD count )
244 dwOutput = MultiByteToWideChar(CP_UNIXCP, 0, str, count, wcOutput, sizeof(wcOutput)/sizeof(WCHAR));
246 if (pImmAssociateContext && (focus = GetFocus()))
247 pImmAssociateContext(focus,root_context);
249 X11DRV_ImmSetInternalString(GCS_RESULTSTR,0,0,wcOutput,dwOutput);
252 static void X11DRV_ImmSetOpenStatus(BOOL fOpen)
256 if (dwCompStringSize)
257 HeapFree(GetProcessHeap(),0,CompositionString);
259 dwCompStringSize = 0;
260 dwCompStringLength = 0;
261 CompositionString = NULL;
263 if (dwResultStringSize)
264 HeapFree(GetProcessHeap(),0,ResultString);
266 dwResultStringSize = 0;
270 if (pImmSetOpenStatus)
271 pImmSetOpenStatus((HIMC)FROM_IME,fOpen);
274 static int XIMPreEditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
276 TRACE("PreEditStartCallback %p\n",ic);
277 X11DRV_ImmSetOpenStatus(TRUE);
278 ximInComposeMode = TRUE;
282 static void XIMPreEditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
284 TRACE("PreeditDoneCallback %p\n",ic);
285 ximInComposeMode = FALSE;
286 X11DRV_ImmSetOpenStatus(FALSE);
289 static void XIMPreEditDrawCallback(XIM ic, XPointer client_data,
290 XIMPreeditDrawCallbackStruct *P_DR)
295 TRACE("PreEditDrawCallback %p\n",ic);
299 int sel = P_DR->chg_first;
300 int len = P_DR->chg_length;
303 if (! P_DR->text->encoding_is_wchar)
305 TRACE("multibyte\n");
306 dwOutput = MultiByteToWideChar(CP_UNIXCP, 0,
307 P_DR->text->string.multi_byte, -1,
312 X11DRV_ImmSetInternalString (GCS_COMPSTR, sel, len, wcOutput, dwOutput);
316 FIXME("wchar PROBIBILY WRONG\n");
317 X11DRV_ImmSetInternalString (GCS_COMPSTR, sel, len,
318 (LPWSTR)P_DR->text->string.wide_char,
323 X11DRV_ImmSetInternalString (GCS_COMPSTR, sel, len, NULL, 0);
328 static void XIMPreEditCaretCallback(XIC ic, XPointer client_data,
329 XIMPreeditCaretCallbackStruct *P_C)
331 TRACE("PreeditCaretCallback %p\n",ic);
335 int pos = pImmGetCompositionString(root_context, GCS_CURSORPOS, NULL, 0);
336 TRACE("pos: %d\n", pos);
337 switch(P_C->direction)
343 case XIMBackwardChar:
344 case XIMBackwardWord:
350 case XIMAbsolutePosition:
358 case XIMPreviousLine:
361 FIXME("Not implemented\n");
364 SendMessageW(((InputContextData*)root_context)->IMC.hWnd,
365 EM_SETSEL, pos, pos);
371 void X11DRV_ForceXIMReset(HWND hwnd)
373 XIC ic = X11DRV_get_ic(hwnd);
377 TRACE("Forcing Reset %p\n",ic);
379 leftover = XmbResetIC(ic);
385 /***********************************************************************
386 * X11DRV Ime creation
388 XIM X11DRV_SetupXIM(Display *display, const char *input_style)
390 XIMStyle ximStyleRequest, ximStyleCallback, ximStyleNone;
391 XIMStyles *ximStyles = NULL;
395 ximStyleRequest = STYLE_CALLBACK;
397 if (!strcasecmp(input_style, "offthespot"))
398 ximStyleRequest = STYLE_OFFTHESPOT;
399 else if (!strcasecmp(input_style, "overthespot"))
400 ximStyleRequest = STYLE_OVERTHESPOT;
401 else if (!strcasecmp(input_style, "root"))
402 ximStyleRequest = STYLE_ROOT;
406 if(!XSupportsLocale())
408 WARN("X does not support locale.\n");
411 if(XSetLocaleModifiers("") == NULL)
413 WARN("Could not set locale modifiers.\n");
417 xim = XOpenIM(display, NULL, NULL, NULL);
420 WARN("Could not open input method.\n");
424 TRACE("X display of IM = %p\n", XDisplayOfIM(xim));
425 TRACE("Using %s locale of Input Method\n", XLocaleOfIM(xim));
427 XGetIMValues(xim, XNQueryInputStyle, &ximStyles, NULL);
430 WARN("Could not find supported input style.\n");
434 TRACE("ximStyles->count_styles = %d\n", ximStyles->count_styles);
438 ximStyleCallback = 0;
440 for (i = 0; i < ximStyles->count_styles; ++i)
442 int style = ximStyles->supported_styles[i];
443 TRACE("ximStyles[%d] = %s%s%s%s%s\n", i,
444 (style&XIMPreeditArea)?"XIMPreeditArea ":"",
445 (style&XIMPreeditCallbacks)?"XIMPreeditCallbacks ":"",
446 (style&XIMPreeditPosition)?"XIMPreeditPosition ":"",
447 (style&XIMPreeditNothing)?"XIMPreeditNothing ":"",
448 (style&XIMPreeditNone)?"XIMPreeditNone ":"");
449 if (!ximStyle && (ximStyles->supported_styles[i] ==
452 ximStyle = ximStyleRequest;
453 TRACE("Setting Style: ximStyle = ximStyleRequest\n");
455 else if (!ximStyleRoot &&(ximStyles->supported_styles[i] ==
458 ximStyleRoot = STYLE_ROOT;
459 TRACE("Setting Style: ximStyleRoot = STYLE_ROOT\n");
461 else if (!ximStyleCallback &&(ximStyles->supported_styles[i] ==
464 ximStyleCallback = STYLE_CALLBACK;
465 TRACE("Setting Style: ximStyleCallback = STYLE_CALLBACK\n");
467 else if (!ximStyleNone && (ximStyles->supported_styles[i] ==
470 TRACE("Setting Style: ximStyleNone = STYLE_NONE\n");
471 ximStyleNone = STYLE_NONE;
477 ximStyle = ximStyleRoot;
480 ximStyle = ximStyleNone;
482 if (ximStyleCallback == 0)
484 TRACE("No callback style avalable\n");
485 ximStyleCallback = ximStyle;
496 if (pImmCreateContext)
498 root_context = pImmCreateContext();
499 if (pImmAssociateContext)
500 pImmAssociateContext(0,root_context);
512 XIC X11DRV_CreateIC(XIM xim, Display *display, Window win)
515 XVaNestedList preedit = NULL;
516 XVaNestedList status = NULL;
518 XIMCallback P_StartCB;
519 XIMCallback P_DoneCB;
520 XIMCallback P_DrawCB;
521 XIMCallback P_CaretCB;
522 LANGID langid = PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale()));
526 /* use complex and slow XIC initialization method only for CJK */
527 if (langid != LANG_CHINESE &&
528 langid != LANG_JAPANESE &&
529 langid != LANG_KOREAN)
532 XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
540 /* create callbacks */
541 P_StartCB.client_data = NULL;
542 P_StartCB.callback = (XIMProc)XIMPreEditStartCallback;
543 P_DoneCB.client_data = NULL;
544 P_DoneCB.callback = (XIMProc)XIMPreEditDoneCallback;
545 P_DrawCB.client_data = NULL;
546 P_DrawCB.callback = (XIMProc)XIMPreEditDrawCallback;
547 P_CaretCB.client_data = NULL;
548 P_CaretCB.callback = (XIMProc)XIMPreEditCaretCallback;
550 if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0)
552 preedit = XVaCreateNestedList(0,
553 XNSpotLocation, &spot,
554 XNPreeditStartCallback, &P_StartCB,
555 XNPreeditDoneCallback, &P_DoneCB,
556 XNPreeditDrawCallback, &P_DrawCB,
557 XNPreeditCaretCallback, &P_CaretCB,
559 TRACE("preedit = %p\n", preedit);
563 preedit = XVaCreateNestedList(0,
564 XNPreeditStartCallback, &P_StartCB,
565 XNPreeditDoneCallback, &P_DoneCB,
566 XNPreeditDrawCallback, &P_DrawCB,
567 XNPreeditCaretCallback, &P_CaretCB,
570 TRACE("preedit = %p\n", preedit);
573 if ((ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0)
575 status = XVaCreateNestedList(0,
577 TRACE("status = %p\n", status);
580 if (preedit != NULL && status != NULL)
583 XNInputStyle, ximStyle,
584 XNPreeditAttributes, preedit,
585 XNStatusAttributes, status,
590 else if (preedit != NULL)
593 XNInputStyle, ximStyle,
594 XNPreeditAttributes, preedit,
599 else if (status != NULL)
602 XNInputStyle, ximStyle,
603 XNStatusAttributes, status,
611 XNInputStyle, ximStyle,
617 TRACE("xic = %p\n", xic);