+
+ }
+ 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 charcaters 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[256];
+ int has_AltGr = mswindows_current_layout_has_AltGr ();
+ int mods;
+ int extendedp = lParam & 0x1000000;
+ Lisp_Object keysym;
+
+ frame = XFRAME (mswindows_find_frame (hwnd));
+ GetKeyboardState (keymap);
+ mods = mswindows_modifier_state (keymap, has_AltGr);
+
+ /* Handle non-printables */
+ if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
+ extendedp)))
+ mswindows_enqueue_keypress_event (hwnd, keysym, mods);
+ else /* Normal keys & modifiers */
+ {
+ Emchar quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
+ BYTE keymap_orig[256];
+ 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 [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
+ else if (wParam == VK_MENU)
+ keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
+
+ memcpy (keymap_orig, keymap, 256);
+
+ 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;
+
+ /* 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 [VK_LCONTROL] = 0;
+ keymap [VK_CONTROL] = 0;
+ keymap [VK_RMENU] = 0;
+ keymap [VK_MENU] = 0;
+ }
+ SetKeyboardState (keymap);
+
+ /* 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 &&
+ msw_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)
+ {
+ TranslateMessage (&msg);
+ goto defproc;
+ }
+ } /* 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), 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)
+ {
+ msframe->ignore_next_lbutton_up = 0;