root/src/w32inevt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. w32_read_console_input
  2. fill_queue
  3. get_frame
  4. is_dead_key
  5. key_event
  6. w32_console_mouse_position
  7. mouse_moved_to
  8. do_mouse_event
  9. resize_event
  10. maybe_generate_resize_event
  11. handle_file_notifications
  12. handle_file_notifications
  13. w32_console_read_socket

     1 /* Input event support for Emacs on the Microsoft Windows API.
     2    Copyright (C) 1992-1993, 1995, 2001-2023 Free Software Foundation,
     3    Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    19 
    20 /*
    21    Drew Bliss                   01-Oct-93
    22      Adapted from ntkbd.c by Tim Fleehart
    23 */
    24 
    25 
    26 #include <config.h>
    27 #include <stdio.h>
    28 #include <windows.h>
    29 
    30 #ifndef MOUSE_MOVED
    31 #define MOUSE_MOVED   1
    32 #endif
    33 #ifndef MOUSE_HWHEELED
    34 #define MOUSE_HWHEELED 8
    35 #endif
    36 
    37 #include "lisp.h"
    38 #include "keyboard.h"
    39 #include "frame.h"
    40 #include "blockinput.h"
    41 #include "termchar.h"   /* for Mouse_HLInfo, tty_display_info */
    42 #include "w32term.h"
    43 #include "w32inevt.h"
    44 #include "w32common.h"
    45 
    46 /* stdin, from w32console.c */
    47 extern HANDLE keyboard_handle;
    48 
    49 /* Info for last mouse motion */
    50 static COORD movement_pos;
    51 static Time movement_time;
    52 
    53 /* from w32fns.c */
    54 extern unsigned int map_keypad_keys (unsigned int, unsigned int);
    55 extern unsigned int w32_key_to_modifier (int key);
    56 
    57 /* Event queue */
    58 #define EVENT_QUEUE_SIZE 50
    59 static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE];
    60 static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue;
    61 
    62 /* Temporarily store lead byte of DBCS input sequences.  */
    63 static char dbcs_lead = 0;
    64 
    65 static inline BOOL
    66 w32_read_console_input (HANDLE h, INPUT_RECORD *rec, DWORD recsize,
    67                         DWORD *waiting)
    68 {
    69   return (w32_console_unicode_input
    70           ? ReadConsoleInputW (h, rec, recsize, waiting)
    71           : ReadConsoleInputA (h, rec, recsize, waiting));
    72 }
    73 
    74 /* Set by w32_console_toggle_lock_key.  */
    75 int faked_key;
    76 
    77 static int
    78 fill_queue (BOOL block)
    79 {
    80   BOOL rc;
    81   DWORD events_waiting;
    82 
    83   if (queue_ptr < queue_end)
    84     return queue_end-queue_ptr;
    85 
    86   if (!block)
    87     {
    88       /* Check to see if there are some events to read before we try
    89          because we can't block.  */
    90       if (!GetNumberOfConsoleInputEvents (keyboard_handle, &events_waiting))
    91         return -1;
    92       if (events_waiting == 0)
    93         return 0;
    94     }
    95 
    96   rc = w32_read_console_input (keyboard_handle, event_queue, EVENT_QUEUE_SIZE,
    97                                &events_waiting);
    98   if (!rc)
    99     return -1;
   100   queue_ptr = event_queue;
   101   queue_end = event_queue + events_waiting;
   102   return (int) events_waiting;
   103 }
   104 
   105 /* In a generic, multi-frame world this should take a console handle
   106    and return the frame for it.
   107 
   108    Right now, there's only one frame so return it.  */
   109 static struct frame *
   110 get_frame (void)
   111 {
   112   return SELECTED_FRAME ();
   113 }
   114 
   115 /* Translate console modifiers to emacs modifiers.
   116    German keyboard support (Kai Morgan Zeise 2/18/95).  */
   117 
   118 
   119 #if 0
   120 /* Return nonzero if the virtual key is a dead key.  */
   121 static int
   122 is_dead_key (int wparam)
   123 {
   124   unsigned int code = MapVirtualKey (wparam, 2);
   125 
   126   /* Windows 95 returns 0x8000, NT returns 0x80000000.  */
   127   return (code & 0x80008000) ? 1 : 0;
   128 }
   129 #endif
   130 
   131 /* The return code indicates key code size.  cpID is the codepage to
   132    use for translation to Unicode; -1 means use the current console
   133    input codepage.  */
   134 
   135 
   136 /* return code -1 means that event_queue_ptr won't be incremented.
   137    In other word, this event makes two key codes.   (by himi)       */
   138 static int
   139 key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
   140 {
   141   static int mod_key_state = 0;
   142   int wParam;
   143 
   144   *isdead = 0;
   145 
   146   /* Skip key-up events.  */
   147   if (!event->bKeyDown)
   148     {
   149       switch (event->wVirtualKeyCode)
   150         {
   151         case VK_LWIN:
   152           if (!w32_kbdhook_active)
   153             mod_key_state &= ~LEFT_WIN_PRESSED;
   154           break;
   155         case VK_RWIN:
   156           if (!w32_kbdhook_active)
   157             mod_key_state &= ~RIGHT_WIN_PRESSED;
   158           break;
   159         case VK_APPS:
   160           mod_key_state &= ~APPS_PRESSED;
   161           break;
   162         }
   163       return 0;
   164     }
   165 
   166   /* Ignore keystrokes we fake ourself; see below.  */
   167   if (faked_key == event->wVirtualKeyCode)
   168     {
   169       faked_key = 0;
   170       return 0;
   171     }
   172 
   173   /* To make it easier to debug this code, ignore modifier keys!  */
   174   switch (event->wVirtualKeyCode)
   175     {
   176     case VK_LWIN:
   177       if (NILP (Vw32_pass_lwindow_to_system))
   178         {
   179           /* Prevent system from acting on keyup (which opens the Start
   180              menu if no other key was pressed) by simulating a press of
   181              Space which we will ignore.  */
   182           if ((mod_key_state & LEFT_WIN_PRESSED) == 0)
   183             {
   184               if (FIXNUMP (Vw32_phantom_key_code))
   185                 faked_key = XUFIXNUM (Vw32_phantom_key_code) & 255;
   186               else
   187                 faked_key = VK_SPACE;
   188               keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
   189             }
   190         }
   191       if (!w32_kbdhook_active)
   192         mod_key_state |= LEFT_WIN_PRESSED;
   193       if (!NILP (Vw32_lwindow_modifier))
   194         return 0;
   195       break;
   196     case VK_RWIN:
   197       if (NILP (Vw32_pass_rwindow_to_system))
   198         {
   199           if ((mod_key_state & RIGHT_WIN_PRESSED) == 0)
   200             {
   201               if (FIXNUMP (Vw32_phantom_key_code))
   202                 faked_key = XUFIXNUM (Vw32_phantom_key_code) & 255;
   203               else
   204                 faked_key = VK_SPACE;
   205               keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
   206             }
   207         }
   208       if (!w32_kbdhook_active)
   209         mod_key_state |= RIGHT_WIN_PRESSED;
   210       if (!NILP (Vw32_rwindow_modifier))
   211         return 0;
   212       break;
   213     case VK_APPS:
   214       mod_key_state |= APPS_PRESSED;
   215       if (!NILP (Vw32_apps_modifier))
   216         return 0;
   217       break;
   218     case VK_CAPITAL:
   219       /* Decide whether to treat as modifier or function key.  */
   220       if (NILP (Vw32_enable_caps_lock))
   221         goto disable_lock_key;
   222       return 0;
   223     case VK_NUMLOCK:
   224       /* Decide whether to treat as modifier or function key.  */
   225       if (NILP (Vw32_enable_num_lock))
   226         goto disable_lock_key;
   227       return 0;
   228     case VK_SCROLL:
   229       /* Decide whether to treat as modifier or function key.  */
   230       if (NILP (Vw32_scroll_lock_modifier))
   231         goto disable_lock_key;
   232       return 0;
   233     disable_lock_key:
   234       /* Ensure the appropriate lock key state is off (and the
   235          indicator light as well).  */
   236       wParam = event->wVirtualKeyCode;
   237       if (GetAsyncKeyState (wParam) & 0x8000)
   238         {
   239           /* Fake another press of the relevant key.  Apparently, this
   240              really is the only way to turn off the indicator.  */
   241           faked_key = wParam;
   242           keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
   243                        KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
   244           keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
   245                        KEYEVENTF_EXTENDEDKEY | 0, 0);
   246           keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
   247                        KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
   248         }
   249       break;
   250     case VK_MENU:
   251     case VK_CONTROL:
   252     case VK_SHIFT:
   253       return 0;
   254     case VK_CANCEL:
   255       /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
   256          which is confusing for purposes of key binding; convert
   257          VK_CANCEL events into VK_PAUSE events.  */
   258       event->wVirtualKeyCode = VK_PAUSE;
   259       break;
   260     case VK_PAUSE:
   261       /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
   262          for purposes of key binding; convert these back into
   263          VK_NUMLOCK events, at least when we want to see NumLock key
   264          presses.  (Note that there is never any possibility that
   265          VK_PAUSE with Ctrl really is C-Pause as per above.)  */
   266       if (NILP (Vw32_enable_num_lock)
   267           && (event->dwControlKeyState
   268               & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0)
   269         event->wVirtualKeyCode = VK_NUMLOCK;
   270       break;
   271     }
   272 
   273   /* Recognize state of Windows and Apps keys.  */
   274   event->dwControlKeyState |= mod_key_state;
   275   if (w32_kbdhook_active)
   276     {
   277       if (check_w32_winkey_state (VK_LWIN))
   278         event->dwControlKeyState |= LEFT_WIN_PRESSED;
   279       if (check_w32_winkey_state (VK_RWIN))
   280         event->dwControlKeyState |= RIGHT_WIN_PRESSED;
   281     }
   282 
   283   /* Distinguish numeric keypad keys from extended keys.  */
   284   event->wVirtualKeyCode =
   285     map_keypad_keys (event->wVirtualKeyCode,
   286                      (event->dwControlKeyState & ENHANCED_KEY));
   287 
   288   if (lispy_function_keys[event->wVirtualKeyCode] == 0)
   289     {
   290       if (!NILP (Vw32_recognize_altgr)
   291           && (event->dwControlKeyState & LEFT_CTRL_PRESSED)
   292           && (event->dwControlKeyState & RIGHT_ALT_PRESSED))
   293         {
   294           /* Don't try to interpret AltGr key chords; ToAscii seems not
   295              to process them correctly.  */
   296         }
   297       /* Handle key chords including any modifiers other than shift
   298          directly, in order to preserve as much modifier information as
   299          possible.  */
   300       else if (event->dwControlKeyState
   301                & (  RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED
   302                   | RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED
   303                   | (!NILP (Vw32_lwindow_modifier) ? LEFT_WIN_PRESSED : 0)
   304                   | (!NILP (Vw32_rwindow_modifier) ? RIGHT_WIN_PRESSED : 0)
   305                   | (!NILP (Vw32_apps_modifier) ? APPS_PRESSED : 0)
   306                   | (!NILP (Vw32_scroll_lock_modifier) ? SCROLLLOCK_ON : 0)))
   307         {
   308           /* Don't translate modified alphabetic keystrokes, so the user
   309              doesn't need to constantly switch layout to type control or
   310              meta keystrokes when the normal layout translates
   311              alphabetic characters to non-ascii characters.  */
   312           if ('A' <= event->wVirtualKeyCode && event->wVirtualKeyCode <= 'Z')
   313             {
   314               event->uChar.AsciiChar = event->wVirtualKeyCode;
   315               if ((event->dwControlKeyState & SHIFT_PRESSED) == 0)
   316                 event->uChar.AsciiChar += ('a' - 'A');
   317             }
   318           /* Try to handle unrecognized keystrokes by determining the
   319              base character (ie. translating the base key plus shift
   320              modifier).  */
   321           else if (event->uChar.AsciiChar == 0)
   322             w32_kbd_patch_key (event, -1);
   323         }
   324 
   325       if (event->uChar.AsciiChar == 0)
   326         {
   327           emacs_ev->kind = NO_EVENT;
   328           return 0;
   329         }
   330       else if (event->uChar.AsciiChar > 0)
   331         {
   332           /* Pure ASCII characters < 128.  */
   333           emacs_ev->kind = ASCII_KEYSTROKE_EVENT;
   334           emacs_ev->code = event->uChar.AsciiChar;
   335         }
   336       else if (event->uChar.UnicodeChar > 0
   337                && w32_console_unicode_input)
   338         {
   339           /* Unicode codepoint; only valid if we are using Unicode
   340              console input mode.  */
   341           emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
   342           emacs_ev->code = event->uChar.UnicodeChar;
   343         }
   344       else
   345         {
   346           /* Fallback handling of non-ASCII characters for non-Unicode
   347              versions of Windows, and for non-Unicode input on NT
   348              family of Windows.  Only characters in the current
   349              console codepage are supported by this fallback.  */
   350           wchar_t code;
   351           char dbcs[2];
   352           int cpId;
   353 
   354           /* Get the current console input codepage to interpret this
   355              key with.  Note that the system defaults for the OEM
   356              codepage could have been changed by calling SetConsoleCP
   357              or w32-set-console-codepage, so using GetLocaleInfo to
   358              get LOCALE_IDEFAULTCODEPAGE is not TRT here.  */
   359           cpId = GetConsoleCP ();
   360 
   361           dbcs[0] = dbcs_lead;
   362           dbcs[1] = event->uChar.AsciiChar;
   363           if (dbcs_lead)
   364             {
   365               dbcs_lead = 0;
   366               if (!MultiByteToWideChar (cpId, 0, dbcs, 2, &code, 1))
   367                 {
   368                   /* Garbage  */
   369                   DebPrint (("Invalid DBCS sequence: %d %d\n",
   370                              dbcs[0], dbcs[1]));
   371                   emacs_ev->kind = NO_EVENT;
   372                 }
   373             }
   374           else if (IsDBCSLeadByteEx (cpId, dbcs[1]))
   375             {
   376               dbcs_lead = dbcs[1];
   377               emacs_ev->kind = NO_EVENT;
   378             }
   379           else
   380             {
   381               if (!MultiByteToWideChar (cpId, 0, &dbcs[1], 1, &code, 1))
   382                 {
   383                   /* Garbage  */
   384                   DebPrint (("Invalid character: %d\n", dbcs[1]));
   385                   emacs_ev->kind = NO_EVENT;
   386                 }
   387             }
   388           emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
   389           emacs_ev->code = code;
   390         }
   391     }
   392   else
   393     {
   394       /* Function keys and other non-character keys.  */
   395       emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT;
   396       emacs_ev->code = event->wVirtualKeyCode;
   397     }
   398 
   399   XSETFRAME (emacs_ev->frame_or_window, get_frame ());
   400   emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState,
   401                                                event->wVirtualKeyCode);
   402   emacs_ev->timestamp = GetTickCount ();
   403   return 1;
   404 }
   405 
   406 /* Mouse position hook.  */
   407 void
   408 w32_console_mouse_position (struct frame **f,
   409                             int insist,
   410                             Lisp_Object *bar_window,
   411                             enum scroll_bar_part *part,
   412                             Lisp_Object *x,
   413                             Lisp_Object *y,
   414                             Time *time)
   415 {
   416   block_input ();
   417 
   418   insist = insist;
   419 
   420   *f = get_frame ();
   421   *bar_window = Qnil;
   422   *part = scroll_bar_above_handle;
   423   (*f)->mouse_moved = 0;
   424 
   425   XSETINT (*x, movement_pos.X);
   426   XSETINT (*y, movement_pos.Y);
   427   *time = movement_time;
   428 
   429   unblock_input ();
   430 }
   431 
   432 /* Remember mouse motion and notify emacs.  */
   433 static void
   434 mouse_moved_to (int x, int y)
   435 {
   436   /* If we're in the same place, ignore it.  */
   437   if (x != movement_pos.X || y != movement_pos.Y)
   438     {
   439       struct frame *f = get_frame ();
   440       f->mouse_moved = 1;
   441       movement_pos.X = x;
   442       movement_pos.Y = y;
   443       movement_time = GetTickCount ();
   444     }
   445 }
   446 
   447 /* Consoles return button bits in a strange order:
   448      least significant - Leftmost button
   449      next - Rightmost button
   450      next - Leftmost+1
   451      next - Leftmost+2...
   452 
   453    For the 3 standard buttons, we have:
   454      Left == 0
   455      Middle == 1
   456      Right == 2
   457    Others increase from there.  */
   458 
   459 #define NUM_TRANSLATED_MOUSE_BUTTONS 5
   460 static int emacs_button_translation[NUM_TRANSLATED_MOUSE_BUTTONS] =
   461 {
   462   0, 2, 1, 3, 4
   463 };
   464 
   465 static int
   466 do_mouse_event (MOUSE_EVENT_RECORD *event,
   467                 struct input_event *emacs_ev)
   468 {
   469   static DWORD button_state = 0;
   470   static Lisp_Object last_mouse_window;
   471   DWORD but_change, mask, flags = event->dwEventFlags;
   472   int i;
   473 
   474   /* Mouse didn't move unless MOUSE_MOVED says it did.  */
   475   struct frame *f = get_frame ();
   476   f->mouse_moved = 0;
   477 
   478   switch (flags)
   479     {
   480     case MOUSE_MOVED:
   481       {
   482         Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
   483         int mx = event->dwMousePosition.X, my = event->dwMousePosition.Y;
   484 
   485         mouse_moved_to (mx, my);
   486 
   487         if (f->mouse_moved)
   488           {
   489             if (hlinfo->mouse_face_hidden)
   490               {
   491                 hlinfo->mouse_face_hidden = 0;
   492                 clear_mouse_face (hlinfo);
   493               }
   494 
   495             /* Generate SELECT_WINDOW_EVENTs when needed.  */
   496             if (!NILP (Vmouse_autoselect_window))
   497               {
   498                 Lisp_Object mouse_window = window_from_coordinates (f, mx, my,
   499                                                                     0, 0, 0);
   500                 /* A window will be selected only when it is not
   501                    selected now, and the last mouse movement event was
   502                    not in it.  A minibuffer window will be selected iff
   503                    it is active.  */
   504                 if (WINDOWP (mouse_window)
   505                     && !EQ (mouse_window, last_mouse_window)
   506                     && !EQ (mouse_window, selected_window))
   507                   {
   508                     struct input_event event;
   509 
   510                     EVENT_INIT (event);
   511                     event.kind = SELECT_WINDOW_EVENT;
   512                     event.frame_or_window = mouse_window;
   513                     event.arg = Qnil;
   514                     event.timestamp = movement_time;
   515                     kbd_buffer_store_event (&event);
   516                   }
   517                 last_mouse_window = mouse_window;
   518               }
   519             else
   520               last_mouse_window = Qnil;
   521 
   522             previous_help_echo_string = help_echo_string;
   523             help_echo_string = help_echo_object = help_echo_window = Qnil;
   524             help_echo_pos = -1;
   525             note_mouse_highlight (f, mx, my);
   526             /* If the contents of the global variable help_echo has
   527                changed (inside note_mouse_highlight), generate a HELP_EVENT.  */
   528             if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
   529               gen_help_event (help_echo_string, selected_frame,
   530                               help_echo_window, help_echo_object,
   531                               help_echo_pos);
   532           }
   533         /* We already called kbd_buffer_store_event, so indicate to
   534            the caller it shouldn't.  */
   535         return 0;
   536       }
   537     case MOUSE_WHEELED:
   538     case MOUSE_HWHEELED:
   539       {
   540         /* Mouse positions in console wheel events are reported to
   541            ReadConsoleInput relative to the display's top-left
   542            corner(!), not relative to the origin of the console screen
   543            buffer.  This makes these coordinates unusable; e.g.,
   544            scrolling the tab-line in general doesn't work.
   545            FIXME (but how?).  */
   546         int mx = event->dwMousePosition.X, my = event->dwMousePosition.Y;
   547         bool down_p = (event->dwButtonState & 0x10000000) != 0;
   548 
   549         emacs_ev->kind =
   550           flags == MOUSE_HWHEELED ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
   551         emacs_ev->code = 0;
   552         emacs_ev->modifiers = down_p ? down_modifier : up_modifier;
   553         emacs_ev->modifiers |=
   554           w32_kbd_mods_to_emacs (event->dwControlKeyState, 0);
   555         XSETINT (emacs_ev->x, mx);
   556         XSETINT (emacs_ev->y, my);
   557         XSETFRAME (emacs_ev->frame_or_window, f);
   558         emacs_ev->arg = Qnil;
   559         emacs_ev->timestamp = GetTickCount ();
   560         return 1;
   561       }
   562     case DOUBLE_CLICK:
   563     default:    /* mouse pressed or released */
   564       /* It looks like the console code sends us a button-release
   565          mouse event with dwButtonState == 0 when a window is
   566          activated and when the mouse is first clicked.  Ignore this
   567          case.  */
   568       if (event->dwButtonState == button_state)
   569         return 0;
   570 
   571       /* Find out what button has changed state since the last button
   572          event.  */
   573       but_change = button_state ^ event->dwButtonState;
   574       mask = 1;
   575       for (i = 0; mask; i++, mask <<= 1)
   576         if (but_change & mask)
   577           {
   578             if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
   579               emacs_ev->code = emacs_button_translation[i];
   580             else
   581               emacs_ev->code = i;
   582             break;
   583           }
   584 
   585       button_state = event->dwButtonState;
   586       emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0);
   587       emacs_ev->timestamp = GetTickCount ();
   588 
   589       int x = event->dwMousePosition.X;
   590       int y = event->dwMousePosition.Y;
   591       emacs_ev->arg = tty_handle_tab_bar_click (f, x, y,
   592                                                 (button_state & mask) != 0,
   593                                                 emacs_ev);
   594 
   595       emacs_ev->modifiers |= ((button_state & mask)
   596                               ? down_modifier : up_modifier);
   597 
   598       emacs_ev->kind = MOUSE_CLICK_EVENT;
   599       XSETFASTINT (emacs_ev->x, x);
   600       XSETFASTINT (emacs_ev->y, y);
   601       XSETFRAME (emacs_ev->frame_or_window, f);
   602 
   603       return 1;
   604     }
   605 }
   606 
   607 static void
   608 resize_event (WINDOW_BUFFER_SIZE_RECORD *event)
   609 {
   610   struct frame *f = get_frame ();
   611 
   612   change_frame_size (f, event->dwSize.X, event->dwSize.Y, false, true, false);
   613   SET_FRAME_GARBAGED (f);
   614 }
   615 
   616 static void
   617 maybe_generate_resize_event (void)
   618 {
   619   CONSOLE_SCREEN_BUFFER_INFO info;
   620   struct frame *f = get_frame ();
   621 
   622   GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
   623 
   624   /* It is okay to call this unconditionally, since it will do nothing
   625      if the size hasn't actually changed.  */
   626   change_frame_size (f, 1 + info.srWindow.Right - info.srWindow.Left,
   627                      1 + info.srWindow.Bottom - info.srWindow.Top,
   628                      false, true, false);
   629 }
   630 
   631 #if HAVE_W32NOTIFY
   632 int
   633 handle_file_notifications (struct input_event *hold_quit)
   634 {
   635   struct notifications_set *ns = NULL;
   636   int nevents = 0;
   637   int done = 0;
   638 
   639   /* We cannot process notification before Emacs is fully initialized,
   640      since we need the UTF-16LE coding-system to be set up.  */
   641   if (!initialized)
   642     {
   643       return nevents;
   644     }
   645 
   646   while (!done)
   647     {
   648       ns = NULL;
   649 
   650       /* Find out if there is a record available in the linked list of
   651          notifications sets.  If so, unlink the set from the linked list.
   652          Use the critical section.  */
   653       enter_crit ();
   654       if (notifications_set_head->next != notifications_set_head)
   655         {
   656           ns = notifications_set_head->next;
   657           ns->prev->next = ns->next;
   658           ns->next->prev = ns->prev;
   659         }
   660       else
   661         done = 1;
   662       leave_crit();
   663 
   664       if (ns)
   665         {
   666           BYTE *p = ns->notifications;
   667           FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
   668           const DWORD min_size
   669             = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
   670           struct input_event inev;
   671           DWORD info_size = ns->size;
   672           Lisp_Object cs = Qutf_16le;
   673           Lisp_Object obj = w32_get_watch_object (ns->desc);
   674 
   675           /* notifications size could be zero when the buffer of
   676              notifications overflowed on the OS level, or when the
   677              directory being watched was itself deleted.  Do nothing in
   678              that case.  */
   679           if (info_size
   680               && !NILP (obj) && CONSP (obj))
   681             {
   682               Lisp_Object callback = XCDR (obj);
   683 
   684               EVENT_INIT (inev);
   685 
   686               while (info_size >= min_size)
   687                 {
   688                   Lisp_Object utf_16_fn
   689                     = make_unibyte_string ((char *)fni->FileName,
   690                                            fni->FileNameLength);
   691                   /* Note: mule-conf is preloaded, so utf-16le must
   692                      already be defined at this point.  */
   693                   Lisp_Object fname
   694                     = code_convert_string_norecord (utf_16_fn, cs, 0);
   695                   Lisp_Object action = w32_lispy_file_action (fni->Action);
   696 
   697                   inev.kind = FILE_NOTIFY_EVENT;
   698                   inev.timestamp = GetTickCount ();
   699                   inev.modifiers = 0;
   700                   inev.frame_or_window = callback;
   701                   inev.arg = Fcons (action, fname);
   702                   inev.arg = list3 (make_pointer_integer (ns->desc),
   703                                     action, fname);
   704                   kbd_buffer_store_event_hold (&inev, hold_quit);
   705                   nevents++;
   706                   if (!fni->NextEntryOffset)
   707                     break;
   708                   p += fni->NextEntryOffset;
   709                   fni = (PFILE_NOTIFY_INFORMATION)p;
   710                   info_size -= fni->NextEntryOffset;
   711                 }
   712             }
   713           /* Free this notification set.  */
   714           free (ns->notifications);
   715           free (ns);
   716         }
   717     }
   718   return nevents;
   719 }
   720 #else  /* !HAVE_W32NOTIFY */
   721 int
   722 handle_file_notifications (struct input_event *hold_quit)
   723 {
   724   return 0;
   725 }
   726 #endif  /* !HAVE_W32NOTIFY */
   727 
   728 /* Here's an overview of how Emacs input works in non-GUI sessions on
   729    MS-Windows.  (For description of the GUI input, see the commentary
   730    before w32_msg_pump in w32fns.c.)
   731 
   732    When Emacs is idle, it loops inside wait_reading_process_output,
   733    calling pselect periodically to check whether any input is
   734    available.  On Windows, pselect is redirected to sys_select, which
   735    uses MsgWaitForMultipleObjects to wait for input, either from the
   736    keyboard or from any of the Emacs subprocesses.  In addition,
   737    MsgWaitForMultipleObjects wakes up when some Windows message is
   738    posted to the input queue of the Emacs's main thread (which is the
   739    thread in which sys_select runs).
   740 
   741    When the Emacs's console window has focus, Windows sends input
   742    events that originate from the keyboard or the mouse; these events
   743    wake up MsgWaitForMultipleObjects, which reports that input is
   744    available.  Emacs then calls w32_console_read_socket, below, to
   745    read the input.  w32_console_read_socket uses
   746    GetNumberOfConsoleInputEvents and ReadConsoleInput to peek at and
   747    read the console input events.
   748 
   749    One type of non-keyboard input event that gets reported as input
   750    available is due to the Emacs's console window receiving focus.
   751    When that happens, Emacs gets the FOCUS_EVENT event and sys_select
   752    reports some input; however, w32_console_read_socket ignores such
   753    events when called to read them.
   754 
   755    Note that any other Windows message sent to the main thread will
   756    also wake up MsgWaitForMultipleObjects.  These messages get
   757    immediately dispatched to their destinations by calling
   758    drain_message_queue.  */
   759 
   760 int
   761 w32_console_read_socket (struct terminal *terminal,
   762                          struct input_event *hold_quit)
   763 {
   764   int nev, add;
   765   int isdead;
   766 
   767   block_input ();
   768 
   769   for (;;)
   770     {
   771       int nfnotify = handle_file_notifications (hold_quit);
   772 
   773       nev = fill_queue (0);
   774       if (nev <= 0)
   775         {
   776           /* If nev == -1, there was some kind of error
   777              If nev == 0 then no events were available
   778              so return.  */
   779           if (nfnotify)
   780             nev = 0;
   781           break;
   782         }
   783 
   784       while (nev > 0)
   785         {
   786           struct input_event inev;
   787           /* Having a separate variable with this value makes
   788              debugging easier, as otherwise the compiler might
   789              rearrange the switch below in a way that makes it hard to
   790              track the event type.  */
   791           unsigned evtype = queue_ptr->EventType;
   792 
   793           EVENT_INIT (inev);
   794           inev.kind = NO_EVENT;
   795           inev.arg = Qnil;
   796 
   797           switch (evtype)
   798             {
   799             case KEY_EVENT:
   800               add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead);
   801               if (add == -1) /* 95.7.25 by himi */
   802                 {
   803                   queue_ptr--;
   804                   add = 1;
   805                 }
   806               if (add)
   807                 kbd_buffer_store_event_hold (&inev, hold_quit);
   808               break;
   809 
   810             case MOUSE_EVENT:
   811               add = do_mouse_event (&queue_ptr->Event.MouseEvent, &inev);
   812               if (add)
   813                 kbd_buffer_store_event_hold (&inev, hold_quit);
   814               break;
   815 
   816             case WINDOW_BUFFER_SIZE_EVENT:
   817               if (w32_use_full_screen_buffer)
   818                 resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
   819               break;
   820 
   821             case MENU_EVENT:
   822             case FOCUS_EVENT:
   823               /* Internal event types, ignored. */
   824               break;
   825             }
   826 
   827           queue_ptr++;
   828           nev--;
   829         }
   830     }
   831 
   832   /* We don't get told about changes in the window size (only the buffer
   833      size, which we no longer care about), so we have to check it
   834      periodically.  */
   835   if (!w32_use_full_screen_buffer)
   836     maybe_generate_resize_event ();
   837 
   838   unblock_input ();
   839   return nev;
   840 }

/* [<][>][^][v][top][bottom][index][help] */