From 739d4321a3b8dd6e1073ecb19aa5b09eb5893571 Mon Sep 17 00:00:00 2001 From: hobbs Date: Fri, 30 Mar 2001 23:50:17 +0000 Subject: * win/makefile.vc: * win/configure: * win/tcl.m4: added imm32.lib to LIBS_GUI for Tk IME support. * win/tkWinInt.h: * win/tkWinKey.c: * win/tkWinX.c: added support for changing IME on the fly in Windows (2000). (lam) [Patch #402993] --- ChangeLog | 24 ++++++ win/configure | 2 +- win/makefile.vc | 5 +- win/tcl.m4 | 2 +- win/tkWinInt.h | 4 +- win/tkWinKey.c | 29 +++++-- win/tkWinX.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 288 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index c282062..829de88 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2001-03-30 Jeff Hobbs + + * win/makefile.vc: + * win/configure: + * win/tcl.m4: added imm32.lib to LIBS_GUI for Tk IME support. + * win/tkWinInt.h: + * win/tkWinKey.c: + * win/tkWinX.c: added support for changing IME on the fly in + Windows (2000). (lam) [Patch #402993] + + * tests/bind.test (bind-22.18): + * generic/tkBind.c (NameToWindow): handled the error case where a + valid-looking but invalid identifier could be passed in certain + event generate options causing a crash. [Bug #411307] + + * win/tkWinWm.c (UpdateWrapper): ensured that the passed in winPtr + had an existent window to operate on. [Bug #409172] + + * win/Makefile.in (install-*): improved install-* targets to use + their base build dependency. + + * generic/tkImage.c (Tk_ImageObjCmd, EventuallyDeleteImage): + added casts to allow compiling on Windows with debbuging. + 2001-03-29 Jeff Hobbs * library/msgs/de.msg: fixed translations. [Patch #403525] diff --git a/win/configure b/win/configure index dcfce43..ecaed2e 100755 --- a/win/configure +++ b/win/configure @@ -1234,7 +1234,7 @@ echo "configure:1192: checking whether $ld_prog supports -shared option" >&5 SHLIB_LD="link -dll -nologo" SHLIB_LD_LIBS="user32.lib advapi32.lib" LIBS="user32.lib advapi32.lib" - LIBS_GUI="gdi32.lib comdlg32.lib" + LIBS_GUI="gdi32.lib comdlg32.lib imm32.lib" AR="lib -nologo" STLIB_LD="lib -nologo" RC="rc" diff --git a/win/makefile.vc b/win/makefile.vc index 3171c87..2c4ebd6 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -6,7 +6,7 @@ # Copyright (c) 1995-1997 Sun Microsystems, Inc. # Copyright (c) 1998-2000 Ajuba Solutions. # -# RCS: @(#) $Id: makefile.vc,v 1.39 2000/11/03 01:16:30 hobbs Exp $ +# RCS: @(#) $Id: makefile.vc,v 1.40 2001/03/30 23:50:17 hobbs Exp $ # Does not depend on the presence of any environment variables in # order to compile tcl; all needed information is derived from @@ -317,7 +317,8 @@ libcdll = msvcrt$(DBGX).lib oldnames.lib !ENDIF baselibs = kernel32.lib $(optlibs) advapi32.lib -winlibs = $(baselibs) user32.lib gdi32.lib comdlg32.lib winspool.lib +winlibs = $(baselibs) user32.lib gdi32.lib comdlg32.lib winspool.lib \ + imm32.lib guilibs = $(libc) $(winlibs) conlibs = $(libc) $(baselibs) guilibsdll = $(libcdll) $(winlibs) diff --git a/win/tcl.m4 b/win/tcl.m4 index 29e64fc..e25a999 100644 --- a/win/tcl.m4 +++ b/win/tcl.m4 @@ -444,7 +444,7 @@ AC_DEFUN(SC_CONFIG_CFLAGS, [ SHLIB_LD="link -dll -nologo" SHLIB_LD_LIBS="user32.lib advapi32.lib" LIBS="user32.lib advapi32.lib" - LIBS_GUI="gdi32.lib comdlg32.lib" + LIBS_GUI="gdi32.lib comdlg32.lib imm32.lib" AR="lib -nologo" STLIB_LD="lib -nologo" RC="rc" diff --git a/win/tkWinInt.h b/win/tkWinInt.h index 710779a..57eef8d 100644 --- a/win/tkWinInt.h +++ b/win/tkWinInt.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinInt.h,v 1.10 2000/04/12 18:51:11 hobbs Exp $ + * RCS: @(#) $Id: tkWinInt.h,v 1.11 2001/03/30 23:50:17 hobbs Exp $ */ #ifndef _TKWININT @@ -167,5 +167,7 @@ EXTERN void TkWinUpdatingClipboard(int mode); #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT +extern Tcl_Encoding TkWinGetKeyInputEncoding _ANSI_ARGS_((void)); + #endif /* _TKWININT */ diff --git a/win/tkWinKey.c b/win/tkWinKey.c index bb61d23..e2b67dd 100644 --- a/win/tkWinKey.c +++ b/win/tkWinKey.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinKey.c,v 1.12 2000/04/15 17:41:20 hobbs Exp $ + * RCS: @(#) $Id: tkWinKey.c,v 1.13 2001/03/30 23:50:17 hobbs Exp $ */ #include "tkWinInt.h" @@ -90,7 +90,29 @@ TkpGetString(winPtr, eventPtr, dsPtr) XKeyEvent* keyEv = &eventPtr->xkey; Tcl_DStringInit(dsPtr); - if (eventPtr->xkey.send_event != -1) { + if (eventPtr->xkey.send_event == -1) { + if (eventPtr->xkey.nbytes > 0) { + Tcl_ExternalToUtfDString(TkWinGetKeyInputEncoding(), + eventPtr->xkey.trans_chars, eventPtr->xkey.nbytes, dsPtr); + } + } else if (eventPtr->xkey.send_event == -2) { + /* + * Special case for win2000 multi-lingal IME input. + * xkey.trans_chars[] already contains a UNICODE char. + */ + + int unichar; + char buf[TCL_UTF_MAX]; + int len; + + unichar = (eventPtr->xkey.trans_chars[1] & 0xff); + unichar <<= 8; + unichar |= (eventPtr->xkey.trans_chars[0] & 0xff); + + len = Tcl_UniCharToUtf((Tcl_UniChar) unichar, buf); + + Tcl_DStringAppend(dsPtr, buf, len); + } else { /* * This is an event generated from generic code. It has no * nchars or trans_chars members. @@ -105,9 +127,6 @@ TkpGetString(winPtr, eventPtr, dsPtr) int len = Tcl_UniCharToUtf((Tcl_UniChar) (keysym & 255), buf); Tcl_DStringAppend(dsPtr, buf, len); } - } else if (eventPtr->xkey.nbytes > 0) { - Tcl_ExternalToUtfDString(NULL, eventPtr->xkey.trans_chars, - eventPtr->xkey.nbytes, dsPtr); } return Tcl_DStringValue(dsPtr); } diff --git a/win/tkWinX.c b/win/tkWinX.c index 0325df7..1b2c0e7 100644 --- a/win/tkWinX.c +++ b/win/tkWinX.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinX.c,v 1.11 2000/07/06 03:17:45 mo Exp $ + * RCS: @(#) $Id: tkWinX.c,v 1.12 2001/03/30 23:50:18 hobbs Exp $ */ #include "tkWinInt.h" @@ -30,6 +30,10 @@ static HINSTANCE tkInstance; /* Application instance handle. */ static int childClassInitialized; /* Registered child class? */ static WNDCLASS childClass; /* Window class for child windows. */ static int tkPlatformId; /* version of Windows platform */ +static Tcl_Encoding keyInputEncoding = NULL;/* The current character + * encoding for keyboard input */ +static int keyInputCharset = -1; /* The Win32 CHARSET for the keyboard + * encoding */ /* * Thread local storage. Notice that now each thread must have its @@ -52,6 +56,9 @@ static void GenerateXEvent _ANSI_ARGS_((HWND hwnd, UINT message, static unsigned int GetState _ANSI_ARGS_((UINT message, WPARAM wParam, LPARAM lParam)); static void GetTranslatedKey _ANSI_ARGS_((XKeyEvent *xkey)); +static void UpdateInputLanguage _ANSI_ARGS_((int charset)); +static int HandleIMEComposition _ANSI_ARGS_((HWND hwnd, + LPARAM lParam)); /* *---------------------------------------------------------------------- @@ -524,6 +531,18 @@ TkWinChildProc(hwnd, message, wParam, lParam) LRESULT result; switch (message) { + case WM_INPUTLANGCHANGE: + UpdateInputLanguage(wParam); + result = 1; + break; + + case WM_IME_COMPOSITION: + result = 0; + if (HandleIMEComposition(hwnd, lParam) == 0) { + result = DefWindowProc(hwnd, message, wParam, lParam); + } + break; + case WM_SETCURSOR: /* * Short circuit the WM_SETCURSOR message since we set @@ -826,13 +845,11 @@ GenerateXEvent(hwnd, message, wParam, lParam) /* * Check for translated characters in the event queue. * Setting xany.send_event to -1 indicates to the - * Windows implementation of XLookupString that this + * Windows implementation of TkpGetString() that this * event was generated by windows and that the Windows * extension xkey.trans_chars is filled with the - * characters that came from the TranslateMessage - * call. If it is not -1, xkey.keycode is the - * virtual key being sent programmatically by generic - * code. + * MBCS characters that came from the TranslateMessage + * call. */ event.type = KeyPress; @@ -1017,7 +1034,6 @@ GetTranslatedKey(xkey) XKeyEvent *xkey; { MSG msg; - char buf[XMaxTransChars]; xkey->nbytes = 0; @@ -1037,9 +1053,21 @@ GetTranslatedKey(xkey) if ((msg.message == WM_CHAR) && (msg.lParam & 0x20000000)) { xkey->state = 0; } - buf[xkey->nbytes] = (char) msg.wParam; xkey->trans_chars[xkey->nbytes] = (char) msg.wParam; xkey->nbytes++; + + if (((unsigned short) msg.wParam) > ((unsigned short) 0xff)) { + /* + * Some "addon" input devices, such as the popular + * PenPower Chinese writing pad, generate 16 bit + * values in WM_CHAR messages (instead of passing them + * in two separate WM_CHAR messages containing two + * 8-bit values. + */ + + xkey->trans_chars[xkey->nbytes] = (char) (msg.wParam >> 8); + xkey->nbytes ++; + } } else { break; } @@ -1049,6 +1077,202 @@ GetTranslatedKey(xkey) /* *---------------------------------------------------------------------- * + * UpdateInputLanguage -- + * + * Gets called when a WM_INPUTLANGCHANGE message is received + * by the TK child window procedure. This message is sent + * by the Input Method Editor system when the user chooses + * a different input method. All subsequent WM_CHAR + * messages will contain characters in the new encoding. We record + * the new encoding so that TkpGetString() knows how to + * correctly translate the WM_CHAR into unicode. + * + * Results: + * Records the new encoding in keyInputEncoding. + * + * Side effects: + * Old value of keyInputEncoding is freed. + * + *---------------------------------------------------------------------- + */ + +static void +UpdateInputLanguage(charset) + int charset; +{ + CHARSETINFO charsetInfo; + Tcl_Encoding encoding; + char codepage[4 + TCL_INTEGER_SPACE]; + + if (keyInputCharset == charset) { + return; + } + if (TranslateCharsetInfo((DWORD*)charset, &charsetInfo, TCI_SRCCHARSET) + == 0) { + /* + * Some mysterious failure. + */ + + return; + } + + wsprintfA(codepage, "cp%d", charsetInfo.ciACP); + + if ((encoding = Tcl_GetEncoding(NULL, codepage)) == NULL) { + /* + * The encoding is not supported by Tcl. + */ + + return; + } + + if (keyInputEncoding != NULL) { + Tcl_FreeEncoding(keyInputEncoding); + } + + keyInputEncoding = encoding; + keyInputCharset = charset; +} + +/* + *---------------------------------------------------------------------- + * + * TkWinGetKeyInputEncoding -- + * + * Returns the current keyboard input encoding selected by the + * user (with WM_INPUTLANGCHANGE events). + * + * Results: + * The current keyboard input encoding. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_Encoding +TkWinGetKeyInputEncoding() +{ + return keyInputEncoding; +} + +/* + *---------------------------------------------------------------------- + * + * HandleIMEComposition -- + * + * This function works around a definciency in some versions + * of Windows 2000 to make it possible to entry multi-lingual + * characters under all versions of Windows 2000. + * + * When an Input Method Editor (IME) is ready to send input + * characters to an application, it sends a WM_IME_COMPOSITION + * message with the GCS_RESULTSTR. However, The DefWindowProc() + * on English Windows 2000 arbitrarily converts all non-Latin-1 + * characters in the composition to "?". + * + * This function correctly processes the composition data and + * sends the UNICODE values of the composed characters to + * TK's event queue. + * + * Results: + * If this function has processed the composition data, returns 1. + * Otherwise returns 0. + * + * Side effects: + * Key events are put into the TK event queue. + * + *---------------------------------------------------------------------- + */ + +static int +HandleIMEComposition(hwnd, lParam) + HWND hwnd; /* Window receiving the message. */ + LPARAM lParam; /* Flags for the WM_IME_COMPOSITION + * message */ +{ + HIMC hIMC; + int i, n; + XEvent event; + char * buff; + TkWindow *winPtr; + + if (tkPlatformId != VER_PLATFORM_WIN32_NT) { + /* + * The ImmGetCompositionStringW function works only on WinNT. + */ + + return 0; + } + + if ((lParam & GCS_RESULTSTR) == 0) { + /* + * Composition is not finished yet. + */ + + return 0; + } + + hIMC = ImmGetContext(hwnd); + if (hIMC) { + n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0); + + if (n > 0) { + buff = (char*)ckalloc(n); + n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buff, n); + + /* + * Set up the fields pertinent to key event. + * + * We set send_event to the special value of -2, so that + * TkpGetString() in tkWinKey.c knows that trans_chars[] + * already contains a UNICODE char and there's no need to + * do encoding conversion. + */ + + winPtr = (TkWindow *)Tk_HWNDToWindow(hwnd); + + event.xkey.serial = winPtr->display->request++; + event.xkey.send_event = -2; + event.xkey.display = winPtr->display; + event.xkey.window = winPtr->window; + event.xkey.root = RootWindow(winPtr->display, winPtr->screenNum); + event.xkey.subwindow = None; + event.xkey.state = TkWinGetModifierState(); + event.xkey.time = TkpGetMS(); + event.xkey.same_screen = True; + event.xkey.keycode = 0; + event.xkey.nbytes = 2; + + for (i=0; i