This patch is intended to implement XIM support in wine. I hope it will support Chinese, Japanese and Korean input method. But as I am Chinese I only tested it with Chinese IM. For this patch is based on the patch of Mike McCormack, which is made for Japanese IM, I think mine will work with Japanese too. But I am not sure whether this one can get along with Korean IMs. If u would like to try it, please give me some suggestions or/and bug reports. This patch implemented features include: One thread only create one connection with XIM server and one IC. Support OVER_THE_SPOT and ROOT IM style. Enable/disable XIM support by editing the config file. The font used in the XIM can be specified in the config file. Some other modifications for convenience purpose. Hope this one helps CJK users. __________________________________________________ Do you Yahoo!? Yahoo! Mail Plus - Powerful. Affordable. Sign up now. http://mailplus.yahoo.com
? patch.diff ? dlls/x11drv/xim.h Index: controls/edit.c =================================================================== RCS file: /home/wine/wine/controls/edit.c,v retrieving revision 1.108 diff -r1.108 edit.c 58a59 > WINE_DECLARE_DEBUG_CHANNEL(xim); 275a277 > extern BOOL XIM_SetIMPos(RECT ); 762a765,777 > case WM_IME_CHAR: > { > WCHAR charW = wParam; > if ((charW == VK_RETURN || charW == VK_ESCAPE) && es->hwndListBox) > { > if (SendMessageW(GetParent(hwnd), CB_GETDROPPEDSTATE, 0, 0)) > SendMessageW(GetParent(hwnd), WM_KEYDOWN, charW, 0); > break; > } > TRACE_(xim)("charW:%d\n",charW); > EDIT_WM_Char(es, charW); > break; > } Index: dlls/kernel/locale.c =================================================================== RCS file: /home/wine/wine/dlls/kernel/locale.c,v retrieving revision 1.5 diff -r1.5 locale.c 51a52 > char charset[128]; 181a183 > char buf_charset[128]; 189a192 > buf_charset[0] = '\0'; 198a202,205 > GetLocaleInfoA(lcid, LOCALE_SCHARSETNAMES | LOCALE_NOUSEROVERRIDE, > buf_charset, sizeof(buf_charset)); > TRACE("LOCALE_SCHARSETNAMES: %s\n", buf_charset); > 204a212 > #if (0) 208a217,258 > #endif > char *p, *q; > > if (l_data->charset != NULL && strlen(l_data->charset) > 0) { > p = buf_charset; > do { > q = p; > if ((p = strchr(p, ',')) != NULL) { > *p++ = '\0'; > } > TRACE("q = 0x%x, %s\n", q, ((q == NULL) ? "" : q)); > if (q != NULL && strcasecmp(l_data->charset, q) == 0) { > l_data->found_lang_id[0] = LangID; > l_data->n_found = 1; > TRACE("Found lang_id %04X for %s_%s.%s\n", LangID, l_data->lang, l_data->country, l_data->charset); > return FALSE; > } > } while (p != NULL); > } else { > p = buf_charset; > do { > q = p; > if ((p = strchr(p, ',')) != NULL) { > *p++ = '\0'; > } > TRACE("q = 0x%x, %s\n", q, ((q == NULL) ? "" : q)); > if (q == NULL || *q == '\0') { > l_data->found_lang_id[0] = LangID; > l_data->n_found = 1; > TRACE("Found lang_id %04X for %s_%s\n", LangID, l_data->lang, l_data->country); > return FALSE; > } > } while (p != NULL); > } > if (l_data->n_found < NLS_MAX_LANGUAGES) { > l_data->found_lang_id[l_data->n_found] = LangID; > strncpy(l_data->found_country[l_data->n_found], buf_country, 3); > strncpy(l_data->found_language[l_data->n_found], buf_language, 3); > l_data->n_found++; > TRACE("Found lang_id %04X for %s_%s\n", LangID, l_data->lang, l_data->country); > return TRUE; > } 267a318,320 > FIXME(" Lang(%s) Country(%s) CharSet(%s) Dialect(%s)\n", > Lang, Country, Charset, Dialect); > 279a333,336 > if (Charset != NULL && strlen(Charset) > 0) { > strncpy(l_data.charset, Charset, sizeof(l_data.charset)); > } > 289a347,355 > if (!l_data.n_found) { > if (l_data.charset != NULL && strlen(l_data.charset) > 0) { > MESSAGE("Warning: Language '%s.%s' was not found, retrying without charset name...\n", lang_string, l_data.charset); > l_data.charset[0] = '\0'; > EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA, > (LPCSTR) LOCALE_ILANGUAGE, find_language_id_proc, (LONG) &l_data); > } > } > 306a373,377 > } > > if (l_data.charset != NULL && strlen(l_data.charset) > 0) { > strcat(lang_string, "."); > strcat(lang_string, l_data.charset); Index: dlls/x11drv/X11_calls =================================================================== RCS file: /home/wine/wine/dlls/x11drv/X11_calls,v retrieving revision 1.1 diff -r1.1 X11_calls 12a13 > XCloseIM 16a18 > XCreateFontSet 19a22 > XDestroyIC 28a32 > XFilterEvent 34a39 > XFreeFontSet 35a41 > XFreeStringList 68a75 > XSetICFocus 80a88,89 > XUnsetICFocus > XmbLookupString Index: dlls/x11drv/event.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/event.c,v retrieving revision 1.15 diff -r1.15 event.c 48a49 > WINE_DECLARE_DEBUG_CHANNEL(xim); 194c195,201 < TRACE( "called.\n" ); --- > if( event->type != KeyPress && event->type != KeyRelease > && TSXFilterEvent(event, None)) > { > TRACE_(xim)("Filtered event: %s(%d) window %08x\n",event_names[event->type], > event->type, (unsigned int)event->xany.window); > return; > } 477a485,489 > XIC xic = NULL; > xic = X11DRV_GetXIC(event->window); > if(xic) > TSXSetICFocus(xic); > Index: dlls/x11drv/keyboard.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/keyboard.c,v retrieving revision 1.15 diff -r1.15 keyboard.c 41a42 > #include "heap.h" 51a53 > WINE_DECLARE_DEBUG_CHANNEL(xim); 63a66 > extern Window root_window; 941a945,1062 > #define NALLOC 64 > static BOOL XIM_KeyEvent(HWND hwnd, XKeyEvent *event) > { > static BOOL updatedXIMPos = 0; > BOOL done = FALSE; > Window orgWindow = event->window; > struct x11drv_thread_data *data = NtCurrentTeb()->driver_data; > > TRACE_(xim)("hwnd %04x root_window(%08lx)\n", (unsigned int) hwnd, root_window); > > event->window = root_window; > if (!data->xim) > done = FALSE; /* No input method defined */ > else if (TSXFilterEvent((XEvent *) event, None)) > { > TRACE_(xim)("Filtered.\n"); > if (!updatedXIMPos){ > XIC xic = X11DRV_GetXIC(root_window); > POINT p; > XVaNestedList preedit_attr; > GetCaretPos(&p); > ClientToScreen(hwnd, &p); > XPoint spot; > spot.x = p.x; > spot.y = p.y; > spot.y += 25; //FIXME: How to get the caret's height > preedit_attr = XVaCreateNestedList(0, > XNSpotLocation, &spot, > NULL); > XSetICValues(xic,XNPreeditAttributes,preedit_attr,NULL); > /* use this variable to check whether we need to update XIM position */ > updatedXIMPos = 1; > } > done = TRUE; > } > else if (event->type == KeyPress) > { > XIC xic; > KeySym keysym; > Status status; > int i, nbyte; > DWORD dwOutput; > WCHAR wcOutput[NALLOC]; > LPSTR bytes; > DWORD nalloc = NALLOC; > Window w = root_window; > > updatedXIMPos = 0; > if ((xic = X11DRV_GetXIC(w)) == NULL) > { > WARN_(xim)("Unable tp retrieve input context\n"); > return FALSE; > } > > bytes = HeapAlloc(GetProcessHeap(),0,NALLOC); > > nbyte = TSXmbLookupString(xic, event, bytes, nalloc, &keysym, &status); > TRACE_(xim)("nbyte = %d, status = 0x%x\n", nbyte, status); > > if (status == XBufferOverflow) > { > nalloc = nbyte; > bytes = HeapReAlloc(GetProcessHeap(), 0, bytes, nbyte); > nbyte = TSXmbLookupString(xic, event, bytes, nalloc, &keysym, &status); > TRACE_(xim)("nbyte = %d, status = 0x%x\n", nbyte, status); > } > > switch (status) > { > case XLookupBoth: > if (keysym < 128 || (keysym & 0xff00) == 0xff00) > { > TRACE_(xim)("keysym = 0x%x\n", (int)keysym); > break; /* Leave to the default handler */ > } > /* fall through */ > case XLookupChars: > { > INT codepage = GetACP(); > if (codepage == 932) > { > /* > * Japanese is encoded with windows as SJIS (932) however > * Under unix we use EUS (20932) So we need to translate > * the input as 20932... > */ > dwOutput = MultiByteToWideChar(20932, > 0, bytes, nbyte, wcOutput, sizeof(wcOutput)); > } > else > dwOutput = MultiByteToWideChar(codepage, > 0, bytes, nbyte, wcOutput, sizeof(wcOutput)); > > for(i=0; i<dwOutput; i++) > { > TRACE_(xim)("sending wchar %04x\n", wcOutput[i]); > PostMessageW(hwnd, WM_IME_CHAR, wcOutput[i], 1); > } > done = True; > break; > } > > case XLookupKeySym: > TRACE_(xim)("XLookupKeySym\n"); > break; /* Leave to the default handler */ > > case XLookupNone: > TRACE_(xim)("XLookupNone\n"); > done = True; /* No further processing is necessary */ > break; > } > > HeapFree(GetProcessHeap(),0,bytes); > } > event->window = orgWindow; > return done; > } > 955a1077,1080 > > /* forward to XIM */ > if(XIM_KeyEvent(GetFocus(), event) && event->type == KeyPress) > return; Index: dlls/x11drv/ts_xlib.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/ts_xlib.c,v retrieving revision 1.1 diff -r1.1 ts_xlib.c 11a12 > #include <X11/Xutil.h> 672a674,689 > XFontSet TSXCreateFontSet(Display* a0, const char* a1, char*** a2, int* a3, char** a4) > { > XFontSet r; > wine_tsx11_lock(); > r = XCreateFontSet(a0, a1, a2, a3, a4); > wine_tsx11_unlock(); > return r; > } > > void TSXFreeFontSet(Display* a0, XFontSet a1) > { > wine_tsx11_lock(); > XFreeFontSet(a0, a1); > wine_tsx11_unlock(); > } > 679a697,737 > } > > int TSXCloseIM(XIM a0) > { > int r; > wine_tsx11_lock(); > r = XCloseIM(a0); > wine_tsx11_unlock(); > return r; > } > > void TSXSetICFocus(XIC a0) > { > wine_tsx11_lock(); > XSetICFocus(a0); > wine_tsx11_unlock(); > } > > void TSXUnsetICFocus(XIC a0) > { > wine_tsx11_lock(); > XUnsetICFocus(a0); > wine_tsx11_unlock(); > } > > int TSXFilterEvent(XEvent* a0, Window a1) > { > int r; > wine_tsx11_lock(); > r = XFilterEvent(a0, a1); > wine_tsx11_unlock(); > return r; > } > > int TSXmbLookupString(XIC a0, XKeyPressedEvent* a1, char* a2, int a3, KeySym* a4, int * a5) > { > int r; > wine_tsx11_lock(); > r = XmbLookupString(a0, a1, a2, a3, a4, a5); > wine_tsx11_unlock(); > return r; Index: dlls/x11drv/ts_xlib.h =================================================================== RCS file: /home/wine/wine/dlls/x11drv/ts_xlib.h,v retrieving revision 1.1 diff -r1.1 ts_xlib.h 30a31,32 > //xim added > //extern void TSXFreeStringList(char**); 94a97,100 > //xim added > extern XFontSet TSXCreateFontSet(Display*, const char*, char***, int*, char**); > extern void TSXFreeFontSet(Display*, XFontSet); > 95a102,107 > //xim added > extern int TSXCloseIM(XIM); > extern void TSXSetICFocus(XIC); > extern void TSXUnsetICFocus(XIC); > extern int TSXFilterEvent(XEvent*, Window); > extern int TSXmbLookupString(XIC, XKeyPressedEvent*, char*, int, KeySym*, int *); Index: dlls/x11drv/window.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/window.c,v retrieving revision 1.46 diff -r1.46 window.c 42a43,44 > #include "xim.h" > 43a46 > WINE_DECLARE_DEBUG_CHANNEL(xim); 52a56,58 > XContext ximContext = 0; > > extern Window root_window; 98a105,118 > } > > //xim added > XIC X11DRV_GetXIC(Window w) > { > > XIC xic = NULL; > > if (ximContext != 0 ){ > wine_tsx11_lock(); > XFindContext(thread_display(), root_window , ximContext, (XPointer *) &xic); > wine_tsx11_unlock(); > } > return xic; Index: documentation/samples/config =================================================================== RCS file: /home/wine/wine/documentation/samples/config,v retrieving revision 1.37 diff -r1.37 config 179a180,186 > [InputMethod] > ; Use XIM Input Method > "UseXIM" = "Y" > ; XIM Input Style : "overthespot" or "offthespot" or "root" (default). > "InputStyle" = "overthespot" > "XIMFontSet" = "-adobe-helvetica-medium-r-normal--16-*-*-*-*-*-*-*,-*-*-medium-r-normal--18-*-*-*-*-*-gb2312.1980-0,*-r-*" > Index: include/winnls.h =================================================================== RCS file: /home/wine/wine/include/winnls.h,v retrieving revision 1.37 diff -r1.37 winnls.h 147a148,149 > //xim added > #define LOCALE_SCHARSETNAMES 0x00001015 Index: include/x11drv.h =================================================================== RCS file: /home/wine/wine/include/x11drv.h,v retrieving revision 1.118 diff -r1.118 x11drv.h 101a102,105 > //xim added > extern XIMStyle ximStyle; > extern XFontSet ximFontSet; > extern XIC X11DRV_GetXIC(Window w); 339a344 > XIM xim; --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ dlls/x11drv/xim.h 2002-12-13 11:40:39.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * xim.h + * define some constant used in XIM + * + * Copyright 2002 liuspider + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#if !defined(__WINE_XIM_H) + +#define __WINE_XIM_H + +#define STYLE_OFFTHESPOT (XIMPreeditArea | XIMStatusArea) +#define STYLE_OVERTHESPOT (XIMPreeditPosition | XIMStatusNothing) +#define STYLE_ROOT (XIMPreeditNothing | XIMStatusNothing) +#define STYLE_NONE (XIMPreeditNone | XIMStatusNone) + +#endif /* !defined(__WINE_XIM_H) */