1 /* -*-C-*-
2 
3 Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
4     1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5     2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Massachusetts
6     Institute of Technology
7 
8 This file is part of MIT/GNU Scheme.
9 
10 MIT/GNU Scheme is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or (at
13 your option) any later version.
14 
15 MIT/GNU Scheme is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with MIT/GNU Scheme; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
23 USA.
24 
25 */
26 
27 #include "nt.h"
28 #include "ntscreen.h"
29 #include "ntgui.h"
30 #include <windowsx.h>
31 
32 /* constant definitions */
33 
34 #define GWL_SCREEN        0
35 #define SCREENEXTRABYTES        (sizeof(LONG))
36 
37 #define MAXCOLS 180
38 #define MAXROWS 100
39 
40 /* ascii definitions */
41 
42 #define ASCII_BEL       (0x07)
43 #define ASCII_BS        (0x08)
44 #define ASCII_LF        (0x0A)
45 #define ASCII_FF        (0x0C)
46 #define ASCII_CR        (0x0D)
47 #define ASCII_ESC       (0x1B)
48 #define ASCII_DEL       (0x7F)
49 
50 #define ASCII_CONTROLIFY(ascii) ((ascii) - '@')
51 #define ASCII_METAFY(ascii)     ((ascii) | 0200)
52 
53 /* data structures */
54 
55 #ifndef MAX_FREE_EVENTS
56 #define MAX_FREE_EVENTS 1024
57 #endif
58 
59 typedef struct tagSCREEN_EVENT_LINK
60 {
61   SCREEN_EVENT event;
62   struct tagSCREEN_EVENT_LINK * next;
63 } SCREEN_EVENT_LINK;
64 
65 #define MAX_COMMANDS 30
66 
67 #define MAX_BINDINGS 10
68 
69 #define MAX_LINEINPUT 1024
70 
71 #define COMPUTE_SCROLL_LINES(height)    ((((height) * 2) + 4) / 5)
72 
73 #define DEFAULT_ICON "DEFAULT_ICON"
74 
75 typedef struct tagSCREENINFO
76 {
77    SCREEN  registry_link;
78 
79    HWND    hWnd;
80    HICON   hIcon;
81 
82    char              * chars;
83    SCREEN_ATTRIBUTE  * attrs;
84    unsigned long mode_flags;	/* event types & modes */
85    SCREEN_ATTRIBUTE  write_attribute;
86 
87    BOOL    cursor_visible;
88    BOOL    has_focus;
89 
90    HFONT   hFont;
91    LOGFONT lfFont;
92    DWORD   rgbFGColour;
93    DWORD   rgbBGColour;
94    int     xSize, ySize;
95    int     xScroll, yScroll;
96    int     xOffset, yOffset; /* coords of top left corner of client area wrt */
97                              /* character area */
98    int     column, row;      /* caret position */
99    int     xChar, yChar;     /* size of characters in pixels */
100    int     width, height;    /* size of text ares in characters */
101 
102    int n_commands;
103    struct
104    {
105      WORD wID;
106      COMMAND_HANDLER thunk;
107    } commands[MAX_COMMANDS];
108 
109    int n_bindings;
110    struct
111    {
112      char   key;
113      WORD   command;
114    } bindings[MAX_BINDINGS];
115 
116    /* for line input */
117    int n_chars;
118    char * line_buffer;
119 
120    /* ANSI emulator overflow */
121    int n_pending;
122    LPSTR pending;
123 
124    HBRUSH bkgnd_brush;
125    int scroll_lines;
126 
127 } SCREEN_STRUCT;
128 
129 /* #define WIDTH(screen) (screen->width) */
130 #define WIDTH(screen) MAXCOLS
131 #define HEIGHT(screen) MAXROWS
132 /* macros ( for easier readability ) */
133 
134 #define GETSCREEN( x ) ((SCREEN) GetWindowLong( x, GWL_SCREEN ))
135 #define SETSCREEN( x, y ) SetWindowLong( x, GWL_SCREEN, (LONG) y )
136 
137 /* CRT mappings to NT API */
138 
139 #define _fmemset   memset
140 #define _fmemmove  memmove
141 
142 static LRESULT CreateScreenInfo (HWND);
143 static VOID DestroyScreenInfo (HWND);
144 static BOOL ResetScreen (SCREEN);
145 extern BOOL KillScreenFocus (HWND);
146 static VOID PaintScreen (HWND);
147 /* static VOID EraseScreen (HWND, HDC); */
148 static BOOL SetScreenFocus (HWND);
149 static BOOL ScrollScreenHorz (HWND, WORD, WORD);
150 static BOOL ScrollScreenVert (HWND, WORD, WORD);
151 static BOOL SizeScreen (HWND, WORD, WORD);
152 static BOOL handle_window_pos_changing (HWND, LPWINDOWPOS);
153 static void reset_modifiers (void);
154 static void record_modifier_transition (WPARAM, LPARAM, BOOL);
155 static int process_keydown (HWND, UINT, WPARAM, LPARAM);
156 static void process_character (HWND, UINT, WPARAM, LPARAM);
157 static VOID ProcessMouseButton (HWND, UINT, UINT, LONG, BOOL);
158 static VOID ProcessCloseMessage (SCREEN);
159 static void process_focus_message (HWND, int);
160 static void process_show_message (HWND, int);
161 static BOOL WriteScreenBlock (HWND, LPSTR, int);
162 static int  ReadScreen (SCREEN, char*, int);
163 static VOID MoveScreenCursor (SCREEN);
164 extern UINT ScreenPeekOrRead
165   (SCREEN, int count, SCREEN_EVENT* buffer, BOOL remove);
166 extern void flush_typeahead (SCREEN);
167 static COMMAND_HANDLER ScreenSetCommand
168   (SCREEN, WORD cmd, COMMAND_HANDLER handler);
169 static WORD ScreenSetBinding (SCREEN, char key, WORD command);
170 static VOID GetMinMaxSizes(HWND,LPPOINT,LPPOINT);
171 static BOOL AdjustedSize (SCREEN,int*,int*);
172 extern VOID Screen_Clear (SCREEN,int);
173 static BOOL SelectScreenFont (SCREEN, HWND);
174 static BOOL SelectScreenBackColor (SCREEN, HWND);
175 
176 static HFONT set_font_1 (char *, LOGFONT *);
177 static BOOL parse_logfont (char *, LOGFONT *);
178 static long points_to_logical_units (long);
179 static BOOL search_for_font (LOGFONT *);
180 static int CALLBACK search_for_font_proc
181   (ENUMLOGFONT *, NEWTEXTMETRIC *, int, LPARAM);
182 
183 extern LRESULT ScreenCommand_ChooseFont (HWND, WORD);
184 extern LRESULT ScreenCommand_ChooseBackColor (HWND, WORD);
185 
186 static SCREEN_EVENT * allocate_event (SCREEN, SCREEN_EVENT_TYPE);
187 static int read_event (SCREEN, SCREEN_EVENT_TYPE, int, SCREEN_EVENT *);
188 
189 /* void *xmalloc (int size); */
190 /* void xfree (void*); */
191 #define xfree free
192 #define xmalloc malloc
193 
194 extern LRESULT FAR CALLBACK ScreenWndProc (HWND, UINT, WPARAM, LPARAM);
195 
196 static VOID RegisterScreen (SCREEN);
197 static VOID UnregisterScreen (SCREEN);
198 
199 static const char * translate_message_code (UINT);
200 
201 /* FILE GLOBAL VARIABLES */
202 
203 static  HANDLE  ghInstance;
204 static  HICON   ghDefaultIcon;
205 
206 static  LOGFONT lfDefaultLogFont;
207 
208 static unsigned int n_free_events;
209 static SCREEN_EVENT_LINK * free_events;
210 static SCREEN_EVENT_LINK * event_queue_head;
211 static SCREEN_EVENT_LINK * event_queue_tail;
212 
213 FILE * win32_trace_file;
214 unsigned long win32_trace_level;
215 
216 static long
screen_x_extra(SCREEN screen)217 screen_x_extra (SCREEN screen)
218 {
219   return ((GetSystemMetrics (SM_CXFRAME)) * 2);
220 }
221 
222 static long
screen_y_extra(SCREEN screen)223 screen_y_extra (SCREEN screen)
224 {
225   return (((GetSystemMetrics (SM_CYFRAME)) * 2)
226 	  + (GetSystemMetrics (SM_CYCAPTION))
227 	  + ((GetMenu (screen -> hWnd)) ? (GetSystemMetrics (SM_CYMENU)) : 0)
228 #ifdef __WATCOMC__
229 	  /* Magic: when the combination of cyframe*2 and cycaption is
230 	     28, AdjustWindowRect indicates that it should be 27.  I
231 	     don't know why this only happens under Watcom.  */
232 	  - 1
233 #endif
234 	  );
235 }
236 
237 static long
pixel_to_char_width(SCREEN screen,long pixel_width)238 pixel_to_char_width (SCREEN screen, long pixel_width)
239 {
240   return
241     (((pixel_width - (screen_x_extra (screen))) + (screen -> xOffset))
242      / (screen -> xChar));
243 }
244 
245 static long
pixel_to_char_height(SCREEN screen,long pixel_height)246 pixel_to_char_height (SCREEN screen, long pixel_height)
247 {
248   return
249     (((pixel_height - (screen_y_extra (screen))) + (screen -> yOffset))
250      / (screen -> yChar));
251 }
252 
253 static long
char_to_pixel_width(SCREEN screen,long char_width)254 char_to_pixel_width (SCREEN screen, long char_width)
255 {
256   return
257     (((char_width * (screen -> xChar)) - (screen -> xOffset))
258      + (screen_x_extra (screen)));
259 }
260 
261 static long
char_to_pixel_height(SCREEN screen,long char_height)262 char_to_pixel_height (SCREEN screen, long char_height)
263 {
264   return
265     (((char_height * (screen -> yChar)) - (screen -> yOffset))
266      + (screen_y_extra (screen)));
267 }
268 
269 static void
init_LOGFONT(LOGFONT * lf)270 init_LOGFONT (LOGFONT *lf)
271 {
272     lf->lfHeight =         0;
273     lf->lfWidth =          0;
274     lf->lfEscapement =     0;
275     lf->lfOrientation =    0;
276     lf->lfWeight =         FW_NORMAL;
277     lf->lfItalic =         0;
278     lf->lfUnderline =      0;
279     lf->lfStrikeOut =      0;
280     lf->lfCharSet =        ANSI_CHARSET;
281     lf->lfOutPrecision =   OUT_RASTER_PRECIS;
282     lf->lfClipPrecision =  CLIP_DEFAULT_PRECIS;
283     lf->lfQuality =        PROOF_QUALITY;
284     lf->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
285     lstrcpy (lf->lfFaceName, "");
286 }
287 
288 static BOOL
init_color(char * color_symbol,HWND hWnd,DWORD * color)289 init_color (char *color_symbol, HWND hWnd, DWORD *color)
290 {
291   HDC hdc;
292   char * envvar = getenv (color_symbol);
293   if (envvar == NULL)
294     return  FALSE;
295   /* Use GetNearestColor to ensure consistency with the background
296      text color. */
297   hdc = GetDC (hWnd);
298   *color = GetNearestColor (hdc, strtoul (envvar, NULL, 0));
299   ReleaseDC (hWnd, hdc);
300   return  TRUE;
301 }
302 
303 static BOOL
init_geometry(char * geom_symbol,int * params)304 init_geometry (char *geom_symbol, int *params)
305 {
306   int ctr;
307   char * token;
308   char * envvar = getenv (geom_symbol);
309   char tempvar[100];
310 
311   if (envvar == NULL)
312     return  FALSE;
313 
314   envvar = lstrcpy (tempvar, envvar);
315 
316   for (ctr = 0, token = (strtok (envvar, ",;*+ \t\n"));
317        ((ctr < 4) && (token != ((char *) NULL)));
318        ctr++, token = (strtok (((char *) NULL), ",;*+ \t\n")))
319     params[ctr] = strtoul (token, NULL, 0);
320   return  FALSE;
321 }
322 
323 #ifdef WINDOWSLOSES
324 
325 static BOOL
326   MIT_trap_alt_tab = ((BOOL) 1),
327   MIT_trap_alt_escape = ((BOOL) 1);
328 
329 static VOID
init_flag(char * flag_symbol,BOOL * flag)330 init_flag (char *flag_symbol, BOOL *flag)
331 {
332   extern int strcmp_ci (char *, char *);
333   char *envvar = getenv (flag_symbol);
334   if (envvar != NULL)
335   {
336     if ((strcmp_ci (envvar, "true")) || (strcmp_ci (envvar, "yes")))
337       *flag = (BOOL) 1;
338     else if ((strcmp_ci (envvar, "false")) || (strcmp_ci (envvar, "no")))
339       *flag = (BOOL) 0;
340   }
341 }
342 
343 VOID
init_MIT_Keyboard(VOID)344 init_MIT_Keyboard (VOID)
345 {
346   init_flag ("MITSCHEME_TRAP_ALT_TAB", (& MIT_trap_alt_tab));
347   init_flag ("MITSCHEME_TRAP_ALT_ESCAPE", (& MIT_trap_alt_escape));
348 }
349 #endif /* WINDOWSLOSES */
350 
351 /* BOOL Screen_InitApplication (HANDLE hInstance)
352 
353    Description:
354      First time initialization stuff for screen class.
355      This registers information such as window classes.
356 
357    Parameters:
358      HANDLE hInstance
359         Handle to this instance of the application.
360 */
361 
362 BOOL
Screen_InitApplication(HANDLE hInstance)363 Screen_InitApplication (HANDLE hInstance)
364 {
365    WNDCLASSEX wndclass;
366    char * font_name = getenv ("MITSCHEME_FONT");
367 
368    init_LOGFONT (&lfDefaultLogFont);
369    if (font_name)
370      ScreenSetDefaultFont (font_name);
371 
372    win32_trace_file = 0;
373    win32_trace_level = 0;
374 
375 #ifdef WINDOWSLOSES
376    init_MIT_Keyboard ();
377 #endif /* WINDOWSLOSES */
378 
379    wndclass.cbSize =        (sizeof (wndclass));
380    wndclass.style =         0;
381    wndclass.lpfnWndProc =   ScreenWndProc;
382    wndclass.cbClsExtra =    0;
383    wndclass.cbWndExtra =    SCREENEXTRABYTES;
384    wndclass.hInstance =     hInstance;
385    wndclass.hIcon =         (LoadIcon (hInstance, DEFAULT_ICON));
386    wndclass.hCursor =       (LoadCursor (NULL, IDC_ARROW));
387    wndclass.hbrBackground = 0;
388    wndclass.lpszMenuName =  0;
389    wndclass.lpszClassName = "MIT-SCREEN";
390    wndclass.hIconSm =       (wndclass . hIcon);
391 
392    n_free_events = 0;
393    free_events = 0;
394    event_queue_head = 0;
395    event_queue_tail = 0;
396 
397    return (RegisterClassEx (&wndclass));
398 }
399 
400 /* BOOL Screen_InitInstance (HANDLE hInstance, int nCmdShow )
401 
402    Description:
403       Initializes instance specific information for the screen class.
404       returns TRUE on success.
405 
406    Parameters:
407       HANDLE hInstance
408          Handle to instance
409 
410       int nCmdShow
411          How do we show the window?
412 */
413 
414 BOOL
Screen_InitInstance(HANDLE hInstance,int nCmdShow)415 Screen_InitInstance (HANDLE hInstance, int nCmdShow )
416 {
417   ghInstance = hInstance;
418   ghDefaultIcon = LoadIcon (hInstance, DEFAULT_ICON);
419   return  TRUE;
420 }
421 
422 /* SCREEN  Screen_Create (HANDLE hParent, LPCSTR title, int nCmdShow)
423 
424    Description:
425       Create a screen window with a given parent.
426 
427    Parameters:
428       hParent
429          Handle to parent window
430 */
431 
432 static int def_params[4] =
433 {
434   CW_USEDEFAULT,                /* Left */
435   CW_USEDEFAULT,                /* Top */
436   CW_USEDEFAULT,                /* Width */
437   CW_USEDEFAULT                 /* Height */
438 };
439 
440 HANDLE
Screen_Create(HANDLE hParent,LPCSTR title,int nCmdShow)441 Screen_Create (HANDLE hParent, LPCSTR title, int nCmdShow)
442 {
443   HWND hwnd;
444   int ctr, params[4] = {-1, -1, -1, -1};
445 
446   if (hParent == ((HANDLE) NULL))
447     init_geometry ("MITSCHEME_GEOMETRY", &params[0]);
448 
449   for (ctr = 0; ctr < 4; ctr++)
450     if (params[ctr] == -1)
451       params[ctr] = def_params[ctr];
452 
453   hwnd = CreateWindow ("MIT-SCREEN", title,
454 		       WS_OVERLAPPEDWINDOW,
455 		       params[0], params[1],
456 		       params[2], params[3],
457 		       hParent, NULL, ghInstance,
458 		       ((LPVOID) nCmdShow));
459   return  hwnd;
460 }
461 
462 VOID
Screen_Destroy(BOOL root,HANDLE hwnd)463 Screen_Destroy (BOOL root, HANDLE hwnd)
464 {
465   DestroyWindow (hwnd);
466 }
467 
468 /* Registry of screen handles */
469 
470 static SCREEN registered_screens = 0;
471 
472 static VOID
RegisterScreen(SCREEN screen)473 RegisterScreen (SCREEN screen)
474 {
475   screen->registry_link = registered_screens;
476   registered_screens = screen;
477 }
478 
479 static SCREEN*
head_to_registered_screen(HWND hWnd)480 head_to_registered_screen (HWND hWnd)
481 {
482   SCREEN *link = &registered_screens;
483   while (*link)
484     if ((*link)->hWnd == hWnd)
485       return  link;
486     else
487       link = &((*link)->registry_link);
488   return  0;
489 }
490 
491 static VOID
UnregisterScreen(SCREEN screen)492 UnregisterScreen (SCREEN screen)
493 {
494   SCREEN *link = head_to_registered_screen (screen->hWnd);
495   /* if (link) */
496   *link = screen->registry_link;
497 }
498 
499 BOOL
Screen_IsScreenHandle(HANDLE handle)500 Screen_IsScreenHandle (HANDLE handle)
501 {
502   return  head_to_registered_screen (handle) != 0;
503 }
504 
505 /* LRESULT FAR CALLBACK ScreenWndProc (HWND hWnd, UINT uMsg,
506                                        WPARAM wParam, LPARAM lParam )
507 
508    This is the TTY Window Proc.  This handles ALL messages to the tty
509    window.
510 */
511 
512 LRESULT FAR CALLBACK
ScreenWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)513 ScreenWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
514 {
515    SCREEN  screen = GETSCREEN (hWnd);
516 
517    /* Ignore common but uninteresting messages.  */
518    if (win32_trace_level
519        > (((uMsg == WM_SCHEME_INTERRUPT)
520 	   || (uMsg == WM_PAINT)
521 	   || (uMsg == WM_TIMER)
522 	   || (uMsg == WM_NCHITTEST)
523 	   || (uMsg == WM_SETCURSOR)
524 	   || (uMsg == WM_MOUSEMOVE))
525 	  ? 2
526 	  : 0))
527      {
528        const char * name = (translate_message_code (uMsg));
529        fprintf (win32_trace_file, "ScreenWndProc: ");
530        fprintf (win32_trace_file, "hWnd=0x%x, ", hWnd);
531        if (name)
532 	 fprintf (win32_trace_file, "uMsg=%s, ", name);
533        else
534 	 fprintf (win32_trace_file, "uMsg=0x%x, ", uMsg);
535        fprintf (win32_trace_file, "wParam=0x%x, lParam=0x%x\n",
536 		wParam, lParam);
537        fflush (win32_trace_file);
538      }
539    switch (uMsg)
540      {
541      case WM_CREATE:
542        {
543 	 LRESULT result = CreateScreenInfo (hWnd);
544 	 ShowWindow (hWnd,
545 		     ((int) ((LPCREATESTRUCT) lParam) -> lpCreateParams));
546 	 UpdateWindow (hWnd);
547 	 return  result;
548        }
549 
550      case WM_SCHEME_INTERRUPT:
551        return (0);
552 
553      case SCREEN_SETPOSITION:
554        return  (LRESULT)Screen_SetPosition
555 	 (screen, HIWORD(lParam), LOWORD(lParam));
556 
557      case SCREEN_GETPOSITION:
558        return  MAKELRESULT(screen->column, screen->row);
559 
560      case SCREEN_SETATTRIBUTE:
561        screen->write_attribute = (SCREEN_ATTRIBUTE) wParam;
562        return  0;
563 
564      case SCREEN_GETATTRIBUTE:
565        return  (LRESULT) screen->write_attribute;
566 
567      case SCREEN_SETMODES:
568        (screen -> mode_flags) = ((unsigned long) wParam);
569        return (0);
570 
571      case SCREEN_GETMODES:
572        return  (LRESULT) screen->mode_flags;
573 
574      case SCREEN_SETCOMMAND:
575        return  (LRESULT)
576 	 ScreenSetCommand(screen, LOWORD(wParam), (COMMAND_HANDLER)lParam);
577 
578      case SCREEN_GETCOMMAND:
579        return  (LRESULT)
580 	 ScreenSetCommand(screen, LOWORD(wParam), (COMMAND_HANDLER)-1);
581 
582      case SCREEN_SETBINDING:
583        return  (LRESULT)
584 	 ScreenSetBinding(screen, LOBYTE(wParam), (WORD)lParam);
585 
586      case SCREEN_GETBINDING:
587        return  (LRESULT)
588 	 ScreenSetBinding(screen, LOBYTE(wParam), (WORD)-1);
589 
590      case SCREEN_PEEKEVENT:
591        return  (LRESULT)
592 	 ScreenPeekOrRead(screen, (int)wParam, (SCREEN_EVENT*)lParam, FALSE);
593 
594      case SCREEN_READEVENT:
595        return  (LRESULT)
596 	 ScreenPeekOrRead(screen, (int)wParam, (SCREEN_EVENT*)lParam, TRUE);
597 
598      case SCREEN_WRITE:
599        return  (LRESULT)WriteScreenBlock (hWnd, (LPSTR)lParam, (int)wParam);
600 
601      case SCREEN_READ:
602        return  (LRESULT)ReadScreen (screen, (LPSTR)lParam, (int)wParam);
603 
604      case SCREEN_SETMENU:
605        Screen_SetMenu (screen, (HMENU)lParam);
606        return  0L;
607 
608      case SCREEN_CLEAR:
609        Screen_Clear (screen, (int)wParam);
610        return  0L;
611 
612      case WM_MOUSEACTIVATE:
613        if ((LOWORD (lParam)) == HTCLIENT)
614 	 return (MA_ACTIVATEANDEAT);
615        break;
616 
617      case WM_LBUTTONDOWN:
618      case WM_MBUTTONDOWN:
619      case WM_RBUTTONDOWN:
620        if (IsIconic (hWnd)) goto use_default;
621        ProcessMouseButton (hWnd, uMsg, wParam, lParam, FALSE);
622        break;
623 
624      case WM_LBUTTONUP:
625      case WM_MBUTTONUP:
626      case WM_RBUTTONUP:
627        if (IsIconic (hWnd)) goto use_default;
628        ProcessMouseButton (hWnd, uMsg, wParam, lParam, TRUE);
629        break;
630 
631      case WM_COMMAND:
632      case WM_SYSCOMMAND:
633        {
634 	 WORD  wID = LOWORD (wParam);
635 	 int  i;
636 	 for (i=0;  i<screen->n_commands; i++)
637 	   if (screen->commands[i].wID == wID)
638 	     {
639 	       LRESULT intrpt = (screen->commands[i].thunk(hWnd, wID));
640 
641 	       if (intrpt)
642 		 flush_typeahead (screen);
643 	       return  intrpt;
644 	     }
645 	 return  DefWindowProc (hWnd, uMsg, wParam, lParam);
646        }
647        break;
648 
649      case WM_GETMINMAXINFO:
650        {
651 	 LPMINMAXINFO info = ((LPMINMAXINFO) lParam);
652 	 GetMinMaxSizes (hWnd, &info->ptMinTrackSize, &info->ptMaxTrackSize);
653        }
654        break;
655 
656      case WM_PAINT:
657        PaintScreen (hWnd);
658        break;
659 
660      case WM_ERASEBKGND:
661        /* We now do this in PaintScreen as it reduces flicker after
662 	  resizing.  */
663        break;
664 
665      case WM_QUERYDRAGICON:
666        return (LRESULT) (screen->hIcon ? screen->hIcon : ghDefaultIcon);
667 
668      case WM_SIZE:
669        if (wParam!=SIZE_MINIMIZED)
670 	 SizeScreen (hWnd, HIWORD(lParam), LOWORD(lParam));
671        break;
672 
673      HANDLE_MSG (hWnd, WM_WINDOWPOSCHANGING, handle_window_pos_changing);
674 
675      case WM_HSCROLL:
676        ScrollScreenHorz (hWnd, LOWORD(wParam), HIWORD(wParam));
677        break;
678 
679      case WM_VSCROLL:
680        ScrollScreenVert (hWnd, LOWORD(wParam), HIWORD(wParam));
681        break;
682 
683      case WM_SYSKEYDOWN:
684      case WM_KEYDOWN:
685        record_modifier_transition (wParam, lParam, 1);
686        if ((IsIconic (hWnd))
687 	   || (!process_keydown (hWnd, uMsg, wParam, lParam)))
688 	 goto use_default;
689        break;
690 
691      case WM_SYSKEYUP:
692      case WM_KEYUP:
693        record_modifier_transition (wParam, lParam, 0);
694        goto use_default;
695 
696      case WM_SYSCHAR:
697      case WM_CHAR:
698        if (IsIconic (hWnd)) goto use_default;
699        process_character (hWnd, uMsg, wParam, lParam);
700        break;
701 
702       case WM_NCACTIVATE:
703        /* Windows doesn't send us focus messages when putting up and
704 	  taking down a system popup dialog as for Ctrl-Alt-Del on
705 	  Windows 95. The only indication we get that something
706 	  happened is receiving this message afterwards.  So this is a
707 	  good time to reset our keyboard modifiers' state. */
708        reset_modifiers ();
709        goto use_default;
710 
711      case WM_INPUTLANGCHANGE:
712        /* Clear dead keys in the keyboard state; for simplicity only
713 	  preserve modifier key states.  */
714        {
715 	 BYTE keystate [256];
716 	 GetKeyboardState (keystate);
717 	 {
718 	   unsigned int i;
719 	   for (i = 0; (i < 256); i += 1)
720 	     switch (i)
721 	       {
722 	       case VK_SHIFT:
723 	       case VK_LSHIFT:
724 	       case VK_RSHIFT:
725 	       case VK_CAPITAL:
726 	       case VK_NUMLOCK:
727 	       case VK_SCROLL:
728 	       case VK_CONTROL:
729 	       case VK_LCONTROL:
730 	       case VK_RCONTROL:
731 	       case VK_MENU:
732 	       case VK_LMENU:
733 	       case VK_RMENU:
734 	       case VK_LWIN:
735 	       case VK_RWIN:
736 		 (keystate[i]) = 0;
737 		 break;
738 	       }
739 	 }
740 	 SetKeyboardState (keystate);
741        }
742       goto use_default;
743 
744      case WM_SETFOCUS:
745        SetScreenFocus (hWnd);
746        reset_modifiers ();
747        process_focus_message (hWnd, 1);
748        goto use_default;
749 
750      case WM_KILLFOCUS:
751        KillScreenFocus (hWnd);
752        process_focus_message (hWnd, 0);
753        goto use_default;
754 
755      case WM_SHOWWINDOW:
756        process_show_message (hWnd, ((int) wParam));
757        goto use_default;
758 
759      case WM_DESTROY:
760        DestroyScreenInfo (hWnd);
761        break;
762 
763      case WM_CATATONIC:
764        {
765 	 extern void catatonia_trigger (void);
766 	 catatonia_trigger ();
767        }
768        break;
769 
770      case WM_CLOSE:
771        {
772 	 extern HANDLE master_tty_window;
773 
774 	 if (!(screen->mode_flags & SCREEN_EVENT_TYPE_CLOSE))
775 	   {
776 	     if (IDOK !=
777 		 MessageBox (hWnd,
778 			     hWnd==(HWND)master_tty_window
779 			     ? ("Closing this window will terminate Scheme.\n"
780 				"Changes to Edwin buffers might be lost.\n"
781 				"\n"
782 				"Really Exit Scheme?")
783 			     : "OK to close this window?",
784 			     "MIT/GNU Scheme",
785 			     (MB_ICONQUESTION | MB_OKCANCEL)))
786 	       break;
787 	   }
788 	 else
789 	   {
790 	     ProcessCloseMessage (screen);
791 	     break;
792 	   }
793 
794 	 if (hWnd == ((HWND) master_tty_window))
795 	   termination_normal (0);
796 	 goto use_default;
797        }
798 
799 #ifdef USE_WM_TIMER
800      case WM_TIMER:
801        {
802 	 extern void TimerProc (HWND, UINT, UINT, DWORD);
803 	 TimerProc (hWnd, uMsg, wParam, lParam);
804        }
805        break;
806 #endif /* USE_WM_TIMER */
807 
808      case WM_HOTKEY:
809        {
810 	 extern int signal_keyboard_character_interrupt (int);
811 	 signal_keyboard_character_interrupt (-2);
812        }
813 
814      use_default:
815      default:
816        return (DefWindowProc (hWnd, uMsg, wParam, lParam));
817      }
818    return (0L);
819 }
820 
821 static VOID
ClearScreen_internal(SCREEN screen)822 ClearScreen_internal (SCREEN screen)
823 {
824   screen->row                   = 0;
825   screen->column                = 0;
826   _fmemset (screen->chars, ' ', MAXROWS * MAXCOLS);
827   _fmemset (screen->attrs, screen->write_attribute,
828 	    MAXROWS * MAXCOLS * sizeof(SCREEN_ATTRIBUTE));
829 }
830 
831 /* LRESULT CreateScreenInfo (HWND hWnd)
832 
833    Description:
834       Creates the tty information structure and sets
835       menu option availability.  Returns -1 if unsuccessful.
836 
837    Parameters:
838       HWND  hWnd
839 */
840 
841 static LRESULT
CreateScreenInfo(HWND hWnd)842 CreateScreenInfo (HWND hWnd)
843 {
844    HMENU   hMenu;
845    SCREEN  screen;
846 
847    if (NULL == (screen =
848 		(SCREEN) LocalAlloc (LPTR, sizeof(SCREEN_STRUCT) )))
849       return  (LRESULT) -1;
850 
851    screen->hWnd                 = hWnd;
852    screen->hIcon                =
853      LoadIcon ((HINSTANCE) GetWindowLong(hWnd,GWL_HINSTANCE), DEFAULT_ICON);
854    screen->chars                = NULL;
855    screen->attrs                = NULL;
856    screen->write_attribute      = 0;
857    screen->cursor_visible       = TRUE;
858    screen->has_focus            = TRUE;
859 #if 0
860    screen->mode_flags           = (SCREEN_EVENT_TYPE_MASK
861 #endif
862    screen->mode_flags           = (SCREEN_EVENT_TYPE_KEY
863 				   | SCREEN_MODE_AUTOWRAP
864 				   | SCREEN_MODE_ECHO
865 #if 0
866 				   | SCREEN_MODE_CR_NEWLINES
867 #endif
868 				   | SCREEN_MODE_LINE_INPUT
869 				   | SCREEN_MODE_PROCESS_OUTPUT
870 				   | SCREEN_MODE_EAGER_UPDATE
871 				   | SCREEN_MODE_NEWLINE_CRS);
872    screen->xSize                = 0;
873    screen->ySize                = 0;
874    screen->xScroll              = 0;
875    screen->yScroll              = 0;
876    screen->xOffset              = 0;
877    screen->yOffset              = 0;
878    screen->hFont                = NULL;
879    if (! (init_color ("MITSCHEME_FOREGROUND", hWnd, &screen->rgbFGColour)))
880      screen->rgbFGColour        = GetSysColor (COLOR_WINDOWTEXT);
881    if (! (init_color ("MITSCHEME_BACKGROUND", hWnd, &screen->rgbBGColour)))
882      screen->rgbBGColour        = GetSysColor (COLOR_WINDOW);
883    screen->width                = 0;
884    screen->height               = 0;
885    screen->scroll_lines         = 1;
886 
887    screen->chars = xmalloc (MAXROWS * MAXCOLS);
888    screen->attrs = xmalloc (MAXROWS * MAXCOLS * sizeof(SCREEN_ATTRIBUTE));
889 
890    /* clear screen space */
891    ClearScreen_internal (screen);
892 
893    /* setup default font information */
894    screen->lfFont = lfDefaultLogFont;
895 
896    /* set handle before any further message processing. */
897    SETSCREEN (hWnd, screen);
898    RegisterScreen (screen);
899 
900    screen->n_commands = 0;
901    screen->n_bindings = 0;
902    /* reset the character information, etc. */
903 
904    screen->bkgnd_brush = NULL;
905    ResetScreen (screen);
906 
907    hMenu = GetSystemMenu (hWnd, FALSE);
908    AppendMenu (hMenu, MF_SEPARATOR, 0, 0);
909 /* AppendMenu (hMenu, MF_STRING, IDM_SETTINGS, "&Settings..."); */
910    AppendMenu (hMenu, MF_STRING, SCREEN_COMMAND_CHOOSEFONT, "&Font...");
911    AppendMenu (hMenu, MF_STRING, SCREEN_COMMAND_CHOOSEBACKCOLOR,
912 	       "&Background...");
913 
914    SendMessage (hWnd, SCREEN_SETCOMMAND,
915 		SCREEN_COMMAND_CHOOSEFONT, (LPARAM)ScreenCommand_ChooseFont);
916 /* SendMessage (hWnd, SCREEN_SETBINDING, 6, SCREEN_COMMAND_CHOOSEFONT); */
917    SendMessage (hWnd, SCREEN_SETCOMMAND, SCREEN_COMMAND_CHOOSEBACKCOLOR,
918 		(LPARAM)ScreenCommand_ChooseBackColor);
919 /* SendMessage (hWnd, SCREEN_SETBINDING, 7, SCREEN_COMMAND_CHOOSEBACKCOLOR); */
920 
921    screen->n_chars = 0;
922    screen->line_buffer = xmalloc (MAX_LINEINPUT + 1);
923 
924    screen->n_pending = 0;
925    screen->pending = ((LPSTR) NULL);
926    return  (LRESULT) TRUE;
927 }
928 
929 /* VOID DestroyScreenInfo (HWND hWnd )
930 
931    Description:
932       Destroys block associated with TTY window handle.
933 
934    Parameters:
935       HWND hWnd
936          handle to TTY window
937 */
938 
939 static VOID
DestroyScreenInfo(HWND hWnd)940 DestroyScreenInfo (HWND hWnd)
941 {
942    SCREEN screen = GETSCREEN (hWnd);
943 
944    if (NULL == screen)
945      return;
946 
947    /* KillScreenFocus (hWnd); */
948    UnregisterScreen (screen);
949    DeleteObject (screen->hFont);
950 
951    if (screen->chars)
952      xfree (screen->chars);
953    if (screen->attrs)
954      xfree (screen->attrs);
955 
956    LocalFree (screen);
957 }
958 
959 /* COMMAND_HANDLER  ScreenSetCommand (SCREEN, WORD cmd, COMMAND_HANDLER h) */
960 
961 static COMMAND_HANDLER
ScreenSetCommand(SCREEN screen,WORD cmd,COMMAND_HANDLER thunk)962 ScreenSetCommand (SCREEN screen, WORD cmd, COMMAND_HANDLER thunk)
963 {
964     int i;
965     for (i = 0; i < screen->n_commands; i++)
966       if (screen->commands[i].wID == cmd)
967       {
968 	COMMAND_HANDLER  result = screen->commands[i].thunk;
969 	if (thunk == 0)
970 	{
971 	  /* remove by overwriting with last in list */
972 	  screen->commands[i] = screen->commands[screen->n_commands-1];
973 	  screen->n_commands--;
974 	}
975 	else if (thunk == ((COMMAND_HANDLER) -1))
976 	{
977 	  /* just leave it alone */
978 	}
979 	else
980 	  /* redefine */
981 	  screen->commands[i].thunk = thunk;
982 	return  result;
983       }
984 
985     /* didnt find it */
986     if ((thunk == 0) || (thunk == ((COMMAND_HANDLER) -1)))
987       return  0;
988     /* add new command */
989     if (screen->n_commands == MAX_COMMANDS)
990       return ((COMMAND_HANDLER) - 1);
991 
992     screen->commands[screen->n_commands].wID   = cmd;
993     screen->commands[screen->n_commands].thunk = thunk;
994     screen->n_commands++;
995 
996     return  0;
997 }
998 
999 /* WORD  ScreenSetBinding (SCREEN, char key, WORD command) */
1000 
1001 static WORD
ScreenSetBinding(SCREEN screen,char key,WORD command)1002 ScreenSetBinding (SCREEN screen, char key, WORD command)
1003 {
1004     int i;
1005     for (i=0; i < screen->n_bindings; i++)
1006       if (screen->bindings[i].key == key)
1007       {
1008 	WORD  result = screen->bindings[i].command;
1009 	if (command == 0)
1010 	{
1011 	  /* remove by blatting with last in list */
1012 	  screen->bindings[i] = screen->bindings[screen->n_bindings-1];
1013 	  screen->n_bindings--;
1014 	}
1015 	else if (command == ((WORD) -1))
1016 	{
1017 	  /* let it be */
1018 	}
1019 	else
1020 	  /* redefine */
1021 	  screen->bindings[i].command = command;
1022 	return  result;
1023       }
1024 
1025     /* no existing binding for key */
1026     if ((command == 0) || (command == ((WORD) -1)))
1027       return  0;
1028     /* add new binding */
1029     if (screen->n_bindings == MAX_BINDINGS)
1030       return ((WORD) - 1);
1031 
1032     screen->bindings[screen->n_bindings].key     = key;
1033     screen->bindings[screen->n_bindings].command = command;
1034     screen->n_bindings++;
1035 
1036     return  0;
1037 }
1038 
1039 /* Standard commands */
1040 
1041 LRESULT
ScreenCommand_ChooseFont(HWND hWnd,WORD command)1042 ScreenCommand_ChooseFont (HWND hWnd, WORD command)
1043 {
1044   SCREEN  screen = GETSCREEN (hWnd);
1045   if (screen == 0)
1046     return  1L;
1047   SelectScreenFont (screen, hWnd);
1048   return  0L;
1049 }
1050 
1051 LRESULT
ScreenCommand_ChooseBackColor(HWND hWnd,WORD command)1052 ScreenCommand_ChooseBackColor (HWND hWnd, WORD command)
1053 {
1054   SCREEN  screen = GETSCREEN (hWnd);
1055   if (screen == 0)
1056     return  1L;
1057   SelectScreenBackColor (screen, hWnd);
1058   return  0L;
1059 }
1060 
1061 VOID
Screen_SetMenu(SCREEN screen,HMENU hMenu)1062 Screen_SetMenu (SCREEN screen, HMENU hMenu)
1063 {
1064   HMENU hOld = GetMenu (screen->hWnd);
1065   SetMenu (screen->hWnd, hMenu);
1066   if (hOld)
1067     DestroyMenu (hOld);
1068 }
1069 
1070 /* BOOL AdjustedSize
1071     make sure that proposed width & height of screen are ok.
1072     return TRUE if adjusted, FALSE if OK.  */
1073 static BOOL
AdjustedSize(SCREEN screen,int * width,int * height)1074 AdjustedSize (SCREEN screen, int *width, int *height)
1075 {
1076   POINT minsz, maxsz;
1077   GetMinMaxSizes (screen->hWnd, &minsz, &maxsz);
1078   if (*width<minsz.x || *width>maxsz.x || *height<minsz.y || *height>maxsz.y)
1079     {
1080       *width  = min (maxsz.x, max(minsz.x, *width));
1081       *height = min (maxsz.y, max(minsz.y, *height));
1082       return (TRUE);
1083     }
1084   return (FALSE);
1085 }
1086 
1087 /* BOOL ResetScreen (SCREEN  screen)
1088    Description:
1089       Resets the SCREEN character information and causes the
1090       screen to resize to update the scroll information.  */
1091 
1092 static BOOL
ResetScreen(SCREEN screen)1093 ResetScreen (SCREEN screen)
1094 {
1095    HWND        hWnd;
1096    HDC         hDC;
1097    TEXTMETRIC  tm;
1098    RECT        rcWindow;
1099 
1100    if (NULL == screen)
1101       return  FALSE;
1102 
1103    hWnd = screen->hWnd;
1104 
1105    if (screen->hFont)
1106      DeleteObject (screen->hFont);
1107 
1108    screen->hFont = CreateFontIndirect (&screen->lfFont);
1109 
1110    hDC = GetDC (hWnd);
1111    SelectObject (hDC, screen->hFont);
1112    GetTextMetrics (hDC, &tm);
1113    ReleaseDC (hWnd, hDC);
1114 
1115    screen->xChar = tm.tmAveCharWidth;
1116    screen->yChar = tm.tmHeight /* + tm.tmExternalLeading */;
1117 
1118    /* a slimy hack to make the caret the correct size: un- and re- focus */
1119    if (screen->cursor_visible) {
1120      KillScreenFocus (hWnd);
1121      SetScreenFocus (hWnd);
1122    }
1123 
1124    if (screen->bkgnd_brush != NULL)
1125      DeleteObject (screen->bkgnd_brush);
1126    screen->bkgnd_brush = CreateSolidBrush (screen->rgbBGColour);
1127 
1128    /* a slimy hack to force the scroll position, region to */
1129    /* be recalculated based on the new character sizes ???? */
1130 
1131    /* Veto screens that are too small or too large */
1132    {
1133      int width, height;
1134      GetWindowRect (hWnd, &rcWindow);
1135      width  = (rcWindow.right - rcWindow.left - (screen_x_extra (screen)));
1136      height = (rcWindow.bottom - rcWindow.top - (screen_y_extra (screen)));
1137      if (AdjustedSize (screen, &width, &height))
1138        MoveWindow (hWnd, rcWindow.left, rcWindow.top, width, height, TRUE);
1139      else
1140        SendMessage (hWnd, WM_SIZE, SIZENORMAL,
1141 		    ((LPARAM) (MAKELONG (width,height))));
1142    }
1143    return  TRUE;
1144 }
1145 
1146 static VOID
Do_PaintScreen(HWND hWnd,SCREEN screen,HDC hDC,PAINTSTRUCT * ps)1147 Do_PaintScreen (HWND hWnd, SCREEN screen, HDC hDC, PAINTSTRUCT * ps)
1148 {
1149   RECT          rect;
1150 
1151   int         nRow, nCol, nEndRow, nEndCol, nCount;
1152   int         nHorzPos, nVertPos, bias;
1153   HFONT       hOldFont;
1154 
1155   hOldFont = SelectObject (hDC, screen->hFont);
1156   rect = ps->rcPaint;
1157 
1158   { /* paint the background on the area surrounding the character grid */
1159     /* left strip */
1160     if (rect.left < - screen->xOffset) {
1161       RECT r = rect;
1162       r.right = -screen->xOffset;
1163       FillRect (hDC, &r, screen->bkgnd_brush);
1164     }
1165     /* right strip */
1166     if (rect.right > (screen->width * screen->xChar + screen->xOffset)) {
1167       RECT r = rect;
1168       r.left = (screen->width * screen->xChar + screen->xOffset);
1169       FillRect (hDC, &r, screen->bkgnd_brush);
1170     }
1171     /* top strip */
1172     if (rect.top < - screen->yOffset) {
1173       RECT r = rect;
1174       r.bottom =  - screen->yOffset;
1175       FillRect (hDC, &r, screen->bkgnd_brush);
1176     }
1177     /* bottom strip */
1178     if (rect.bottom > (screen->height * screen->yChar + screen->yOffset)) {
1179       RECT r = rect;
1180       r.top = (screen->height * screen->yChar + screen->yOffset);
1181       FillRect (hDC, &r, screen->bkgnd_brush);
1182     }
1183   }
1184 
1185   nRow =
1186     min (screen->height - 1,
1187 	 max (0, (rect.top + screen->yOffset) / screen->yChar));
1188   nEndRow =
1189     min (screen->height - 1,
1190 	 max (0, (rect.bottom + screen->yOffset - 1) / screen->yChar));
1191   nCol =
1192     min (screen->width - 1,
1193 	 max (0, (rect.left + screen->xOffset) / screen->xChar));
1194   nEndCol =
1195     min (screen->width - 1,
1196 	 max (0, (rect.right + screen->xOffset - 1) / screen->xChar));
1197   nCount = ((nEndCol - nCol) + 1);
1198   SetBkMode (hDC, OPAQUE);
1199   SetTextColor (hDC, screen->rgbFGColour);
1200   SetBkColor (hDC, screen->rgbBGColour);
1201 
1202   for (bias = ((nRow * MAXCOLS) + nCol),
1203        nVertPos = ((nRow * screen->yChar) - screen->yOffset);
1204        nRow <= nEndRow;
1205        nRow++, bias += MAXCOLS, nVertPos += screen->yChar)
1206   {
1207     int pos = 0;
1208     while (pos < nCount)
1209     {
1210       /* find consistent run of attributes */
1211       SCREEN_ATTRIBUTE  *attribp = &screen->attrs[bias + pos];
1212       SCREEN_ATTRIBUTE  attrib   = *attribp;
1213       int  nposn = (pos + 1);
1214       int  run_length;
1215 
1216       while ((nposn < nCount) && (*++attribp == attrib))
1217 	nposn++;
1218 
1219       run_length = (nposn - pos);
1220       nHorzPos = (((nCol + pos) * screen->xChar) - screen->xOffset);
1221       rect.top    = nVertPos;
1222       rect.bottom = nVertPos + screen->yChar;
1223       rect.left   = nHorzPos;
1224       rect.right  = nHorzPos + (screen->xChar * run_length);
1225       if (attrib&1)
1226       {
1227 	SetTextColor (hDC, screen->rgbBGColour);
1228 	SetBkColor (hDC, screen->rgbFGColour);
1229       }
1230       ExtTextOut (hDC, nHorzPos, nVertPos, (ETO_OPAQUE | ETO_CLIPPED),
1231 		  &rect, &screen->chars[bias + pos],
1232 		  run_length, NULL);
1233 #if 0
1234       if (attrib&2)  /* Bolden by horizontal 1-pixel smear */
1235         ExtTextOut (hDC, nHorzPos+1, nVertPos, (ETO_CLIPPED),
1236 		    &rect, &screen->chars[bias + pos],
1237 		    run_length, NULL);
1238 #endif
1239       if (attrib&1)
1240       {
1241 	SetTextColor (hDC, screen->rgbFGColour);
1242 	SetBkColor (hDC, screen->rgbBGColour);
1243       }
1244       pos = nposn;
1245     }
1246   }
1247   SelectObject (hDC, hOldFont);
1248 }
1249 
1250 /* VOID PaintScreen (HWND hWnd )
1251 
1252    Description:
1253       Paints the rectangle determined by the paint struct of
1254       the DC.
1255 
1256    Parameters:
1257       HWND hWnd
1258          handle to TTY window (as always)
1259 */
1260 
1261 static VOID
PaintScreen(HWND hWnd)1262 PaintScreen (HWND hWnd)
1263 {
1264   SCREEN        screen = GETSCREEN (hWnd);
1265   HDC           hDC;
1266   PAINTSTRUCT   ps;
1267 
1268   if (NULL == screen)
1269     return;
1270 
1271   hDC =  BeginPaint (hWnd, &ps);
1272   if (IsIconic (hWnd)) {
1273     DefWindowProc (hWnd, WM_ICONERASEBKGND, (WPARAM) hDC, 0L);
1274     DrawIcon (hDC, 0, 0, screen->hIcon ? screen->hIcon : ghDefaultIcon);
1275   } else {
1276     Do_PaintScreen (hWnd, screen, hDC, &ps);
1277   }
1278   EndPaint (hWnd, &ps);
1279   MoveScreenCursor (screen);
1280 }
1281 
1282 #if 0
1283 static VOID
1284 EraseScreen (HWND hWnd, HDC hDC)
1285 {
1286   SCREEN    screen = GETSCREEN (hWnd);
1287   RECT      rect;
1288 
1289   if (NULL == screen)
1290     return;
1291 
1292   if (! (IsIconic (hWnd))) {
1293     GetClientRect (hWnd, &rect);
1294     FillRect (hDC, &rect, screen->bkgnd_brush);
1295   }
1296 }
1297 #endif
1298 
1299 static VOID _fastcall
SetCells(SCREEN screen,int row,int col,int count,char ch,SCREEN_ATTRIBUTE attr)1300 SetCells (SCREEN screen, int row, int col, int count,
1301 	  char ch, SCREEN_ATTRIBUTE attr)
1302 {
1303   int  address1 = row * MAXCOLS + col;
1304   int  address2 = address1 + count;
1305   int  i;
1306   for (i = address1;  i<address2;  i++)
1307   {
1308     screen->chars[i] = ch;
1309     screen->attrs[i] = attr;
1310   }
1311 }
1312 
1313 static VOID
ScrollScreenBufferUp(SCREEN screen,int count)1314 ScrollScreenBufferUp (SCREEN  screen,  int count)
1315 {
1316   /* int  total_rows = MAXROWS; */
1317   int  total_rows = screen->height;
1318   int  rows_copied = max (total_rows - count, 0);
1319   count = min (count, total_rows);
1320 
1321   _fmemmove ((LPSTR) (screen->chars),
1322 	     (LPSTR) (screen->chars + count * MAXCOLS),
1323 	     rows_copied * MAXCOLS);
1324   _fmemmove ((LPSTR) (screen->attrs),
1325 	     (LPSTR) (screen->attrs + count * MAXCOLS),
1326 	     rows_copied * MAXCOLS);
1327   _fmemset ((LPSTR)(screen->chars + rows_copied * MAXCOLS),
1328 	    ' ', count*MAXCOLS);
1329   _fmemset ((LPSTR)(screen->attrs + rows_copied * MAXCOLS),
1330 	    screen->write_attribute, count*MAXCOLS);
1331 }
1332 
1333 /* BOOL SizeScreen (HWND hWnd, WORD wVertSize, WORD wHorzSize )
1334    Description:
1335       Set SCREEN size.  */
1336 
1337 static BOOL
SizeScreen(HWND hWnd,WORD wVertSize,WORD wHorzSize)1338 SizeScreen (HWND hWnd, WORD wVertSize, WORD wHorzSize )
1339 {
1340    SCREEN screen = GETSCREEN (hWnd);
1341    int old_width, old_height;
1342    unsigned int new_width;
1343    unsigned int new_height;
1344 
1345    if (NULL == screen)
1346       return  FALSE;
1347 
1348    if (IsIconic(hWnd)) {
1349      /* This entire section is a crock to ensure a reasonably sized window
1350         when Scheme is started minimized.
1351 
1352         Since we protect this procedure against minimizing in the WndProc, we
1353         can get here only when window is launched in a minimized state.  We
1354         get here because of the SendMessage in ScreenReset.  Our duty is to
1355 	fake a normal position and size.
1356         Luckily none of the scrolling business happens because all the cursor
1357         etc are at zero.  (Hopefully it would be clipped).
1358      */
1359      WINDOWPLACEMENT pl;
1360      int width, height, params[4] = {-1, -1, 0, 0};  /* left,top,width,height*/
1361      init_geometry ("MITSCHEME_GEOMETRY", &params[0]);
1362      width   = min (params[2] ? params[2] : 80*screen->xChar,
1363 		    GetSystemMetrics(SM_CXSCREEN));
1364      height  = min (params[3] ? params[3] : 40*screen->yChar,
1365 		    GetSystemMetrics(SM_CYSCREEN));
1366      pl.length = (sizeof (pl));
1367      GetWindowPlacement (hWnd, &pl);
1368      AdjustedSize (screen, &width, &height);
1369      pl.rcNormalPosition.left = params[0]==-1 ? 0 : params[0];
1370      pl.rcNormalPosition.top  = params[1]==-1 ? 0 : params[1];
1371      pl.rcNormalPosition.bottom = pl.rcNormalPosition.top + height;
1372      pl.rcNormalPosition.right  = pl.rcNormalPosition.left + width;
1373      SetWindowPlacement (hWnd, &pl);
1374      wVertSize = height;
1375      wHorzSize = width;
1376    }
1377 
1378    /* if (GetMenu(hWnd)) wVertSize -= GetSystemMetrics(SM_CYMENU); */
1379    old_width  = screen->width;
1380    old_height = screen->height;
1381 
1382    new_width  =
1383      max (1, min ((wHorzSize + screen->xOffset) / screen->xChar, MAXCOLS));
1384    new_height =
1385      max (1, min ((wVertSize + screen->yOffset) / screen->yChar, MAXROWS));
1386 
1387    if (new_width > old_width)
1388    {
1389      /* Clear out revealed character cells */
1390      int  row, rows = min (old_height, new_height);
1391      for (row = 0; row < rows; row++)
1392        SetCells (screen, row, old_width, new_width-old_width, ' ', 0);
1393    }
1394 
1395    if (new_height > old_height)
1396    {
1397      /* Clear out revealed character cells */
1398      int  row;
1399      for (row = old_height; row < new_height; row++)
1400        SetCells (screen, row, 0, new_width, ' ', 0);
1401    }
1402    else if (screen->row >= new_height)
1403    {
1404      ScrollScreenBufferUp (screen, ((screen->row - new_height) + 1));
1405      screen->row = (new_height - 1);
1406    }
1407 
1408    screen->width  = new_width;
1409    screen->height = new_height;
1410 
1411    /* scroll window to fit in cursor */
1412    if (screen->column >= new_width)
1413    {
1414      screen->column = 0;
1415      screen->row += 1;
1416    }
1417    if (screen->row >= new_height)
1418    {
1419      ScrollScreenBufferUp (screen, 1);
1420      screen->row = (new_height - 1);
1421    }
1422    MoveScreenCursor (screen);
1423 
1424    screen->ySize = (int) wVertSize;
1425    screen->xSize = (int) wHorzSize;
1426    screen->yScroll = 0;
1427    screen->xScroll = 0;
1428 
1429    if ((screen->mode_flags & SCREEN_MODE_EDWIN) == 0)
1430      screen->scroll_lines = (COMPUTE_SCROLL_LINES (new_height));
1431    else if (screen->mode_flags & SCREEN_EVENT_TYPE_RESIZE)
1432      {
1433        /* queue RESIZE event */
1434        SCREEN_EVENT * event
1435 	 = (allocate_event (screen, SCREEN_EVENT_TYPE_RESIZE));
1436        if (event)
1437 	 {
1438 	   event->event.resize.rows = new_height;
1439 	   event->event.resize.columns = new_width;
1440 	 }
1441      }
1442    else
1443      {
1444        /* Queue a character based resize event */
1445        SCREEN_EVENT * event = (allocate_event (screen, SCREEN_EVENT_TYPE_KEY));
1446        if (event)
1447 	 {
1448 	   event->event.key.repeat_count = 1;
1449 	   event->event.key.virtual_keycode = 0;
1450 	   event->event.key.virtual_scancode = 0;
1451 	   event->event.key.ch = SCREEN_EDWIN_RESIZE_COMMAND;
1452 	   event->event.key.control_key_state = 0;
1453 	 }
1454      }
1455    /* Cause screen to be redrawn, but if we are under Edwin, don't
1456       bother as Edwin has to calculate the redisplay anyway.  Well, we
1457       do bother otherwise we would have to clear the part of the
1458       screen that is not in a character box.  */
1459 #if 0
1460    if ((screen->mode_flags & SCREEN_MODE_EDWIN) == 0)
1461 #endif
1462      {
1463        InvalidateRect (hWnd, NULL, TRUE);
1464      }
1465 
1466    return  TRUE;
1467 
1468 }
1469 
1470 static BOOL
handle_window_pos_changing(HWND hwnd,LPWINDOWPOS wp)1471 handle_window_pos_changing (HWND hwnd, LPWINDOWPOS wp)
1472 {
1473   BOOL result = (FORWARD_WM_WINDOWPOSCHANGING (hwnd, wp, DefWindowProc));
1474   if ((wp -> flags) & SWP_NOSIZE)
1475     return (result);
1476   {
1477     SCREEN screen = (GETSCREEN (hwnd));
1478     (wp -> cx)
1479       = (char_to_pixel_width (screen,
1480 			      (pixel_to_char_width (screen, (wp -> cx)))));
1481     (wp -> cy)
1482       = (char_to_pixel_height (screen,
1483 			       (pixel_to_char_height (screen, (wp -> cy)))));
1484   }
1485   return (0);
1486 }
1487 
1488 void
screen_char_dimensions(HWND hwnd,int * xchar,int * ychar)1489 screen_char_dimensions (HWND hwnd, int * xchar, int * ychar)
1490 {
1491   SCREEN screen = (GETSCREEN (hwnd));
1492   (*xchar) = (screen -> xChar);
1493   (*ychar) = (screen -> yChar);
1494 }
1495 
1496 /* BOOL ScrollScreenVert (HWND hWnd, WORD wScrollCmd, WORD wScrollPos )
1497 
1498    Description:
1499       Scrolls TTY window vertically.
1500 
1501    Parameters:
1502       HWND hWnd
1503          handle to TTY window
1504 
1505       WORD wScrollCmd
1506          type of scrolling we're doing
1507 
1508       WORD wScrollPos
1509          scroll position
1510 */
1511 
1512 static BOOL
ScrollScreenVert(HWND hWnd,WORD wScrollCmd,WORD wScrollPos)1513 ScrollScreenVert (HWND hWnd, WORD wScrollCmd, WORD wScrollPos)
1514 {
1515    int        nScrollAmt;
1516    SCREEN     screen = GETSCREEN (hWnd);
1517 
1518    if (NULL == screen)
1519       return  FALSE;
1520 
1521    switch (wScrollCmd)
1522    {
1523       case SB_TOP:
1524 	 nScrollAmt = -screen->yOffset;
1525 	 break;
1526 
1527       case SB_BOTTOM:
1528 	 nScrollAmt = screen->yScroll - screen->yOffset;
1529 	 break;
1530 
1531       case SB_PAGEUP:
1532 	 nScrollAmt = -screen->ySize;
1533 	 break;
1534 
1535       case SB_PAGEDOWN:
1536 	 nScrollAmt = screen->ySize;
1537 	 break;
1538 
1539       case SB_LINEUP:
1540 	 nScrollAmt = -screen->yChar;
1541 	 break;
1542 
1543       case SB_LINEDOWN:
1544 	 nScrollAmt = screen->yChar;
1545 	 break;
1546 
1547       case SB_THUMBPOSITION:
1548 	 nScrollAmt = wScrollPos - screen->yOffset;
1549 	 break;
1550 
1551       default:
1552 	 return  FALSE;
1553    }
1554    if ((screen->yOffset + nScrollAmt) > screen->yScroll)
1555       nScrollAmt = screen->yScroll - screen->yOffset;
1556    if ((screen->yOffset + nScrollAmt) < 0)
1557       nScrollAmt = -screen->yOffset;
1558    ScrollWindow (hWnd, 0, -nScrollAmt, NULL, NULL);
1559    screen->yOffset = screen->yOffset + nScrollAmt;
1560    SetScrollPos (hWnd, SB_VERT, screen->yOffset, TRUE);
1561 
1562    return  TRUE;
1563 }
1564 
1565 /* BOOL ScrollScreenHorz (HWND hWnd, WORD wScrollCmd, WORD wScrollPos )
1566 
1567    Description:
1568       Scrolls TTY window horizontally.
1569 
1570    Parameters:
1571       HWND hWnd
1572          handle to TTY window
1573 
1574       WORD wScrollCmd
1575          type of scrolling we're doing
1576 
1577       WORD wScrollPos
1578          scroll position
1579 */
1580 
1581 static BOOL
ScrollScreenHorz(HWND hWnd,WORD wScrollCmd,WORD wScrollPos)1582 ScrollScreenHorz (HWND hWnd, WORD wScrollCmd, WORD wScrollPos)
1583 {
1584    int        nScrollAmt;
1585    SCREEN     screen = GETSCREEN (hWnd);
1586 
1587    if (NULL == screen)
1588       return  FALSE;
1589 
1590    switch (wScrollCmd)
1591    {
1592       case SB_TOP:
1593 	 nScrollAmt = -screen->xOffset;
1594 	 break;
1595 
1596       case SB_BOTTOM:
1597 	 nScrollAmt = screen->xScroll - screen->xOffset;
1598 	 break;
1599 
1600       case SB_PAGEUP:
1601 	 nScrollAmt = -screen->xSize;
1602 	 break;
1603 
1604       case SB_PAGEDOWN:
1605 	 nScrollAmt = screen->xSize;
1606 	 break;
1607 
1608       case SB_LINEUP:
1609 	 nScrollAmt = -screen->xChar;
1610 	 break;
1611 
1612       case SB_LINEDOWN:
1613 	 nScrollAmt = screen->xChar;
1614 	 break;
1615 
1616       case SB_THUMBPOSITION:
1617 	 nScrollAmt = wScrollPos - screen->xOffset;
1618 	 break;
1619 
1620       default:
1621 	 return  FALSE;
1622    }
1623    if ((screen->xOffset + nScrollAmt) > screen->xScroll)
1624       nScrollAmt = screen->xScroll - screen->xOffset;
1625    if ((screen->xOffset + nScrollAmt) < 0)
1626       nScrollAmt = -screen->xOffset;
1627    ScrollWindow (hWnd, -nScrollAmt, 0, NULL, NULL);
1628    screen->xOffset = screen->xOffset + nScrollAmt;
1629    SetScrollPos (hWnd, SB_HORZ, screen->xOffset, TRUE);
1630 
1631    return  TRUE;
1632 }
1633 
1634 static SCREEN screen_focus = NULL;
1635 
1636 HWND
ScreenCurrentFocus(void)1637 ScreenCurrentFocus (void)
1638 {
1639   SCREEN *link;
1640   HWND   hWnd;
1641 
1642   if (screen_focus)
1643     return  screen_focus->hWnd;
1644   hWnd = GetFocus();
1645   if (NULL == hWnd)
1646     return  NULL;
1647   link = head_to_registered_screen (hWnd);
1648   if (NULL == link)
1649     return  NULL;
1650   screen_focus = (*link);
1651   return  hWnd;
1652 }
1653 
1654 /* BOOL SetScreenFocus (HWND hWnd )
1655 
1656    Description:
1657       Sets the focus to the TTY window also creates caret.
1658 
1659    Parameters:
1660       HWND hWnd
1661          handle to TTY window
1662 */
1663 
1664 static BOOL
SetScreenFocus(HWND hWnd)1665 SetScreenFocus (HWND hWnd)
1666 {
1667    SCREEN  screen = GETSCREEN (hWnd);
1668 
1669    if (NULL == screen)  return  FALSE;
1670 
1671    screen_focus = screen;
1672    CreateCaret (hWnd, NULL, screen->xChar, screen->yChar);
1673    if (screen->cursor_visible)
1674       ShowCaret (hWnd);
1675 
1676    MoveScreenCursor (screen);
1677    return  TRUE;
1678 }
1679 
1680 /* BOOL KillScreenFocus (HWND hWnd )
1681 
1682    Description:
1683       Kills TTY focus and destroys the caret.
1684 
1685    Parameters:
1686       HWND hWnd
1687          handle to TTY window
1688 */
1689 
1690 BOOL
KillScreenFocus(HWND hWnd)1691 KillScreenFocus (HWND hWnd )
1692 {
1693    SCREEN  screen = GETSCREEN (hWnd);
1694 
1695    if (NULL == screen)  return  FALSE;
1696 
1697    screen_focus = NULL;
1698 #if 0
1699    if (screen->cursor_visible)
1700      HideCaret (hWnd);
1701 #endif
1702    DestroyCaret ();
1703    return  TRUE;
1704 }
1705 
1706 /* VOID MoveScreenCursor (SCREEN screen)
1707 
1708    Description:
1709       Moves caret to current position.
1710 */
1711 
1712 static VOID
MoveScreenCursor(SCREEN screen)1713 MoveScreenCursor (SCREEN screen)
1714 {
1715   ScreenCurrentFocus();
1716   if (screen == screen_focus)
1717 #if 0
1718     SetCaretPos (screen->column * screen->xChar - screen->xOffset
1719 		 /* This ensures visiblity at the far left: */
1720 		 + ((screen->column == screen->width) ? -2 : 0),
1721 		 screen->row * screen->yChar - screen->yOffset);
1722 #endif
1723   SetCaretPos (/* This ensures visiblity at the far left: */
1724 	       (screen->column >= screen->width)
1725 	       ? (screen->width * screen->xChar - screen->xOffset - 2)
1726 	       : (screen->column * screen->xChar - screen->xOffset),
1727 	       screen->row * screen->yChar - screen->yOffset);
1728 }
1729 
1730 BOOL
Screen_SetPosition(SCREEN screen,int row,int column)1731 Screen_SetPosition (SCREEN screen, int row, int column)
1732 {
1733   if ((row < 0) || (row >= screen->height))
1734     return (FALSE);
1735 #if 0
1736   if ((column < 0) || (column > screen->width))         /* may be == */
1737 #endif
1738   if ((column < 0) || (column >= MAXCOLS))
1739     return (FALSE);
1740   screen->row    = row;
1741   screen->column = column;
1742   MoveScreenCursor (screen);
1743   return  TRUE;
1744 }
1745 
1746 /* UINT ScreenPeekOrRead (SCREEN, n_to_read, SCREEN_EVENT* buffer, BOOL remove)
1747 
1748    Copy events into buffer.  Return number of events processed.
1749    If remove=TRUE, remove events from screen queue (i.e. Read)
1750    If remove=FALSE, leave events in queue (i.e. Peek)
1751    If buffer=NULL, process without copying.
1752    If n_to_read<0, process all events.
1753     .  n_to_read=-1, buffer=NULL, remove=FALSE -> count of pending events
1754     .  n_to_read=-1, buffer=NULL, remove=TRUE  -> flush queue
1755     .  n_to_read=n,  buffer=NULL, remove=TRUE  -> discard n events
1756 
1757    NB: if (n_to_read < 0), buffer is ignored.
1758 */
1759 
1760 UINT
ScreenPeekOrRead(SCREEN screen,int n_to_read,SCREEN_EVENT * buffer,BOOL remove)1761 ScreenPeekOrRead (SCREEN screen, int n_to_read, SCREEN_EVENT * buffer,
1762 		  BOOL remove)
1763 {
1764   SCREEN_EVENT * scan_buffer = ((n_to_read < 0) ? 0 : buffer);
1765   SCREEN_EVENT event;
1766   int n_read = 0;
1767 
1768   if (remove)
1769     while (((n_read < n_to_read) || (n_to_read < 0))
1770 	   && (read_event (screen, 0, 1, (&event))))
1771       {
1772 	if (scan_buffer)
1773 	  (*scan_buffer++) = event;
1774 	n_read += 1;
1775       }
1776   else
1777     {
1778       SCREEN_EVENT_LINK * scan_queue = event_queue_head;
1779       while (((n_read < n_to_read) || (n_to_read < 0))
1780 	     && (scan_queue != 0))
1781 	if (((scan_queue -> event) . handle) == (screen -> hWnd))
1782 	  {
1783 	    if (scan_buffer)
1784 	      (*scan_buffer++) = (scan_queue -> event);
1785 	    scan_queue = (scan_queue -> next);
1786 	    n_read += 1;
1787 	  }
1788     }
1789   return (n_read);
1790 }
1791 
1792 void
flush_typeahead(SCREEN screen)1793 flush_typeahead (SCREEN screen)
1794 {
1795   while (read_event (screen, SCREEN_EVENT_TYPE_KEY, 1, 0))
1796     ;
1797   (screen -> n_chars) = 0;
1798 }
1799 
1800 /* The following handling of the keyboard is taken with only minor
1801    changes from Emacs 20.5.  */
1802 
1803 #define LP_REPEAT(lparam)     ((lparam) & 0x0000ffff)
1804 #define LP_SCAN_CODE(lparam) (((lparam) & 0x00ff0000) >> 16)
1805 #define LP_EXTENDED(lparam)  (((lparam) & 0x01000000) != 0)
1806 
1807 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
1808    between left and right keys as advertised.  We test for this
1809    support dynamically, and set a flag when the support is absent.  If
1810    absent, we keep track of the left and right control and alt keys
1811    ourselves.  This is particularly necessary on keyboards that rely
1812    upon the AltGr key, which is represented as having the left control
1813    and right alt keys pressed.  For these keyboards, we need to know
1814    when the left alt key has been pressed in addition to the AltGr key
1815    so that we can properly support M-AltGr-key sequences (such as M-@
1816    on Swedish keyboards).  */
1817 
1818 #define MOD_LCONTROL 0
1819 #define MOD_RCONTROL 1
1820 #define MOD_LMENU 2
1821 #define MOD_RMENU 3
1822 
1823 static int modifiers [4] = { 0, 0, 0, 0 };
1824 static int record_modifiers_p;
1825 
1826 static void
record_modifier_transition(WPARAM wparam,LPARAM lparam,int down_p)1827 record_modifier_transition (WPARAM wparam, LPARAM lparam, int down_p)
1828 {
1829   static int modifier_key_support_tested = 0;
1830   if (down_p && (!modifier_key_support_tested))
1831     {
1832       if (wparam == VK_CONTROL)
1833 	{
1834 	  record_modifiers_p
1835 	    = (((GetKeyState (VK_LCONTROL) & 0x8000) == 0)
1836 	       && ((GetKeyState (VK_RCONTROL) & 0x8000) == 0));
1837 	  modifier_key_support_tested = 1;
1838 	}
1839       else if (wparam == VK_MENU)
1840 	{
1841 	  record_modifiers_p
1842 	    = (((GetKeyState (VK_LMENU) & 0x8000) == 0)
1843 	       && ((GetKeyState (VK_RMENU) & 0x8000) == 0));
1844 	  modifier_key_support_tested = 1;
1845 	}
1846     }
1847   if (record_modifiers_p)
1848     {
1849       if (down_p)
1850 	{
1851 	  /* Synchronize modifier state with what is reported with the
1852 	     current keystroke.  Even if we cannot distinguish between
1853 	     left and right modifier keys, we know that, if no
1854 	     modifiers are set, then neither the left nor right
1855 	     modifier should be set.  */
1856 	  if ((GetKeyState (VK_CONTROL) & 0x8000) == 0)
1857 	    {
1858 	      (modifiers[MOD_RCONTROL]) = 0;
1859 	      (modifiers[MOD_LCONTROL]) = 0;
1860 	    }
1861 	  if ((GetKeyState (VK_MENU) & 0x8000) == 0)
1862 	    {
1863 	      (modifiers[MOD_RMENU]) = 0;
1864 	      (modifiers[MOD_LMENU]) = 0;
1865 	    }
1866 	}
1867       if (wparam == VK_CONTROL)
1868 	(modifiers [(LP_EXTENDED (lparam)) ? MOD_RCONTROL : MOD_LCONTROL])
1869 	  = down_p;
1870       else if (wparam == VK_MENU)
1871 	(modifiers [(LP_EXTENDED (lparam)) ? MOD_RMENU : MOD_LMENU]) = down_p;
1872     }
1873 }
1874 
1875 /* We can lose focus while a modifier key has been pressed.  When
1876    we regain focus, be conservative and clear all modifiers since
1877    we cannot reconstruct the left and right modifier state.  */
1878 
1879 static void
copy_current_state(unsigned int vk,BYTE * keystate)1880 copy_current_state (unsigned int vk, BYTE * keystate)
1881 {
1882   (keystate[vk]) = ((GetAsyncKeyState (vk) & 0x8000) >> 8);
1883 }
1884 
1885 static void
reset_modifiers(void)1886 reset_modifiers (void)
1887 {
1888   if ((GetFocus ()) != 0)
1889     {
1890       if (((GetAsyncKeyState (VK_CONTROL)) & 0x08000) == 0)
1891 	{
1892 	  /* Clear any recorded control modifier state.  */
1893 	  (modifiers[MOD_RCONTROL]) = 0;
1894 	  (modifiers[MOD_LCONTROL]) = 0;
1895 	}
1896       if (((GetAsyncKeyState (VK_MENU)) & 0x08000) == 0)
1897 	{
1898 	  /* Clear any recorded alt modifier state.  */
1899 	  (modifiers[MOD_RMENU]) = 0;
1900 	  (modifiers[MOD_LMENU]) = 0;
1901 	}
1902       /* Update the state of all modifier keys, because modifiers used in
1903 	 hot-key combinations can get stuck on if Scheme loses focus as a
1904 	 result of a hot-key being pressed.  */
1905       {
1906 	BYTE keystate [256];
1907 	GetKeyboardState (keystate);
1908 	copy_current_state (VK_SHIFT, keystate);
1909 	copy_current_state (VK_CONTROL, keystate);
1910 	copy_current_state (VK_LCONTROL, keystate);
1911 	copy_current_state (VK_RCONTROL, keystate);
1912 	copy_current_state (VK_MENU, keystate);
1913 	copy_current_state (VK_LMENU, keystate);
1914 	copy_current_state (VK_RMENU, keystate);
1915 	copy_current_state (VK_LWIN, keystate);
1916 	copy_current_state (VK_RWIN, keystate);
1917 	copy_current_state (VK_APPS, keystate);
1918 	SetKeyboardState (keystate);
1919       }
1920     }
1921 }
1922 
1923 static int
modifier_set_p(int vk)1924 modifier_set_p (int vk)
1925 {
1926   if (record_modifiers_p)
1927     switch (vk)
1928       {
1929       case VK_LCONTROL:
1930 	return (modifiers[MOD_LCONTROL]);
1931       case VK_RCONTROL:
1932 	return (modifiers[MOD_RCONTROL]);
1933       case VK_LMENU:
1934 	return (modifiers[MOD_LMENU]);
1935       case VK_RMENU:
1936 	return (modifiers[MOD_RMENU]);
1937       }
1938   /* For toggled modifiers, test the low-order bit; otherwise the
1939      high-order bit.  */
1940   return
1941     (((GetKeyState (vk))
1942       & (((vk == VK_CAPITAL) || (vk == VK_NUMLOCK) || (vk == VK_SCROLL))
1943 	 ? 0x0001
1944 	 : 0x8000))
1945      != 0);
1946 }
1947 
1948 static unsigned int
get_modifiers(void)1949 get_modifiers (void)
1950 {
1951   unsigned int mods = 0;
1952 
1953   if (modifier_set_p (VK_SHIFT))    mods |= SCREEN_SHIFT_PRESSED;
1954   if (modifier_set_p (VK_CAPITAL))  mods |= SCREEN_CAPSLOCK_ON;
1955   if (modifier_set_p (VK_NUMLOCK))  mods |= SCREEN_NUMLOCK_ON;
1956   if (modifier_set_p (VK_SCROLL))   mods |= SCREEN_SCROLLLOCK_ON;
1957 
1958   if (modifier_set_p (VK_RCONTROL))
1959     mods |= (SCREEN_RIGHT_CONTROL_PRESSED | SCREEN_CONTROL_PRESSED);
1960   if (modifier_set_p (VK_LMENU))
1961     mods |= (SCREEN_LEFT_ALT_PRESSED | SCREEN_ALT_PRESSED);
1962 
1963   /* Slight complication to handle case where AltGr is pressed.  */
1964   if ((modifier_set_p (VK_LCONTROL)) && (!modifier_set_p (VK_RMENU)))
1965     mods |= (SCREEN_LEFT_CONTROL_PRESSED | SCREEN_CONTROL_PRESSED);
1966   if ((modifier_set_p (VK_RMENU)) && (!modifier_set_p (VK_LCONTROL)))
1967     mods |= (SCREEN_RIGHT_ALT_PRESSED | SCREEN_ALT_PRESSED);
1968 
1969   return (mods);
1970 }
1971 
1972 static void
use_translate_message(HWND handle,UINT message,WPARAM wparam,LPARAM lparam)1973 use_translate_message (HWND handle, UINT message, WPARAM wparam, LPARAM lparam)
1974 {
1975   MSG msg;
1976   (msg . hwnd) = handle;
1977   (msg . message) = message;
1978   (msg . wParam) = wparam;
1979   (msg . lParam) = lparam;
1980   (msg . time) = (GetMessageTime ());
1981   (msg . pt . x) = 0;
1982   (msg . pt . y) = 0;
1983   TranslateMessage (&msg);
1984 }
1985 
1986 static void
make_key_event(HWND handle,WPARAM wparam,LPARAM lparam,int ch)1987 make_key_event (HWND handle, WPARAM wparam, LPARAM lparam, int ch)
1988 {
1989   SCREEN screen = (GETSCREEN (handle));
1990   SCREEN_EVENT * event;
1991   unsigned int modifiers = (get_modifiers ());
1992 
1993   /* Translate the Backspace key to the Delete character.  */
1994   if ((ch == 0x08) && (wparam == VK_BACK))
1995     ch = ASCII_DEL;
1996 
1997   /* If the unmodified key is bound to a command, send the command.
1998      Extra hair here is due to need to handle control characters.  */
1999   if (((modifiers & SCREEN_ALT_PRESSED) == 0)
2000       && (((modifiers & SCREEN_CONTROL_PRESSED) == 0)
2001 	  || (('A' <= ch) && (ch <= 'Z'))
2002 	  || (('a' <= ch) && (ch <= 'z'))
2003 	  || (ch == '@') || (ch == '[') || (ch == '\\')
2004 	  || (ch == ']') || (ch == '^') || (ch == '_')))
2005     {
2006       int ch2 = ch;
2007       unsigned int i;
2008       if ((modifiers & SCREEN_CONTROL_PRESSED) != 0)
2009 	{
2010 	  if (('a' <= ch) && (ch <= 'z'))
2011 	    ch2 -= ('a' - 'A');
2012 	  ch2 -= '@';
2013 	}
2014       for (i = 0; (i < (screen -> n_bindings)); i += 1)
2015 	if ((((screen -> bindings) [i]) . key) == ch2)
2016 	  {
2017 	    if (SendMessage
2018 		(handle,
2019 		 WM_COMMAND,
2020 		 (MAKEWPARAM ((((screen -> bindings) [i]) . command), 0)),
2021 		 0))
2022 	      return;
2023 	    else
2024 	      break;
2025 	  }
2026     }
2027 
2028   if ((ch == (-1)) && (((screen -> mode_flags) & SCREEN_MODE_VK_KEYS) == 0))
2029     return;
2030 
2031   event = (allocate_event (screen, SCREEN_EVENT_TYPE_KEY));
2032   if (!event) return;
2033   ((event -> event.key) . repeat_count) = (LP_REPEAT (lparam));
2034   ((event -> event.key) . virtual_keycode) = wparam;
2035   ((event -> event.key) . virtual_scancode) = (LP_SCAN_CODE (lparam));
2036   ((event -> event.key) . ch) = ch;
2037   ((event -> event.key) . control_key_state) = modifiers;
2038 
2039   if (win32_trace_level > 0)
2040     {
2041       fprintf (win32_trace_file, "make_key_event: ");
2042       fprintf
2043 	(win32_trace_file,
2044 	 "handle=0x%x keycode=0x%x scancode=0x%x ch=0x%x modifiers=0x%x\n",
2045 	 handle, wparam, (LP_SCAN_CODE (lparam)), ch, modifiers);
2046       fflush (win32_trace_file);
2047     }
2048 }
2049 
2050 /* Process WM_KEYDOWN and WM_SYSKEYDOWN.  Return 1 to indicate that
2051    the key was handled, and that the message proc should return;
2052    return 0 to indicate that the default action should take place.  */
2053 
2054 static int
process_keydown(HWND handle,UINT message,WPARAM wparam,LPARAM lparam)2055 process_keydown (HWND handle, UINT message, WPARAM wparam, LPARAM lparam)
2056 {
2057   switch (wparam)
2058     {
2059     case VK_MENU:
2060       /* Prevent Windows from activating the menu bar if an Alt key is
2061 	 pressed and released by itself.  */
2062       return (1);
2063 
2064     case VK_LWIN:
2065     case VK_RWIN:
2066     case VK_APPS:
2067     case VK_NUMLOCK:
2068     case VK_SCROLL:
2069     case VK_CAPITAL:
2070     case VK_CONTROL:
2071     case VK_SHIFT:
2072       /* Let Windows handle the modifier keys.  */
2073       use_translate_message (handle, message, wparam, lparam);
2074       return (0);
2075     }
2076 
2077   /* Always let Windows handle AltGr key chords; for some reason,
2078      ToAscii doesn't always process AltGr chords correctly.  */
2079   if ((modifier_set_p (VK_LCONTROL)) && (modifier_set_p (VK_RMENU)))
2080     {
2081       use_translate_message (handle, message, wparam, lparam);
2082       return (0);
2083     }
2084 
2085   /* Edwin handles some of the special keys directly, so provide
2086      symbols for those keys rather than translating them.  */
2087   if ((((GETSCREEN (handle)) -> mode_flags) & SCREEN_MODE_VK_KEYS)
2088       && ((wparam == VK_LEFT)
2089 	  || (wparam == VK_RIGHT)
2090 	  || (wparam == VK_UP)
2091 	  || (wparam == VK_DOWN)
2092 	  || (wparam == VK_HOME)
2093 	  || (wparam == VK_END)
2094 	  || (wparam == VK_PRIOR)
2095 	  || (wparam == VK_NEXT)
2096 	  || (wparam == VK_INSERT)
2097 	  || (wparam == VK_DELETE)
2098 	  || ((wparam >= VK_F1) && (wparam <= VK_F24))))
2099     {
2100       make_key_event (handle, wparam, lparam, (-1));
2101       return (1);
2102     }
2103 
2104   /* Let TranslateMessage handle anything not involving Alt or Ctrl.  */
2105   if (((get_modifiers ())
2106        & (SCREEN_ALT_PRESSED | SCREEN_CONTROL_PRESSED))
2107       == 0)
2108     {
2109       use_translate_message (handle, message, wparam, lparam);
2110       return (0);
2111     }
2112 
2113   /* Otherwise, handle translation directly, as otherwise Windows
2114      will do the wrong thing.  Translate the unmodified keystroke to
2115      the corresponding character(s), then add the modifiers back in.  */
2116   {
2117     BYTE keystate [256];
2118     BYTE ansi_code [4];
2119     int n_chars;
2120     int i;
2121 
2122     memset (keystate, 0, (sizeof (keystate)));
2123     (keystate[wparam]) = 0x80;
2124     if (modifier_set_p (VK_SHIFT))
2125       (keystate[VK_SHIFT]) = 0x80;
2126     if (modifier_set_p (VK_CAPITAL))
2127       (keystate[VK_CAPITAL]) = 0x01;
2128 
2129     /* On NT, call ToUnicode instead and then convert to the current
2130        locale's default codepage.  */
2131     if (NT_windows_type == wintype_nt)
2132       {
2133 	WCHAR buffer [128];
2134 	char code_page [20];
2135 	int code_page_number;
2136 
2137 	n_chars
2138 	  = (ToUnicode (wparam, (LP_SCAN_CODE (lparam)), keystate,
2139 			buffer, 128, 0));
2140 	if (n_chars <= 0)
2141 	  return (1);
2142 	GetLocaleInfo ((GetThreadLocale ()), LOCALE_IDEFAULTANSICODEPAGE,
2143 		       code_page, (sizeof (code_page)));
2144 	code_page_number = (atoi (code_page));
2145 	n_chars
2146 	  = (WideCharToMultiByte (code_page_number, 0, buffer, n_chars,
2147 				  ansi_code, (sizeof (ansi_code)), 0, 0));
2148       }
2149     else
2150       n_chars
2151 	= (ToAscii (wparam, (LP_SCAN_CODE (lparam)), keystate,
2152 		    ((LPWORD) ansi_code), 0));
2153     for (i = 0; (i < n_chars); i += 1)
2154       make_key_event (handle, wparam, lparam, (ansi_code[i]));
2155     return (1);
2156   }
2157 }
2158 
2159 static void
process_character(HWND handle,UINT message,WPARAM wparam,LPARAM lparam)2160 process_character (HWND handle, UINT message, WPARAM wparam, LPARAM lparam)
2161 {
2162   make_key_event
2163     (handle, (MapVirtualKey ((LP_SCAN_CODE (lparam)), 1)), lparam, wparam);
2164 }
2165 
2166 static void
process_focus_message(HWND handle,int gained_p)2167 process_focus_message (HWND handle, int gained_p)
2168 {
2169   SCREEN screen = (GETSCREEN (handle));
2170   SCREEN_EVENT * event = (allocate_event (screen, SCREEN_EVENT_TYPE_FOCUS));
2171   if (event)
2172     (event->event.focus.gained_p) = gained_p;
2173 }
2174 
2175 static void
process_show_message(HWND handle,int show_p)2176 process_show_message (HWND handle, int show_p)
2177 {
2178   SCREEN screen = (GETSCREEN (handle));
2179   SCREEN_EVENT * event
2180     = (allocate_event (screen, SCREEN_EVENT_TYPE_VISIBILITY));
2181   if (event)
2182     (event->event.visibility.show_p) = show_p;
2183 }
2184 
2185 static VOID
ProcessCloseMessage(SCREEN screen)2186 ProcessCloseMessage (SCREEN screen)
2187 {
2188   (void) allocate_event (screen, SCREEN_EVENT_TYPE_CLOSE);
2189 }
2190 
2191 static VOID
ProcessMouseButton(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL up)2192 ProcessMouseButton (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
2193                     BOOL up)
2194 {
2195   SCREEN screen = GETSCREEN (hWnd);
2196   SCREEN_EVENT * event;
2197   unsigned int control = 0;
2198   unsigned int button = 0;
2199 
2200   if (NULL == screen)
2201     return;
2202 
2203   if (uMsg & MK_CONTROL)
2204     control |= SCREEN_CONTROL_PRESSED;
2205   if (uMsg & MK_SHIFT)
2206     control |= SCREEN_SHIFT_PRESSED;
2207 
2208   switch (uMsg)
2209     {
2210     case WM_LBUTTONDOWN:
2211     case WM_LBUTTONUP:
2212       button = SCREEN_MOUSE_EVENT_LEFT_PRESSED;
2213       break;
2214 
2215     case WM_MBUTTONDOWN:
2216     case WM_MBUTTONUP:
2217       button = SCREEN_MOUSE_EVENT_MIDDLE_PRESSED;
2218       break;
2219 
2220     case WM_RBUTTONDOWN:
2221     case WM_RBUTTONUP:
2222       button = SCREEN_MOUSE_EVENT_RIGHT_PRESSED;
2223       break;
2224     }
2225   event = (allocate_event (screen, SCREEN_EVENT_TYPE_MOUSE));
2226   if (event)
2227     {
2228       event->event.mouse.row = ((HIWORD (lParam)) / (screen -> yChar));
2229       event->event.mouse.column = ((LOWORD (lParam)) / (screen -> xChar));
2230       event->event.mouse.control_key_state = control;
2231       event->event.mouse.button_state = button;
2232       event->event.mouse.up = up;
2233       event->event.mouse.mouse_moved = 0;
2234       event->event.mouse.double_click = 0;
2235     }
2236 }
2237 
2238 /* Utilities for WriteScreenBlock */
2239 
2240 static VOID _fastcall
Screen_BS(SCREEN screen)2241 Screen_BS (SCREEN screen)
2242 {
2243   if (screen->column > 0)
2244     screen->column --;
2245   else if (screen->row > 0)
2246   {
2247     screen->row--;
2248     screen->column = (screen->width - 1);
2249   }
2250   if (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE)
2251     MoveScreenCursor (screen);
2252 }
2253 
2254 static VOID _fastcall
Screen_LF(SCREEN screen)2255 Screen_LF (SCREEN screen)
2256 {
2257   if ((screen->row++) >= (screen->height - 1))
2258   {
2259     ScrollScreenBufferUp (screen, screen->scroll_lines);
2260     ScrollWindow (screen->hWnd, 0,
2261 		  (-screen->yChar * screen->scroll_lines),
2262 		  NULL,
2263 		  NULL);
2264 #if 0
2265     InvalidateRect (hWnd, NULL, FALSE);
2266     screen->row--;
2267 #endif
2268     screen->row = (screen->height - screen->scroll_lines);
2269   }
2270   if (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE)
2271   {
2272     MoveScreenCursor (screen);
2273     UpdateWindow (screen->hWnd);
2274   }
2275 }
2276 
2277 static VOID _fastcall
Screen_CR(SCREEN screen)2278 Screen_CR (SCREEN screen)
2279 {
2280   screen->column = 0;
2281   if (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE)
2282     MoveScreenCursor (screen);
2283 }
2284 
2285 static VOID _fastcall
Screen_CRLF(SCREEN screen)2286 Screen_CRLF (SCREEN screen)
2287 {
2288   Screen_CR (screen);
2289   Screen_LF (screen);
2290 }
2291 
2292 VOID _fastcall
clear_screen_rectangle(SCREEN screen,int lo_row,int lo_col,int hi_row,int hi_col)2293 clear_screen_rectangle (SCREEN screen,
2294 			int lo_row, int lo_col,
2295 			int hi_row, int hi_col)
2296 {
2297   RECT rect;
2298   int row, delta_col;
2299   char * screen_chars;
2300   SCREEN_ATTRIBUTE * screen_attrs;
2301 
2302   delta_col = (hi_col - lo_col);
2303 
2304   for (row = lo_row,
2305        screen_chars = &screen->chars[lo_row * MAXCOLS + lo_col],
2306        screen_attrs = &screen->attrs[lo_row * MAXCOLS + lo_col];
2307        row < hi_row;
2308        row++,
2309        screen_chars += MAXCOLS,
2310        screen_attrs += MAXCOLS)
2311   {
2312     _fmemset (screen_chars, ' ', delta_col);
2313     _fmemset (screen_attrs,
2314 	      screen->write_attribute,
2315 	      (delta_col * (sizeof (SCREEN_ATTRIBUTE))));
2316   }
2317 
2318   rect.left   = ((lo_col * screen->xChar) - screen->xOffset);
2319   rect.right  = ((hi_col * screen->xChar) - screen->xOffset);
2320   rect.top    = ((lo_row * screen->yChar) - screen->yOffset);
2321   rect.bottom = ((hi_row * screen->yChar) - screen->yOffset);
2322   InvalidateRect (screen->hWnd, &rect, FALSE);
2323 }
2324 
2325 #define INIT_SCREEN_WRITE_CHAR_STATE(state) state.row = -1
2326 
2327 static VOID _fastcall
Finish_ScreenWriteChar(SCREEN screen,struct screen_write_char_s * rectp)2328 Finish_ScreenWriteChar (SCREEN screen, struct screen_write_char_s * rectp)
2329 {
2330   if (rectp->row != -1)
2331     InvalidateRect (screen->hWnd, &rectp->rect, FALSE);
2332   if ((screen->column >= screen->width)
2333       && ((screen->mode_flags & SCREEN_MODE_AUTOWRAP) != 0))
2334     Screen_CRLF (screen);
2335   rectp->row = -1;
2336 }
2337 
2338 VOID _fastcall
Screen_WriteCharUninterpreted(SCREEN screen,int ch,struct screen_write_char_s * rectp)2339 Screen_WriteCharUninterpreted (SCREEN screen, int ch,
2340 			       struct screen_write_char_s * rectp)
2341 {
2342   /* Line wrap/overwrite the last position */
2343 
2344   if (screen->column >= screen->width)
2345   {
2346     if ((screen->mode_flags & SCREEN_MODE_AUTOWRAP) != 0)
2347     {
2348       if ((rectp != ((struct screen_write_char_s *) NULL))
2349 	  && (rectp->row != -1))
2350       {
2351 	InvalidateRect (screen->hWnd, &rectp->rect, FALSE);
2352 	rectp->row = -1;
2353       }
2354       Screen_CRLF (screen);
2355     }
2356     else
2357     {
2358       screen->column -= 1;
2359       if (rectp != ((struct screen_write_char_s *) NULL))
2360       {
2361 	rectp->col -= 1;
2362 	rectp->rect.right -= screen->xChar;
2363       }
2364     }
2365   }
2366   if (screen->row >= MAXROWS)
2367     screen->row = (MAXROWS - 1);
2368 
2369   if (screen->column >= MAXCOLS)
2370     screen->column = (MAXCOLS - 1);
2371 
2372   if (screen->row < 0)
2373     screen->row = 0;
2374 
2375   if (screen->column < 0)
2376     screen->column = 0;
2377 
2378   screen->chars[screen->row * MAXCOLS + screen->column] = ch;
2379   screen->attrs[screen->row * MAXCOLS + screen->column] =
2380     screen->write_attribute;
2381   if (rectp == ((struct screen_write_char_s *) NULL))
2382   {
2383     RECT       rect;
2384 
2385     rect.left   = ((screen->column * screen->xChar) - screen->xOffset);
2386     rect.right  = rect.left + screen->xChar;
2387     rect.top    = ((screen->row * screen->yChar) - screen->yOffset);
2388     rect.bottom = rect.top + screen->yChar;
2389     InvalidateRect (screen->hWnd, &rect, FALSE);
2390   }
2391   else if ((rectp->row == screen->row) && (rectp->col == screen->column))
2392   {
2393     rectp->col += 1;
2394     rectp->rect.right += screen->xChar;
2395   }
2396   else
2397   {
2398     if (rectp->row != -1)
2399       InvalidateRect (screen->hWnd, &rectp->rect, FALSE);
2400 
2401     rectp->rect.left   = ((screen->column * screen->xChar) - screen->xOffset);
2402     rectp->rect.right  = rectp->rect.left + screen->xChar;
2403     rectp->rect.top    = ((screen->row * screen->yChar) - screen->yOffset);
2404     rectp->rect.bottom = rectp->rect.top + screen->yChar;
2405     rectp->col = (screen->column + 1);
2406     rectp->row = screen->row;
2407   }
2408   screen->column += 1;
2409 }
2410 
2411 static VOID _fastcall
Screen_TAB(SCREEN screen,struct screen_write_char_s * rectp)2412 Screen_TAB (SCREEN screen, struct screen_write_char_s * rectp)
2413 {
2414   do
2415     Screen_WriteCharUninterpreted (screen, ' ', rectp);
2416   while ((screen->column % 8) != 0);
2417 }
2418 
2419 static VOID _fastcall
relocate_cursor(SCREEN screen,int row,int col)2420 relocate_cursor (SCREEN screen, int row, int col)
2421 {
2422   screen->row = ((row < 0)
2423 		 ? 0
2424 		 : ((row >= screen->height)
2425 		    ? (screen->height - 1)
2426 		    : row));
2427   screen->column = ((col < 0)
2428 		    ? 0
2429 		    : ((col >= screen->width)
2430 		       ? (screen->width - 1)
2431 		       : col));
2432   if (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE)
2433     MoveScreenCursor (screen);
2434 }
2435 
2436 static VOID _fastcall
cursor_right(SCREEN screen,int delta)2437 cursor_right (SCREEN screen, int delta)
2438 {
2439   int new_col = (screen->column + delta);
2440 
2441   if (new_col < screen->width)
2442     screen->column = new_col;
2443   else if ((screen->mode_flags & SCREEN_MODE_AUTOWRAP) == 0)
2444     screen->column = (screen->width - 1);
2445   else
2446   {
2447     while (new_col >= screen->width)
2448     {
2449       Screen_CRLF (screen);
2450       new_col -= screen->width;
2451     }
2452     screen->column = new_col;
2453   }
2454 }
2455 
2456 VOID _fastcall
scroll_screen_vertically(SCREEN screen,int lo_row_from,int lo_col,int hi_row_from,int hi_col,int lo_row_to)2457 scroll_screen_vertically (SCREEN screen,
2458 			  int lo_row_from, int lo_col,
2459 			  int hi_row_from, int hi_col,
2460 			  int lo_row_to)
2461 {
2462   RECT rect;
2463   int row, delta_col, hi_row_to;
2464   char * chars_from, * chars_to;
2465   SCREEN_ATTRIBUTE * attrs_from, * attrs_to;
2466 
2467   if (lo_row_to < 0)
2468     lo_row_to = 0;
2469   if (lo_row_to > MAXCOLS)
2470     lo_row_to = MAXCOLS;
2471 
2472   delta_col = (hi_col - lo_col);
2473   hi_row_to = (lo_row_to + (hi_row_from - lo_row_from));
2474 
2475   if (lo_row_from > lo_row_to)          /* Scrolling up. */
2476     for (row = lo_row_from,
2477 	 chars_from = &screen->chars[lo_row_from * MAXCOLS + lo_col],
2478 	 attrs_from = &screen->attrs[lo_row_from * MAXCOLS + lo_col],
2479 	 chars_to = &screen->chars[lo_row_to * MAXCOLS + lo_col],
2480 	 attrs_to = &screen->attrs[lo_row_to * MAXCOLS + lo_col];
2481 	 row < hi_row_from;
2482 	 row++,
2483 	 chars_from += MAXCOLS,
2484 	 attrs_from += MAXCOLS,
2485 	 chars_to += MAXCOLS,
2486 	 attrs_to += MAXCOLS)
2487     {
2488       _fmemmove (((LPSTR) chars_to), ((LPSTR) chars_from), delta_col);
2489       _fmemmove (((LPSTR) attrs_to), ((LPSTR) attrs_from), delta_col);
2490     }
2491   else                                   /* Scrolling down. */
2492     for (row = (hi_row_from - 1),
2493 	 chars_from =  &screen->chars[(hi_row_from - 1) * MAXCOLS + lo_col],
2494 	 attrs_from =  &screen->attrs[(hi_row_from - 1) * MAXCOLS + lo_col],
2495 	 chars_to =  &screen->chars[(hi_row_to - 1) * MAXCOLS + lo_col],
2496 	 attrs_to =  &screen->attrs[(hi_row_to - 1) * MAXCOLS + lo_col];
2497 	 row >= lo_row_from;
2498 	 row--,
2499 	 chars_from -= MAXCOLS,
2500 	 attrs_from -= MAXCOLS,
2501 	 chars_to -= MAXCOLS,
2502 	 attrs_to -= MAXCOLS)
2503     {
2504       _fmemmove (((LPSTR) chars_to), ((LPSTR) chars_from), delta_col);
2505       _fmemmove (((LPSTR) attrs_to), ((LPSTR) attrs_from), delta_col);
2506     }
2507 
2508   rect.left   = ((lo_col * screen->xChar) - screen->xOffset);
2509   rect.right  = ((hi_col * screen->xChar) - screen->xOffset);
2510   rect.top    = ((lo_row_to * screen->yChar) - screen->yOffset);
2511   rect.bottom = ((hi_row_to * screen->yChar) - screen->yOffset);
2512   InvalidateRect (screen->hWnd, &rect, FALSE);
2513 }
2514 
2515 static VOID _fastcall
scroll_screen_line_horizontally(SCREEN screen,int row,int lo_col_from,int hi_col_from,int lo_col_to)2516 scroll_screen_line_horizontally (SCREEN screen, int row,
2517 				 int lo_col_from, int hi_col_from,
2518 				 int lo_col_to)
2519 {
2520   RECT rect;
2521   int delta_col = (hi_col_from - lo_col_from);
2522   int hi_col_to = (lo_col_to + delta_col);
2523 
2524   _fmemmove (((LPSTR) &screen->chars[(row * MAXCOLS) + lo_col_to]),
2525 	     ((LPSTR) &screen->chars[(row * MAXCOLS) + lo_col_from]),
2526 	     delta_col);
2527   _fmemmove (((LPSTR) &screen->attrs[(row * MAXCOLS) + lo_col_to]),
2528 	     ((LPSTR) &screen->attrs[(row * MAXCOLS) + lo_col_from]),
2529 	     delta_col);
2530 
2531   rect.left   = ((lo_col_to * screen->xChar) - screen->xOffset);
2532   rect.right  = ((hi_col_to * screen->xChar) - screen->xOffset);
2533   rect.top    = ((row * screen->yChar) - screen->yOffset);
2534   rect.bottom = (((row + 1) * screen->yChar) - screen->yOffset);
2535   InvalidateRect (screen->hWnd, &rect, FALSE);
2536 }
2537 
2538 static int _fastcall
read_decimal(LPSTR str,int lo,int len,int * hi)2539 read_decimal (LPSTR str, int lo, int len, int * hi)
2540 {
2541   int ctr, result;
2542 
2543   for (result = 0, ctr = lo;
2544        ctr < len;
2545        result = ((result * 10) + ((str[ctr]) - '0')), ctr++)
2546     if ((str[ctr] < '0') || (str[ctr] > '9'))
2547       break;
2548 
2549   * hi = ctr;
2550   return (result);
2551 }
2552 
2553 #ifdef PRETTY_PRINT_CHARS
2554 static VOID _fastcall
screen_write_octal(SCREEN screen,unsigned char the_char,struct screen_write_char_s * rectp)2555 screen_write_octal (SCREEN screen, unsigned char the_char,
2556 		    struct screen_write_char_s * rectp)
2557 {
2558   Screen_WriteCharUninterpreted (screen, '\\', rectp);
2559   Screen_WriteCharUninterpreted (screen, ((the_char / 0100) + '0'), rectp);
2560   Screen_WriteCharUninterpreted (screen, (((the_char % 0100) / 010) + '0'),
2561 				 rectp);
2562   Screen_WriteCharUninterpreted (screen, ((the_char % 010) + '0'), rectp);
2563 }
2564 #endif /* PRETTY_PRINT_CHARS */
2565 
2566 static VOID
WriteScreenBlock_suspend(SCREEN screen,LPSTR lpBlock,int i,int nLength)2567 WriteScreenBlock_suspend (SCREEN screen, LPSTR lpBlock, int i, int nLength)
2568 {
2569   screen->n_pending = (nLength - i);
2570   screen->pending = ((LPSTR) (LocalAlloc (NONZEROLPTR, screen->n_pending)));
2571   if (screen->pending != ((LPSTR) NULL))
2572     strncpy (screen->pending, (lpBlock + i), screen->n_pending);
2573   else
2574   {
2575     screen->n_pending = 0;
2576     MessageBeep (0);
2577   }
2578 }
2579 
2580 static VOID
WriteScreenBlock_continue(SCREEN screen,LPSTR lpBlock_in,int nLength_in,LPSTR * lpBlock,int * nLength)2581 WriteScreenBlock_continue (SCREEN screen,
2582 			   LPSTR lpBlock_in, int nLength_in,
2583 			   LPSTR * lpBlock, int * nLength)
2584 {
2585   (* nLength) = (screen->n_pending + nLength_in);
2586   (* lpBlock) = ((LPSTR) (LocalAlloc (NONZEROLPTR, (* nLength))));
2587   if ((* lpBlock) == ((LPSTR) NULL))
2588   {
2589     MessageBeep (0);
2590     (* nLength) = nLength_in;
2591     (* lpBlock) = lpBlock_in;
2592   }
2593   else
2594   {
2595     strncpy ((* lpBlock), screen->pending, screen->n_pending);
2596     strncpy (((* lpBlock) + screen->n_pending), lpBlock_in, nLength_in);
2597   }
2598   LocalFree (screen->pending);
2599   screen->n_pending = 0;
2600 }
2601 
2602 /* BOOL WriteScreenBlock (HWND hWnd, LPSTR lpBlock_in, int nLength_in )
2603 
2604    Description:
2605       Writes block of characters to TTY screen.  Interprets lots of ANSI
2606       sequences.
2607 */
2608 
2609 BOOL
WriteScreenBlock(HWND hWnd,LPSTR lpBlock_in,int nLength_in)2610 WriteScreenBlock (HWND hWnd, LPSTR lpBlock_in, int nLength_in)
2611 {
2612   int i;
2613   LPSTR lpBlock;
2614   int nLength;
2615   WORD saved_mode_flags;
2616   SCREEN screen = (GETSCREEN (hWnd));
2617   struct screen_write_char_s state;
2618 
2619   if (NULL == screen)
2620     return (FALSE);
2621 
2622   INIT_SCREEN_WRITE_CHAR_STATE (state);
2623   saved_mode_flags = (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE);
2624   screen->mode_flags &= (~ (SCREEN_MODE_EAGER_UPDATE));
2625 
2626   if (screen->n_pending != 0)
2627     WriteScreenBlock_continue (screen,
2628 			       lpBlock_in, nLength_in,
2629 			       &lpBlock, &nLength);
2630   else
2631   {
2632     nLength = nLength_in;
2633     lpBlock = lpBlock_in;
2634   }
2635 
2636   if ((screen->mode_flags & SCREEN_MODE_PROCESS_OUTPUT) == 0)
2637     for (i = 0; i < nLength; i++)
2638       Screen_WriteCharUninterpreted (screen, (lpBlock[i]), &state);
2639   else for (i = 0; i < nLength; i++)
2640   {
2641     unsigned char the_char = ((unsigned char) (lpBlock[i]));
2642 
2643     switch (the_char)
2644     {
2645     case ASCII_BEL:
2646       MessageBeep (0);
2647       break;
2648 
2649     case ASCII_BS:
2650       Screen_BS (screen);
2651       break;
2652 
2653     case '\t':
2654       Screen_TAB (screen, &state);
2655       break;
2656 
2657     case ASCII_LF:
2658       if (screen->mode_flags & SCREEN_MODE_NEWLINE_CRS)
2659 	Screen_CR (screen);
2660       Finish_ScreenWriteChar (screen, &state);
2661       Screen_LF (screen);
2662       break;
2663 
2664     case ASCII_CR:
2665       Screen_CR (screen);
2666       if (screen->mode_flags & SCREEN_MODE_CR_NEWLINES)
2667       {
2668 	Finish_ScreenWriteChar (screen, &state);
2669 	Screen_LF (screen);
2670       }
2671       break;
2672 
2673     case ASCII_FF:
2674       Finish_ScreenWriteChar (screen, &state);
2675       Screen_Clear (screen, 0);
2676       break;
2677 
2678     default:
2679     char_default:
2680 #ifdef PRETTY_PRINT_CHARS
2681       if (the_char < ' ')
2682       {
2683 	Screen_WriteCharUninterpreted (screen, '^', &state);
2684 	Screen_WriteCharUninterpreted (screen, (the_char + '@'), &state);
2685       }
2686       else if (the_char < ASCII_DEL)
2687 	Screen_WriteCharUninterpreted (screen, the_char, &state);
2688       else if (the_char == ASCII_DEL)
2689       {
2690 	Screen_WriteCharUninterpreted (screen, '^', &state);
2691 	Screen_WriteCharUninterpreted (screen, '?', &state);
2692       }
2693       else
2694 	screen_write_octal (screen, ((unsigned char) the_char), &state);
2695 #else /* not PRETTY_PRINT_CHARS */
2696       Screen_WriteCharUninterpreted (screen, the_char, &state);
2697 #endif /* PRETTY_PRINT_CHARS */
2698       break;
2699 
2700     case ASCII_ESC:
2701     {
2702       char dispatch;
2703 
2704       Finish_ScreenWriteChar (screen, &state);
2705       if ((i + 2) >= nLength)
2706       {
2707 	WriteScreenBlock_suspend (screen, lpBlock, i, nLength);
2708 	i = (nLength - 1);      /* 1 added in for loop */
2709 	break;
2710       }
2711 
2712       if (lpBlock[i + 1] != '[')
2713 	goto char_default;
2714 
2715       dispatch = (lpBlock[i + 2]);
2716       switch (dispatch)
2717       {
2718       case 'K':
2719 	/* Clear Line */
2720 	clear_screen_rectangle (screen,
2721 				screen->row, screen->column,
2722 				(screen->row + 1), screen->width);
2723 	i += 2;         /* 1 added in for loop */
2724 	continue;
2725 
2726       case 'J':
2727 	/* Clear to bottom */
2728 	if (screen->column == 0)
2729 	  clear_screen_rectangle (screen, screen->row, 0,
2730 				  screen->height, screen->width);
2731 	else
2732 	{
2733 	  clear_screen_rectangle (screen,
2734 				  screen->row, screen->column,
2735 				  (screen->row + 1), screen->width);
2736 	  clear_screen_rectangle (screen, (screen->row + 1), 0,
2737 				  screen->height, screen->width);
2738 	}
2739 	i += 2;         /* 1 added in for loop */
2740 	continue;
2741 
2742       case 'H':
2743 	/* Cursor home */
2744 	relocate_cursor (screen, 0, 0);
2745 	i += 2;         /* 1 added in for loop */
2746 	continue;
2747 
2748       case 'A':
2749 	/* Cursor up */
2750 	relocate_cursor (screen, (screen->row - 1), screen->column);
2751 	i += 2;         /* 1 added in for loop */
2752 	continue;
2753 
2754       case 'C':
2755 	/* Cursor right */
2756 	cursor_right (screen, 1);
2757 	i += 2;         /* 1 added in for loop */
2758 	continue;
2759 
2760       case 'L':
2761 	/* Insert line */
2762 	scroll_screen_vertically (screen,
2763 				  screen->row, screen->column,
2764 				  (screen->height - 1), screen->width,
2765 				  (screen->row + 1));
2766 	clear_screen_rectangle (screen,
2767 				screen->row, screen->column,
2768 				(screen->row + 1), screen->width);
2769 	i += 2;         /* 1 added in for loop */
2770 	continue;
2771 
2772       case 'M':
2773 	/* Delete line */
2774 	scroll_screen_vertically (screen,
2775 				  (screen->row + 1), screen->column,
2776 				  screen->height, screen->width,
2777 				  screen->row);
2778 	clear_screen_rectangle (screen,
2779 				(screen->height - 1), screen->column,
2780 				screen->height, screen->width);
2781 	i += 2;         /* 1 added in for loop */
2782 	continue;
2783 
2784       case 'P':
2785 	/* Delete char */
2786 	scroll_screen_line_horizontally (screen, screen->row,
2787 					 (screen->column + 1), screen->width,
2788 					 screen->column);
2789 	i += 2;
2790 	continue;
2791 
2792       case '@':
2793 	/* Insert char */
2794 	scroll_screen_line_horizontally (screen, screen->row,
2795 					 screen->column, (screen->width - 1),
2796 					 (screen->column + 1));
2797 	i += 2;
2798 	continue;
2799 
2800       default:
2801 	if ((dispatch >= '0') && (dispatch <= '9'))
2802 	{
2803 	  int j, x_value;
2804 
2805 	  x_value = (read_decimal (&lpBlock[0], (i + 2), nLength, &j));
2806 	  if (j >= nLength)
2807 	  {
2808 	    WriteScreenBlock_suspend (screen, lpBlock, i, nLength);
2809 	    i = (j - 1); /* 1 added in for loop */
2810 	    continue;
2811 	  }
2812 	  else switch (lpBlock[j])
2813 	  {
2814 	    case ';':
2815 	    {
2816 	      int k, y_value;
2817 
2818 	      y_value = (read_decimal (&lpBlock[0], (j + 1), nLength, &k));
2819 	      if ((k < nLength) && (lpBlock[k] == 'H'))
2820 		/* Direct cursor motion */
2821 		relocate_cursor (screen, (x_value - 1), (y_value - 1));
2822 	      else if (k < nLength)
2823 		MessageBeep (0);
2824 	      else
2825 		WriteScreenBlock_suspend (screen, lpBlock, i, nLength);
2826 	      i = k;    /* 1 added in for loop */
2827 	      continue;
2828 	    }
2829 
2830 	    case 'A':
2831 	      /* Multi cursor up */
2832 	      relocate_cursor (screen, (screen->row - x_value),
2833 			       screen->column);
2834 	      i = j; /* 1 added in for loop */
2835 	      continue;
2836 
2837 	    case 'C':
2838 	      /* Multi cursor right */
2839 	      cursor_right (screen, x_value);
2840 	      i = j; /* 1 added in for loop */
2841 	      continue;
2842 
2843 	    case 'L':
2844 	      /* Multi insert line */
2845 	      scroll_screen_vertically (screen,
2846 					screen->row, screen->column,
2847 					(screen->height - 1), screen->width,
2848 					(screen->row + x_value));
2849 	      clear_screen_rectangle (screen,
2850 				      screen->row, screen->column,
2851 				      (screen->row + x_value), screen->width);
2852 	      i = j; /* 1 added in for loop */
2853 	      continue;
2854 
2855 	    case 'M':
2856 	      /* Multi delete line */
2857 	      scroll_screen_vertically (screen,
2858 					(screen->row + x_value),
2859 					screen->column,
2860 					screen->height, screen->width,
2861 					screen->row);
2862 	      clear_screen_rectangle (screen,
2863 				      (screen->height - x_value),
2864 				      screen->column,
2865 				      screen->height, screen->width);
2866 	      i = j; /* 1 added in for loop */
2867 	      continue;
2868 
2869 	    case 'P':
2870 	      /* Multi delete char */
2871 	      scroll_screen_line_horizontally (screen, screen->row,
2872 					       (screen->column + x_value),
2873 					       screen->width,
2874 					       screen->column);
2875 	      i = j; /* 1 added in for loop */
2876 	      continue;
2877 
2878 	    case '@':
2879 	      /* Multi insert char */
2880 	      scroll_screen_line_horizontally (screen, screen->row,
2881 					       screen->column,
2882 					       (screen->width - x_value),
2883 					       (screen->column + x_value));
2884 	      i = j; /* 1 added in for loop */
2885 	      continue;
2886 
2887 	    case 'm':
2888 	      if ((j == (i + 3)) && ((x_value == 0) || (x_value == 7)))
2889 	      {
2890 		/* Enter stdout (7) or exit stdout (0) */
2891 		screen->write_attribute = (x_value == 7);
2892 		i = j;  /* 1 added in for loop */
2893 		continue;
2894 	      }
2895 	      goto use_default;
2896 
2897 	    case 'p':
2898 	      /* Not a real ANSI escape.  Modelled after aaa. */
2899 	      if ((j == (i + 3)) && (x_value < 2))
2900 	      {
2901 		/* Enter edwin/emacs (1) mode or exit edwin/emacs (0) mode. */
2902 		if (x_value == 1)
2903 		{
2904 		  screen->mode_flags |= SCREEN_MODE_EDWIN;
2905 		  screen->mode_flags &= (~ SCREEN_MODE_NEWLINE_CRS);
2906 		  screen->scroll_lines = 1;
2907 		  SetWindowText (screen->hWnd, "Edwin");
2908 		}
2909 		else
2910 		{
2911 		  screen->mode_flags &= (~ SCREEN_MODE_EDWIN);
2912 		  screen->mode_flags |= SCREEN_MODE_NEWLINE_CRS;
2913 		  screen->scroll_lines
2914 		    = (COMPUTE_SCROLL_LINES (screen->height));
2915 		  SetWindowText (screen->hWnd, "MIT/GNU Scheme");
2916 		}
2917 		i = j;  /* 1 added in for loop */
2918 		continue;
2919 	      }
2920 	      goto use_default;
2921 
2922 	    default:
2923 	    use_default:
2924 	      MessageBeep (0);
2925 	      i = j;    /* 1 added in for loop */
2926 	      continue;
2927 	  }
2928 	}
2929 	break;
2930       }
2931     }
2932     }
2933   }
2934 
2935   if (lpBlock != lpBlock_in)
2936     LocalFree (lpBlock);
2937 
2938   Finish_ScreenWriteChar (screen, &state);
2939   if (saved_mode_flags != 0)
2940   {
2941     UpdateWindow (screen->hWnd);
2942     MoveScreenCursor (screen);
2943     screen->mode_flags |= saved_mode_flags;
2944   }
2945   return  TRUE;
2946 }
2947 
2948 /* A fast raw write to the screen memory. */
2949 /* Client is responsible for invalidating the correct region */
2950 
2951 VOID
WriteScreenBlock_NoInvalidRect(SCREEN screen,int row,int column,LPSTR lpBlock,int nLength)2952 WriteScreenBlock_NoInvalidRect (SCREEN screen, int row, int column,
2953 				LPSTR lpBlock, int nLength)
2954 {
2955   int i, limit, start;
2956 
2957   if (row < 0  ||  row >= MAXROWS)
2958     return;
2959 
2960   if (column < 0) {
2961     lpBlock += (- column);
2962     nLength += column;
2963     column = 0;
2964   }
2965 
2966   if (column + nLength >= MAXCOLS)
2967     limit = MAXCOLS - column;
2968   else
2969     limit = nLength;
2970 
2971   start = row * MAXCOLS + column;
2972   for (i = 0; i < limit; i++) {
2973     int place = start + i;
2974     screen->chars[place] = lpBlock[i];
2975     screen->attrs[place] = screen->write_attribute;
2976   }
2977 }
2978 
2979 /* Utilities for line-buffered input. */
2980 
2981 static VOID
key_buffer_insert_self(SCREEN screen,int ch)2982 key_buffer_insert_self (SCREEN screen, int ch)
2983 {
2984   if (screen->n_chars < MAX_LINEINPUT)
2985   {
2986     screen->line_buffer[screen->n_chars++] = ch;
2987     if (screen->mode_flags & SCREEN_MODE_ECHO)
2988     {
2989       if (ch == '\n')
2990 	Screen_CRLF (screen);
2991       else
2992       {
2993 	char c = ((char) ch);
2994 #if 0
2995 	Screen_WriteCharUninterpreted (screen, ch, NULL);
2996 #endif
2997 	WriteScreenBlock (screen->hWnd, &c, 1);
2998       }
2999     }
3000   }
3001 }
3002 
3003 static VOID
key_buffer_erase_character(SCREEN screen)3004 key_buffer_erase_character (SCREEN screen)
3005 {
3006   if (screen->n_chars > 0)
3007   {
3008     screen->n_chars -= 1;
3009     if (screen->mode_flags & SCREEN_MODE_ECHO)
3010     {
3011       Screen_BS (screen);
3012       Screen_WriteCharUninterpreted (screen, ' ', NULL);
3013       Screen_BS (screen);
3014     }
3015   }
3016 }
3017 
3018 static VOID
buffered_key_command(SCREEN screen,int ch)3019 buffered_key_command (SCREEN screen,  int ch)
3020 {
3021   switch (ch)
3022   {
3023     case '\n':
3024     case '\r':
3025       key_buffer_insert_self (screen, '\n');
3026       break;
3027 
3028     case '\b':
3029     case ASCII_DEL:
3030       key_buffer_erase_character (screen);
3031       break;
3032 
3033     default:
3034       key_buffer_insert_self (screen, ch);
3035       break;
3036   }
3037   if (screen->mode_flags & SCREEN_MODE_EAGER_UPDATE)
3038     UpdateWindow (screen->hWnd);
3039 }
3040 
3041 /* Line-buffered input. */
3042 
3043 static int
ReadScreen_line_input(SCREEN screen,LPSTR buffer,int buflen)3044 ReadScreen_line_input (SCREEN screen, LPSTR buffer, int buflen)
3045 {
3046   SCREEN_EVENT event;
3047   int result = (-1);			/* No EOL seen yet. */
3048 
3049   while (read_event (screen, SCREEN_EVENT_TYPE_KEY, 1, (&event)))
3050     {
3051       int ch = event.event.key.ch;
3052       if ((event.event.key.control_key_state & SCREEN_ANY_ALT_KEY_MASK) != 0)
3053 	ch |= 0200;
3054 
3055       if (ch != 0)
3056 	buffered_key_command (screen, ch);
3057 
3058       if ((ch == '\n') || (ch == '\r'))
3059 	{
3060 	  int i, count = (min (screen->n_chars, buflen));
3061 
3062 	  for (i = 0; i < count; i++)
3063 	    buffer[i] = screen->line_buffer[i];
3064 	  screen->n_chars -= count;
3065 	  if (screen->n_chars > 0)
3066 	    _fmemmove (&screen->line_buffer[0],
3067 		       &screen->line_buffer[count],
3068 		       screen->n_chars);
3069 	  result = (count);
3070 	  break;
3071 	}
3072     }
3073   return (result);
3074 }
3075 
3076 /* Untranslated/unbuffered input */
3077 
3078 static int
ReadScreen_raw(SCREEN screen,LPSTR buffer,int buflen)3079 ReadScreen_raw (SCREEN screen, LPSTR buffer, int buflen)
3080 {
3081   SCREEN_EVENT event;
3082   int position = 0;
3083 
3084   while ((position < buflen)
3085 	 && (read_event (screen, SCREEN_EVENT_TYPE_KEY, 1, (&event))))
3086     {
3087       int ch = event.event.key.ch;
3088       if ((event.event.key.control_key_state & SCREEN_ANY_ALT_KEY_MASK) != 0)
3089 	ch |= 0200;
3090 
3091       /* Store the character */
3092       buffer[position++] = ch;
3093       if (screen->mode_flags & SCREEN_MODE_ECHO)
3094 	{
3095 	  char c = ((char) ch);
3096 	  WriteScreenBlock (screen->hWnd, &c, 1);
3097 	}
3098     }
3099   return ((position == 0) ? -1 : position);
3100 }
3101 
3102 /* int  ReadScreen (SCREEN screen, LPSTR buffer, int buflen)
3103 
3104    Read characters into buffer.
3105    If in line mode, collect characters into the line buffer.
3106    Return the number of characters read.
3107    In raw mode, return -1 if there are no characters.
3108    If in line mode and not yet at end of line, return -1 (i.e. this
3109      is a non-blocking read
3110 */
3111 
3112 static int
ReadScreen(SCREEN screen,LPSTR buffer,int buflen)3113 ReadScreen (SCREEN screen, LPSTR buffer, int buflen)
3114 {
3115   if (screen->mode_flags & SCREEN_MODE_LINE_INPUT)
3116     return (ReadScreen_line_input (screen, buffer, buflen));
3117   else
3118     return (ReadScreen_raw (screen, buffer, buflen));
3119 }
3120 
3121 VOID
Screen_Clear(SCREEN screen,int kind)3122 Screen_Clear (SCREEN screen, int kind)
3123 {
3124   if (kind == 0)
3125   {
3126     /* clear whole screen */
3127       ClearScreen_internal(screen);
3128     InvalidateRect (screen->hWnd, NULL, TRUE);
3129     return;
3130   }
3131   if (kind == 1)
3132     /* clear to eol */
3133     return;
3134 }
3135 
3136 /* VOID GetMinMaxSizes (HWND hWnd, LPPOINT min_size, LPPOINT max_size)
3137 
3138    Description:
3139       determine the minimum and maxinum sizes for a screen window.
3140 */
3141 
3142 static VOID
GetMinMaxSizes(HWND hWnd,LPPOINT min_size,LPPOINT max_size)3143 GetMinMaxSizes (HWND hWnd, LPPOINT min_size, LPPOINT max_size)
3144 {
3145     SCREEN  screen = GETSCREEN (hWnd);
3146     int  extra_width, extra_height;
3147 
3148     if (screen==0) return;
3149     extra_width  = 2*GetSystemMetrics(SM_CXFRAME);
3150     extra_height = 2*GetSystemMetrics(SM_CYFRAME)
3151 		 + GetSystemMetrics(SM_CYCAPTION)
3152 		 + (GetMenu(hWnd) ? GetSystemMetrics(SM_CYMENU) : 0);
3153     /* The min size sould be configurable so Edwin can configure it */
3154     /* to prevent the window being shrunk so far that the displayed */
3155     /* buffers wont fit. */
3156     min_size->x = screen->xChar * 5  +  extra_width;
3157     min_size->y = screen->yChar * 3  +  extra_height;
3158     max_size->x = screen->xChar * MAXCOLS  +  extra_width;
3159     max_size->y = screen->yChar * MAXROWS  +  extra_height;
3160 }
3161 
3162 static BOOL
SelectScreenFont(SCREEN screen,HWND owner)3163 SelectScreenFont (SCREEN  screen,  HWND owner)
3164 {
3165    CHOOSEFONT  cfTTYFont;
3166 
3167    if (NULL == screen)  return  FALSE;
3168 
3169    cfTTYFont.lStructSize    = sizeof (CHOOSEFONT);
3170    cfTTYFont.hwndOwner      = owner;
3171    cfTTYFont.hDC            = NULL;
3172    cfTTYFont.rgbColors      = screen->rgbFGColour;
3173    cfTTYFont.lpLogFont      = &screen->lfFont;
3174    cfTTYFont.Flags          = (CF_FIXEDPITCHONLY
3175 			       | CF_SCREENFONTS
3176 			       | CF_EFFECTS
3177 			       | CF_INITTOLOGFONTSTRUCT
3178 			       );
3179    cfTTYFont.lCustData      = 0;
3180    cfTTYFont.lpfnHook       = NULL;
3181    cfTTYFont.lpTemplateName = NULL;
3182    cfTTYFont.hInstance      = (HINSTANCE) GetWindowLong(owner, GWL_HINSTANCE);
3183 
3184    if (ChooseFont (&cfTTYFont))
3185    {
3186      screen->rgbFGColour = cfTTYFont.rgbColors;
3187      ResetScreen (screen);
3188    }
3189    return  TRUE;
3190 }
3191 
3192 /* BOOL SelectScreenBackColor (SCREEN screen, HWND owner)
3193 
3194    Description:
3195       Selects the background color for the TTY screen.
3196       Uses the Common Dialog ChooseColor() API.
3197 */
3198 
3199 static BOOL
SelectScreenBackColor(SCREEN screen,HWND owner)3200 SelectScreenBackColor (SCREEN  screen,  HWND owner)
3201 {
3202    static DWORD custcolors[16] = {
3203       RGB(0x00,0x00,0x00)
3204      ,RGB(0x80,0x00,0x00)
3205      ,RGB(0x00,0x80,0x00)
3206      ,RGB(0x80,0x80,0x00)
3207      ,RGB(0x00,0x00,0x80)
3208      ,RGB(0x80,0x00,0x80)
3209      ,RGB(0x00,0x80,0x80)
3210      ,RGB(0xC0,0xC0,0xC0)
3211      ,RGB(0xC0,0xDC,0xC0)
3212      ,RGB(0xA6,0xCA,0xF0)
3213      ,RGB(0xFF,0xFB,0xF0)
3214      ,RGB(0xA0,0xA0,0xA4)
3215      ,RGB(0x80,0x80,0x80)
3216      /* ,RGB(0xFF,0x00,0x00) */
3217      ,RGB(0x00,0xFF,0x00)
3218      ,RGB(0xFF,0xFF,0x00)
3219      /* ,RGB(0x00,0x00,0xFF) */
3220      /* ,RGB(0xFF,0x00,0xFF) */
3221      /* ,RGB(0x00,0xFF,0xFF) */
3222      ,RGB(0xFF,0xFF,0xFF)
3223      };
3224 
3225    CHOOSECOLOR backcolor;
3226 
3227    if (NULL == screen)
3228      return  FALSE;
3229 
3230    backcolor.lStructSize    = sizeof (CHOOSECOLOR);
3231    backcolor.hwndOwner      = owner;
3232    backcolor.hInstance      = (HINSTANCE) GetWindowLong(owner, GWL_HINSTANCE);
3233 
3234    backcolor.rgbResult      = screen->rgbBGColour;
3235    backcolor.lpCustColors   = &custcolors[0];
3236    backcolor.Flags          = (CC_RGBINIT);
3237 
3238    backcolor.lCustData      = 0;
3239    backcolor.lpfnHook       = NULL;
3240    backcolor.lpTemplateName = NULL;
3241 
3242    if (ChooseColor (&backcolor))
3243    {
3244      HDC hdc = GetDC (owner);
3245 
3246      /* Use GetNearestColor to ensure consistency with the background */
3247      /* text color. */
3248      screen->rgbBGColour = GetNearestColor (hdc, (backcolor.rgbResult));
3249      if (screen->bkgnd_brush != NULL)
3250        DeleteObject (screen->bkgnd_brush);
3251      screen->bkgnd_brush = CreateSolidBrush (screen->rgbBGColour);
3252      InvalidateRect (owner, NULL, TRUE);
3253      ReleaseDC (owner, hdc);
3254    }
3255    return  TRUE;
3256 }
3257 
3258 /* Event Queue */
3259 
3260 static SCREEN_EVENT *
allocate_event(SCREEN screen,SCREEN_EVENT_TYPE type)3261 allocate_event (SCREEN screen, SCREEN_EVENT_TYPE type)
3262 {
3263   SCREEN_EVENT_LINK * new_event;
3264   if (((screen -> mode_flags) & type) == 0)
3265     return (0);
3266   if (free_events == 0)
3267     new_event = (xmalloc (sizeof (SCREEN_EVENT_LINK)));
3268   else
3269     {
3270       new_event = free_events;
3271       free_events = (free_events -> next);
3272       n_free_events -= 1;
3273     }
3274   (new_event -> next) = 0;
3275   if (event_queue_tail == 0)
3276     event_queue_head = new_event;
3277   else
3278     (event_queue_tail -> next) = new_event;
3279   event_queue_tail = new_event;
3280   ((new_event -> event) . handle) = (screen -> hWnd);
3281   ((new_event -> event) . type) = type;
3282   return (& (new_event -> event));
3283 }
3284 
3285 /* read_event (screen, type, delete_p, event)
3286    Reads the next matching event out of the queue.
3287    Returns non-zero iff a matching event is found.
3288    If screen is non-zero, only events for that screen are considered.
3289    If type is non-zero, only events of that type are considered.
3290    If delete_p is non-zero, the event is deleted from the queue.  */
3291 
3292 static int
read_event(SCREEN screen,SCREEN_EVENT_TYPE type,int delete_p,SCREEN_EVENT * event)3293 read_event (SCREEN screen, SCREEN_EVENT_TYPE type, int delete_p,
3294 	    SCREEN_EVENT * event)
3295 {
3296   SCREEN_EVENT_LINK * scan_queue = event_queue_head;
3297   SCREEN_EVENT_LINK * prev_queue = 0;
3298   while (scan_queue != 0)
3299     {
3300       if (((screen == 0)
3301 	   || (((scan_queue -> event) . handle) == (screen -> hWnd)))
3302 	  && ((type == 0) || (((scan_queue -> event) . type) == type)))
3303 	{
3304 	  if (event != 0)
3305 	    (*event) = (scan_queue -> event);
3306 	  if (delete_p)
3307 	    {
3308 	      if (prev_queue == 0)
3309 		{
3310 		  event_queue_head = (event_queue_head -> next);
3311 		  if (event_queue_head == 0)
3312 		    event_queue_tail = 0;
3313 		}
3314 	      else
3315 		{
3316 		  (prev_queue -> next) = (scan_queue -> next);
3317 		  if (event_queue_tail == scan_queue)
3318 		    event_queue_tail = prev_queue;
3319 		}
3320 	      ((scan_queue -> event) . handle) = INVALID_HANDLE_VALUE;
3321 	      if (n_free_events < MAX_FREE_EVENTS)
3322 		{
3323 		  (scan_queue -> next) = free_events;
3324 		  free_events = scan_queue;
3325 		  n_free_events += 1;
3326 		}
3327 	      else
3328 		free (scan_queue);
3329 	    }
3330 	  return (1);
3331 	}
3332       else
3333 	{
3334 	  prev_queue = scan_queue;
3335 	  scan_queue = (scan_queue -> next);
3336 	}
3337     }
3338   return (0);
3339 }
3340 
3341 int
Screen_read_event(SCREEN_EVENT * event)3342 Screen_read_event (SCREEN_EVENT * event)
3343 {
3344   int result = (read_event (0, 0, 1, event));
3345   if (win32_trace_level > 1)
3346     {
3347       fprintf (win32_trace_file, "Screen_read_event: result=%d\n", result);
3348       fflush (win32_trace_file);
3349     }
3350   return (result);
3351 }
3352 
3353 int
Screen_pending_events_p(void)3354 Screen_pending_events_p (void)
3355 {
3356   return (read_event (0, 0, 0, 0));
3357 }
3358 
3359 VOID
Screen_SetAttribute(HANDLE screen,SCREEN_ATTRIBUTE sa)3360 Screen_SetAttribute (HANDLE screen, SCREEN_ATTRIBUTE sa)
3361 {
3362   SendMessage (screen, SCREEN_SETATTRIBUTE, (WPARAM)sa, 0);
3363 }
3364 
3365 VOID _fastcall
Screen_SetAttributeDirect(SCREEN screen,SCREEN_ATTRIBUTE sa)3366 Screen_SetAttributeDirect (SCREEN screen, SCREEN_ATTRIBUTE sa)
3367 {
3368   screen->write_attribute = sa;
3369 }
3370 
3371 VOID
Screen_WriteChar(HANDLE screen,char ch)3372 Screen_WriteChar (HANDLE screen, char ch)
3373 {
3374   SendMessage (screen, SCREEN_WRITE, 1, (LPARAM)(LPSTR) &ch);
3375 }
3376 
3377 VOID
Screen_WriteText(HANDLE screen,char * string)3378 Screen_WriteText (HANDLE screen, char *string)
3379 {
3380   SendMessage (screen, SCREEN_WRITE, strlen(string), (LPARAM)(LPSTR)string);
3381 }
3382 
3383 VOID
Screen_SetCursorPosition(HANDLE screen,int line,int column)3384 Screen_SetCursorPosition (HANDLE screen, int line, int column)
3385 {
3386   SendMessage (screen, SCREEN_SETPOSITION, 0, MAKELPARAM(column,line));
3387 }
3388 
3389 VOID
Screen_SetMode(HANDLE screen,int mode)3390 Screen_SetMode (HANDLE screen, int mode)
3391 {
3392   SendMessage (screen, SCREEN_SETMODES, ((WPARAM) mode), 0);
3393 }
3394 
3395 int
Screen_GetMode(HANDLE screen)3396 Screen_GetMode (HANDLE screen)
3397 {
3398   return  SendMessage (screen, SCREEN_GETMODES, 0, 0);
3399 }
3400 
3401 #define SCREEN_MODE_COOKED (SCREEN_MODE_LINE_INPUT | SCREEN_MODE_ECHO)
3402 
3403 int
Screen_Read(HANDLE hWnd,BOOL buffered_p,char * buffer,int buflen)3404 Screen_Read (HANDLE hWnd, BOOL buffered_p, char * buffer, int buflen)
3405 {
3406   int result;
3407   WORD input_flags;
3408   SCREEN screen = (GETSCREEN (hWnd));
3409 
3410   if (screen != NULL)
3411   {
3412     input_flags = (screen->mode_flags & SCREEN_MODE_COOKED);
3413     screen->mode_flags &= (~ SCREEN_MODE_COOKED);
3414     if (buffered_p)
3415       screen->mode_flags |= SCREEN_MODE_COOKED;
3416   }
3417 
3418   result = (SendMessage (hWnd, SCREEN_READ,
3419 			 ((WPARAM) buflen), ((LPARAM) buffer)));
3420 
3421   if (screen != NULL)
3422   {
3423     screen->mode_flags &= (~ SCREEN_MODE_COOKED);
3424     screen->mode_flags |= input_flags;
3425   }
3426 
3427   return  result;
3428 }
3429 
3430 VOID
Screen_GetSize(HWND hWnd,int * rows,int * columns)3431 Screen_GetSize (HWND hWnd, int *rows, int *columns)
3432 {
3433   SCREEN  screen = GETSCREEN (hWnd);
3434   if (screen == 0)
3435     return;
3436   *rows    = screen->height;
3437   *columns = screen->width;
3438 }
3439 
3440 VOID
Screen_CR_to_RECT(RECT * rect,SCREEN screen,int lo_row,int lo_col,int hi_row,int hi_col)3441 Screen_CR_to_RECT (RECT * rect, SCREEN screen,
3442 		   int lo_row, int lo_col,
3443 		   int hi_row, int hi_col)
3444 {
3445   rect->left   = ((lo_col * screen->xChar) - screen->xOffset);
3446   rect->right  = ((hi_col * screen->xChar) - screen->xOffset);
3447   rect->top    = ((lo_row * screen->yChar) - screen->yOffset);
3448   rect->bottom = ((hi_row * screen->yChar) - screen->yOffset);
3449 }
3450 
3451 VOID
Enable_Cursor(SCREEN screen,BOOL show)3452 Enable_Cursor (SCREEN screen, BOOL show)
3453 {
3454   ScreenCurrentFocus();
3455   if (show) {
3456     if (!screen->cursor_visible) {
3457       screen->cursor_visible = TRUE;
3458       if (screen && screen == screen_focus)
3459 	ShowCaret (screen->hWnd);
3460     }
3461   } else {
3462     if (screen->cursor_visible) {
3463       screen->cursor_visible = FALSE;
3464       if (screen && screen == screen_focus)
3465 	HideCaret (screen->hWnd);
3466     }
3467   }
3468 }
3469 
3470 HICON
ScreenSetIcon(SCREEN screen,HICON hIcon)3471 ScreenSetIcon(SCREEN screen, HICON hIcon)
3472 {
3473   HICON  result = screen->hIcon;
3474   screen->hIcon = hIcon;
3475   return  result;
3476 }
3477 
3478 BOOL
ScreenSetDefaultFont(char * description)3479 ScreenSetDefaultFont (char *description)
3480 {
3481   LOGFONT lf;
3482   HFONT hfont;
3483 
3484   /* modify default name & size, but undo characteristics */
3485   lf = lfDefaultLogFont;
3486   (lf . lfWeight) = FW_NORMAL;
3487   (lf . lfItalic) = FALSE;
3488   (lf . lfUnderline) = FALSE;
3489   (lf . lfStrikeOut) = FALSE;
3490   hfont = (set_font_1 (description, (&lf)));
3491   if (hfont == NULL)
3492     return (FALSE);
3493   else
3494     {
3495       DeleteObject (hfont);
3496       lfDefaultLogFont = lf;
3497       return (TRUE);
3498     }
3499 }
3500 
3501 BOOL
ScreenSetFont(SCREEN screen,char * description)3502 ScreenSetFont (SCREEN screen, char *description)
3503 {
3504   LOGFONT lf;
3505   HFONT hfont;
3506 
3507   init_LOGFONT (&lf);
3508   hfont = (set_font_1 (description, (&lf)));
3509   if (hfont == NULL)
3510     return (FALSE);
3511   else
3512     {
3513       (screen -> hFont) = hfont;
3514       (screen -> lfFont) = lf;
3515       ResetScreen (screen);
3516       return (TRUE);
3517     }
3518 }
3519 
3520 static HFONT
set_font_1(char * description,LOGFONT * lf)3521 set_font_1 (char * description, LOGFONT * lf)
3522 {
3523   HFONT hfont = NULL;
3524   if (parse_logfont (description, lf))
3525     {
3526       (void) search_for_font (lf);
3527       hfont = (CreateFontIndirect (lf));
3528     }
3529   return (hfont);
3530 }
3531 
3532 static BOOL
parse_logfont(char * name,LOGFONT * lf)3533 parse_logfont (char * name, LOGFONT * lf)
3534 {
3535   int i = 0;
3536   int name_ended = 0;
3537   int number_p;
3538   int len;
3539   char * start = name;
3540   char * end = name;
3541   char * scan;
3542 
3543   while (1)
3544     {
3545       while ((*start) == ' ')
3546 	start += 1;
3547       if ((*start) == '\0')
3548 	return (TRUE);
3549       end = start;
3550       while (((*end) != ' ') && ((*end) != '\0'))
3551 	end += 1;
3552       len = (end - start);
3553       scan = start;
3554       number_p = 0;
3555       if (scan < end)
3556 	while (1)
3557 	  {
3558 	    if (scan == end)
3559 	      {
3560 		number_p = 1;
3561 		break;
3562 	      }
3563 	    if (! (((*scan) >= '0') && ((*scan) <= '9')))
3564 	      {
3565 		number_p = 0;
3566 		break;
3567 	      }
3568 	    scan += 1;
3569 	  }
3570       if (number_p)
3571 	{
3572 	  long points = (atol (start));
3573 	  (lf -> lfHeight) = (- (points_to_logical_units (points)));
3574 	  name_ended = 1;
3575 	}
3576       else if ((len == 4) && ((_strnicmp (start, "bold", len)) == 0))
3577 	{
3578 	  (lf -> lfWeight) = FW_BOLD;
3579 	  name_ended = 1;
3580 	}
3581       else if ((len == 6) && ((_strnicmp (start, "italic", len)) == 0))
3582 	{
3583 	  (lf -> lfItalic) = TRUE;
3584 	  name_ended = 1;
3585 	}
3586       else if ((len == 7) && ((_strnicmp (start, "regular", len)) == 0))
3587 	{
3588 	  (lf -> lfWeight) = FW_NORMAL;
3589 	  (lf -> lfItalic) = FALSE;
3590 	  name_ended = 1;
3591 	}
3592       else if ((len == 9) && ((_strnicmp (start, "underline", len)) == 0))
3593 	{
3594 	  (lf -> lfUnderline) = TRUE;
3595 	  name_ended = 1;
3596 	}
3597       else if ((len == 9) && ((_strnicmp (start, "strikeout", len)) == 0))
3598 	{
3599 	  (lf -> lfStrikeOut) = TRUE;
3600 	  name_ended = 1;
3601 	}
3602       else if ((len < (LF_FACESIZE - i)) && (!name_ended))
3603 	{
3604 	  if (i > 0)
3605 	    ((lf -> lfFaceName) [i++]) = ' ';
3606 	  while (start < end)
3607 	    ((lf -> lfFaceName) [i++]) = (*start++);
3608 	  ((lf -> lfFaceName) [i]) = '\0';
3609 	}
3610       else
3611 	return (FALSE);
3612       start = end;
3613     }
3614 }
3615 
3616 static long
points_to_logical_units(long points)3617 points_to_logical_units (long points)
3618 {
3619   HDC hdc = (CreateDC ("DISPLAY", NULL, NULL, NULL));
3620   float pixels_per_inch_y = ((float) (GetDeviceCaps (hdc, LOGPIXELSY)));
3621   float pixels = ((((float) points) / 72.0) * pixels_per_inch_y);
3622   POINT pt;
3623   (pt . x) = 0;
3624   (pt . y) = ((int) (pixels * 10.0));
3625   DPtoLP (hdc, (&pt), 1);
3626   DeleteDC (hdc);
3627   return ((pt . y) / 10);
3628 }
3629 
3630 struct enum_font_args
3631 {
3632   LOGFONT * lf;
3633   ENUMLOGFONT elf;
3634   BOOL foundp;
3635 };
3636 
3637 static BOOL
search_for_font(LOGFONT * lf)3638 search_for_font (LOGFONT * lf)
3639 {
3640   HDC hdc = (CreateDC ("DISPLAY", NULL, NULL, NULL));
3641   struct enum_font_args args;
3642   (args . lf) = lf;
3643   (args . foundp) = FALSE;
3644   (void) EnumFontFamilies (hdc,
3645 			   (lf -> lfFaceName),
3646 			   ((void *) search_for_font_proc),
3647 			   ((LPARAM) (&args)));
3648   if (args . foundp)
3649     (*lf) = (args . elf . elfLogFont);
3650   DeleteDC (hdc);
3651   return (args . foundp);
3652 }
3653 
3654 static int CALLBACK
search_for_font_proc(ENUMLOGFONT * elf,NEWTEXTMETRIC * ntm,int type,LPARAM a)3655 search_for_font_proc (ENUMLOGFONT * elf, NEWTEXTMETRIC * ntm, int type,
3656 		      LPARAM a)
3657 {
3658   struct enum_font_args * args = ((struct enum_font_args *) a);
3659   if ((((elf -> elfLogFont) . lfHeight) == (- (args -> lf -> lfHeight)))
3660       && (((elf -> elfLogFont) . lfWeight) == (args -> lf -> lfWeight))
3661       && (((elf -> elfLogFont) . lfItalic) == (args -> lf -> lfItalic))
3662       && (((elf -> elfLogFont) . lfUnderline) == (args -> lf -> lfUnderline))
3663       && (((elf -> elfLogFont) . lfStrikeOut) == (args -> lf -> lfStrikeOut)))
3664     {
3665       (args -> elf) = (*elf);
3666       (args -> foundp) = TRUE;
3667       return (0);
3668     }
3669   else
3670     return (1);
3671 }
3672 
3673 static BOOL
change_colour(SCREEN screen,DWORD requested_colour,DWORD * colour_slot)3674 change_colour (SCREEN screen, DWORD requested_colour, DWORD *colour_slot)
3675 {
3676   HWND hWnd = screen->hWnd;
3677   HDC hdc = GetDC (hWnd);
3678   COLORREF actual_colour = GetNearestColor (hdc, requested_colour);
3679   if (actual_colour == CLR_INVALID) {
3680     ReleaseDC (hWnd, hdc);
3681     return  FALSE;
3682   }
3683   *colour_slot = actual_colour;
3684 
3685   /* Redraw screen with new colours */
3686   if (screen->bkgnd_brush != NULL)
3687     DeleteObject (screen->bkgnd_brush);
3688   screen->bkgnd_brush = CreateSolidBrush (screen->rgbBGColour);
3689   InvalidateRect (hWnd, NULL, TRUE);
3690   ReleaseDC (hWnd, hdc);
3691 
3692   return  TRUE;
3693 }
3694 
3695 BOOL
ScreenSetForegroundColour(SCREEN screen,DWORD colour)3696 ScreenSetForegroundColour (SCREEN screen, DWORD colour)
3697 {
3698   return  change_colour (screen, colour, &screen->rgbFGColour);
3699 }
3700 
3701 BOOL
ScreenSetBackgroundColour(SCREEN screen,DWORD colour)3702 ScreenSetBackgroundColour (SCREEN screen, DWORD colour)
3703 {
3704   return  change_colour (screen, colour, &screen->rgbBGColour);
3705 }
3706 
3707 static const char *
translate_message_code(UINT uMsg)3708 translate_message_code (UINT uMsg)
3709 {
3710   switch (uMsg)
3711     {
3712     case WM_NULL: return ("WM_NULL");
3713     case WM_CREATE: return ("WM_CREATE");
3714     case WM_DESTROY: return ("WM_DESTROY");
3715     case WM_MOVE: return ("WM_MOVE");
3716     case WM_SIZE: return ("WM_SIZE");
3717     case WM_ACTIVATE: return ("WM_ACTIVATE");
3718     case WM_SETFOCUS: return ("WM_SETFOCUS");
3719     case WM_KILLFOCUS: return ("WM_KILLFOCUS");
3720     case WM_ENABLE: return ("WM_ENABLE");
3721     case WM_SETREDRAW: return ("WM_SETREDRAW");
3722     case WM_SETTEXT: return ("WM_SETTEXT");
3723     case WM_GETTEXT: return ("WM_GETTEXT");
3724     case WM_GETTEXTLENGTH: return ("WM_GETTEXTLENGTH");
3725     case WM_PAINT: return ("WM_PAINT");
3726     case WM_CLOSE: return ("WM_CLOSE");
3727     case WM_QUERYENDSESSION: return ("WM_QUERYENDSESSION");
3728     case WM_QUIT: return ("WM_QUIT");
3729     case WM_QUERYOPEN: return ("WM_QUERYOPEN");
3730     case WM_ERASEBKGND: return ("WM_ERASEBKGND");
3731     case WM_SYSCOLORCHANGE: return ("WM_SYSCOLORCHANGE");
3732     case WM_ENDSESSION: return ("WM_ENDSESSION");
3733     case WM_SHOWWINDOW: return ("WM_SHOWWINDOW");
3734     case WM_WININICHANGE: return ("WM_WININICHANGE");
3735     case WM_DEVMODECHANGE: return ("WM_DEVMODECHANGE");
3736     case WM_ACTIVATEAPP: return ("WM_ACTIVATEAPP");
3737     case WM_FONTCHANGE: return ("WM_FONTCHANGE");
3738     case WM_TIMECHANGE: return ("WM_TIMECHANGE");
3739     case WM_CANCELMODE: return ("WM_CANCELMODE");
3740     case WM_SETCURSOR: return ("WM_SETCURSOR");
3741     case WM_MOUSEACTIVATE: return ("WM_MOUSEACTIVATE");
3742     case WM_CHILDACTIVATE: return ("WM_CHILDACTIVATE");
3743     case WM_QUEUESYNC: return ("WM_QUEUESYNC");
3744     case WM_GETMINMAXINFO: return ("WM_GETMINMAXINFO");
3745     case WM_PAINTICON: return ("WM_PAINTICON");
3746     case WM_ICONERASEBKGND: return ("WM_ICONERASEBKGND");
3747     case WM_NEXTDLGCTL: return ("WM_NEXTDLGCTL");
3748     case WM_SPOOLERSTATUS: return ("WM_SPOOLERSTATUS");
3749     case WM_DRAWITEM: return ("WM_DRAWITEM");
3750     case WM_MEASUREITEM: return ("WM_MEASUREITEM");
3751     case WM_DELETEITEM: return ("WM_DELETEITEM");
3752     case WM_VKEYTOITEM: return ("WM_VKEYTOITEM");
3753     case WM_CHARTOITEM: return ("WM_CHARTOITEM");
3754     case WM_SETFONT: return ("WM_SETFONT");
3755     case WM_GETFONT: return ("WM_GETFONT");
3756     case WM_SETHOTKEY: return ("WM_SETHOTKEY");
3757     case WM_GETHOTKEY: return ("WM_GETHOTKEY");
3758     case WM_QUERYDRAGICON: return ("WM_QUERYDRAGICON");
3759     case WM_COMPAREITEM: return ("WM_COMPAREITEM");
3760     case WM_COMPACTING: return ("WM_COMPACTING");
3761     case WM_COMMNOTIFY: return ("WM_COMMNOTIFY");
3762     case WM_WINDOWPOSCHANGING: return ("WM_WINDOWPOSCHANGING");
3763     case WM_WINDOWPOSCHANGED: return ("WM_WINDOWPOSCHANGED");
3764     case WM_POWER: return ("WM_POWER");
3765     case WM_COPYDATA: return ("WM_COPYDATA");
3766     case WM_CANCELJOURNAL: return ("WM_CANCELJOURNAL");
3767     case WM_NCCREATE: return ("WM_NCCREATE");
3768     case WM_NCDESTROY: return ("WM_NCDESTROY");
3769     case WM_NCCALCSIZE: return ("WM_NCCALCSIZE");
3770     case WM_NCHITTEST: return ("WM_NCHITTEST");
3771     case WM_NCPAINT: return ("WM_NCPAINT");
3772     case WM_NCACTIVATE: return ("WM_NCACTIVATE");
3773     case WM_GETDLGCODE: return ("WM_GETDLGCODE");
3774     case WM_NCMOUSEMOVE: return ("WM_NCMOUSEMOVE");
3775     case WM_NCLBUTTONDOWN: return ("WM_NCLBUTTONDOWN");
3776     case WM_NCLBUTTONUP: return ("WM_NCLBUTTONUP");
3777     case WM_NCLBUTTONDBLCLK: return ("WM_NCLBUTTONDBLCLK");
3778     case WM_NCRBUTTONDOWN: return ("WM_NCRBUTTONDOWN");
3779     case WM_NCRBUTTONUP: return ("WM_NCRBUTTONUP");
3780     case WM_NCRBUTTONDBLCLK: return ("WM_NCRBUTTONDBLCLK");
3781     case WM_NCMBUTTONDOWN: return ("WM_NCMBUTTONDOWN");
3782     case WM_NCMBUTTONUP: return ("WM_NCMBUTTONUP");
3783     case WM_NCMBUTTONDBLCLK: return ("WM_NCMBUTTONDBLCLK");
3784     case WM_KEYDOWN: return ("WM_KEYDOWN");
3785     case WM_KEYUP: return ("WM_KEYUP");
3786     case WM_CHAR: return ("WM_CHAR");
3787     case WM_DEADCHAR: return ("WM_DEADCHAR");
3788     case WM_SYSKEYDOWN: return ("WM_SYSKEYDOWN");
3789     case WM_SYSKEYUP: return ("WM_SYSKEYUP");
3790     case WM_SYSCHAR: return ("WM_SYSCHAR");
3791     case WM_SYSDEADCHAR: return ("WM_SYSDEADCHAR");
3792     case WM_KEYLAST: return ("WM_KEYLAST");
3793     case WM_INITDIALOG: return ("WM_INITDIALOG");
3794     case WM_COMMAND: return ("WM_COMMAND");
3795     case WM_SYSCOMMAND: return ("WM_SYSCOMMAND");
3796     case WM_TIMER: return ("WM_TIMER");
3797     case WM_HSCROLL: return ("WM_HSCROLL");
3798     case WM_VSCROLL: return ("WM_VSCROLL");
3799     case WM_INITMENU: return ("WM_INITMENU");
3800     case WM_INITMENUPOPUP: return ("WM_INITMENUPOPUP");
3801     case WM_MENUSELECT: return ("WM_MENUSELECT");
3802     case WM_MENUCHAR: return ("WM_MENUCHAR");
3803     case WM_ENTERIDLE: return ("WM_ENTERIDLE");
3804     case WM_CTLCOLORMSGBOX: return ("WM_CTLCOLORMSGBOX");
3805     case WM_CTLCOLOREDIT: return ("WM_CTLCOLOREDIT");
3806     case WM_CTLCOLORLISTBOX: return ("WM_CTLCOLORLISTBOX");
3807     case WM_CTLCOLORBTN: return ("WM_CTLCOLORBTN");
3808     case WM_CTLCOLORDLG: return ("WM_CTLCOLORDLG");
3809     case WM_CTLCOLORSCROLLBAR: return ("WM_CTLCOLORSCROLLBAR");
3810     case WM_CTLCOLORSTATIC: return ("WM_CTLCOLORSTATIC");
3811     case WM_MOUSEMOVE: return ("WM_MOUSEMOVE");
3812     case WM_LBUTTONDOWN: return ("WM_LBUTTONDOWN");
3813     case WM_LBUTTONUP: return ("WM_LBUTTONUP");
3814     case WM_LBUTTONDBLCLK: return ("WM_LBUTTONDBLCLK");
3815     case WM_RBUTTONDOWN: return ("WM_RBUTTONDOWN");
3816     case WM_RBUTTONUP: return ("WM_RBUTTONUP");
3817     case WM_RBUTTONDBLCLK: return ("WM_RBUTTONDBLCLK");
3818     case WM_MBUTTONDOWN: return ("WM_MBUTTONDOWN");
3819     case WM_MBUTTONUP: return ("WM_MBUTTONUP");
3820     case WM_MBUTTONDBLCLK: return ("WM_MBUTTONDBLCLK");
3821     case WM_PARENTNOTIFY: return ("WM_PARENTNOTIFY");
3822     case WM_ENTERMENULOOP: return ("WM_ENTERMENULOOP");
3823     case WM_EXITMENULOOP: return ("WM_EXITMENULOOP");
3824     case WM_MDICREATE: return ("WM_MDICREATE");
3825     case WM_MDIDESTROY: return ("WM_MDIDESTROY");
3826     case WM_MDIACTIVATE: return ("WM_MDIACTIVATE");
3827     case WM_MDIRESTORE: return ("WM_MDIRESTORE");
3828     case WM_MDINEXT: return ("WM_MDINEXT");
3829     case WM_MDIMAXIMIZE: return ("WM_MDIMAXIMIZE");
3830     case WM_MDITILE: return ("WM_MDITILE");
3831     case WM_MDICASCADE: return ("WM_MDICASCADE");
3832     case WM_MDIICONARRANGE: return ("WM_MDIICONARRANGE");
3833     case WM_MDIGETACTIVE: return ("WM_MDIGETACTIVE");
3834     case WM_MDISETMENU: return ("WM_MDISETMENU");
3835     case WM_ENTERSIZEMOVE: return ("WM_ENTERSIZEMOVE");
3836     case WM_EXITSIZEMOVE: return ("WM_EXITSIZEMOVE");
3837     case WM_DROPFILES: return ("WM_DROPFILES");
3838     case WM_MDIREFRESHMENU: return ("WM_MDIREFRESHMENU");
3839     case WM_CUT: return ("WM_CUT");
3840     case WM_COPY: return ("WM_COPY");
3841     case WM_PASTE: return ("WM_PASTE");
3842     case WM_CLEAR: return ("WM_CLEAR");
3843     case WM_UNDO: return ("WM_UNDO");
3844     case WM_RENDERFORMAT: return ("WM_RENDERFORMAT");
3845     case WM_RENDERALLFORMATS: return ("WM_RENDERALLFORMATS");
3846     case WM_DESTROYCLIPBOARD: return ("WM_DESTROYCLIPBOARD");
3847     case WM_DRAWCLIPBOARD: return ("WM_DRAWCLIPBOARD");
3848     case WM_PAINTCLIPBOARD: return ("WM_PAINTCLIPBOARD");
3849     case WM_VSCROLLCLIPBOARD: return ("WM_VSCROLLCLIPBOARD");
3850     case WM_SIZECLIPBOARD: return ("WM_SIZECLIPBOARD");
3851     case WM_ASKCBFORMATNAME: return ("WM_ASKCBFORMATNAME");
3852     case WM_CHANGECBCHAIN: return ("WM_CHANGECBCHAIN");
3853     case WM_HSCROLLCLIPBOARD: return ("WM_HSCROLLCLIPBOARD");
3854     case WM_QUERYNEWPALETTE: return ("WM_QUERYNEWPALETTE");
3855     case WM_PALETTEISCHANGING: return ("WM_PALETTEISCHANGING");
3856     case WM_PALETTECHANGED: return ("WM_PALETTECHANGED");
3857     case WM_HOTKEY: return ("WM_HOTKEY");
3858     case WM_PENWINFIRST: return ("WM_PENWINFIRST");
3859     case WM_PENWINLAST: return ("WM_PENWINLAST");
3860 
3861 #if(WINVER >= 0x0400)
3862     case WM_NOTIFY: return ("WM_NOTIFY");
3863     case WM_INPUTLANGCHANGEREQUEST: return ("WM_INPUTLANGCHANGEREQUEST");
3864     case WM_INPUTLANGCHANGE: return ("WM_INPUTLANGCHANGE");
3865     case WM_TCARD: return ("WM_TCARD");
3866     case WM_HELP: return ("WM_HELP");
3867     case WM_USERCHANGED: return ("WM_USERCHANGED");
3868     case WM_NOTIFYFORMAT: return ("WM_NOTIFYFORMAT");
3869     case WM_CONTEXTMENU: return ("WM_CONTEXTMENU");
3870     case WM_STYLECHANGING: return ("WM_STYLECHANGING");
3871     case WM_STYLECHANGED: return ("WM_STYLECHANGED");
3872     case WM_DISPLAYCHANGE: return ("WM_DISPLAYCHANGE");
3873     case WM_GETICON: return ("WM_GETICON");
3874     case WM_SETICON: return ("WM_SETICON");
3875     case WM_IME_STARTCOMPOSITION: return ("WM_IME_STARTCOMPOSITION");
3876     case WM_IME_ENDCOMPOSITION: return ("WM_IME_ENDCOMPOSITION");
3877     case WM_IME_COMPOSITION: return ("WM_IME_COMPOSITION");
3878     case WM_NEXTMENU: return ("WM_NEXTMENU");
3879     case WM_SIZING: return ("WM_SIZING");
3880     case WM_CAPTURECHANGED: return ("WM_CAPTURECHANGED");
3881     case WM_MOVING: return ("WM_MOVING");
3882     case WM_POWERBROADCAST: return ("WM_POWERBROADCAST");
3883     case WM_DEVICECHANGE: return ("WM_DEVICECHANGE");
3884     case WM_IME_SETCONTEXT: return ("WM_IME_SETCONTEXT");
3885     case WM_IME_NOTIFY: return ("WM_IME_NOTIFY");
3886     case WM_IME_CONTROL: return ("WM_IME_CONTROL");
3887     case WM_IME_COMPOSITIONFULL: return ("WM_IME_COMPOSITIONFULL");
3888     case WM_IME_SELECT: return ("WM_IME_SELECT");
3889     case WM_IME_CHAR: return ("WM_IME_CHAR");
3890     case WM_IME_KEYDOWN: return ("WM_IME_KEYDOWN");
3891     case WM_IME_KEYUP: return ("WM_IME_KEYUP");
3892     case WM_PRINT: return ("WM_PRINT");
3893     case WM_PRINTCLIENT: return ("WM_PRINTCLIENT");
3894     case WM_HANDHELDFIRST: return ("WM_HANDHELDFIRST");
3895     case WM_HANDHELDLAST: return ("WM_HANDHELDLAST");
3896     case WM_AFXFIRST: return ("WM_AFXFIRST");
3897     case WM_AFXLAST: return ("WM_AFXLAST");
3898     case WM_APP: return ("WM_APP");
3899 #endif /* WINVER >= 0x0400 */
3900     case SCREEN_WRITE: return ("SCREEN_WRITE");
3901     case SCREEN_SETPOSITION: return ("SCREEN_SETPOSITION");
3902     case SCREEN_GETPOSITION: return ("SCREEN_GETPOSITION");
3903     case SCREEN_SETATTRIBUTE: return ("SCREEN_SETATTRIBUTE");
3904     case SCREEN_GETATTRIBUTE: return ("SCREEN_GETATTRIBUTE");
3905     case SCREEN_PEEKEVENT: return ("SCREEN_PEEKEVENT");
3906     case SCREEN_READEVENT: return ("SCREEN_READEVENT");
3907     case SCREEN_SETMODES: return ("SCREEN_SETMODES");
3908     case SCREEN_GETMODES: return ("SCREEN_GETMODES");
3909     case SCREEN_SETCOMMAND: return ("SCREEN_SETCOMMAND");
3910     case SCREEN_GETCOMMAND: return ("SCREEN_GETCOMMAND");
3911     case SCREEN_SETBINDING: return ("SCREEN_SETBINDING");
3912     case SCREEN_GETBINDING: return ("SCREEN_GETBINDING");
3913     case SCREEN_SETMENU: return ("SCREEN_SETMENU");
3914     case SCREEN_READ: return ("SCREEN_READ");
3915     case SCREEN_CLEAR: return ("SCREEN_CLEAR");
3916     case WM_CATATONIC: return ("WM_CATATONIC");
3917     case WM_SCHEME_INTERRUPT: return ("WM_SCHEME_INTERRUPT");
3918     default: return (0);
3919     }
3920 }
3921