diff options
Diffstat (limited to 'win/tkWinX.c')
-rw-r--r-- | win/tkWinX.c | 1636 |
1 files changed, 889 insertions, 747 deletions
diff --git a/win/tkWinX.c b/win/tkWinX.c index cafacb9..288da26 100644 --- a/win/tkWinX.c +++ b/win/tkWinX.c @@ -1,22 +1,30 @@ -/* +/* * tkWinX.c -- * - * This file contains Windows emulation procedures for X routines. + * This file contains Windows emulation procedures for X routines. * * Copyright (c) 1995-1996 Sun Microsystems, Inc. * Copyright (c) 1994 Software Research Associates, Inc. * Copyright (c) 1998-2000 by Scriptics Corporation. * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +/* + * Make sure the SendInput API is available (NT SP 3): + */ +#if (_WIN32_WINNT <= 0x0400) +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0403 +#endif + #include "tkWinInt.h" /* - * The w32api 1.1 package (included in Mingw 1.1) does not define _WIN32_IE - * by default. Define it here to gain access to the InitCommonControlsEx API - * in commctrl.h. + * The w32api 1.1 package (included in Mingw 1.1) does not define _WIN32_IE by + * default. Define it here to gain access to the InitCommonControlsEx API in + * commctrl.h. */ #ifndef _WIN32_IE @@ -24,6 +32,10 @@ #endif #include <commctrl.h> +#ifdef _MSC_VER +# pragma comment (lib, "comctl32.lib") +# pragma comment (lib, "advapi32.lib") +#endif /* * The zmouse.h file includes the definition for WM_MOUSEWHEEL. @@ -36,6 +48,9 @@ */ #include <imm.h> +#ifdef _MSC_VER +# pragma comment (lib, "imm32.lib") +#endif /* * WM_UNICHAR is a message for Unicode input on all windows systems. @@ -61,6 +76,7 @@ static TkWinProcs asciiProcs = { HINSTANCE hInstance, LPVOID lpParam)) CreateWindowExA, (BOOL (WINAPI *)(HMENU hMenu, UINT uPosition, UINT uFlags, UINT uIDNewItem, LPCTSTR lpNewItem)) InsertMenuA, + (int (WINAPI *)(HWND hWnd, LPCTSTR lpString, int nMaxCount)) GetWindowTextA, }; static TkWinProcs unicodeProcs = { @@ -78,6 +94,7 @@ static TkWinProcs unicodeProcs = { HINSTANCE hInstance, LPVOID lpParam)) CreateWindowExW, (BOOL (WINAPI *)(HMENU hMenu, UINT uPosition, UINT uFlags, UINT uIDNewItem, LPCTSTR lpNewItem)) InsertMenuW, + (int (WINAPI *)(HWND hWnd, LPCTSTR lpString, int nMaxCount)) GetWindowTextW, }; TkWinProcs *tkWinProcs; @@ -86,51 +103,52 @@ TkWinProcs *tkWinProcs; * Declarations of static variables used in this file. */ -static char winScreenName[] = ":0"; /* Default name of windows display. */ -static HINSTANCE tkInstance = NULL; /* Application instance handle. */ -static int childClassInitialized; /* Registered child class? */ -static WNDCLASS childClass; /* Window class for child windows. */ -static int tkPlatformId = 0; /* version of Windows platform */ -static int tkWinTheme = 0; /* See TkWinGetPlatformTheme */ -static Tcl_Encoding keyInputEncoding = NULL;/* The current character - * encoding for keyboard input */ -static int keyInputCharset = -1; /* The Win32 CHARSET for the keyboard - * encoding */ -static Tcl_Encoding unicodeEncoding = NULL; /* unicode encoding */ +static char winScreenName[] = ":0"; /* Default name of windows display. */ +static HINSTANCE tkInstance = NULL; /* Application instance handle. */ +static int childClassInitialized; /* Registered child class? */ +static WNDCLASS childClass; /* Window class for child windows. */ +static int tkPlatformId = 0; /* version of Windows platform */ +static int tkWinTheme = 0; /* See TkWinGetPlatformTheme */ +static Tcl_Encoding keyInputEncoding = NULL; + /* The current character encoding for + * keyboard input */ +static int keyInputCharset = -1; /* The Win32 CHARSET for the keyboard + * encoding */ +static Tcl_Encoding unicodeEncoding = NULL; + /* The UNICODE encoding */ /* - * Thread local storage. Notice that now each thread must have its - * own TkDisplay structure, since this structure contains most of - * the thread-specific date for threads. + * Thread local storage. Notice that now each thread must have its own + * TkDisplay structure, since this structure contains most of the thread- + * specific date for threads. */ + typedef struct ThreadSpecificData { - TkDisplay *winDisplay; /* TkDisplay structure that * - * represents Windows screen. */ - int updatingClipboard; /* If 1, we are updating the clipboard */ + TkDisplay *winDisplay; /* TkDisplay structure that represents Windows + * screen. */ + int updatingClipboard; /* If 1, we are updating the clipboard. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* - * Forward declarations of procedures used in this file. + * Forward declarations of functions used in this file. */ -static void GenerateXEvent _ANSI_ARGS_((HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam)); -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)); +static void GenerateXEvent(HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam); +static unsigned int GetState(UINT message, WPARAM wParam, LPARAM lParam); +static void GetTranslatedKey(XKeyEvent *xkey); +static void UpdateInputLanguage(int charset); +static int HandleIMEComposition(HWND hwnd, LPARAM lParam); /* *---------------------------------------------------------------------- * * TkGetServerInfo -- * - * Given a window, this procedure returns information about - * the window server for that window. This procedure provides - * the guts of the "winfo server" command. + * Given a window, this function returns information about the window + * server for that window. This function provides the guts of the "winfo + * server" command. * * Results: * None. @@ -142,25 +160,25 @@ static int HandleIMEComposition _ANSI_ARGS_((HWND hwnd, */ void -TkGetServerInfo(interp, tkwin) - Tcl_Interp *interp; /* The server information is returned in - * this interpreter's result. */ - Tk_Window tkwin; /* Token for window; this selects a - * particular display and server. */ +TkGetServerInfo( + Tcl_Interp *interp, /* The server information is returned in this + * interpreter's result. */ + Tk_Window tkwin) /* Token for window; this selects a particular + * display and server. */ { char buffer[60]; OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&os); - sprintf(buffer, "Windows %d.%d %d %s", os.dwMajorVersion, - os.dwMinorVersion, os.dwBuildNumber, + sprintf(buffer, "Windows %d.%d %d %s", (int)os.dwMajorVersion, + (int)os.dwMinorVersion, (int)os.dwBuildNumber, #ifdef _WIN64 "Win64" #else "Win32" #endif - ); + ); Tcl_SetResult(interp, buffer, TCL_VOLATILE); } @@ -181,7 +199,7 @@ TkGetServerInfo(interp, tkwin) */ HINSTANCE -Tk_GetHINSTANCE() +Tk_GetHINSTANCE(void) { if (tkInstance == NULL) { tkInstance = GetModuleHandle(NULL); @@ -194,8 +212,8 @@ Tk_GetHINSTANCE() * * TkWinSetHINSTANCE -- * - * Sets the global instance handle used by the Tk library. - * This should be called by DllMain. + * Sets the global instance handle used by the Tk library. This should be + * called by DllMain. * * Results: * None. @@ -207,8 +225,8 @@ Tk_GetHINSTANCE() */ void -TkWinSetHINSTANCE(hInstance) - HINSTANCE hInstance; +TkWinSetHINSTANCE( + HINSTANCE hInstance) { tkInstance = hInstance; } @@ -230,9 +248,10 @@ TkWinSetHINSTANCE(hInstance) */ void -TkWinXInit(hInstance) - HINSTANCE hInstance; +TkWinXInit( + HINSTANCE hInstance) { + INITCOMMONCONTROLSEX comctl; CHARSETINFO lpCs; DWORD lpCP; @@ -241,16 +260,13 @@ TkWinXInit(hInstance) } childClassInitialized = 1; - if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { - /* - * This is necessary to enable the use of themeable elements on XP, - * so we don't even try and call it for Win9*. - */ - - INITCOMMONCONTROLSEX comctl; - ZeroMemory(&comctl, sizeof(comctl)); - (void) InitCommonControlsEx(&comctl); + comctl.dwSize = sizeof(INITCOMMONCONTROLSEX); + comctl.dwICC = ICC_WIN95_CLASSES; + if (!InitCommonControlsEx(&comctl)) { + Tcl_Panic("Unable to load common controls?!"); + } + if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { tkWinProcs = &unicodeProcs; } else { tkWinProcs = &asciiProcs; @@ -273,23 +289,24 @@ TkWinXInit(hInstance) childClass.hCursor = NULL; if (!RegisterClass(&childClass)) { - panic("Unable to register TkChild class"); + Tcl_Panic("Unable to register TkChild class"); } /* * Initialize input language info */ - if (GetLocaleInfo(LANGIDFROMLCID(GetKeyboardLayout(0)), + if (GetLocaleInfo(LANGIDFROMLCID((DWORD)GetKeyboardLayout(0)), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (LPTSTR) &lpCP, sizeof(lpCP)/sizeof(TCHAR)) && TranslateCharsetInfo((DWORD *)lpCP, &lpCs, TCI_SRCCODEPAGE)) { - UpdateInputLanguage(lpCs.ciCharset); + UpdateInputLanguage((int) lpCs.ciCharset); } /* * Make sure we cleanup on finalize. */ + TkCreateExitHandler(TkWinXCleanup, (ClientData) hInstance); } @@ -310,17 +327,18 @@ TkWinXInit(hInstance) */ void -TkWinXCleanup(clientData) - ClientData clientData; +TkWinXCleanup( + ClientData clientData) { HINSTANCE hInstance = (HINSTANCE) clientData; + /* * Clean up our own class. */ - + if (childClassInitialized) { - childClassInitialized = 0; - UnregisterClass(TK_WIN_CHILD_CLASS_NAME, hInstance); + childClassInitialized = 0; + UnregisterClass(TK_WIN_CHILD_CLASS_NAME, hInstance); } if (unicodeEncoding != NULL) { @@ -331,8 +349,9 @@ TkWinXCleanup(clientData) /* * And let the window manager clean up its own class(es). */ - + TkWinWmCleanup(hInstance); + TkWinCleanupContainerList(); } /* @@ -340,12 +359,12 @@ TkWinXCleanup(clientData) * * TkWinGetPlatformId -- * - * Determines whether running under NT, 95, or Win32s, to allow - * runtime conditional code. Win32s is no longer supported. + * Determines whether running under NT, 95, or Win32s, to allow runtime + * conditional code. Win32s is no longer supported. * * Results: * The return value is one of: - * VER_PLATFORM_WIN32s Win32s on Windows 3.1. + * VER_PLATFORM_WIN32s Win32s on Windows 3.1. * VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95. * VER_PLATFORM_WIN32_NT Win32 on Windows NT * @@ -356,7 +375,7 @@ TkWinXCleanup(clientData) */ int -TkWinGetPlatformId() +TkWinGetPlatformId(void) { if (tkPlatformId == 0) { OSVERSIONINFO os; @@ -364,29 +383,33 @@ TkWinGetPlatformId() os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&os); tkPlatformId = os.dwPlatformId; - - /* Set tkWinTheme to be TK_THEME_WIN_XP or TK_THEME_WIN_CLASSIC. - * The TK_THEME_WIN_CLASSIC could be set even when running - * under XP if the windows classic theme was selected. */ + + /* + * Set tkWinTheme to be TK_THEME_WIN_XP or TK_THEME_WIN_CLASSIC. The + * TK_THEME_WIN_CLASSIC could be set even when running under XP if the + * windows classic theme was selected. + */ + if ((os.dwPlatformId == VER_PLATFORM_WIN32_NT) && - (os.dwMajorVersion == 5 && os.dwMinorVersion == 1)) { - HKEY hKey; - LPCSTR szSubKey = TEXT("Control Panel\\Appearance"); + (os.dwMajorVersion == 5 && os.dwMinorVersion == 1)) { + HKEY hKey; + LPCSTR szSubKey = TEXT("Control Panel\\Appearance"); LPCSTR szCurrent = TEXT("Current"); - DWORD dwSize = 200; + DWORD dwSize = 200; char pBuffer[200]; + memset(pBuffer, 0, dwSize); if (RegOpenKeyEx(HKEY_CURRENT_USER, szSubKey, 0L, - KEY_READ, &hKey) != ERROR_SUCCESS) { - tkWinTheme = TK_THEME_WIN_XP; + KEY_READ, &hKey) != ERROR_SUCCESS) { + tkWinTheme = TK_THEME_WIN_XP; } else { - RegQueryValueEx(hKey, szCurrent, NULL, NULL, pBuffer, &dwSize); - RegCloseKey(hKey); - if (strcmp(pBuffer, "Windows Standard") == 0) { - tkWinTheme = TK_THEME_WIN_CLASSIC; - } else { - tkWinTheme = TK_THEME_WIN_XP; - } + RegQueryValueEx(hKey, szCurrent, NULL, NULL, (LPBYTE) pBuffer, &dwSize); + RegCloseKey(hKey); + if (strcmp(pBuffer, "Windows Standard") == 0) { + tkWinTheme = TK_THEME_WIN_CLASSIC; + } else { + tkWinTheme = TK_THEME_WIN_XP; + } } } else { tkWinTheme = TK_THEME_WIN_CLASSIC; @@ -404,8 +427,8 @@ TkWinGetPlatformId() * * Results: * The return value is one of: - * TK_THEME_WIN_CLASSIC 95/98/NT or XP in classic mode - * TK_THEME_WIN_XP XP not in classic mode + * TK_THEME_WIN_CLASSIC 95/98/NT or XP in classic mode + * TK_THEME_WIN_XP XP not in classic mode * * Side effects: * Could invoke TkWinGetPlatformId. @@ -414,10 +437,10 @@ TkWinGetPlatformId() */ int -TkWinGetPlatformTheme() +TkWinGetPlatformTheme(void) { if (tkPlatformId == 0) { - TkWinGetPlatformId(); + TkWinGetPlatformId(); } return tkWinTheme; } @@ -440,9 +463,9 @@ TkWinGetPlatformTheme() */ CONST char * -TkGetDefaultScreenName(interp, screenName) - Tcl_Interp *interp; /* Not used. */ - CONST char *screenName; /* If NULL, use default string. */ +TkGetDefaultScreenName( + Tcl_Interp *interp, /* Not used. */ + CONST char *screenName) /* If NULL, use default string. */ { if ((screenName == NULL) || (screenName[0] == '\0')) { screenName = winScreenName; @@ -468,7 +491,8 @@ TkGetDefaultScreenName(interp, screenName) */ void -TkWinDisplayChanged(Display *display) +TkWinDisplayChanged( + Display *display) { HDC dc; Screen *screen; @@ -489,9 +513,9 @@ TkWinDisplayChanged(Display *display) /* * On windows, when creating a color bitmap, need two pieces of * information: the number of color planes and the number of pixels per - * plane. Need to remember both quantities so that when constructing an + * plane. Need to remember both quantities so that when constructing an * HBITMAP for offscreen rendering, we can specify the correct value for - * the number of planes. Otherwise the HBITMAP won't be compatible with + * the number of planes. Otherwise the HBITMAP won't be compatible with * the HWND and we'll just get blank spots copied onto the screen. */ @@ -549,8 +573,8 @@ TkWinDisplayChanged(Display *display) * * TkpOpenDisplay -- * - * Create the Display structure and fill it with device - * specific information. + * Create the Display structure and fill it with device specific + * information. * * Results: * Returns a TkDisplay structure on success or NULL on failure. @@ -562,18 +586,17 @@ TkWinDisplayChanged(Display *display) */ TkDisplay * -TkpOpenDisplay(display_name) - CONST char *display_name; +TkpOpenDisplay( + CONST char *display_name) { Screen *screen; TkWinDrawable *twdPtr; Display *display; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (tsdPtr->winDisplay != NULL) { - if (strcmp(tsdPtr->winDisplay->display->display_name, display_name) - == 0) { + if (!strcmp(tsdPtr->winDisplay->display->display_name, display_name)) { return tsdPtr->winDisplay; } else { return NULL; @@ -587,9 +610,9 @@ TkpOpenDisplay(display_name) strcpy(display->display_name, display_name); display->cursor_font = 1; - display->nscreens = 1; - display->request = 1; - display->qlen = 0; + display->nscreens = 1; + display->request = 1; + display->qlen = 0; screen = (Screen *) ckalloc(sizeof(Screen)); ZeroMemory(screen, sizeof(Screen)); @@ -614,7 +637,7 @@ TkpOpenDisplay(display_name) screen->white_pixel = RGB(255, 255, 255); screen->black_pixel = RGB(0, 0, 0); - screen->cmap = None; + screen->cmap = None; display->screens = screen; display->nscreens = 1; @@ -648,49 +671,34 @@ TkpOpenDisplay(display_name) */ void -TkpCloseDisplay(dispPtr) - TkDisplay *dispPtr; +TkpCloseDisplay( + TkDisplay *dispPtr) { Display *display = dispPtr->display; - HWND hwnd; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (dispPtr != tsdPtr->winDisplay) { - panic("TkpCloseDisplay: tried to call TkpCloseDisplay on another display"); - return; - } - - /* - * Force the clipboard to be rendered if we are the clipboard owner. - */ - - if (dispPtr->clipWindow) { - hwnd = Tk_GetHWND(Tk_WindowId(dispPtr->clipWindow)); - if (GetClipboardOwner() == hwnd) { - OpenClipboard(hwnd); - EmptyClipboard(); - TkWinClipboardRender(dispPtr, CF_TEXT); - CloseClipboard(); - } + Tcl_Panic("TkpCloseDisplay: tried to call TkpCloseDisplay on another display"); + return; /* not reached */ } tsdPtr->winDisplay = NULL; - if (display->display_name != (char *) NULL) { - ckfree(display->display_name); + if (display->display_name != NULL) { + ckfree(display->display_name); } - if (display->screens != (Screen *) NULL) { - if (display->screens->root_visual != NULL) { - ckfree((char *) display->screens->root_visual); - } - if (display->screens->root != None) { - ckfree((char *) display->screens->root); - } - if (display->screens->cmap != None) { - XFreeColormap(display, display->screens->cmap); - } - ckfree((char *) display->screens); + if (display->screens != NULL) { + if (display->screens->root_visual != NULL) { + ckfree((char *) display->screens->root_visual); + } + if (display->screens->root != None) { + ckfree((char *) display->screens->root); + } + if (display->screens->cmap != None) { + XFreeColormap(display, display->screens->cmap); + } + ckfree((char *) display->screens); } ckfree((char *) display); } @@ -700,11 +708,10 @@ TkpCloseDisplay(dispPtr) * * TkClipCleanup -- * - * This procedure is called to cleanup resources associated with - * claiming clipboard ownership and for receiving selection get - * results. This function is called in tkWindow.c. This has to be - * called by the display cleanup function because we still need the - * access display elements. + * This function is called to cleanup resources associated with claiming + * clipboard ownership and for receiving selection get results. This + * function is called in tkWindow.c. This has to be called by the display + * cleanup function because we still need the access display elements. * * Results: * None. @@ -716,8 +723,8 @@ TkpCloseDisplay(dispPtr) */ void -TkClipCleanup(dispPtr) - TkDisplay *dispPtr; /* display associated with clipboard */ +TkClipCleanup( + TkDisplay *dispPtr) /* Display associated with clipboard. */ { if (dispPtr->clipWindow != NULL) { /* @@ -725,6 +732,7 @@ TkClipCleanup(dispPtr) */ HWND hwnd = Tk_GetHWND(Tk_WindowId(dispPtr->clipWindow)); + if (GetClipboardOwner() == hwnd) { OpenClipboard(hwnd); EmptyClipboard(); @@ -760,9 +768,9 @@ TkClipCleanup(dispPtr) */ void -XBell(display, percent) - Display* display; - int percent; +XBell( + Display *display, + int percent) { MessageBeep(MB_OK); } @@ -772,8 +780,7 @@ XBell(display, percent) * * TkWinChildProc -- * - * Callback from Windows whenever an event occurs on a child - * window. + * Callback from Windows whenever an event occurs on a child window. * * Results: * Standard Windows return value. @@ -785,75 +792,83 @@ XBell(display, percent) */ LRESULT CALLBACK -TkWinChildProc(hwnd, message, wParam, lParam) - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; +TkWinChildProc( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM 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 - * the cursor elsewhere. - */ - - result = TRUE; - break; - - case WM_CREATE: - case WM_ERASEBKGND: - result = 0; - break; - - case WM_PAINT: - GenerateXEvent(hwnd, message, wParam, lParam); + case WM_INPUTLANGCHANGE: + UpdateInputLanguage((int) wParam); + result = 1; + break; + + case WM_IME_COMPOSITION: + result = 0; + if (HandleIMEComposition(hwnd, lParam) == 0) { result = DefWindowProc(hwnd, message, wParam, lParam); - break; + } + break; - case TK_CLAIMFOCUS: - case TK_GEOMETRYREQ: - case TK_ATTACHWINDOW: - case TK_DETACHWINDOW: - result = TkWinEmbeddedEventProc(hwnd, message, wParam, lParam); - break; + case WM_SETCURSOR: + /* + * Short circuit the WM_SETCURSOR message since we set the cursor + * elsewhere. + */ - case WM_UNICHAR: - if (wParam == UNICODE_NOCHAR) { - /* If wParam is UNICODE_NOCHAR and the application processes - * this message, then return TRUE. */ - result = 1; + result = TRUE; + break; + + case WM_CREATE: + case WM_ERASEBKGND: + result = 0; + break; + + case WM_PAINT: + GenerateXEvent(hwnd, message, wParam, lParam); + result = DefWindowProc(hwnd, message, wParam, lParam); + break; + + case TK_CLAIMFOCUS: + case TK_GEOMETRYREQ: + case TK_ATTACHWINDOW: + case TK_DETACHWINDOW: + case TK_ICONIFY: + case TK_DEICONIFY: + case TK_MOVEWINDOW: + case TK_WITHDRAW: + case TK_RAISEWINDOW: + case TK_GETFRAMEWID: + case TK_OVERRIDEREDIRECT: + case TK_SETMENU: + case TK_STATE: + case TK_INFO: + result = TkWinEmbeddedEventProc(hwnd, message, wParam, lParam); + break; + + case WM_UNICHAR: + if (wParam == UNICODE_NOCHAR) { + /* If wParam is UNICODE_NOCHAR and the application processes + * this message, then return TRUE. */ + result = 1; + } else { + /* If the event was translated, we must return 0 */ + if (Tk_TranslateWinEvent(hwnd, message, wParam, lParam, &result)) { + result = 0; } else { - /* If the event was translated, we must return 0 */ - if (Tk_TranslateWinEvent(hwnd, message, wParam, lParam, - &result)) { - result = 0; - } else { - result = 1; - } + result = 1; } - break; + } + break; - default: - if (!Tk_TranslateWinEvent(hwnd, message, wParam, lParam, - &result)) { - result = DefWindowProc(hwnd, message, wParam, lParam); - } - break; + default: + if (!Tk_TranslateWinEvent(hwnd, message, wParam, lParam, &result)) { + result = DefWindowProc(hwnd, message, wParam, lParam); + } + break; } /* @@ -869,8 +884,8 @@ TkWinChildProc(hwnd, message, wParam, lParam) * * Tk_TranslateWinEvent -- * - * This function is called by widget window procedures to handle - * the translation from Win32 events to Tk events. + * This function is called by widget window functions to handle the + * translation from Win32 events to Tk events. * * Results: * Returns 1 if the event was handled, else 0. @@ -882,75 +897,80 @@ TkWinChildProc(hwnd, message, wParam, lParam) */ int -Tk_TranslateWinEvent(hwnd, message, wParam, lParam, resultPtr) - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; - LRESULT *resultPtr; +Tk_TranslateWinEvent( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam, + LRESULT *resultPtr) { *resultPtr = 0; switch (message) { - case WM_RENDERFORMAT: { - TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd); - if (winPtr) { - TkWinClipboardRender(winPtr->dispPtr, wParam); - } - return 1; + case WM_RENDERFORMAT: { + TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd); + + if (winPtr) { + TkWinClipboardRender(winPtr->dispPtr, wParam); } + return 1; + } - case WM_COMMAND: - case WM_NOTIFY: - case WM_VSCROLL: - case WM_HSCROLL: { - /* - * Reflect these messages back to the sender so that they - * can be handled by the window proc for the control. Note - * that we need to be careful not to reflect a message that - * is targeted to this window, or we will loop. - */ + case WM_COMMAND: + case WM_NOTIFY: + case WM_VSCROLL: + case WM_HSCROLL: { + /* + * Reflect these messages back to the sender so that they can be + * handled by the window proc for the control. Note that we need to be + * careful not to reflect a message that is targeted to this window, + * or we will loop. + */ - HWND target = (message == WM_NOTIFY) + HWND target = (message == WM_NOTIFY) ? ((NMHDR*)lParam)->hwndFrom : (HWND) lParam; - if (target && target != hwnd) { - *resultPtr = SendMessage(target, message, wParam, lParam); - return 1; - } - break; - } - case WM_LBUTTONDOWN: - case WM_LBUTTONDBLCLK: - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: - case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - case WM_MOUSEMOVE: - Tk_PointerEvent(hwnd, (short) LOWORD(lParam), - (short) HIWORD(lParam)); + if (target && target != hwnd) { + *resultPtr = SendMessage(target, message, wParam, lParam); return 1; + } + break; + } - case WM_CLOSE: - case WM_SETFOCUS: - case WM_KILLFOCUS: - case WM_DESTROYCLIPBOARD: - case WM_UNICHAR: - case WM_CHAR: - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - case WM_KEYDOWN: - case WM_KEYUP: - case WM_MOUSEWHEEL: - GenerateXEvent(hwnd, message, wParam, lParam); - return 1; - case WM_MENUCHAR: - GenerateXEvent(hwnd, message, wParam, lParam); - /* MNC_CLOSE is the only one that looks right. This is a hack. */ - *resultPtr = MAKELONG (0, MNC_CLOSE); - return 1; + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_MOUSEMOVE: + Tk_PointerEvent(hwnd, (short) LOWORD(lParam), (short) HIWORD(lParam)); + return 1; + + case WM_CLOSE: + case WM_SETFOCUS: + case WM_KILLFOCUS: + case WM_DESTROYCLIPBOARD: + case WM_UNICHAR: + case WM_CHAR: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_KEYDOWN: + case WM_KEYUP: + case WM_MOUSEWHEEL: + GenerateXEvent(hwnd, message, wParam, lParam); + return 1; + case WM_MENUCHAR: + GenerateXEvent(hwnd, message, wParam, lParam); + + /* + * MNC_CLOSE is the only one that looks right. This is a hack. + */ + + *resultPtr = MAKELONG (0, MNC_CLOSE); + return 1; } return 0; } @@ -960,8 +980,8 @@ Tk_TranslateWinEvent(hwnd, message, wParam, lParam, resultPtr) * * GenerateXEvent -- * - * This routine generates an X event from the corresponding - * Windows event. + * This routine generates an X event from the corresponding Windows + * event. * * Results: * None. @@ -973,281 +993,286 @@ Tk_TranslateWinEvent(hwnd, message, wParam, lParam, resultPtr) */ static void -GenerateXEvent(hwnd, message, wParam, lParam) - HWND hwnd; - UINT message; - WPARAM wParam; - LPARAM lParam; +GenerateXEvent( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam) { XEvent event; - TkWindow *winPtr = (TkWindow *)Tk_HWNDToWindow(hwnd); - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + TkWindow *winPtr; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + winPtr = (TkWindow *)Tk_HWNDToWindow(hwnd); if (!winPtr || winPtr->window == None) { return; } + memset(&event, 0, sizeof(XEvent)); event.xany.serial = winPtr->display->request++; event.xany.send_event = False; event.xany.display = winPtr->display; event.xany.window = winPtr->window; switch (message) { - case WM_PAINT: { - PAINTSTRUCT ps; - - event.type = Expose; - BeginPaint(hwnd, &ps); - event.xexpose.x = ps.rcPaint.left; - event.xexpose.y = ps.rcPaint.top; - event.xexpose.width = ps.rcPaint.right - ps.rcPaint.left; - event.xexpose.height = ps.rcPaint.bottom - ps.rcPaint.top; - EndPaint(hwnd, &ps); - event.xexpose.count = 0; - break; - } + case WM_PAINT: { + PAINTSTRUCT ps; + + event.type = Expose; + BeginPaint(hwnd, &ps); + event.xexpose.x = ps.rcPaint.left; + event.xexpose.y = ps.rcPaint.top; + event.xexpose.width = ps.rcPaint.right - ps.rcPaint.left; + event.xexpose.height = ps.rcPaint.bottom - ps.rcPaint.top; + EndPaint(hwnd, &ps); + event.xexpose.count = 0; + break; + } - case WM_CLOSE: - event.type = ClientMessage; - event.xclient.message_type = + case WM_CLOSE: + event.type = ClientMessage; + event.xclient.message_type = Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"); - event.xclient.format = 32; - event.xclient.data.l[0] = + event.xclient.format = 32; + event.xclient.data.l[0] = Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW"); - break; + break; - case WM_SETFOCUS: - case WM_KILLFOCUS: { - TkWindow *otherWinPtr = (TkWindow *)Tk_HWNDToWindow((HWND) wParam); + case WM_SETFOCUS: + case WM_KILLFOCUS: { + TkWindow *otherWinPtr = (TkWindow *) Tk_HWNDToWindow((HWND) wParam); - /* - * Compare toplevel windows to avoid reporting focus - * changes within the same toplevel. - */ + /* + * Compare toplevel windows to avoid reporting focus changes within + * the same toplevel. + */ - while (!(winPtr->flags & TK_TOP_LEVEL)) { - winPtr = winPtr->parentPtr; - if (winPtr == NULL) { - return; - } - } - while (otherWinPtr && !(otherWinPtr->flags & TK_TOP_LEVEL)) { - otherWinPtr = otherWinPtr->parentPtr; + while (!(winPtr->flags & TK_TOP_LEVEL)) { + winPtr = winPtr->parentPtr; + if (winPtr == NULL) { + return; } + } + while (otherWinPtr && !(otherWinPtr->flags & TK_TOP_LEVEL)) { + otherWinPtr = otherWinPtr->parentPtr; + } - /* - * Do a catch-all Tk_SetCaretPos here to make sure that the - * window receiving focus sets the caret at least once. - */ - if (message == WM_SETFOCUS) { - Tk_SetCaretPos((Tk_Window) winPtr, 0, 0, 0); - } + /* + * Do a catch-all Tk_SetCaretPos here to make sure that the window + * receiving focus sets the caret at least once. + */ - if (otherWinPtr == winPtr) { - return; - } + if (message == WM_SETFOCUS) { + Tk_SetCaretPos((Tk_Window) winPtr, 0, 0, 0); + } - event.xany.window = winPtr->window; - event.type = (message == WM_SETFOCUS) ? FocusIn : FocusOut; - event.xfocus.mode = NotifyNormal; - event.xfocus.detail = NotifyNonlinear; + if (otherWinPtr == winPtr) { + return; + } + + event.xany.window = winPtr->window; + event.type = (message == WM_SETFOCUS) ? FocusIn : FocusOut; + event.xfocus.mode = NotifyNormal; + event.xfocus.detail = NotifyNonlinear; + + /* + * Destroy the caret if we own it. If we are moving to another Tk + * window, it will reclaim and reposition it with Tk_SetCaretPos. + */ + if (message == WM_KILLFOCUS) { + DestroyCaret(); + } + break; + } + + case WM_DESTROYCLIPBOARD: + if (tsdPtr->updatingClipboard == TRUE) { /* - * Destroy the caret if we own it. If we are moving to another Tk - * window, it will reclaim and reposition it with Tk_SetCaretPos. + * We want to avoid this event if we are the ones that caused this + * event. */ - if (message == WM_KILLFOCUS) { - DestroyCaret(); - } - break; - } - case WM_DESTROYCLIPBOARD: - if (tsdPtr->updatingClipboard == TRUE) { - /* - * We want to avoid this event if we are the ones that caused - * this event. - */ - return; - } - event.type = SelectionClear; - event.xselectionclear.selection = + return; + } + event.type = SelectionClear; + event.xselectionclear.selection = Tk_InternAtom((Tk_Window)winPtr, "CLIPBOARD"); - event.xselectionclear.time = TkpGetMS(); - break; + event.xselectionclear.time = TkpGetMS(); + break; + case WM_MOUSEWHEEL: + /* + * The mouse wheel event is closer to a key event than a mouse event + * in that the message is sent to the window that has focus. + */ + + case WM_CHAR: + case WM_UNICHAR: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_KEYDOWN: + case WM_KEYUP: { + unsigned int state = GetState(message, wParam, lParam); + Time time = TkpGetMS(); + POINT clientPoint; + union {DWORD msgpos; POINTS point;} root; /* Note: POINT and POINTS are different */ + + /* + * Compute the screen and window coordinates of the event. + */ + + root.msgpos = GetMessagePos(); + clientPoint.x = root.point.x; + clientPoint.y = root.point.y; + ScreenToClient(hwnd, &clientPoint); + + /* + * Set up the common event fields. + */ + + event.xbutton.root = RootWindow(winPtr->display, winPtr->screenNum); + event.xbutton.subwindow = None; + event.xbutton.x = clientPoint.x; + event.xbutton.y = clientPoint.y; + event.xbutton.x_root = root.point.x; + event.xbutton.y_root = root.point.y; + event.xbutton.state = state; + event.xbutton.time = time; + event.xbutton.same_screen = True; + + /* + * Now set up event specific fields. + */ + + switch (message) { case WM_MOUSEWHEEL: /* - * The mouse wheel event is closer to a key event than a - * mouse event in that the message is sent to the window - * that has focus. + * We have invented a new X event type to handle this event. It + * still uses the KeyPress struct. However, the keycode field has + * been overloaded to hold the zDelta of the wheel. Set nbytes to + * 0 to prevent conversion of the keycode to a keysym in + * TkpGetString. [Bug 1118340]. */ - case WM_CHAR: - case WM_UNICHAR: + event.type = MouseWheelEvent; + event.xany.send_event = -1; + event.xkey.nbytes = 0; + event.xkey.keycode = (short) HIWORD(wParam); + break; case WM_SYSKEYDOWN: - case WM_SYSKEYUP: case WM_KEYDOWN: - case WM_KEYUP: { - unsigned int state = GetState(message, wParam, lParam); - Time time = TkpGetMS(); - POINT clientPoint; - POINTS rootPoint; /* Note: POINT and POINTS are different */ - DWORD msgPos; - /* - * Compute the screen and window coordinates of the event. + * Check for translated characters in the event queue. Setting + * xany.send_event to -1 indicates to the Windows implementation + * of TkpGetString() that this event was generated by windows and + * that the Windows extension xkey.trans_chars is filled with the + * MBCS characters that came from the TranslateMessage call. */ - msgPos = GetMessagePos(); - rootPoint = MAKEPOINTS(msgPos); - clientPoint.x = rootPoint.x; - clientPoint.y = rootPoint.y; - ScreenToClient(hwnd, &clientPoint); + event.type = KeyPress; + event.xany.send_event = -1; + event.xkey.keycode = wParam; + GetTranslatedKey(&event.xkey); + break; + case WM_SYSKEYUP: + case WM_KEYUP: /* - * Set up the common event fields. + * We don't check for translated characters on keyup because Tk + * won't know what to do with them. Instead, we wait for the + * WM_CHAR messages which will follow. */ - event.xbutton.root = RootWindow(winPtr->display, - winPtr->screenNum); - event.xbutton.subwindow = None; - event.xbutton.x = clientPoint.x; - event.xbutton.y = clientPoint.y; - event.xbutton.x_root = rootPoint.x; - event.xbutton.y_root = rootPoint.y; - event.xbutton.state = state; - event.xbutton.time = time; - event.xbutton.same_screen = True; + event.type = KeyRelease; + event.xkey.keycode = wParam; + event.xkey.nbytes = 0; + break; + case WM_CHAR: /* - * Now set up event specific fields. + * Synthesize both a KeyPress and a KeyRelease. Strings generated + * by Input Method Editor are handled in the following manner: + * 1. A series of WM_KEYDOWN & WM_KEYUP messages that cause + * GetTranslatedKey() to be called and return immediately + * because the WM_KEYDOWNs have no associated WM_CHAR messages + * -- the IME window is accumulating the characters and + * translating them itself. In the "bind" command, you get an + * event with a mystery keysym and %A == "" for each WM_KEYDOWN + * that actually was meant for the IME. + * 2. A WM_KEYDOWN corresponding to the "confirm typing" + * character. This causes GetTranslatedKey() to be called. + * 3. A WM_IME_NOTIFY message saying that the IME is done. A side + * effect of this message is that GetTranslatedKey() thinks + * this means that there are no WM_CHAR messages and returns + * immediately. In the "bind" command, you get an another event + * with a mystery keysym and %A == "". + * 4. A sequence of WM_CHAR messages that correspond to the + * characters in the IME window. A bunch of simulated + * KeyPress/KeyRelease events will be generated, one for each + * character. Adjacent WM_CHAR messages may actually specify + * the high and low bytes of a multi-byte character -- in that + * case the two WM_CHAR messages will be combined into one + * event. It is the event-consumer's responsibility to convert + * the string returned from XLookupString from system encoding + * to UTF-8. + * 5. And finally we get the WM_KEYUP for the "confirm typing" + * character. */ - switch (message) { - case WM_MOUSEWHEEL: - /* - * We have invented a new X event type to handle - * this event. It still uses the KeyPress struct. - * However, the keycode field has been overloaded - * to hold the zDelta of the wheel. Set nbytes to 0 - * to prevent conversion of the keycode to a keysym - * in TkpGetString. [Bug 1118340]. - */ - - event.type = MouseWheelEvent; - event.xany.send_event = -1; - event.xkey.nbytes = 0; - event.xkey.keycode = (short) HIWORD(wParam); - break; - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - /* - * Check for translated characters in the event queue. - * Setting xany.send_event to -1 indicates to the - * Windows implementation of TkpGetString() that this - * event was generated by windows and that the Windows - * extension xkey.trans_chars is filled with the - * MBCS characters that came from the TranslateMessage - * call. - */ - - event.type = KeyPress; - event.xany.send_event = -1; - event.xkey.keycode = wParam; - GetTranslatedKey(&event.xkey); - break; - - case WM_SYSKEYUP: - case WM_KEYUP: - /* - * We don't check for translated characters on keyup - * because Tk won't know what to do with them. Instead, we - * wait for the WM_CHAR messages which will follow. - */ - event.type = KeyRelease; - event.xkey.keycode = wParam; - event.xkey.nbytes = 0; - break; - - case WM_CHAR: - /* - * Synthesize both a KeyPress and a KeyRelease. - * Strings generated by Input Method Editor are handled - * in the following manner: - * 1. A series of WM_KEYDOWN & WM_KEYUP messages that - * cause GetTranslatedKey() to be called and return - * immediately because the WM_KEYDOWNs have no - * associated WM_CHAR messages -- the IME window is - * accumulating the characters and translating them - * itself. In the "bind" command, you get an event - * with a mystery keysym and %A == "" for each - * WM_KEYDOWN that actually was meant for the IME. - * 2. A WM_KEYDOWN corresponding to the "confirm typing" - * character. This causes GetTranslatedKey() to be - * called. - * 3. A WM_IME_NOTIFY message saying that the IME is - * done. A side effect of this message is that - * GetTranslatedKey() thinks this means that there - * are no WM_CHAR messages and returns immediately. - * In the "bind" command, you get an another event - * with a mystery keysym and %A == "". - * 4. A sequence of WM_CHAR messages that correspond to - * the characters in the IME window. A bunch of - * simulated KeyPress/KeyRelease events will be - * generated, one for each character. Adjacent - * WM_CHAR messages may actually specify the high - * and low bytes of a multi-byte character -- in that - * case the two WM_CHAR messages will be combined into - * one event. It is the event-consumer's - * responsibility to convert the string returned from - * XLookupString from system encoding to UTF-8. - * 5. And finally we get the WM_KEYUP for the "confirm - * typing" character. - */ - - event.type = KeyPress; - event.xany.send_event = -1; - event.xkey.keycode = 0; - event.xkey.nbytes = 1; - event.xkey.trans_chars[0] = (char) wParam; - - if (IsDBCSLeadByte((BYTE) wParam)) { - MSG msg; - - if ((PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) != 0) - && (msg.message == WM_CHAR)) { - GetMessage(&msg, NULL, 0, 0); - event.xkey.nbytes = 2; - event.xkey.trans_chars[1] = (char) msg.wParam; - } - } - Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - event.type = KeyRelease; - break; - - case WM_UNICHAR: { - char buffer[TCL_UTF_MAX+1]; - int i; - event.type = KeyPress; - event.xany.send_event = -3; - event.xkey.keycode = wParam; - event.xkey.nbytes = Tcl_UniCharToUtf(wParam, buffer); - for (i=0; i<event.xkey.nbytes && i<TCL_UTF_MAX; ++i) { - event.xkey.trans_chars[i] = buffer[i]; - } - Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); - event.type = KeyRelease; - break; + event.type = KeyPress; + event.xany.send_event = -1; + event.xkey.keycode = 0; + event.xkey.nbytes = 1; + event.xkey.trans_chars[0] = (char) wParam; + + if (IsDBCSLeadByte((BYTE) wParam)) { + MSG msg; + + if ((PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) != 0) + && (msg.message == WM_CHAR)) { + GetMessage(&msg, NULL, 0, 0); + event.xkey.nbytes = 2; + event.xkey.trans_chars[1] = (char) msg.wParam; } } + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + event.type = KeyRelease; + break; + + case WM_UNICHAR: { + char buffer[TCL_UTF_MAX+1]; + int i; + event.type = KeyPress; + event.xany.send_event = -3; + event.xkey.keycode = wParam; + event.xkey.nbytes = Tcl_UniCharToUtf((int)wParam, buffer); + for (i=0; i<event.xkey.nbytes && i<TCL_UTF_MAX; ++i) { + event.xkey.trans_chars[i] = buffer[i]; + } + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + event.type = KeyRelease; break; } - default: - return; + } + break; + } + + default: + /* + * Don't know how to translate this event, so ignore it. (It probably + * should not have got here, but ignoring it should be harmless.) + */ + + return; } + + /* + * Post the translated event to the main Tk event queue. + */ + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); } @@ -1256,12 +1281,12 @@ GenerateXEvent(hwnd, message, wParam, lParam) * * GetState -- * - * This function constructs a state mask for the mouse buttons - * and modifier keys as they were before the event occured. + * This function constructs a state mask for the mouse buttons and + * modifier keys as they were before the event occured. * * Results: - * Returns a composite value of all the modifier and button state - * flags that were set at the time the event occurred. + * Returns a composite value of all the modifier and button state flags + * that were set at the time the event occurred. * * Side effects: * None. @@ -1270,18 +1295,18 @@ GenerateXEvent(hwnd, message, wParam, lParam) */ static unsigned int -GetState(message, wParam, lParam) - UINT message; /* Win32 message type */ - WPARAM wParam; /* wParam of message, used if key message */ - LPARAM lParam; /* lParam of message, used if key message */ +GetState( + UINT message, /* Win32 message type */ + WPARAM wParam, /* wParam of message, used if key message */ + LPARAM lParam) /* lParam of message, used if key message */ { int mask; int prevState; /* 1 if key was previously down */ unsigned int state = TkWinGetModifierState(); /* - * If the event is a key press or release, we check for modifier - * keys so we can report the state of the world before the event. + * If the event is a key press or release, we check for modifier keys so + * we can report the state of the world before the event. */ if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN @@ -1289,39 +1314,46 @@ GetState(message, wParam, lParam) mask = 0; prevState = HIWORD(lParam) & KF_REPEAT; switch(wParam) { - case VK_SHIFT: - mask = ShiftMask; - break; - case VK_CONTROL: - mask = ControlMask; - break; - case VK_MENU: - mask = ALT_MASK; - break; - case VK_CAPITAL: - if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) { - mask = LockMask; - prevState = ((state & mask) ^ prevState) ? 0 : 1; - } - break; - case VK_NUMLOCK: - if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) { - mask = Mod1Mask; - prevState = ((state & mask) ^ prevState) ? 0 : 1; - } - break; - case VK_SCROLL: - if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) { - mask = Mod3Mask; - prevState = ((state & mask) ^ prevState) ? 0 : 1; - } - break; + case VK_SHIFT: + mask = ShiftMask; + break; + case VK_CONTROL: + mask = ControlMask; + break; + case VK_MENU: + mask = ALT_MASK; + break; + case VK_CAPITAL: + if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) { + mask = LockMask; + prevState = ((state & mask) ^ prevState) ? 0 : 1; + } + break; + case VK_NUMLOCK: + if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) { + mask = Mod1Mask; + prevState = ((state & mask) ^ prevState) ? 0 : 1; + } + break; + case VK_SCROLL: + if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) { + mask = Mod3Mask; + prevState = ((state & mask) ^ prevState) ? 0 : 1; + } + break; } if (prevState) { state |= mask; } else { state &= ~mask; } + if (HIWORD(lParam) & KF_EXTENDED) { + if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) { + state |= EXTENDED_MASK; + } else { + state &= ~EXTENDED_MASK; + } + } } return state; } @@ -1331,61 +1363,59 @@ GetState(message, wParam, lParam) * * GetTranslatedKey -- * - * Retrieves WM_CHAR messages that are placed on the system queue - * by the TranslateMessage system call and places them in the - * given KeyPress event. + * Retrieves WM_CHAR messages that are placed on the system queue by the + * TranslateMessage system call and places them in the given KeyPress + * event. * * Results: * Sets the trans_chars and nbytes member of the key event. * * Side effects: - * Removes any WM_CHAR messages waiting on the top of the system - * event queue. + * Removes any WM_CHAR messages waiting on the top of the system event + * queue. * *---------------------------------------------------------------------- */ static void -GetTranslatedKey(xkey) - XKeyEvent *xkey; +GetTranslatedKey( + XKeyEvent *xkey) { MSG msg; - + xkey->nbytes = 0; while ((xkey->nbytes < XMaxTransChars) && PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { - if ((msg.message == WM_CHAR) || (msg.message == WM_SYSCHAR)) { - GetMessage(&msg, NULL, 0, 0); + if ((msg.message != WM_CHAR) && (msg.message != WM_SYSCHAR)) { + break; + } + + GetMessage(&msg, NULL, 0, 0); + + /* + * If this is a normal character message, we may need to strip off the + * Alt modifier (e.g. Alt-digits). Note that we don't want to do this + * for system messages, because those were presumably generated as an + * Alt-char sequence (e.g. accelerator keys). + */ + if ((msg.message == WM_CHAR) && (msg.lParam & 0x20000000)) { + xkey->state = 0; + } + xkey->trans_chars[xkey->nbytes] = (char) msg.wParam; + xkey->nbytes++; + + if (((unsigned short) msg.wParam) > ((unsigned short) 0xff)) { /* - * If this is a normal character message, we may need to strip - * off the Alt modifier (e.g. Alt-digits). Note that we don't - * want to do this for system messages, because those were - * presumably generated as an Alt-char sequence (e.g. accelerator - * keys). + * 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. */ - if ((msg.message == WM_CHAR) && (msg.lParam & 0x20000000)) { - xkey->state = 0; - } - 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; + xkey->trans_chars[xkey->nbytes] = (char) (msg.wParam >> 8); + xkey->nbytes ++; } } } @@ -1396,11 +1426,11 @@ 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. + * child window function. 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. @@ -1412,8 +1442,8 @@ GetTranslatedKey(xkey) */ static void -UpdateInputLanguage(charset) - int charset; +UpdateInputLanguage( + int charset) { CHARSETINFO charsetInfo; Tcl_Encoding encoding; @@ -1422,8 +1452,8 @@ UpdateInputLanguage(charset) if (keyInputCharset == charset) { return; } - if (TranslateCharsetInfo((DWORD*)charset, &charsetInfo, TCI_SRCCHARSET) - == 0) { + if (TranslateCharsetInfo((DWORD*)charset, &charsetInfo, + TCI_SRCCHARSET) == 0) { /* * Some mysterious failure. */ @@ -1454,8 +1484,8 @@ UpdateInputLanguage(charset) * * TkWinGetKeyInputEncoding -- * - * Returns the current keyboard input encoding selected by the - * user (with WM_INPUTLANGCHANGE events). + * Returns the current keyboard input encoding selected by the user (with + * WM_INPUTLANGCHANGE events). * * Results: * The current keyboard input encoding. @@ -1467,7 +1497,7 @@ UpdateInputLanguage(charset) */ Tcl_Encoding -TkWinGetKeyInputEncoding() +TkWinGetKeyInputEncoding(void) { return keyInputEncoding; } @@ -1489,7 +1519,7 @@ TkWinGetKeyInputEncoding() */ Tcl_Encoding -TkWinGetUnicodeEncoding() +TkWinGetUnicodeEncoding(void) { if (unicodeEncoding == NULL) { unicodeEncoding = Tcl_GetEncoding(NULL, "unicode"); @@ -1502,23 +1532,22 @@ TkWinGetUnicodeEncoding() * * 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. + * 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 "?". + * 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. + * 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. + * Otherwise returns 0. * * Side effects: * Key events are put into the TK event queue. @@ -1527,109 +1556,115 @@ TkWinGetUnicodeEncoding() */ static int -HandleIMEComposition(hwnd, lParam) - HWND hwnd; /* Window receiving the message. */ - LPARAM lParam; /* Flags for the WM_IME_COMPOSITION - * message */ +HandleIMEComposition( + 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; - Tcl_Encoding unicodeEncoding = TkWinGetUnicodeEncoding(); + int n; BOOL isWinNT = (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT); if ((lParam & GCS_RESULTSTR) == 0) { - /* - * Composition is not finished yet. - */ + /* + * Composition is not finished yet. + */ - return 0; + return 0; } hIMC = ImmGetContext(hwnd); - if (hIMC) { + if (!hIMC) { + return 0; + } + + if (isWinNT) { + n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0); + } else { + n = ImmGetCompositionStringA(hIMC, GCS_RESULTSTR, NULL, 0); + } + + if (n > 0) { + char *buff = ckalloc((unsigned) n); + TkWindow *winPtr; + XEvent event; + int i; + if (isWinNT) { - n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0); + n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buff, + (unsigned) n); } else { - n = ImmGetCompositionStringA(hIMC, GCS_RESULTSTR, NULL, 0); - } + Tcl_DString utfString, unicodeString; + Tcl_Encoding unicodeEncoding = TkWinGetUnicodeEncoding(); + + n = ImmGetCompositionStringA(hIMC, GCS_RESULTSTR, buff, + (unsigned) n); + Tcl_DStringInit(&utfString); + Tcl_ExternalToUtfDString(keyInputEncoding, buff, n, &utfString); + Tcl_UtfToExternalDString(unicodeEncoding, + Tcl_DStringValue(&utfString), -1, &unicodeString); + i = Tcl_DStringLength(&unicodeString); + if (n < i) { + /* + * Only alloc more space if we need, otherwise just use what + * we've created. Don't realloc as that may copy data we no + * longer need. + */ - if ((n > 0) && ((buff = (char *) ckalloc(n)) != NULL)) { - if (isWinNT) { - n = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buff, n); - } else { - Tcl_DString utfString, unicodeString; - - n = ImmGetCompositionStringA(hIMC, GCS_RESULTSTR, buff, n); - Tcl_DStringInit(&utfString); - Tcl_ExternalToUtfDString(keyInputEncoding, buff, n, - &utfString); - Tcl_UtfToExternalDString(unicodeEncoding, - Tcl_DStringValue(&utfString), -1, &unicodeString); - i = Tcl_DStringLength(&unicodeString); - if (n < i) { - /* - * Only alloc more space if we need, otherwise just - * use what we've created. Don't realloc as that may - * copy data we no longer need. - */ - ckfree((char *) buff); - buff = (char *) ckalloc(i); - } - n = i; - memcpy(buff, Tcl_DStringValue(&unicodeString), n); - Tcl_DStringFree(&utfString); - Tcl_DStringFree(&unicodeString); + ckfree((char *) buff); + buff = (char *) ckalloc((unsigned) i); } + n = i; + memcpy(buff, Tcl_DStringValue(&unicodeString), (unsigned) n); + Tcl_DStringFree(&utfString); + Tcl_DStringFree(&unicodeString); + } + /* + * 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. + * + * Note that the event *must* be zeroed out first; Tk plays cunning + * games with the overalls structure. [Bug 2992129] + */ + + winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd); + + memset(&event, 0, sizeof(XEvent)); + 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; ) { /* - * 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. + * Simulate a pair of KeyPress and KeyRelease events for each + * UNICODE character in the composition. */ - 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; - } + event.xkey.trans_chars[0] = (char) buff[i++]; + event.xkey.trans_chars[1] = (char) buff[i++]; - return 0; + 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; } /* @@ -1649,10 +1684,11 @@ HandleIMEComposition(hwnd, lParam) */ void -Tk_FreeXId(display, xid) - Display *display; - XID xid; +Tk_FreeXId( + Display *display, + XID xid) { + /* Do nothing */ } /* @@ -1660,65 +1696,66 @@ Tk_FreeXId(display, xid) * * TkWinResendEvent -- * - * This function converts an X event into a Windows event and - * invokes the specified windo procedure. + * This function converts an X event into a Windows event and invokes the + * specified windo function. * * Results: * A standard Windows result. * * Side effects: - * Invokes the window procedure + * Invokes the window function * *---------------------------------------------------------------------- */ LRESULT -TkWinResendEvent(wndproc, hwnd, eventPtr) - WNDPROC wndproc; - HWND hwnd; - XEvent *eventPtr; +TkWinResendEvent( + WNDPROC wndproc, + HWND hwnd, + XEvent *eventPtr) { UINT msg; WPARAM wparam; LPARAM lparam; - if (eventPtr->type == ButtonPress) { - switch (eventPtr->xbutton.button) { - case Button1: - msg = WM_LBUTTONDOWN; - wparam = MK_LBUTTON; - break; - case Button2: - msg = WM_MBUTTONDOWN; - wparam = MK_MBUTTON; - break; - case Button3: - msg = WM_RBUTTONDOWN; - wparam = MK_RBUTTON; - break; - default: - return 0; - } - if (eventPtr->xbutton.state & Button1Mask) { - wparam |= MK_LBUTTON; - } - if (eventPtr->xbutton.state & Button2Mask) { - wparam |= MK_MBUTTON; - } - if (eventPtr->xbutton.state & Button3Mask) { - wparam |= MK_RBUTTON; - } - if (eventPtr->xbutton.state & ShiftMask) { - wparam |= MK_SHIFT; - } - if (eventPtr->xbutton.state & ControlMask) { - wparam |= MK_CONTROL; - } - lparam = MAKELPARAM((short) eventPtr->xbutton.x, - (short) eventPtr->xbutton.y); - } else { + if (eventPtr->type != ButtonPress) { return 0; } + + switch (eventPtr->xbutton.button) { + case Button1: + msg = WM_LBUTTONDOWN; + wparam = MK_LBUTTON; + break; + case Button2: + msg = WM_MBUTTONDOWN; + wparam = MK_MBUTTON; + break; + case Button3: + msg = WM_RBUTTONDOWN; + wparam = MK_RBUTTON; + break; + default: + return 0; + } + + if (eventPtr->xbutton.state & Button1Mask) { + wparam |= MK_LBUTTON; + } + if (eventPtr->xbutton.state & Button2Mask) { + wparam |= MK_MBUTTON; + } + if (eventPtr->xbutton.state & Button3Mask) { + wparam |= MK_RBUTTON; + } + if (eventPtr->xbutton.state & ShiftMask) { + wparam |= MK_SHIFT; + } + if (eventPtr->xbutton.state & ControlMask) { + wparam |= MK_CONTROL; + } + lparam = MAKELPARAM((short) eventPtr->xbutton.x, + (short) eventPtr->xbutton.y); return CallWindowProc(wndproc, hwnd, msg, wparam, lparam); } @@ -1727,8 +1764,8 @@ TkWinResendEvent(wndproc, hwnd, eventPtr) * * TkpGetMS -- * - * Return a relative time in milliseconds. It doesn't matter - * when the epoch was. + * Return a relative time in milliseconds. It doesn't matter when the + * epoch was. * * Results: * Number of milliseconds. @@ -1740,7 +1777,7 @@ TkWinResendEvent(wndproc, hwnd, eventPtr) */ unsigned long -TkpGetMS() +TkpGetMS(void) { return GetTickCount(); } @@ -1761,9 +1798,10 @@ TkpGetMS() */ void -TkWinUpdatingClipboard(int mode) +TkWinUpdatingClipboard( + int mode) { - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); tsdPtr->updatingClipboard = mode; @@ -1774,17 +1812,17 @@ TkWinUpdatingClipboard(int mode) * * Tk_SetCaretPos -- * - * This enables correct movement of focus in the MS Magnifier, as well - * as allowing us to correctly position the IME Window. The following - * Win32 APIs are used to work with MS caret: + * This enables correct movement of focus in the MS Magnifier, as well as + * allowing us to correctly position the IME Window. The following Win32 + * APIs are used to work with MS caret: * * CreateCaret DestroyCaret SetCaretPos GetCaretPos * - * Only one instance of caret can be active at any time - * (e.g. DestroyCaret API does not take any argument such as handle). - * Since do-it-right approach requires to track the create/destroy - * caret status all the time in a global scope among windows (or - * widgets), we just implement this minimal setup to get the job done. + * Only one instance of caret can be active at any time (e.g. + * DestroyCaret API does not take any argument such as handle). Since + * do-it-right approach requires to track the create/destroy caret status + * all the time in a global scope among windows (or widgets), we just + * implement this minimal setup to get the job done. * * Results: * None @@ -1796,16 +1834,20 @@ TkWinUpdatingClipboard(int mode) */ void -Tk_SetCaretPos(Tk_Window tkwin, int x, int y, int height) +Tk_SetCaretPos( + Tk_Window tkwin, + int x, int y, + int height) { static HWND caretHWND = NULL; TkCaret *caretPtr = &(((TkWindow *) tkwin)->dispPtr->caret); Window win; /* - * Prevent processing anything if the values haven't changed. - * Windows only has one display, so we can do this with statics. + * Prevent processing anything if the values haven't changed. Windows only + * has one display, so we can do this with statics. */ + if ((caretPtr->winPtr == ((TkWindow *) tkwin)) && (caretPtr->x == x) && (caretPtr->y == y)) { return; @@ -1817,9 +1859,8 @@ Tk_SetCaretPos(Tk_Window tkwin, int x, int y, int height) caretPtr->height = height; /* - * We adjust to the toplevel to get the coords right, as setting - * the IME composition window is based on the toplevel hwnd, so - * ignore height. + * We adjust to the toplevel to get the coords right, as setting the IME + * composition window is based on the toplevel hwnd, so ignore height. */ while (!Tk_IsTopLevel(tkwin)) { @@ -1852,11 +1893,13 @@ Tk_SetCaretPos(Tk_Window tkwin, int x, int y, int height) * The IME composition window should be updated whenever the caret * position is changed because a clause of the composition string may * be converted to the final characters and the other clauses still - * stay on the composition window. -- yamamoto + * stay on the composition window. -- yamamoto */ + hIMC = ImmGetContext(hwnd); if (hIMC) { COMPOSITIONFORM cform; + cform.dwStyle = CFS_POINT; cform.ptCurrentPos.x = x; cform.ptCurrentPos.y = y; @@ -1865,3 +1908,102 @@ Tk_SetCaretPos(Tk_Window tkwin, int x, int y, int height) } } } + +/* + *---------------------------------------------------------------------- + * + * Tk_GetUserInactiveTime -- + * + * Return the number of milliseconds the user was inactive. + * + * Results: + * Milliseconds of user inactive time or -1 if the user32.dll doesn't + * have the symbol GetLastInputInfo or GetLastInputInfo returns an error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +long +Tk_GetUserInactiveTime( + Display *dpy) /* Ignored on Windows */ +{ + struct tagLASTINPUTINFO { + UINT cbSize; + DWORD dwTime; + } li; + + /* + * Multiple settings of either of these variables should be OK; any thread + * hazards should just cause inefficiency... + */ + + static FARPROC pfnGetLastInputInfo = NULL; + static int initinfo = 0; + + if (!initinfo) { + HMODULE hMod = GetModuleHandleA("USER32.DLL"); + + initinfo = 1; + if (hMod){ + pfnGetLastInputInfo = GetProcAddress(hMod, "GetLastInputInfo"); + } + } + if (pfnGetLastInputInfo == NULL) { + return -1; + } + li.cbSize = sizeof(li); + if (!(BOOL)(pfnGetLastInputInfo)(&li)) { + return -1; + } + + /* + * Last input info is in milliseconds, since restart time. + */ + + return (GetTickCount()-li.dwTime); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_ResetUserInactiveTime -- + * + * Reset the user inactivity timer + * + * Results: + * none + * + * Side effects: + * The user inactivity timer of the underlaying windowing system is reset + * to zero. + * + *---------------------------------------------------------------------- + */ + +void +Tk_ResetUserInactiveTime( + Display *dpy) +{ + INPUT inp; + + inp.type = INPUT_MOUSE; + inp.mi.dx = 0; + inp.mi.dy = 0; + inp.mi.mouseData = 0; + inp.mi.dwFlags = MOUSEEVENTF_MOVE; + inp.mi.time = 0; + inp.mi.dwExtraInfo = (DWORD) NULL; + + SendInput(1, &inp, sizeof(inp)); +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |