diff options
author | hobbs <hobbs> | 2001-03-30 23:50:17 (GMT) |
---|---|---|
committer | hobbs <hobbs> | 2001-03-30 23:50:17 (GMT) |
commit | 739d4321a3b8dd6e1073ecb19aa5b09eb5893571 (patch) | |
tree | af9d10c78323c178cd299b0ebd3b034ee96b1b25 /win/tkWinX.c | |
parent | 0dcaafd32b3ba64d04c60046ecbc7d774e60de66 (diff) | |
download | tk-739d4321a3b8dd6e1073ecb19aa5b09eb5893571.zip tk-739d4321a3b8dd6e1073ecb19aa5b09eb5893571.tar.gz tk-739d4321a3b8dd6e1073ecb19aa5b09eb5893571.tar.bz2 |
* 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]
Diffstat (limited to 'win/tkWinX.c')
-rw-r--r-- | win/tkWinX.c | 240 |
1 files changed, 232 insertions, 8 deletions
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<n;) { + /* + * Simulate a pair of KeyPress and KeyRelease events + * for each UNICODE character in the composition. + */ + + event.xkey.trans_chars[0] = (char) buff[i++]; + event.xkey.trans_chars[1] = (char) buff[i++]; + + event.type = KeyPress; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + + event.type = KeyRelease; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + } + + ckfree(buff); + } + ImmReleaseContext(hwnd, hIMC); + return 1; + } + + return 0; +} + +/* + *---------------------------------------------------------------------- + * * Tk_FreeXId -- * * This inteface is not needed under Windows. |