1 /* Terminal hooks for Windows NT port of GNU Emacs.
2 Copyright (C) 1992 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any later
11 GNU Emacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 You should have received a copy of the GNU General Public License along
17 with GNU Emacs; see the file COPYING. If not, write to the Free Software
18 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20 Tim Fleehart (apollo@online.com) 1-17-92
21 Geoff Voelker (voelker@cs.washington.edu) 9-12-93
34 #include "termhooks.h"
39 extern Lisp_Object
Frecenter ();
42 extern int detect_input_pending ();
45 extern int read_input_pending ();
47 extern FRAME_PTR updating_frame
;
50 static void move_cursor (int row
, int col
);
51 static void clear_to_end (void);
52 static void clear_frame (void);
53 static void clear_end_of_line (int);
54 static void ins_del_lines (int vpos
, int n
);
55 static void change_line_highlight (int, int, int);
56 static void reassert_line_highlight (int, int);
57 static void insert_glyphs (GLYPH
*start
, int len
);
58 static void write_glyphs (GLYPH
*string
, int len
);
59 static void delete_glyphs (int n
);
60 void nt_ring_bell (void);
61 static void reset_terminal_modes (void);
62 static void set_terminal_modes (void);
63 static void set_terminal_window (int size
);
64 static void update_begin (FRAME_PTR f
);
65 static void update_end (FRAME_PTR f
);
66 static void reset_kbd (void);
67 static void unset_kbd (void);
68 static int hl_mode (int new_highlight
);
75 /* Init hook called in init_keyboard. */
76 void (*keyboard_init_hook
)(void) = reset_kbd
;
79 HANDLE prev_screen
, cur_screen
;
80 UCHAR char_attr
, char_attr_normal
, char_attr_reverse
;
81 HANDLE keyboard_handle
;
84 /* Setting this as the ctrl handler prevents emacs from being killed when
85 someone hits ^C in a 'suspended' session (child shell).
86 Also ignore Ctrl-Break signals. */
89 ctrl_c_handler (unsigned long type
)
91 return (type
== CTRL_C_EVENT
|| type
== CTRL_BREAK_EVENT
);
94 /* If we're updating a frame, use it as the current frame
95 Otherwise, use the selected frame. */
96 #define PICK_FRAME() (updating_frame ? updating_frame : selected_frame)
98 /* Move the cursor to (row, col). */
100 move_cursor (int row
, int col
)
102 cursor_coords
.X
= col
;
103 cursor_coords
.Y
= row
;
105 if (updating_frame
== (FRAME_PTR
) NULL
)
107 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
111 /* Clear from cursor to end of screen. */
115 FRAME_PTR f
= PICK_FRAME ();
117 clear_end_of_line (FRAME_WIDTH (f
) - 1);
118 ins_del_lines (cursor_coords
.Y
, FRAME_HEIGHT (f
) - cursor_coords
.Y
- 1);
121 /* Clear the frame. */
128 FRAME_PTR f
= PICK_FRAME ();
133 scroll
.Bottom
= FRAME_HEIGHT (f
) - 1;
135 scroll
.Right
= FRAME_WIDTH (f
) - 1;
137 dest
.Y
= FRAME_HEIGHT (f
);
140 fill
.Char
.AsciiChar
= 0x20;
141 fill
.Attributes
= char_attr
;
143 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
148 static GLYPH glyph_base
[256];
149 static BOOL ceol_initialized
= FALSE
;
151 /* Clear from Cursor to end (what's "standout marker"?). */
153 clear_end_of_line (int end
)
155 if (!ceol_initialized
)
158 for (i
= 0; i
< 256; i
++)
160 glyph_base
[i
] = SPACEGLYPH
; /* empty space */
162 ceol_initialized
= TRUE
;
164 write_glyphs (glyph_base
, end
- cursor_coords
.X
); /* fencepost ? */
167 /* Insert n lines at vpos. if n is negative delete -n lines. */
169 ins_del_lines (int vpos
, int n
)
171 int i
, nb
, save_highlight
;
175 FRAME_PTR f
= PICK_FRAME ();
179 scroll
.Top
= vpos
- n
;
180 scroll
.Bottom
= FRAME_HEIGHT (f
);
186 scroll
.Bottom
= FRAME_HEIGHT (f
) - n
;
190 scroll
.Right
= FRAME_WIDTH (f
);
194 save_highlight
= hl_mode (0);
196 fill
.Char
.AsciiChar
= 0x20;
197 fill
.Attributes
= char_attr
;
199 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
201 /* Here we have to deal with a win32 console flake: If the scroll
202 region looks like abc and we scroll c to a and fill with d we get
203 cbd... if we scroll block c one line at a time to a, we get cdd...
204 Emacs expects cdd consistently... So we have to deal with that
205 here... (this also occurs scrolling the same way in the other
210 if (scroll
.Bottom
< dest
.Y
)
212 for (i
= scroll
.Bottom
; i
< dest
.Y
; i
++)
215 clear_end_of_line (FRAME_WIDTH (f
));
221 nb
= dest
.Y
+ (scroll
.Bottom
- scroll
.Top
) + 1;
225 for (i
= nb
; i
< scroll
.Top
; i
++)
228 clear_end_of_line (FRAME_WIDTH (f
));
234 cursor_coords
.Y
= vpos
;
236 hl_mode (save_highlight
);
239 /* Changes attribute to use when drawing characters to control. */
241 hl_mode (int new_highlight
)
243 static int highlight
= 0;
246 old_highlight
= highlight
;
247 highlight
= (new_highlight
!= 0);
250 char_attr
= char_attr_reverse
;
254 char_attr
= char_attr_normal
;
256 return old_highlight
;
259 /* Call this when about to modify line at position VPOS and change whether it
262 change_line_highlight (int new_highlight
, int vpos
, int first_unused_hpos
)
264 hl_mode (new_highlight
);
265 move_cursor (vpos
, 0);
266 clear_end_of_line (first_unused_hpos
);
269 /* External interface to control of standout mode. Call this when about to
270 * modify line at position VPOS and not change whether it is highlighted. */
272 reassert_line_highlight (int highlight
, int vpos
)
275 vpos
; /* pedantic compiler silencer */
284 scroll_line (int dist
, int direction
)
286 /* The idea here is to implement a horizontal scroll in one line to
287 implement delete and half of insert. */
291 FRAME_PTR f
= PICK_FRAME ();
293 scroll
.Top
= cursor_coords
.Y
;
294 scroll
.Bottom
= cursor_coords
.Y
;
296 if (direction
== LEFT
)
298 scroll
.Left
= cursor_coords
.X
+ dist
;
299 scroll
.Right
= FRAME_WIDTH (f
) - 1;
303 scroll
.Left
= cursor_coords
.X
;
304 scroll
.Right
= FRAME_WIDTH (f
) - dist
- 1;
307 dest
.X
= cursor_coords
.X
;
308 dest
.Y
= cursor_coords
.Y
;
310 fill
.Char
.AsciiChar
= 0x20;
311 fill
.Attributes
= char_attr
;
313 ScrollConsoleScreenBuffer (cur_screen
, &scroll
, NULL
, dest
, &fill
);
317 /* If start is zero insert blanks instead of a string at start ?. */
319 insert_glyphs (register GLYPH
*start
, register int len
)
321 scroll_line (len
, RIGHT
);
323 /* Move len chars to the right starting at cursor_coords, fill with blanks */
326 /* Print the first len characters of start, cursor_coords.X adjusted
329 write_glyphs (start
, len
);
333 clear_end_of_line (cursor_coords
.X
+ len
);
338 write_glyphs (register GLYPH
*string
, register int len
)
340 register unsigned int glyph_len
= GLYPH_TABLE_LENGTH
;
341 Lisp_Object
*glyph_table
= GLYPH_TABLE_BASE
;
342 FRAME_PTR f
= PICK_FRAME ();
349 attrs
= alloca (len
* sizeof (*attrs
));
350 chars
= alloca (len
* sizeof (*chars
));
351 if (attrs
== NULL
|| chars
== NULL
)
353 printf ("alloca failed in write_glyphs\n");
357 /* We have to deal with the glyph indirection...go over the glyph
358 buffer and extract the characters. */
364 if (glyph
> glyph_len
)
366 *ptr
++ = glyph
& 0xFF;
369 GLYPH_FOLLOW_ALIASES (glyph_table
, glyph_len
, glyph
);
371 if (GLYPH_FACE (fixfix
, glyph
) != 0)
372 printf ("Glyph face is %d\n", GLYPH_FACE (fixfix
, glyph
));
373 #endif /* !HAVE_NTGUI */
374 if (GLYPH_SIMPLE_P (glyph_table
, glyph_len
, glyph
))
376 *ptr
++ = glyph
& 0xFF;
379 for (i
= 0; i
< GLYPH_LENGTH (glyph_table
, glyph
); i
++)
381 *ptr
++ = (GLYPH_STRING (glyph_table
, glyph
))[i
];
385 /* Number of characters we have in the buffer. */
388 /* Fill in the attributes for these characters. */
389 for (i
= 0; i
< len
; i
++)
390 attrs
[i
] = char_attr
;
392 /* Write the attributes. */
393 if (!WriteConsoleOutputAttribute (cur_screen
, attrs
, len
, cursor_coords
, &i
))
395 printf ("Failed writing console attributes: %d\n", GetLastError ());
399 /* Write the characters. */
400 if (!WriteConsoleOutputCharacter (cur_screen
, chars
, len
, cursor_coords
, &i
))
402 printf ("Failed writing console characters: %d\n", GetLastError ());
406 cursor_coords
.X
+= len
;
407 move_cursor (cursor_coords
.Y
, cursor_coords
.X
);
411 delete_glyphs (int n
)
413 /* delete chars means scroll chars from cursor_coords.X + n to
414 cursor_coords.X, anything beyond the edge of the screen should
417 scroll_line (n
, LEFT
);
420 static unsigned int sound_type
= 0xFFFFFFFF;
425 if (sound_type
== 0xFFFFFFFF)
428 MessageBeep (sound_type
);
431 DEFUN ("set-message-beep", Fset_message_beep
, Sset_message_beep
, 1, 1, 0,
432 "Set the sound generated when the bell is rung.\n\
433 SOUND is 'asterisk, 'exclamation, 'hand, 'question, or 'ok\n\
434 to use the corresponding system sound for the bell.\n\
435 SOUND is nil to use the normal beep.")
439 CHECK_SYMBOL (sound
, 0);
442 sound_type
= 0xFFFFFFFF;
443 else if (EQ (sound
, intern ("asterisk")))
444 sound_type
= MB_ICONASTERISK
;
445 else if (EQ (sound
, intern ("exclamation")))
446 sound_type
= MB_ICONEXCLAMATION
;
447 else if (EQ (sound
, intern ("hand")))
448 sound_type
= MB_ICONHAND
;
449 else if (EQ (sound
, intern ("question")))
450 sound_type
= MB_ICONQUESTION
;
451 else if (EQ (sound
, intern ("ok")))
454 sound_type
= 0xFFFFFFFF;
459 /* Put our console back up, for ending a suspended session. */
464 SetConsoleActiveScreenBuffer (cur_screen
);
468 reset_terminal_modes (void)
471 SetConsoleActiveScreenBuffer (prev_screen
);
475 set_terminal_modes (void)
477 CONSOLE_CURSOR_INFO cci
;
479 if (cur_screen
== NULL
)
482 cur_screen
= CreateConsoleScreenBuffer (GENERIC_READ
| GENERIC_WRITE
,
484 CONSOLE_TEXTMODE_BUFFER
,
487 if (cur_screen
== INVALID_HANDLE_VALUE
)
489 printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
490 printf ("LastError = 0x%lx\n", GetLastError ());
495 SetConsoleActiveScreenBuffer (cur_screen
);
497 /* make cursor big and visible (100 on Win95 makes it disappear) */
500 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
504 /* hmmm... perhaps these let us bracket screen changes so that we can flush
505 clumps rather than one-character-at-a-time...
507 we'll start with not moving the cursor while an update is in progress. */
509 update_begin (FRAME_PTR f
)
514 update_end (FRAME_PTR f
)
516 SetConsoleCursorPosition (cur_screen
, cursor_coords
);
520 set_terminal_window (int size
)
527 SetConsoleMode (keyboard_handle
, ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
528 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
);
534 keyboard_handle
= GetStdHandle (STD_INPUT_HANDLE
);
535 SetConsoleMode (keyboard_handle
, ENABLE_MOUSE_INPUT
| ENABLE_WINDOW_INPUT
);
538 typedef int (*term_hook
) ();
541 initialize_win_nt_display (void)
543 CONSOLE_SCREEN_BUFFER_INFO info
;
545 cursor_to_hook
= (term_hook
) move_cursor
;
546 raw_cursor_to_hook
= (term_hook
) move_cursor
;
547 clear_to_end_hook
= (term_hook
) clear_to_end
;
548 clear_frame_hook
= (term_hook
) clear_frame
;
549 clear_end_of_line_hook
= (term_hook
) clear_end_of_line
;
550 ins_del_lines_hook
= (term_hook
) ins_del_lines
;
551 change_line_highlight_hook
= (term_hook
) change_line_highlight
;
552 reassert_line_highlight_hook
= (term_hook
) reassert_line_highlight
;
553 insert_glyphs_hook
= (term_hook
) insert_glyphs
;
554 write_glyphs_hook
= (term_hook
) write_glyphs
;
555 delete_glyphs_hook
= (term_hook
) delete_glyphs
;
556 ring_bell_hook
= (term_hook
) nt_ring_bell
;
557 reset_terminal_modes_hook
= (term_hook
) reset_terminal_modes
;
558 set_terminal_modes_hook
= (term_hook
) set_terminal_modes
;
559 set_terminal_window_hook
= (term_hook
) set_terminal_window
;
560 update_begin_hook
= (term_hook
) update_begin
;
561 update_end_hook
= (term_hook
) update_end
;
563 read_socket_hook
= win32_read_socket
;
564 mouse_position_hook
= win32_mouse_position
;
566 prev_screen
= GetStdHandle (STD_OUTPUT_HANDLE
);
568 set_terminal_modes ();
570 GetConsoleScreenBufferInfo (cur_screen
, &info
);
573 char_attr
= info
.wAttributes
& 0xFF;
574 char_attr_normal
= char_attr
;
575 char_attr_reverse
= ((char_attr
& 0xf) << 4) + ((char_attr
& 0xf0) >> 4);
577 FRAME_HEIGHT (selected_frame
) = info
.dwSize
.Y
; /* lines per page */
578 FRAME_WIDTH (selected_frame
) = info
.dwSize
.X
; /* characters per line */
585 DEFUN ("set-screen-color", Fset_screen_color
, Sset_screen_color
, 2, 2, 0,
586 "Set screen colors.")
587 (foreground
, background
)
588 Lisp_Object foreground
;
589 Lisp_Object background
;
591 char_attr_normal
= XFASTINT (foreground
) + (XFASTINT (background
) << 4);
592 char_attr_reverse
= XFASTINT (background
) + (XFASTINT (foreground
) << 4);
598 DEFUN ("set-cursor-size", Fset_cursor_size
, Sset_cursor_size
, 1, 1, 0,
603 CONSOLE_CURSOR_INFO cci
;
604 cci
.dwSize
= XFASTINT (size
);
606 (void) SetConsoleCursorInfo (cur_screen
, &cci
);
613 pixel_to_glyph_coords (FRAME_PTR f
, int pix_x
, int pix_y
, int *x
, int *y
,
614 void *bounds
, int noclip
)
621 glyph_to_pixel_coords (FRAME_PTR f
, int x
, int y
, int *pix_x
, int *pix_y
)
626 #endif /* !HAVE_NTGUI */
631 defsubr (&Sset_screen_color
);
632 defsubr (&Sset_cursor_size
);
633 defsubr (&Sset_message_beep
);