summaryrefslogtreecommitdiffstats
path: root/win/tkWinX.c
diff options
context:
space:
mode:
authorhobbs <hobbs>2001-03-30 23:50:17 (GMT)
committerhobbs <hobbs>2001-03-30 23:50:17 (GMT)
commit739d4321a3b8dd6e1073ecb19aa5b09eb5893571 (patch)
treeaf9d10c78323c178cd299b0ebd3b034ee96b1b25 /win/tkWinX.c
parent0dcaafd32b3ba64d04c60046ecbc7d774e60de66 (diff)
downloadtk-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.c240
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.