]> code.delx.au - gnu-emacs/blobdiff - src/w32inevt.c
*** empty log message ***
[gnu-emacs] / src / w32inevt.c
index f31f88edf09c618c98f45dbc8452a703418859f0..0fededa6aea5e4a32ac966ec52fde92cf51bb464 100644 (file)
@@ -1,5 +1,6 @@
 /* Input event support for Emacs on the Microsoft W32 API.
-   Copyright (C) 1992, 1993, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1995, 2002, 2003, 2004,
+                 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -15,21 +16,28 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
 
    Drew Bliss                   01-Oct-93
      Adapted from ntkbd.c by Tim Fleehart
 */
 
 
-#include "config.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <windows.h>
 
+#ifndef MOUSE_MOVED
+#define MOUSE_MOVED   1
+#endif
+
 #include "lisp.h"
+#include "keyboard.h"
 #include "frame.h"
 #include "blockinput.h"
 #include "termhooks.h"
@@ -49,6 +57,9 @@ extern void reinvoke_input_signal (void);
 /* from dispnew.c */
 extern int change_frame_size (FRAME_PTR, int, int, int, int);
 
+/* from w32console.c */
+extern int w32_use_full_screen_buffer;
+
 /* from w32fns.c */
 extern Lisp_Object Vw32_alt_is_meta;
 extern unsigned int map_keypad_keys (unsigned int, unsigned int);
@@ -60,6 +71,7 @@ extern Lisp_Object Vw32_enable_num_lock;
 extern Lisp_Object Vw32_recognize_altgr;
 extern Lisp_Object Vw32_pass_lwindow_to_system;
 extern Lisp_Object Vw32_pass_rwindow_to_system;
+extern Lisp_Object Vw32_phantom_key_code;
 extern Lisp_Object Vw32_lwindow_modifier;
 extern Lisp_Object Vw32_rwindow_modifier;
 extern Lisp_Object Vw32_apps_modifier;
@@ -71,15 +83,15 @@ extern unsigned int w32_key_to_modifier (int key);
 static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE];
 static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue;
 
-static int 
+static int
 fill_queue (BOOL block)
 {
   BOOL rc;
   DWORD events_waiting;
-  
+
   if (queue_ptr < queue_end)
     return queue_end-queue_ptr;
-  
+
   if (!block)
     {
       /* Check to see if there are some events to read before we try
@@ -89,7 +101,7 @@ fill_queue (BOOL block)
       if (events_waiting == 0)
        return 0;
     }
-  
+
   rc = ReadConsoleInput (keyboard_handle, event_queue, EVENT_QUEUE_SIZE,
                         &events_waiting);
   if (!rc)
@@ -103,13 +115,13 @@ fill_queue (BOOL block)
    and return the frame for it
 
    Right now, there's only one frame so return it.  */
-static FRAME_PTR 
+static FRAME_PTR
 get_frame (void)
 {
-  return selected_frame;
+  return SELECTED_FRAME ();
 }
 
-/* Translate console modifiers to emacs modifiers.  
+/* Translate console modifiers to emacs modifiers.
    German keyboard support (Kai Morgan Zeise 2/18/95).  */
 int
 w32_kbd_mods_to_emacs (DWORD mods, WORD key)
@@ -118,18 +130,18 @@ w32_kbd_mods_to_emacs (DWORD mods, WORD key)
 
   /* If we recognize right-alt and left-ctrl as AltGr, and it has been
      pressed, first remove those modifiers.  */
-  if (!NILP (Vw32_recognize_altgr) 
-      && (mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)) 
+  if (!NILP (Vw32_recognize_altgr)
+      && (mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
       == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
     mods &= ~ (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED);
 
   if (mods & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
     retval = ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier);
-  
+
   if (mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
     {
       retval |= ctrl_modifier;
-      if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) 
+      if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
          == (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
        retval |= meta_modifier;
     }
@@ -201,14 +213,14 @@ w32_kbd_patch_key (KEY_EVENT_RECORD *event)
       isdead = 0;
       return 1;
     }
-  if (event->uChar.AsciiChar != 0) 
+  if (event->uChar.AsciiChar != 0)
     return 1;
 
   memset (keystate, 0, sizeof (keystate));
   keystate[key_code] = 0x80;
-  if (mods & SHIFT_PRESSED) 
+  if (mods & SHIFT_PRESSED)
     keystate[VK_SHIFT] = 0x80;
-  if (mods & CAPSLOCK_ON) 
+  if (mods & CAPSLOCK_ON)
     keystate[VK_CAPITAL] = 1;
   /* If we recognize right-alt and left-ctrl as AltGr, set the key
      states accordingly before invoking ToAscii.  */
@@ -261,7 +273,7 @@ w32_kbd_patch_key (KEY_EVENT_RECORD *event)
                         keystate, (LPWORD) ansi_code, 0);
     }
 
-  if (isdead == 0) 
+  if (isdead == 0)
     return 0;
   event->uChar.AsciiChar = ansi_code[0];
   return isdead;
@@ -270,12 +282,13 @@ w32_kbd_patch_key (KEY_EVENT_RECORD *event)
 
 extern char *lispy_function_keys[];
 
-/* return code -1 means that event_queue_ptr won't be incremented. 
+static int faked_key = 0;
+
+/* return code -1 means that event_queue_ptr won't be incremented.
    In other word, this event makes two key codes.   (by himi)       */
-int 
+int
 key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
 {
-  static int faked_key = 0;
   static int mod_key_state = 0;
   int wParam;
 
@@ -317,8 +330,11 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
             Space which we will ignore.  */
          if ((mod_key_state & LEFT_WIN_PRESSED) == 0)
            {
-             faked_key = VK_SPACE;
-             keybd_event (VK_SPACE, (BYTE) MapVirtualKey (VK_SPACE, 0), 0, 0);
+             if (NUMBERP (Vw32_phantom_key_code))
+               faked_key = XUINT (Vw32_phantom_key_code) & 255;
+             else
+               faked_key = VK_SPACE;
+             keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
            }
        }
       mod_key_state |= LEFT_WIN_PRESSED;
@@ -330,8 +346,11 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
        {
          if ((mod_key_state & RIGHT_WIN_PRESSED) == 0)
            {
-             faked_key = VK_SPACE;
-             keybd_event (VK_SPACE, (BYTE) MapVirtualKey (VK_SPACE, 0), 0, 0);
+             if (NUMBERP (Vw32_phantom_key_code))
+               faked_key = XUINT (Vw32_phantom_key_code) & 255;
+             else
+               faked_key = VK_SPACE;
+             keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
            }
        }
       mod_key_state |= RIGHT_WIN_PRESSED;
@@ -379,6 +398,23 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
     case VK_CONTROL:
     case VK_SHIFT:
       return 0;
+    case VK_CANCEL:
+      /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
+        which is confusing for purposes of key binding; convert
+        VK_CANCEL events into VK_PAUSE events.  */
+      event->wVirtualKeyCode = VK_PAUSE;
+      break;
+    case VK_PAUSE:
+      /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
+        for purposes of key binding; convert these back into
+        VK_NUMLOCK events, at least when we want to see NumLock key
+        presses.  (Note that there is never any possibility that
+        VK_PAUSE with Ctrl really is C-Pause as per above.)  */
+      if (NILP (Vw32_enable_num_lock)
+         && (event->dwControlKeyState
+             & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0)
+       event->wVirtualKeyCode = VK_NUMLOCK;
+      break;
     }
 
   /* Recognize state of Windows and Apps keys.  */
@@ -391,7 +427,7 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
 
   if (lispy_function_keys[event->wVirtualKeyCode] == 0)
     {
-      emacs_ev->kind = ascii_keystroke;
+      emacs_ev->kind = ASCII_KEYSTROKE_EVENT;
 
       if (!NILP (Vw32_recognize_altgr)
          && (event->dwControlKeyState & LEFT_CTRL_PRESSED)
@@ -429,12 +465,12 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
        }
       if (event->uChar.AsciiChar == 0)
        return 0;
-      XSETINT (emacs_ev->code, event->uChar.AsciiChar);
+      emacs_ev->code = event->uChar.AsciiChar;
     }
   else
     {
-      emacs_ev->kind = non_ascii_keystroke;
-      XSETINT (emacs_ev->code, event->wVirtualKeyCode);
+      emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT;
+      emacs_ev->code = event->wVirtualKeyCode;
     }
 
   XSETFRAME (emacs_ev->frame_or_window, get_frame ());
@@ -444,12 +480,36 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
   return 1;
 }
 
+int
+w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state)
+{
+  int cur_state = (GetKeyState (vk_code) & 1);
+
+  if (NILP (new_state)
+      || (NUMBERP (new_state)
+         && ((XUINT (new_state)) & 1) != cur_state))
+    {
+      faked_key = vk_code;
+
+      keybd_event ((BYTE) vk_code,
+                  (BYTE) MapVirtualKey (vk_code, 0),
+                  KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+      keybd_event ((BYTE) vk_code,
+                  (BYTE) MapVirtualKey (vk_code, 0),
+                  KEYEVENTF_EXTENDEDKEY | 0, 0);
+      keybd_event ((BYTE) vk_code,
+                  (BYTE) MapVirtualKey (vk_code, 0),
+                  KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+      cur_state = !cur_state;
+    }
+
+  return cur_state;
+}
+
 /* Mouse position hook.  */
-void 
+void
 w32_console_mouse_position (FRAME_PTR *f,
-#ifndef MULE
                            int insist,
-#endif
                            Lisp_Object *bar_window,
                            enum scroll_bar_part *part,
                            Lisp_Object *x,
@@ -458,30 +518,28 @@ w32_console_mouse_position (FRAME_PTR *f,
 {
   BLOCK_INPUT;
 
-#ifndef MULE  
   insist = insist;
-#endif
 
   *f = get_frame ();
   *bar_window = Qnil;
   *part = 0;
-  selected_frame->mouse_moved = 0;
-  
-  *x = movement_pos.X;
-  *y = movement_pos.Y;
+  SELECTED_FRAME ()->mouse_moved = 0;
+
+  XSETINT(*x, movement_pos.X);
+  XSETINT(*y, movement_pos.Y);
   *time = movement_time;
-  
+
   UNBLOCK_INPUT;
 }
 
 /* Remember mouse motion and notify emacs.  */
-static void 
+static void
 mouse_moved_to (int x, int y)
 {
   /* If we're in the same place, ignore it */
   if (x != movement_pos.X || y != movement_pos.Y)
     {
-      selected_frame->mouse_moved = 1;
+      SELECTED_FRAME ()->mouse_moved = 1;
       movement_pos.X = x;
       movement_pos.Y = y;
       movement_time = GetTickCount ();
@@ -500,19 +558,20 @@ mouse_moved_to (int x, int y)
      Right == 2
    Others increase from there.  */
 
-static int emacs_button_translation[NUM_MOUSE_BUTTONS] =
+#define NUM_TRANSLATED_MOUSE_BUTTONS 3
+static int emacs_button_translation[NUM_TRANSLATED_MOUSE_BUTTONS] =
 {
-  0, 2, 1, 3, 4,
+  0, 2, 1
 };
 
-static int 
+static int
 do_mouse_event (MOUSE_EVENT_RECORD *event,
                struct input_event *emacs_ev)
 {
   static DWORD button_state = 0;
   DWORD but_change, mask;
   int i;
-  
+
   if (event->dwEventFlags == MOUSE_MOVED)
     {
       /* For movement events we just note that the mouse has moved
@@ -520,34 +579,32 @@ do_mouse_event (MOUSE_EVENT_RECORD *event,
       mouse_moved_to (event->dwMousePosition.X, event->dwMousePosition.Y);
       return 0;
     }
-  
+
   /* It looks like the console code sends us a mouse event with
      dwButtonState == 0 when a window is activated.  Ignore this case.  */
   if (event->dwButtonState == button_state)
     return 0;
-  
-  emacs_ev->kind = mouse_click;
-  
+
+  emacs_ev->kind = MOUSE_CLICK_EVENT;
+
   /* Find out what button has changed state since the last button event.  */
   but_change = button_state ^ event->dwButtonState;
   mask = 1;
-  for (i = 0; i < NUM_MOUSE_BUTTONS; i++, mask <<= 1)
+  for (i = 0; mask; i++, mask <<= 1)
     if (but_change & mask)
       {
-       XSETINT (emacs_ev->code, emacs_button_translation[i]);
+        if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
+          emacs_ev->code = emacs_button_translation[i];
+        else
+          emacs_ev->code = i;
        break;
       }
 
-  /* If the changed button is out of emacs' range (highly unlikely)
-     ignore this event.  */
-  if (i == NUM_MOUSE_BUTTONS)
-    return 0;
-  
   button_state = event->dwButtonState;
   emacs_ev->timestamp = GetTickCount ();
   emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0) |
     ((event->dwButtonState & mask) ? down_modifier : up_modifier);
-  
+
   XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
   XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
 /* for Mule 2.2 (Based on Emacs 19.28 */
@@ -556,22 +613,37 @@ do_mouse_event (MOUSE_EVENT_RECORD *event,
 #else
   XSETFRAME (emacs_ev->frame_or_window, get_frame ());
 #endif
-  
+
   return 1;
 }
 
-static void 
+static void
 resize_event (WINDOW_BUFFER_SIZE_RECORD *event)
 {
   FRAME_PTR f = get_frame ();
-  
+
   change_frame_size (f, event->dwSize.Y, event->dwSize.X, 0, 1);
   SET_FRAME_GARBAGED (f);
 }
 
-int 
-w32_console_read_socket (int sd, struct input_event *bufp, int numchars,
-                        int expected)
+static void
+maybe_generate_resize_event ()
+{
+  CONSOLE_SCREEN_BUFFER_INFO info;
+  FRAME_PTR f = get_frame ();
+
+  GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
+
+  /* It is okay to call this unconditionally, since it will do nothing
+     if the size hasn't actually changed.  */
+  change_frame_size (f,
+                    1 + info.srWindow.Bottom - info.srWindow.Top,
+                    1 + info.srWindow.Right - info.srWindow.Left,
+                    0, 0);
+}
+
+int
+w32_console_read_socket (int sd, int expected, struct input_event *hold_quit)
 {
   BOOL no_events = TRUE;
   int nev, ret = 0, add;
@@ -582,10 +654,10 @@ w32_console_read_socket (int sd, struct input_event *bufp, int numchars,
       interrupt_input_pending = 1;
       return -1;
     }
-  
+
   interrupt_input_pending = 0;
   BLOCK_INPUT;
-  
+
   for (;;)
     {
       nev = fill_queue (0);
@@ -598,39 +670,44 @@ w32_console_read_socket (int sd, struct input_event *bufp, int numchars,
          return nev;
         }
 
-      while (nev > 0 && numchars > 0)
+      while (nev > 0)
         {
+         struct input_event inev;
+
+         EVENT_INIT (inev);
+         inev.kind = NO_EVENT;
+         inev.arg = Qnil;
+
          switch (queue_ptr->EventType)
             {
             case KEY_EVENT:
-             add = key_event (&queue_ptr->Event.KeyEvent, bufp, &isdead);
+             add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead);
              if (add == -1) /* 95.7.25 by himi */
-               { 
+               {
                  queue_ptr--;
                  add = 1;
                }
-             bufp += add;
-             ret += add;
-             numchars -= add;
+             if (add)
+               kbd_buffer_store_event_hold (&inev, hold_quit);
              break;
 
             case MOUSE_EVENT:
-             add = do_mouse_event (&queue_ptr->Event.MouseEvent, bufp);
-             bufp += add;
-             ret += add;
-             numchars -= add;
+             add = do_mouse_event (&queue_ptr->Event.MouseEvent, &inev);
+             if (add)
+               kbd_buffer_store_event_hold (&inev, hold_quit);
              break;
 
             case WINDOW_BUFFER_SIZE_EVENT:
-             resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
+             if (w32_use_full_screen_buffer)
+               resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
              break;
-            
+
             case MENU_EVENT:
             case FOCUS_EVENT:
              /* Internal event types, ignored. */
              break;
             }
-            
+
          queue_ptr++;
          nev--;
         }
@@ -638,7 +715,16 @@ w32_console_read_socket (int sd, struct input_event *bufp, int numchars,
       if (ret > 0 || expected == 0)
        break;
     }
-  
+
+  /* We don't get told about changes in the window size (only the buffer
+     size, which we no longer care about), so we have to check it
+     periodically.  */
+  if (!w32_use_full_screen_buffer)
+    maybe_generate_resize_event ();
+
   UNBLOCK_INPUT;
   return ret;
 }
+
+/* arch-tag: 0bcb39b7-d085-4b85-9070-6750e8c03047
+   (do not change this comment) */