+ 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, 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:
+ /* Erase background only during non-dynamic sizing */
+ msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+ if (msframe->sizing && !mswindows_dynamic_frame_resize)
+ goto defproc;
+ return 1;
+
+ case WM_CLOSE:
+ fobj = mswindows_find_frame (hwnd);
+ mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
+ break;
+
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+
+ /* See Win95 comment under WM_KEYDOWN */
+ {
+ BYTE keymap[256];
+ int should_set_keymap = 0;
+
+#ifdef DEBUG_XEMACS
+ if (debug_mswindows_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);
+ keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
+ should_set_keymap = 1;
+ }
+ else if (wParam == VK_MENU)
+ {
+ GetKeyboardState (keymap);
+ keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
+ should_set_keymap = 1;
+ }
+
+ if (should_set_keymap)
+ // && (message_ != WM_SYSKEYUP
+ // || NILP (Vmenu_accelerator_enabled)))
+ SetKeyboardState (keymap);
+
+ }
+
+ if (key_needs_default_processing_p (wParam))
+ goto defproc;
+ else
+ break;
+
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+
+ /* In some locales the right-hand Alt key is labelled AltGr. This key
+ * should produce alternative characters when combined with another key.
+ * eg on a German keyboard pressing AltGr+q should produce '@'.
+ * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
+ * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
+ * it translates as if AltGr were down.
+ * We get round this by removing all modifiers from the keymap before
+ * calling TranslateMessage() unless AltGr is *really* down. */
+ {
+ BYTE keymap_trans[256];
+ BYTE keymap_orig[256];
+ BYTE keymap_sticky[256];
+ int has_AltGr = mswindows_current_layout_has_AltGr ();
+ int mods = 0;
+ int extendedp = lParam & 0x1000000;
+ Lisp_Object keysym;
+ int sticky_changed;
+
+#ifdef DEBUG_XEMACS
+ if (debug_mswindows_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));
+ 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, (DWORD) -1, has_AltGr);
+
+ /* Handle non-printables */
+ if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
+ extendedp)))
+ {
+ 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)));
+ POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
+ MSG msg, tranmsg;
+ int potential_accelerator = 0;
+ int got_accelerator = 0;
+
+ msg.hwnd = hwnd;
+ msg.message = message_;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ msg.time = GetMessageTime();
+ msg.pt = pnt;
+
+ /* GetKeyboardState() does not work as documented on Win95. We have
+ * 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_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
+ keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
+ }
+ else if (wParam == VK_MENU)
+ {
+ 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)
+ 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_trans[VK_RCONTROL] = 0;
+ keymap_trans[VK_LMENU] = 0;
+ if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
+ || !(keymap_trans[VK_RMENU] & 0x80))
+ {
+ keymap_trans[VK_LCONTROL] = 0;
+ keymap_trans[VK_CONTROL] = 0;
+ keymap_trans[VK_RMENU] = 0;
+ keymap_trans[VK_MENU] = 0;
+ }
+ 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))
+ {
+ int mods1 = mods;
+ WPARAM ch = tranmsg.wParam;
+
+ /* If a quit char with no modifiers other than control and
+ shift, then mark it with a fake modifier, which is removed
+ 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))
+ {
+ mods1 |= FAKE_MOD_QUIT;
+ ++mswindows_quit_chars_count;
+ }
+ else if (potential_accelerator && !got_accelerator &&
+ mswindows_char_is_accelerator (frame, ch))
+ {
+ got_accelerator = 1;
+ break;
+ }
+ mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1);
+ } /* while */
+
+ /* 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
+ break;
+
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ /* 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_,
+ MAKEPOINTS (lParam),
+ wParam &~ MK_MBUTTON,
+ GetMessageTime());
+ break;
+
+ case WM_LBUTTONUP:
+ msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+ msframe->last_click_time = GetMessageTime();
+
+ KillTimer (hwnd, BUTTON_2_TIMER_ID);
+ msframe->button2_need_lbutton = 0;
+ if (msframe->ignore_next_lbutton_up)