X-Git-Url: http://git.chise.org/gitweb/?p=chise%2Fxemacs-chise.git.1;a=blobdiff_plain;f=src%2Fevent-msw.c;h=8f8ecf640602d3c83224b51fb91a26d05d3fc92d;hp=a949be89d146973de0e5211f30011f5821dda586;hb=762383636a99307282c2d93d26c35c046ec24da1;hpb=a1655b870904de973c366d85ebdc8adde4ef5e1e diff --git a/src/event-msw.c b/src/event-msw.c index a949be8..8f8ecf6 100644 --- a/src/event-msw.c +++ b/src/event-msw.c @@ -1,4 +1,4 @@ -/* The mswindows event_stream interface. +/* The mswindows event_stream interface. Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. Copyright (C) 1995 Sun Microsystems, Inc. Copyright (C) 1996, 2000 Ben Wing. @@ -58,6 +58,7 @@ Boston, MA 02111-1307, USA. */ #include "process.h" #include "redisplay.h" #include "select.h" +#include "window.h" #include "sysproc.h" #include "syswait.h" #include "systime.h" @@ -68,20 +69,16 @@ Boston, MA 02111-1307, USA. */ #ifdef HAVE_MSG_SELECT #include "sysfile.h" #include "console-tty.h" -#elif defined(__CYGWIN32__) +#elif defined(CYGWIN) typedef unsigned int SOCKET; #endif #include #include -#if !(defined(__CYGWIN32__) || defined(__MINGW32__)) +#if !(defined(CYGWIN) || defined(MINGW)) # include /* For IShellLink */ #endif -#if defined (__CYGWIN32__) && (CYGWIN_VERSION_DLL_MAJOR < 20) -typedef NMHDR *LPNMHDR; -#endif - #ifdef HAVE_MENUBARS #define ADJR_MENUFLAG TRUE #else @@ -103,6 +100,8 @@ static int mswindows_modifier_state (BYTE* keymap, int has_AltGr); static void mswindows_set_chord_timer (HWND hwnd); static int mswindows_button2_near_enough (POINTS p1, POINTS p2); static int mswindows_current_layout_has_AltGr (void); +static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, + int downp, int keyp); static struct event_stream *mswindows_event_stream; @@ -151,6 +150,10 @@ int mswindows_mouse_button_max_skew_x; int mswindows_mouse_button_max_skew_y; int mswindows_mouse_button_tolerance; +#ifdef DEBUG_XEMACS +int mswindows_debug_events; +#endif + /* This is the event signaled by the event pump. See mswindows_pump_outstanding_events for comments */ static Lisp_Object mswindows_error_caught_in_modal_loop; @@ -468,7 +471,7 @@ init_slurp_stream (void) #define NTPIPE_SHOVE_STREAM_DATA(stream) \ LSTREAM_TYPE_DATA (stream, ntpipe_shove) -#define MAX_SHOVE_BUFFER_SIZE 128 +#define MAX_SHOVE_BUFFER_SIZE 512 struct ntpipe_shove_stream { @@ -502,15 +505,18 @@ shove_thread (LPVOID vparam) InterlockedIncrement (&s->idle_p); WaitForSingleObject (s->hev_thread, INFINITE); - if (s->die_p) - break; - - /* Write passed buffer */ - if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL) - || bytes_written != s->size) + /* Write passed buffer if any */ + if (s->size > 0) { - s->error_p = TRUE; - InterlockedIncrement (&s->die_p); + if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL) + || bytes_written != s->size) + { + s->error_p = TRUE; + InterlockedIncrement (&s->die_p); + } + /* Set size to zero so we won't write it again if the closer sets + die_p and kicks us */ + s->size = 0; } if (s->die_p) @@ -543,6 +549,15 @@ make_ntpipe_output_stream (HANDLE hpipe, LPARAM param) return Qnil; } + /* Set the priority of the thread higher so we don't end up waiting + on it to send things. */ + if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST)) + { + CloseHandle (s->hthread); + Lstream_delete (lstr); + return Qnil; + } + /* hev_thread is an auto-reset event, initially nonsignaled */ s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL); @@ -583,6 +598,9 @@ ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size) /* Start output */ InterlockedDecrement (&s->idle_p); SetEvent (s->hev_thread); + /* Give it a chance to run -- this dramatically improves performance + of things like crypt. */ + (void) SwitchToThread (); return size; } @@ -601,14 +619,18 @@ ntpipe_shove_closer (Lstream *stream) /* Force thread stop */ InterlockedIncrement (&s->die_p); - /* Close pipe handle, possibly breaking it */ - CloseHandle (s->hpipe); - - /* Thread will end upon unblocking */ + /* Thread will end upon unblocking. If it's already unblocked this will + do nothing, but the thread won't look at die_p until it's written any + pending output. */ SetEvent (s->hev_thread); /* Wait while thread terminates */ WaitForSingleObject (s->hthread, INFINITE); + + /* Close pipe handle, possibly breaking it */ + CloseHandle (s->hpipe); + + /* Close the thread handle */ CloseHandle (s->hthread); /* Destroy the event */ @@ -936,17 +958,21 @@ mswindows_enqueue_process_event (Lisp_Process* p) } static void -mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, DWORD when) +mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, + DWORD when) { + int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || + msg == WM_RBUTTONDOWN); /* We always use last message time, because mouse button events may get delayed, and XEmacs double click recognition will fail */ Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); - Lisp_Event* event = XEVENT(emacs_event); + Lisp_Event* event = XEVENT (emacs_event); - event->channel = mswindows_find_frame(hwnd); + mswindows_handle_sticky_modifiers (0, 0, downp, 0); + event->channel = mswindows_find_frame (hwnd); event->timestamp = when; event->event.button.button = (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 : @@ -955,8 +981,7 @@ mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, DWORD w event->event.button.y = where.y; event->event.button.modifiers = mswindows_modifier_state (NULL, 0); - if (msg==WM_LBUTTONDOWN || msg==WM_MBUTTONDOWN || - msg==WM_RBUTTONDOWN) + if (downp) { event->event_type = button_press_event; SetCapture (hwnd); @@ -1245,14 +1270,20 @@ mswindows_drain_windows_queue (void) while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { - /* We have to translate messages that are not sent to the main - window. This is so that key presses work ok in things like - edit fields. However, we *musn't* translate message for the - main window as this is handled in the wnd proc. + /* We have to translate messages that are not sent to an XEmacs + frame. This is so that key presses work ok in things like + edit fields. However, we *musn't* translate message for XEmacs + frames as this is handled in the wnd proc. We also have to avoid generating paint magic events for windows that aren't XEmacs frames */ - if (GetWindowLong (msg.hwnd, GWL_STYLE) & (WS_CHILD|WS_POPUP)) + /* GetClassName will truncate a longer class name. By adding one + extra character, we are forcing textual comparison to fail + if the name is longer than XEMACS_CLASS */ + char class_name_buf [sizeof (XEMACS_CLASS) + 2] = ""; + GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1); + if (stricmp (class_name_buf, XEMACS_CLASS) != 0) { + /* Not an XEmacs frame */ TranslateMessage (&msg); } else if (msg.message == WM_PAINT) @@ -1264,8 +1295,8 @@ mswindows_drain_windows_queue (void) assert (msg.wParam == 0); /* Queue a magic event for handling when safe */ - msframe = FRAME_MSWINDOWS_DATA ( - XFRAME (mswindows_find_frame (msg.hwnd))); + msframe = + FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd))); if (!msframe->paint_pending) { msframe->paint_pending = 1; @@ -1594,7 +1625,7 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv, if (*end) return DDE_FNOTPROCESSED; -#ifdef __CYGWIN32__ +#ifdef CYGWIN filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5); strcpy (filename, "file:"); cygwin32_win32_to_posix_path_list (cmd, filename+5); @@ -1664,6 +1695,9 @@ mswindows_handle_paint (struct frame *frame) windows are unmapped, however once we are in the guts of WM_PAINT we need to make sure that we don't register unmaps then because they will not actually occur. */ + /* #### commenting out the next line seems to fix some problems + but not all. only andy currently understands this stuff and + he needs to review it more carefully. --ben */ if (!check_for_ignored_expose (frame, x, y, width, height)) { hold_ignored_expose_registration = 1; @@ -1681,17 +1715,292 @@ mswindows_handle_paint (struct frame *frame) static int key_needs_default_processing_p (UINT vkey) { - if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU) + if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU + /* if we let ALT activate the menu like this, then sticky ALT-modified + keystrokes become impossible. */ + && !modifier_keys_are_sticky) return 1; return 0; } +/* key-handling code is always ugly. It just ends up working out + that way. + + #### Most of the sticky-modifier code below is copied from similar + code in event-Xt.c. They should somehow or other be merged. + + Here are some pointers: + + -- DOWN_MASK indicates which modifiers should be treated as "down" + when the corresponding upstroke happens. It gets reset for + a particular modifier when that modifier goes up, and reset + for all modifiers when a non-modifier key is pressed. Example: + + I press Control-A-Shift and then release Control-A-Shift. + I want the Shift key to be sticky but not the Control key. + + -- If a modifier key is sticky, I can unstick it by pressing + the modifier key again. */ + +static WPARAM last_downkey; +static int need_to_add_mask, down_mask; + +#define XEMSW_LCONTROL (1<<0) +#define XEMSW_RCONTROL (1<<1) +#define XEMSW_LSHIFT (1<<2) +#define XEMSW_RSHIFT (1<<3) +#define XEMSW_LMENU (1<<4) +#define XEMSW_RMENU (1<<5) + +static int +mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, + int downp, int keyp) +{ + int mods = 0; + + if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */ + return 0; + + if (! (keyp && + (wParam == VK_CONTROL || wParam == VK_LCONTROL || + wParam == VK_RCONTROL || + wParam == VK_MENU || wParam == VK_LMENU || + wParam == VK_RMENU || + wParam == VK_SHIFT || wParam == VK_LSHIFT || + wParam == VK_RSHIFT))) + { /* Not a modifier key */ + if (downp && keyp && !last_downkey) + last_downkey = wParam; + /* If I hold press-and-release the Control key and then press + and hold down the right arrow, I want it to auto-repeat + Control-Right. On the other hand, if I do the same but + manually press the Right arrow a bunch of times, I want + to see one Control-Right and then a bunch of Rights. + This means that we need to distinguish between an + auto-repeated key and a key pressed and released a bunch + of times. */ + else if ((downp && !keyp) || + (downp && keyp && last_downkey && + (wParam != last_downkey || + /* the "previous key state" bit indicates autorepeat */ + ! (lParam & (1 << 30))))) + { + need_to_add_mask = 0; + last_downkey = 0; + } + if (downp) + down_mask = 0; + + mods = need_to_add_mask; + } + else /* Modifier key pressed */ + { + /* If a non-modifier key was pressed in the middle of a bunch + of modifiers, then it unsticks all the modifiers that were + previously pressed. We cannot unstick the modifiers until + now because we want to check for auto-repeat of the + non-modifier key. */ + + if (last_downkey) + { + last_downkey = 0; + need_to_add_mask = 0; + } + +#define FROB(mask) \ +do { \ + if (downp && keyp) \ + { \ + /* If modifier key is already sticky, \ + then unstick it. Note that we do \ + not test down_mask to deal with the \ + unlikely but possible case that the \ + modifier key auto-repeats. */ \ + if (need_to_add_mask & mask) \ + { \ + need_to_add_mask &= ~mask; \ + down_mask &= ~mask; \ + } \ + else \ + down_mask |= mask; \ + } \ + else \ + { \ + if (down_mask & mask) \ + { \ + down_mask &= ~mask; \ + need_to_add_mask |= mask; \ + } \ + } \ +} while (0) + + if ((wParam == VK_CONTROL && (lParam & 0x1000000)) + || wParam == VK_RCONTROL) + FROB (XEMSW_RCONTROL); + if ((wParam == VK_CONTROL && !(lParam & 0x1000000)) + || wParam == VK_LCONTROL) + FROB (XEMSW_LCONTROL); + + if ((wParam == VK_SHIFT && (lParam & 0x1000000)) + || wParam == VK_RSHIFT) + FROB (XEMSW_RSHIFT); + if ((wParam == VK_SHIFT && !(lParam & 0x1000000)) + || wParam == VK_LSHIFT) + FROB (XEMSW_LSHIFT); + + if ((wParam == VK_MENU && (lParam & 0x1000000)) + || wParam == VK_RMENU) + FROB (XEMSW_RMENU); + if ((wParam == VK_MENU && !(lParam & 0x1000000)) + || wParam == VK_LMENU) + FROB (XEMSW_LMENU); + } +#undef FROB + + if (mods && downp) + { + BYTE keymap[256]; + + GetKeyboardState (keymap); + + if (mods & XEMSW_LCONTROL) + { + keymap [VK_CONTROL] |= 0x80; + keymap [VK_LCONTROL] |= 0x80; + } + if (mods & XEMSW_RCONTROL) + { + keymap [VK_CONTROL] |= 0x80; + keymap [VK_RCONTROL] |= 0x80; + } + + if (mods & XEMSW_LSHIFT) + { + keymap [VK_SHIFT] |= 0x80; + keymap [VK_LSHIFT] |= 0x80; + } + if (mods & XEMSW_RSHIFT) + { + keymap [VK_SHIFT] |= 0x80; + keymap [VK_RSHIFT] |= 0x80; + } + + if (mods & XEMSW_LMENU) + { + keymap [VK_MENU] |= 0x80; + keymap [VK_LMENU] |= 0x80; + } + if (mods & XEMSW_RMENU) + { + keymap [VK_MENU] |= 0x80; + keymap [VK_RMENU] |= 0x80; + } + + SetKeyboardState (keymap); + return 1; + } + + return 0; +} + +static void +clear_sticky_modifiers (void) +{ + need_to_add_mask = 0; + last_downkey = 0; + down_mask = 0; +} + +#ifdef DEBUG_XEMACS + +#if 0 + +static void +output_modifier_keyboard_state (void) +{ + BYTE keymap[256]; + + GetKeyboardState (keymap); + + stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", + keymap[VK_MENU] & 0x80 ? 1 : 0, + keymap[VK_MENU] & 0x1 ? 1 : 0, + keymap[VK_LMENU] & 0x80 ? 1 : 0, + keymap[VK_LMENU] & 0x1 ? 1 : 0, + keymap[VK_RMENU] & 0x80 ? 1 : 0, + keymap[VK_RMENU] & 0x1 ? 1 : 0); + stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n", + keymap[VK_CONTROL] & 0x80 ? 1 : 0, + keymap[VK_CONTROL] & 0x1 ? 1 : 0, + keymap[VK_LCONTROL] & 0x80 ? 1 : 0, + keymap[VK_LCONTROL] & 0x1 ? 1 : 0, + keymap[VK_RCONTROL] & 0x80 ? 1 : 0, + keymap[VK_RCONTROL] & 0x1 ? 1 : 0); + stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n", + keymap[VK_SHIFT] & 0x80 ? 1 : 0, + keymap[VK_SHIFT] & 0x1 ? 1 : 0, + keymap[VK_LSHIFT] & 0x80 ? 1 : 0, + keymap[VK_LSHIFT] & 0x1 ? 1 : 0, + keymap[VK_RSHIFT] & 0x80 ? 1 : 0, + keymap[VK_RSHIFT] & 0x1 ? 1 : 0); +} + +#endif + +/* try to debug the stuck-alt-key problem. + + #### this happens only inconsistently, and may only happen when using + StickyKeys in the Win2000 accessibility section of the control panel, + which is extremely broken for other reasons. */ + +static void +output_alt_keyboard_state (void) +{ + BYTE keymap[256]; + SHORT keystate[3]; + // SHORT asyncstate[3]; + + GetKeyboardState (keymap); + keystate[0] = GetKeyState (VK_MENU); + keystate[1] = GetKeyState (VK_LMENU); + keystate[2] = GetKeyState (VK_RMENU); + /* Doing this interferes with key processing. */ +/* asyncstate[0] = GetAsyncKeyState (VK_MENU); */ +/* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */ +/* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */ + + stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", + keymap[VK_MENU] & 0x80 ? 1 : 0, + keymap[VK_MENU] & 0x1 ? 1 : 0, + keymap[VK_LMENU] & 0x80 ? 1 : 0, + keymap[VK_LMENU] & 0x1 ? 1 : 0, + keymap[VK_RMENU] & 0x80 ? 1 : 0, + keymap[VK_RMENU] & 0x1 ? 1 : 0); + stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", + keystate[0] & 0x8000 ? 1 : 0, + keystate[0] & 0x1 ? 1 : 0, + keystate[1] & 0x8000 ? 1 : 0, + keystate[1] & 0x1 ? 1 : 0, + keystate[2] & 0x8000 ? 1 : 0, + keystate[2] & 0x1 ? 1 : 0); +/* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */ +/* asyncstate[0] & 0x8000 ? 1 : 0, */ +/* asyncstate[0] & 0x1 ? 1 : 0, */ +/* asyncstate[1] & 0x8000 ? 1 : 0, */ +/* asyncstate[1] & 0x1 ? 1 : 0, */ +/* asyncstate[2] & 0x8000 ? 1 : 0, */ +/* asyncstate[2] & 0x1 ? 1 : 0); */ +} + +#endif /* DEBUG_XEMACS */ + + /* * The windows procedure for the window class XEMACS_CLASS */ LRESULT WINAPI -mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam) { /* Note: Remember to initialize emacs_event and event before use. This code calls code that can GC. You must GCPRO before calling such code. */ @@ -1703,13 +2012,16 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) struct mswindows_frame* msframe; assert (!GetWindowLong (hwnd, GWL_USERDATA)); - switch (message) + switch (message_) { case WM_DESTROYCLIPBOARD: /* We own the clipboard and someone else wants it. Delete our cached copy of the clipboard contents so we'll ask for it from - Windows again when someone does a paste. */ - handle_selection_clear(QCLIPBOARD); + Windows again when someone does a paste, and destroy any memory + objects we hold on the clipboard that are not in the list of types + that Windows will delete itself. */ + mswindows_destroy_selection (QCLIPBOARD); + handle_selection_clear (QCLIPBOARD); break; case WM_ERASEBKGND: @@ -1726,11 +2038,23 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_KEYUP: case WM_SYSKEYUP: + /* See Win95 comment under WM_KEYDOWN */ { BYTE keymap[256]; int should_set_keymap = 0; +#ifdef DEBUG_XEMACS + if (mswindows_debug_events) + { + stderr_out ("%s wparam=%d lparam=%d\n", + message_ == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP", + wParam, (int)lParam); + output_alt_keyboard_state (); + } +#endif /* DEBUG_XEMACS */ + + mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1); if (wParam == VK_CONTROL) { GetKeyboardState (keymap); @@ -1744,12 +2068,13 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) should_set_keymap = 1; } - if (should_set_keymap - && (message != WM_SYSKEYUP - || NILP (Vmenu_accelerator_enabled))) + if (should_set_keymap) + // && (message_ != WM_SYSKEYUP + // || NILP (Vmenu_accelerator_enabled))) SetKeyboardState (keymap); } + if (key_needs_default_processing_p (wParam)) goto defproc; else @@ -1757,6 +2082,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_KEYDOWN: case WM_SYSKEYDOWN: + /* In some locales the right-hand Alt key is labelled AltGr. This key * should produce alternative charcaters when combined with another key. * eg on a German keyboard pressing AltGr+q should produce '@'. @@ -1766,31 +2092,65 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) * We get round this by removing all modifiers from the keymap before * calling TranslateMessage() unless AltGr is *really* down. */ { - BYTE keymap[256]; + BYTE keymap_trans[256]; + BYTE keymap_orig[256]; + BYTE keymap_sticky[256]; int has_AltGr = mswindows_current_layout_has_AltGr (); - int mods; + int mods = 0; int extendedp = lParam & 0x1000000; Lisp_Object keysym; + int sticky_changed; +#ifdef DEBUG_XEMACS + if (mswindows_debug_events) + { + stderr_out ("%s wparam=%d lparam=%d\n", + message_ == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN", + wParam, (int)lParam); + output_alt_keyboard_state (); + } +#endif /* DEBUG_XEMACS */ + + GetKeyboardState (keymap_orig); frame = XFRAME (mswindows_find_frame (hwnd)); - GetKeyboardState (keymap); - mods = mswindows_modifier_state (keymap, has_AltGr); + if ((sticky_changed = + mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1))) + { + GetKeyboardState (keymap_sticky); + if (keymap_sticky[VK_MENU] & 0x80) + { + message_ = WM_SYSKEYDOWN; + /* We have to set the "context bit" so that the + TranslateMessage() call below that generates the + SYSCHAR message does its thing; see the documentation + on WM_SYSKEYDOWN */ + lParam |= 1 << 29; + } + } + else + memcpy (keymap_sticky, keymap_orig, 256); + + mods = mswindows_modifier_state (keymap_sticky, has_AltGr); /* Handle non-printables */ if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods, extendedp))) - mswindows_enqueue_keypress_event (hwnd, keysym, mods); + { + mswindows_enqueue_keypress_event (hwnd, keysym, mods); + if (sticky_changed) + SetKeyboardState (keymap_orig); + } else /* Normal keys & modifiers */ { - Emchar quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); - BYTE keymap_orig[256]; + Emchar quit_ch = + CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; MSG msg, tranmsg; int potential_accelerator = 0; int got_accelerator = 0; msg.hwnd = hwnd; - msg.message = message; + msg.message = message_; msg.wParam = wParam; msg.lParam = lParam; msg.time = GetMessageTime(); @@ -1800,37 +2160,44 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) * to loosely track Left and Right modifiers on behalf of the OS, * without screwing up Windows NT which tracks them properly. */ if (wParam == VK_CONTROL) - keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; + { + keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; + keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; + } else if (wParam == VK_MENU) - keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80; - - memcpy (keymap_orig, keymap, 256); + { + keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; + keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; + } if (!NILP (Vmenu_accelerator_enabled) && - !(mods & XEMACS_MOD_SHIFT) && message == WM_SYSKEYDOWN) + !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN) potential_accelerator = 1; /* Remove shift modifier from an ascii character */ mods &= ~XEMACS_MOD_SHIFT; + memcpy (keymap_trans, keymap_sticky, 256); + /* Clear control and alt modifiers unless AltGr is pressed */ - keymap [VK_RCONTROL] = 0; - keymap [VK_LMENU] = 0; - if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) - || !(keymap [VK_RMENU] & 0x80)) + keymap_trans[VK_RCONTROL] = 0; + keymap_trans[VK_LMENU] = 0; + if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80) + || !(keymap_trans[VK_RMENU] & 0x80)) { - keymap [VK_LCONTROL] = 0; - keymap [VK_CONTROL] = 0; - keymap [VK_RMENU] = 0; - keymap [VK_MENU] = 0; + keymap_trans[VK_LCONTROL] = 0; + keymap_trans[VK_CONTROL] = 0; + keymap_trans[VK_RMENU] = 0; + keymap_trans[VK_MENU] = 0; } - SetKeyboardState (keymap); + SetKeyboardState (keymap_trans); /* Maybe generate some WM_[SYS]CHARs in the queue */ TranslateMessage (&msg); while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) - || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE)) + || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, + PM_REMOVE)) { int mods1 = mods; WPARAM ch = tranmsg.wParam; @@ -1840,31 +2207,39 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) upon dequeueing the event */ /* #### This might also not withstand localization, if quit character is not a latin-1 symbol */ - if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL) && quit_ch + 'a' - 1 == ch) - || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL) && quit_ch == ch)) - && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT)) == 0)) + if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL) + && quit_ch + 'a' - 1 == ch) + || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL) + && quit_ch == ch)) + && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT)) + == 0)) { mods1 |= FAKE_MOD_QUIT; ++mswindows_quit_chars_count; } else if (potential_accelerator && !got_accelerator && - msw_char_is_accelerator (frame, ch)) + mswindows_char_is_accelerator (frame, ch)) { got_accelerator = 1; break; } mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1); } /* while */ - SetKeyboardState (keymap_orig); + /* This generates WM_SYSCHAR messages, which are interpreted by DefWindowProc as the menu selections. */ if (got_accelerator) { + SetKeyboardState (keymap_sticky); TranslateMessage (&msg); + SetKeyboardState (keymap_orig); goto defproc; } + + SetKeyboardState (keymap_orig); } /* else */ } + if (key_needs_default_processing_p (wParam)) goto defproc; else @@ -1875,7 +2250,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* Real middle mouse button has nothing to do with emulated one: if one wants to exercise fingers playing chords on the mouse, he is allowed to do that! */ - mswindows_enqueue_mouse_button_event (hwnd, message, + mswindows_enqueue_mouse_button_event (hwnd, message_, MAKEPOINTS (lParam), GetMessageTime()); break; @@ -2190,21 +2565,31 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DISPLAYCHANGE: { struct device *d; + DWORD message_tick = GetMessageTime (); fobj = mswindows_find_frame (hwnd); frame = XFRAME (fobj); d = XDEVICE (FRAME_DEVICE (frame)); - DEVICE_MSWINDOWS_HORZRES(d) = LOWORD (lParam); - DEVICE_MSWINDOWS_VERTRES(d) = HIWORD (lParam); - DEVICE_MSWINDOWS_BITSPIXEL(d) = wParam; - break; + /* Do this only once per message. XEmacs can receive this message + through as many frames as it currently has open. Message time + will be the same for all these messages. Despite extreme + efficiency, the code below has about one in 4 billion + probability that the HDC is not recreated, provided that + XEmacs is running sufficiently longer than 52 days. */ + if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick) + { + DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick; + DeleteDC (DEVICE_MSWINDOWS_HCDC(d)); + DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL); + } } + break; /* Misc magic events which only require that the frame be identified */ case WM_SETFOCUS: case WM_KILLFOCUS: - mswindows_enqueue_magic_event (hwnd, message); + mswindows_enqueue_magic_event (hwnd, message_); break; case WM_WINDOWPOSCHANGING: @@ -2353,7 +2738,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; #endif - return DefWindowProc (hwnd, message, wParam, lParam); + return DefWindowProc (hwnd, message_, wParam, lParam); /* Bite me - a spurious command. This used to not be able to happen but with the introduction of widgets its now possible. */ @@ -2389,7 +2774,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) (XCOLOR_INSTANCE (FACE_BACKGROUND (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), - XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + XIMAGE_INSTANCE_FRAME (image_instance))))); } last_widget_brushed = ii; SetTextColor @@ -2398,7 +2783,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) (XCOLOR_INSTANCE (FACE_FOREGROUND (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), - XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + XIMAGE_INSTANCE_FRAME (image_instance))))); SetBkMode (hdc, OPAQUE); SetBkColor (hdc, @@ -2406,7 +2791,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) (XCOLOR_INSTANCE (FACE_BACKGROUND (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), - XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + XIMAGE_INSTANCE_FRAME (image_instance))))); return (LRESULT)widget_brush; } } @@ -2453,7 +2838,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) DragQueryFile ((HANDLE) wParam, i, fname, len+1); /* May be a shell link aka "shortcut" - replace fname if so */ -#if !(defined(__CYGWIN32__) || defined(__MINGW32__)) +#if !(defined(CYGWIN) || defined(MINGW)) /* cygwin doesn't define this COM stuff */ if (!stricmp (fname + strlen (fname) - 4, ".LNK")) { @@ -2490,7 +2875,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } #endif -#ifdef __CYGWIN32__ +#ifdef CYGWIN filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5); strcpy (filename, "file:"); cygwin32_win32_to_posix_path_list (fname, filename+5); @@ -2515,7 +2900,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) defproc: default: - return DefWindowProc (hwnd, message, wParam, lParam); + return DefWindowProc (hwnd, message_, wParam, lParam); } return (0); } @@ -2582,13 +2967,15 @@ mswindows_current_layout_has_AltGr (void) /* Returns the state of the modifier keys in the format expected by the * Lisp_Event key_data, button_data and motion_data modifiers member */ -int mswindows_modifier_state (BYTE* keymap, int has_AltGr) +static int +mswindows_modifier_state (BYTE* keymap, int has_AltGr) { int mods = 0; + BYTE keymap2[256]; if (keymap == NULL) { - keymap = (BYTE*) alloca(256); + keymap = keymap2; GetKeyboardState (keymap); has_AltGr = mswindows_current_layout_has_AltGr (); } @@ -2839,18 +3226,19 @@ emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event) struct frame *f = XFRAME (frame); int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS); Lisp_Object conser; + struct gcpro gcpro1; - /* struct gcpro gcpro1; */ - - /* Clear sticky modifiers here (if we had any) */ + /* On focus change, clear all memory of sticky modifiers + to avoid non-intuitive behavior. */ + clear_sticky_modifiers (); conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); - /* GCPRO1 (conser); XXX Not necessary? */ + GCPRO1 (conser); emacs_handle_focus_change_preliminary (conser); /* Under X the stuff up to here is done in the X event handler. I Don't know why */ emacs_handle_focus_change_final (conser); - /* UNGCPRO; */ + UNGCPRO; } break; @@ -3165,6 +3553,20 @@ vars_of_event_mswindows (void) mswindows_error_caught_in_modal_loop = Qnil; staticpro (&mswindows_error_caught_in_modal_loop); + +#ifdef DEBUG_XEMACS + DEFVAR_INT ("mswindows-debug-events", &mswindows_debug_events /* +If non-zero, display debug information about Windows events that XEmacs sees. +Information is displayed in a console window. Currently defined values are: + +1 == non-verbose output +2 == verbose output + +#### Unfortunately, not yet implemented. +*/ ); + mswindows_debug_events = 0; +#endif + DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu", &mswindows_alt_by_itself_activates_menu /* *Controls whether pressing and releasing the Alt key activates the menubar.