1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995 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
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* Contributed by Morten Welinder */
21 /* New display, keyboard, and mouse control by Kim F. Storm */
23 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
31 #include <sys/param.h>
37 #include "termhooks.h"
38 #include "dispextern.h"
45 /* #include <process.h> */
46 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
67 /* ------------------------ Mouse control ---------------------------
69 * Coordinates are in screen positions and zero based.
70 * Mouse buttons are numbered from left to right and also zero based.
73 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
74 static int mouse_visible
;
76 static int mouse_last_x
;
77 static int mouse_last_y
;
79 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
80 static int mouse_button_count
;
87 if (have_mouse
> 0 && !mouse_visible
)
90 fprintf (termscript
, "<M_ON>");
92 int86 (0x33, ®s
, ®s
);
102 if (have_mouse
> 0 && mouse_visible
)
105 fprintf (termscript
, "<M_OFF>");
107 int86 (0x33, ®s
, ®s
);
119 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
121 mouse_last_x
= regs
.x
.cx
= x
* 8;
122 mouse_last_y
= regs
.x
.dx
= y
* 8;
123 int86 (0x33, ®s
, ®s
);
127 mouse_pressed (b
, xp
, yp
)
132 if (b
>= mouse_button_count
)
135 regs
.x
.bx
= mouse_button_translate
[b
];
136 int86 (0x33, ®s
, ®s
);
138 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
139 return (regs
.x
.bx
!= 0);
143 mouse_released (b
, xp
, yp
)
148 if (b
>= mouse_button_count
)
151 regs
.x
.bx
= mouse_button_translate
[b
];
152 int86 (0x33, ®s
, ®s
);
154 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
155 return (regs
.x
.bx
!= 0);
159 mouse_get_xy (int *x
, int *y
)
164 int86 (0x33, ®s
, ®s
);
170 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
173 Lisp_Object
*bar_window
, *x
, *y
;
174 enum scroll_bar_part
*part
;
181 int86 (0x33, ®s
, ®s
);
184 mouse_get_xy (&ix
, &iy
);
185 selected_frame
->mouse_moved
= 0;
186 *x
= make_number (ix
);
187 *y
= make_number (iy
);
188 *time
= event_timestamp ();
196 mouse_get_xy (&x
, &y
);
197 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
208 fprintf (termscript
, "<M_INIT>");
211 int86 (0x33, ®s
, ®s
);
215 regs
.x
.dx
= 8 * (ScreenCols () - 1);
216 int86 (0x33, ®s
, ®s
);
220 regs
.x
.dx
= 8 * (ScreenRows () - 1);
221 int86 (0x33, ®s
, ®s
);
227 /* ------------------------- Screen control ----------------------
231 static int internal_terminal
= 0;
233 #ifndef HAVE_X_WINDOWS
234 extern unsigned char ScreenAttrib
;
235 static int screen_face
;
236 static int highlight
;
238 static int screen_size_X
;
239 static int screen_size_Y
;
240 static int screen_size
;
242 static int current_pos_X
;
243 static int current_pos_Y
;
244 static int new_pos_X
;
245 static int new_pos_Y
;
247 static void *startup_screen_buffer
;
248 static int startup_screen_size_X
;
249 static int startup_screen_size_Y
;
250 static int startup_pos_X
;
251 static int startup_pos_Y
;
252 static unsigned char startup_screen_attrib
;
254 static int term_setup_done
;
256 /* Similar to the_only_frame. */
257 struct x_output the_only_x_display
;
259 /* This is never dereferenced. */
260 Display
*x_current_display
;
263 #define SCREEN_SET_CURSOR() \
264 if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \
265 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
268 dos_direct_output (y
, x
, buf
, len
)
274 int t
= (int) ScreenPrimary
+ 2 * (x
+ y
* screen_size_X
);
277 dosmemput (buf
++, 1, t
);
283 /* Flash the screen as a substitute for BEEPs. */
287 do_visible_bell (xorattr
)
288 unsigned char xorattr
;
293 movl _ScreenPrimary,%%eax
300 xorb %%al,%%gs:(%%ebx)
316 : "m" (xorattr
), "g" (screen_size
)
317 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
321 ScreenVisualBell (void)
323 /* This creates an xor-mask that will swap the default fore- and
324 background colors. */
325 do_visible_bell (((the_only_x_display
.foreground_pixel
326 ^ the_only_x_display
.background_pixel
)
331 #ifndef HAVE_X_WINDOWS
334 * If we write a character in the position where the mouse is,
335 * the mouse cursor may need to be refreshed.
346 mouse_get_xy (&x
, &y
);
347 if (y
!= new_pos_Y
|| x
< new_pos_X
)
363 union REGS inregs
, outregs
;
366 intdos (&inregs
, &outregs
);
371 IT_set_face (int face
)
374 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
376 if (face
== 1 || (face
== 0 && highlight
))
377 fp
= FRAME_MODE_LINE_FACE (foo
);
378 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
379 fp
= FRAME_DEFAULT_FACE (foo
);
381 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
383 fprintf (termscript
, "<FACE:%d:%d>", FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
385 ScreenAttrib
= (FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
);
389 IT_write_glyphs (GLYPH
*str
, int len
)
393 unsigned char *buf
, *bp
;
395 if (len
== 0) return;
397 buf
= bp
= alloca (len
* 2);
401 newface
= FAST_GLYPH_FACE (*str
);
402 if (newface
!= screen_face
)
403 IT_set_face (newface
);
404 ch
= FAST_GLYPH_CHAR (*str
);
405 *bp
++ = (unsigned char)ch
;
406 *bp
++ = ScreenAttrib
;
409 fputc (ch
, termscript
);
414 dosmemput (buf
, 2 * len
,
415 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
420 IT_clear_end_of_line (first_unused
)
427 fprintf (termscript
, "<CLR:EOL>");
428 i
= (j
= screen_size_X
- new_pos_X
) * 2;
429 spaces
= sp
= alloca (i
);
434 *sp
++ = ScreenAttrib
;
438 dosmemput (spaces
, i
,
439 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
443 IT_clear_screen (void)
446 fprintf (termscript
, "<CLR:SCR>");
450 new_pos_X
= new_pos_Y
= 0;
454 IT_clear_to_end (void)
457 fprintf (termscript
, "<CLR:EOS>");
459 while (new_pos_Y
< screen_size_Y
) {
461 IT_clear_end_of_line (0);
467 IT_cursor_to (int y
, int x
)
470 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
476 IT_reassert_line_highlight (new, vpos
)
480 IT_set_face (0); /* To possibly clear the highlighting. */
484 IT_change_line_highlight (new_highlight
, vpos
, first_unused_hpos
)
486 highlight
= new_highlight
;
487 IT_set_face (0); /* To possibly clear the highlighting. */
488 IT_cursor_to (vpos
, 0);
489 IT_clear_end_of_line (first_unused_hpos
);
496 IT_set_face (0); /* To possibly clear the highlighting. */
505 /* This was more or less copied from xterm.c */
507 IT_set_menu_bar_lines (window
, n
)
511 struct window
*w
= XWINDOW (window
);
513 XSETFASTINT (w
->last_modified
, 0);
514 XSETFASTINT (w
->top
, XFASTINT (w
->top
) + n
);
515 XSETFASTINT (w
->height
, XFASTINT (w
->height
) - n
);
517 /* Handle just the top child in a vertical split. */
518 if (!NILP (w
->vchild
))
519 IT_set_menu_bar_lines (w
->vchild
, n
);
521 /* Adjust all children in a horizontal split. */
522 for (window
= w
->hchild
; !NILP (window
); window
= w
->next
)
524 w
= XWINDOW (window
);
525 IT_set_menu_bar_lines (window
, n
);
530 * IT_set_terminal_modes is called when emacs is started,
531 * resumed, and whenever the screen is redrawn!
535 IT_set_terminal_modes (void)
542 fprintf (termscript
, "\n<SET_TERM>");
545 screen_size_X
= ScreenCols ();
546 screen_size_Y
= ScreenRows ();
547 screen_size
= screen_size_X
* screen_size_Y
;
549 new_pos_X
= new_pos_Y
= 0;
550 current_pos_X
= current_pos_Y
= -1;
556 startup_screen_size_X
= screen_size_X
;
557 startup_screen_size_Y
= screen_size_Y
;
558 startup_screen_attrib
= ScreenAttrib
;
560 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
561 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
564 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
565 screen_size_X
, screen_size_Y
);
569 * IT_reset_terminal_modes is called when emacs is
570 * suspended or killed.
574 IT_reset_terminal_modes (void)
576 int display_row_start
= (int) ScreenPrimary
;
577 int saved_row_len
= startup_screen_size_X
* 2;
578 int update_row_len
= ScreenCols () * 2;
579 int current_rows
= ScreenRows ();
580 int to_next_row
= update_row_len
;
581 unsigned char *saved_row
= startup_screen_buffer
;
582 int cursor_pos_X
= ScreenCols () - 1;
583 int cursor_pos_Y
= ScreenRows () - 1;
586 fprintf (termscript
, "\n<RESET_TERM>");
590 if (!term_setup_done
)
595 /* We have a situation here.
596 We cannot just do ScreenUpdate(startup_screen_buffer) because
597 the luser could have changed screen dimensions inside Emacs
598 and failed (or didn't want) to restore them before killing
599 Emacs. ScreenUpdate() uses the *current* screen dimensions and
600 thus will happily use memory outside what was allocated for
601 `startup_screen_buffer'.
602 Thus we only restore as much as the current screen dimensions
603 can hold, and clear the rest (if the saved screen is smaller than
604 the current) with the color attribute saved at startup. The cursor
605 is also restored within the visible dimensions. */
607 ScreenAttrib
= startup_screen_attrib
;
610 if (update_row_len
> saved_row_len
)
611 update_row_len
= saved_row_len
;
612 if (current_rows
> startup_screen_size_Y
)
613 current_rows
= startup_screen_size_Y
;
616 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
617 update_row_len
/ 2, current_rows
);
619 while (current_rows
--)
621 dosmemput (saved_row
, update_row_len
, display_row_start
);
622 saved_row
+= saved_row_len
;
623 display_row_start
+= to_next_row
;
625 if (startup_pos_X
< cursor_pos_X
)
626 cursor_pos_X
= startup_pos_X
;
627 if (startup_pos_Y
< cursor_pos_Y
)
628 cursor_pos_Y
= startup_pos_Y
;
630 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
631 xfree (startup_screen_buffer
);
637 IT_set_terminal_window (void)
642 IT_set_frame_parameters (frame
, alist
)
648 extern unsigned long load_color ();
649 FRAME_PTR f
= (FRAME_PTR
) &the_only_frame
;
652 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
654 Lisp_Object elt
, prop
, val
;
659 CHECK_SYMBOL (prop
, 1);
661 if (EQ (prop
, intern ("foreground-color")))
663 unsigned long new_color
= load_color (f
, val
);
666 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
670 else if (EQ (prop
, intern ("background-color")))
672 unsigned long new_color
= load_color (f
, val
);
675 FRAME_BACKGROUND_PIXEL (f
) = new_color
& ~8;
679 else if (EQ (prop
, intern ("menu-bar-lines")))
682 int old
= FRAME_MENU_BAR_LINES (the_only_frame
);
688 FRAME_MENU_BAR_LINES (f
) = new;
689 IT_set_menu_bar_lines (the_only_frame
.root_window
, new - old
);
695 recompute_basic_faces (f
);
696 Fredraw_frame (Fselected_frame ());
700 #endif /* !HAVE_X_WINDOWS */
703 /* Do we need the internal terminal? */
705 internal_terminal_init ()
707 char *term
= getenv ("TERM");
710 #ifdef HAVE_X_WINDOWS
711 if (!inhibit_window_system
)
716 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
718 if (getenv ("EMACSTEST"))
719 termscript
= fopen (getenv ("EMACSTEST"), "wt");
721 #ifndef HAVE_X_WINDOWS
722 if (!internal_terminal
|| inhibit_window_system
)
724 the_only_frame
.output_method
= output_termcap
;
728 Vwindow_system
= intern ("pc");
729 Vwindow_system_version
= make_number (1);
731 bzero (&the_only_x_display
, sizeof the_only_x_display
);
732 the_only_x_display
.background_pixel
= 7; /* White */
733 the_only_x_display
.foreground_pixel
= 0; /* Black */
734 colors
= getenv ("EMACSCOLORS");
735 if (colors
&& strlen (colors
) >= 2)
737 the_only_x_display
.foreground_pixel
= colors
[0] & 0x07;
738 the_only_x_display
.background_pixel
= colors
[1] & 0x07;
740 the_only_x_display
.line_height
= 1;
741 the_only_frame
.output_data
.x
= &the_only_x_display
;
742 the_only_frame
.output_method
= output_msdos_raw
;
743 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
745 init_frame_faces ((FRAME_PTR
) &the_only_frame
);
747 ring_bell_hook
= IT_ring_bell
;
748 write_glyphs_hook
= IT_write_glyphs
;
749 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
750 clear_to_end_hook
= IT_clear_to_end
;
751 clear_end_of_line_hook
= IT_clear_end_of_line
;
752 clear_frame_hook
= IT_clear_screen
;
753 change_line_highlight_hook
= IT_change_line_highlight
;
754 update_begin_hook
= IT_update_begin
;
755 update_end_hook
= IT_update_end
;
756 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
758 /* These hooks are called by term.c without being checked. */
759 set_terminal_modes_hook
= IT_set_terminal_modes
;
760 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
761 set_terminal_window_hook
= IT_set_terminal_window
;
765 dos_get_saved_screen (screen
, rows
, cols
)
770 #ifndef HAVE_X_WINDOWS
771 *screen
= startup_screen_buffer
;
772 *cols
= startup_screen_size_X
;
773 *rows
= startup_screen_size_Y
;
780 /* ----------------------- Keyboard control ----------------------
782 * Keymaps reflect the following keyboard layout:
784 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
785 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
786 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
787 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
791 static int extended_kbd
; /* 101 (102) keyboard present. */
793 struct dos_keyboard_map
801 static struct dos_keyboard_map us_keyboard
= {
803 /* 01234567890123456789012345678901234567890 12345678901234 */
804 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
805 /* 0123456789012345678901234567890123456789 012345678901234 */
806 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
807 0 /* no Alt-Gr key */
810 static struct dos_keyboard_map fr_keyboard
= {
812 /* 012 3456789012345678901234567890123456789012345678901234 */
813 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
814 /* 0123456789012345678901234567890123456789012345678901234 */
815 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
816 /* 01234567 89012345678901234567890123456789012345678901234 */
820 static struct dos_keyboard_map dk_keyboard
= {
822 /* 0123456789012345678901234567890123456789012345678901234 */
823 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
824 /* 01 23456789012345678901234567890123456789012345678901234 */
825 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
826 /* 0123456789012345678901234567890123456789012345678901234 */
830 static struct keyboard_layout_list
833 struct dos_keyboard_map
*keyboard_map
;
834 } keyboard_layout_list
[] =
841 static struct dos_keyboard_map
*keyboard
;
842 static int keyboard_map_all
;
845 dos_set_keyboard (code
, always
)
851 /* Initialize to US settings, for countries that don't have their own. */
852 keyboard
= keyboard_layout_list
[0].keyboard_map
;
853 keyboard_map_all
= always
;
854 dos_keyboard_layout
= 1;
856 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
857 if (code
== keyboard_layout_list
[i
].country_code
)
859 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
860 keyboard_map_all
= always
;
861 dos_keyboard_layout
= code
;
867 #define Ignore 0x0000
868 #define Normal 0x0000 /* normal key - alt changes scan-code */
869 #define FctKey 0x1000 /* func key if c == 0, else c */
870 #define Special 0x2000 /* func key even if c != 0 */
871 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
872 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
873 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
874 #define Grey 0x6000 /* Grey keypad key */
876 #define Alt 0x0100 /* alt scan-code */
877 #define Ctrl 0x0200 /* ctrl scan-code */
878 #define Shift 0x0400 /* shift scan-code */
882 unsigned char char_code
; /* normal code */
883 unsigned char meta_code
; /* M- code */
884 unsigned char keypad_code
; /* keypad code */
885 unsigned char editkey_code
; /* edit key */
886 } keypad_translate_map
[] = {
887 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
888 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
889 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
890 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
891 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
892 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
893 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
894 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
895 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
896 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
897 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
902 unsigned char char_code
; /* normal code */
903 unsigned char keypad_code
; /* keypad code */
904 } grey_key_translate_map
[] = {
905 '/', 0xaf, /* kp-decimal */
906 '*', 0xaa, /* kp-multiply */
907 '-', 0xad, /* kp-subtract */
908 '+', 0xab, /* kp-add */
909 '\r', 0x8d /* kp-enter */
912 static unsigned short
913 ibmpc_translate_map
[] =
915 /* --------------- 00 to 0f --------------- */
916 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
917 Alt
| ModFct
| 0x1b, /* Escape */
918 Normal
| 1, /* '1' */
919 Normal
| 2, /* '2' */
920 Normal
| 3, /* '3' */
921 Normal
| 4, /* '4' */
922 Normal
| 5, /* '5' */
923 Normal
| 6, /* '6' */
924 Normal
| 7, /* '7' */
925 Normal
| 8, /* '8' */
926 Normal
| 9, /* '9' */
927 Normal
| 10, /* '0' */
928 Normal
| 11, /* '-' */
929 Normal
| 12, /* '=' */
930 Special
| 0x08, /* Backspace */
931 ModFct
| 0x74, /* Tab/Backtab */
933 /* --------------- 10 to 1f --------------- */
946 ModFct
| 0x0d, /* Return */
951 /* --------------- 20 to 2f --------------- */
962 Ignore
, /* Left shift */
969 /* --------------- 30 to 3f --------------- */
976 Ignore
, /* Right shift */
977 Grey
| 1, /* Grey * */
979 Normal
| ' ', /* ' ' */
980 Ignore
, /* Caps Lock */
981 FctKey
| 0xbe, /* F1 */
982 FctKey
| 0xbf, /* F2 */
983 FctKey
| 0xc0, /* F3 */
984 FctKey
| 0xc1, /* F4 */
985 FctKey
| 0xc2, /* F5 */
987 /* --------------- 40 to 4f --------------- */
988 FctKey
| 0xc3, /* F6 */
989 FctKey
| 0xc4, /* F7 */
990 FctKey
| 0xc5, /* F8 */
991 FctKey
| 0xc6, /* F9 */
992 FctKey
| 0xc7, /* F10 */
993 Ignore
, /* Num Lock */
994 Ignore
, /* Scroll Lock */
995 KeyPad
| 7, /* Home */
997 KeyPad
| 9, /* Page Up */
998 Grey
| 2, /* Grey - */
999 KeyPad
| 4, /* Left */
1000 KeyPad
| 5, /* Keypad 5 */
1001 KeyPad
| 6, /* Right */
1002 Grey
| 3, /* Grey + */
1003 KeyPad
| 1, /* End */
1005 /* --------------- 50 to 5f --------------- */
1006 KeyPad
| 2, /* Down */
1007 KeyPad
| 3, /* Page Down */
1008 KeyPad
| 0, /* Insert */
1009 KeyPad
| 10, /* Delete */
1010 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1011 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1012 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1013 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1014 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1015 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1016 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1017 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1018 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1019 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1020 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1021 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1023 /* --------------- 60 to 6f --------------- */
1024 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1025 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1026 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1027 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1028 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1029 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1030 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1031 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1032 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1033 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1034 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1035 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1036 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1037 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1038 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1039 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1041 /* --------------- 70 to 7f --------------- */
1042 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1043 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1044 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1045 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1046 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1047 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1048 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1049 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1050 Alt
| Map
| 1, /* '1' */
1051 Alt
| Map
| 2, /* '2' */
1052 Alt
| Map
| 3, /* '3' */
1053 Alt
| Map
| 4, /* '4' */
1054 Alt
| Map
| 5, /* '5' */
1055 Alt
| Map
| 6, /* '6' */
1056 Alt
| Map
| 7, /* '7' */
1057 Alt
| Map
| 8, /* '8' */
1059 /* --------------- 80 to 8f --------------- */
1060 Alt
| Map
| 9, /* '9' */
1061 Alt
| Map
| 10, /* '0' */
1062 Alt
| Map
| 11, /* '-' */
1063 Alt
| Map
| 12, /* '=' */
1064 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1065 FctKey
| 0xc8, /* F11 */
1066 FctKey
| 0xc9, /* F12 */
1067 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1068 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1069 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1070 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1071 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1072 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1073 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1074 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1075 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1077 /* --------------- 90 to 9f --------------- */
1078 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1079 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1080 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1081 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1082 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1083 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1084 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1085 Alt
| FctKey
| 0x50, /* (Alt) Home */
1086 Alt
| FctKey
| 0x52, /* (Alt) Up */
1087 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1088 Ignore
, /* NO KEY */
1089 Alt
| FctKey
| 0x51, /* (Alt) Left */
1090 Ignore
, /* NO KEY */
1091 Alt
| FctKey
| 0x53, /* (Alt) Right */
1092 Ignore
, /* NO KEY */
1093 Alt
| FctKey
| 0x57, /* (Alt) End */
1095 /* --------------- a0 to af --------------- */
1096 Alt
| KeyPad
| 2, /* (Alt) Down */
1097 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1098 Alt
| KeyPad
| 0, /* (Alt) Insert */
1099 Alt
| KeyPad
| 10, /* (Alt) Delete */
1100 Alt
| Grey
| 0, /* (Alt) Grey / */
1101 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1102 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1105 /* These bit-positions corresponds to values returned by BIOS */
1106 #define SHIFT_P 0x0003 /* two bits! */
1107 #define CTRL_P 0x0004
1108 #define ALT_P 0x0008
1109 #define SCRLOCK_P 0x0010
1110 #define NUMLOCK_P 0x0020
1111 #define CAPSLOCK_P 0x0040
1112 #define ALT_GR_P 0x0800
1113 #define SUPER_P 0x4000 /* pseudo */
1114 #define HYPER_P 0x8000 /* pseudo */
1117 dos_get_modifiers (keymask
)
1124 /* Calculate modifier bits */
1125 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1126 int86 (0x16, ®s
, ®s
);
1130 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1131 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1135 mask
= regs
.h
.al
& (SHIFT_P
|
1136 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1138 /* Do not break international keyboard support. */
1139 /* When Keyb.Com is loaded, the right Alt key is */
1140 /* used for accessing characters like { and } */
1141 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1144 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1147 if (dos_hyper_key
== 1)
1150 modifiers
|= hyper_modifier
;
1152 else if (dos_super_key
== 1)
1155 modifiers
|= super_modifier
;
1159 if (regs
.h
.ah
& 1) /* Left CTRL pressed
1162 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1164 if (dos_hyper_key
== 2)
1167 modifiers
|= hyper_modifier
;
1169 else if (dos_super_key
== 2)
1172 modifiers
|= super_modifier
;
1180 modifiers
|= shift_modifier
;
1182 modifiers
|= ctrl_modifier
;
1184 modifiers
|= meta_modifier
;
1191 #define NUM_RECENT_DOSKEYS (100)
1192 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1193 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1194 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1196 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1197 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1198 Each input key receives two values in this vector: first the ASCII code,\n\
1199 and then the scan code.")
1202 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1205 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1206 return Fvector (total_doskeys
, keys
);
1209 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1210 bcopy (keys
+ recent_doskeys_index
,
1211 XVECTOR (val
)->contents
,
1212 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1214 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1215 recent_doskeys_index
* sizeof (Lisp_Object
));
1220 /* Get a char from keyboard. Function keys are put into the event queue. */
1224 struct input_event event
;
1227 #ifndef HAVE_X_WINDOWS
1228 SCREEN_SET_CURSOR ();
1229 if (!mouse_visible
) mouse_on ();
1232 /* The following condition is equivalent to `kbhit ()', except that
1233 it uses the bios to do its job. This pleases DESQview/X. */
1234 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1235 int86 (0x16, ®s
, ®s
),
1236 (regs
.x
.flags
& 0x40) == 0)
1239 register unsigned char c
;
1240 int sc
, code
, mask
, kp_mode
;
1243 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1244 int86 (0x16, ®s
, ®s
);
1249 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1251 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1252 recent_doskeys_index
= 0;
1253 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1255 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1256 recent_doskeys_index
= 0;
1258 modifiers
= dos_get_modifiers (&mask
);
1260 #ifndef HAVE_X_WINDOWS
1261 if (!NILP (Vdos_display_scancodes
))
1264 sprintf (buf
, "%02x:%02x*%04x",
1265 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1266 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1274 case 10: /* Ctrl Grey Enter */
1275 code
= Ctrl
| Grey
| 4;
1277 case 13: /* Grey Enter */
1280 case '/': /* Grey / */
1290 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1292 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1299 modifiers
|= meta_modifier
;
1301 modifiers
|= ctrl_modifier
;
1303 modifiers
|= shift_modifier
;
1306 switch (code
& 0xf000)
1309 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1311 c
= 0; /* Special */
1324 if (c
== 0) /* ctrl-break */
1326 return c
; /* ALT-nnn */
1328 if (!keyboard_map_all
)
1337 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1338 if (!keyboard_map_all
)
1342 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1343 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1347 code
= keyboard
->shifted
[code
];
1349 modifiers
&= ~shift_modifier
;
1352 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1353 code
= keyboard
->alt_gr
[code
];
1355 code
= keyboard
->unshifted
[code
];
1360 if (c
== 0xe0) /* edit key */
1363 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1364 kp_mode
= dos_keypad_mode
& 0x03;
1366 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1371 if (code
== 10 && dos_decimal_point
)
1372 return dos_decimal_point
;
1373 return keypad_translate_map
[code
].char_code
;
1376 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1380 code
= keypad_translate_map
[code
].meta_code
;
1381 modifiers
= meta_modifier
;
1385 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1392 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1393 if (dos_keypad_mode
& kp_mode
)
1394 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1396 code
= grey_key_translate_map
[code
].char_code
;
1405 event
.kind
= non_ascii_keystroke
;
1407 event
.kind
= ascii_keystroke
;
1409 event
.modifiers
= modifiers
;
1410 XSETFRAME (event
.frame_or_window
, selected_frame
);
1411 event
.timestamp
= event_timestamp ();
1412 kbd_buffer_store_event (&event
);
1417 int but
, press
, x
, y
, ok
;
1419 /* Check for mouse movement *before* buttons. */
1420 mouse_check_moved ();
1422 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1423 for (press
= 0; press
< 2; press
++)
1426 ok
= mouse_pressed (but
, &x
, &y
);
1428 ok
= mouse_released (but
, &x
, &y
);
1431 event
.kind
= mouse_click
;
1433 event
.modifiers
= dos_get_modifiers (0)
1434 | (press
? down_modifier
: up_modifier
);
1437 XSETFRAME (event
.frame_or_window
, selected_frame
);
1438 event
.timestamp
= event_timestamp ();
1439 kbd_buffer_store_event (&event
);
1447 static int prev_get_char
= -1;
1449 /* Return 1 if a key is ready to be read without suspending execution. */
1452 if (prev_get_char
!= -1)
1455 return ((prev_get_char
= dos_rawgetc ()) != -1);
1458 /* Read a key. Return -1 if no key is ready. */
1461 if (prev_get_char
!= -1)
1463 int c
= prev_get_char
;
1468 return dos_rawgetc ();
1471 #ifndef HAVE_X_WINDOWS
1472 /* See xterm.c for more info. */
1474 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1476 register int pix_x
, pix_y
;
1477 register int *x
, *y
;
1478 void /* XRectangle */ *bounds
;
1481 if (bounds
) abort ();
1483 /* Ignore clipping. */
1490 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1493 register int *pix_x
, *pix_y
;
1499 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1502 Actually, I don't know the meaning of all the parameters of the functions
1503 here -- I only know how they are called by xmenu.c. I could of course
1504 grab the nearest Xlib manual (down the hall, second-to-last door on the
1505 left), but I don't think it's worth the effort. */
1512 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1513 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1517 /* Allocate some (more) memory for MENU ensuring that there is room for one
1521 IT_menu_make_room (XMenu
*menu
)
1523 if (menu
->allocated
== 0)
1525 int count
= menu
->allocated
= 10;
1526 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1527 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1528 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1530 else if (menu
->allocated
== menu
->count
)
1532 int count
= menu
->allocated
= menu
->allocated
+ 10;
1534 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1536 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1538 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1542 /* Search the given menu structure for a given pane number. */
1545 IT_menu_search_pane (XMenu
*menu
, int pane
)
1550 for (i
= 0; i
< menu
->count
; i
++)
1551 if (menu
->submenu
[i
])
1553 if (pane
== menu
->panenumber
[i
])
1554 return menu
->submenu
[i
];
1555 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1561 /* Determine how much screen space a given menu needs. */
1564 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1566 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1569 maxheight
= menu
->count
;
1570 for (i
= 0; i
< menu
->count
; i
++)
1572 if (menu
->submenu
[i
])
1574 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1575 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1576 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1579 *width
= menu
->width
+ maxsubwidth
;
1580 *height
= maxheight
;
1583 /* Display MENU at (X,Y) using FACES. */
1586 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1588 int i
, j
, face
, width
;
1592 int enabled
, mousehere
;
1595 width
= menu
->width
;
1596 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1597 ScreenGetCursor (&row
, &col
);
1598 mouse_get_xy (&mx
, &my
);
1600 for (i
= 0; i
< menu
->count
; i
++)
1602 IT_cursor_to (y
+ i
, x
);
1604 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1605 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1606 face
= faces
[enabled
+ mousehere
* 2];
1608 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1609 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
1610 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
1611 for (; j
< width
; j
++)
1612 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1613 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
1614 IT_write_glyphs (text
, width
+ 2);
1617 IT_cursor_to (row
, col
);
1621 /* --------------------------- X Menu emulation ---------------------- */
1623 /* Report availability of menus. */
1631 /* Create a brand new menu structure. */
1634 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
1636 return IT_menu_create ();
1639 /* Create a new pane and place it on the outer-most level. It is not
1640 clear that it should be placed out there, but I don't know what else
1644 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
1651 IT_menu_make_room (menu
);
1652 menu
->submenu
[menu
->count
] = IT_menu_create ();
1653 menu
->text
[menu
->count
] = txt
;
1654 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
1656 if ((len
= strlen (txt
)) > menu
->width
)
1658 return menu
->panecount
;
1661 /* Create a new item in a menu pane. */
1664 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
1665 int foo
, char *txt
, int enable
)
1670 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
1672 IT_menu_make_room (menu
);
1673 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
1674 menu
->text
[menu
->count
] = txt
;
1675 menu
->panenumber
[menu
->count
] = enable
;
1677 if ((len
= strlen (txt
)) > menu
->width
)
1682 /* Decide where the menu would be placed if requested at (X,Y). */
1685 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
1686 int *ulx
, int *uly
, int *width
, int *height
)
1688 IT_menu_calc_size (menu
, width
, height
);
1694 struct IT_menu_state
1696 void *screen_behind
;
1703 /* Display menu, wait for user's response, and return that response. */
1706 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
1707 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
1709 struct IT_menu_state
*state
;
1713 int faces
[4], selectface
;
1714 int leave
, result
, onepane
;
1715 int title_faces
[4]; /* face to display the menu title */
1717 /* Just in case we got here without a mouse present... */
1718 if (have_mouse
<= 0)
1719 return XM_IA_SELECT
;
1721 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
1722 screensize
= screen_size
* 2;
1724 = compute_glyph_face (&the_only_frame
,
1727 intern ("msdos-menu-passive-face")),
1730 = compute_glyph_face (&the_only_frame
,
1733 intern ("msdos-menu-active-face")),
1736 = face_name_id_number (&the_only_frame
, intern ("msdos-menu-select-face"));
1737 faces
[2] = compute_glyph_face (&the_only_frame
, selectface
, faces
[0]);
1738 faces
[3] = compute_glyph_face (&the_only_frame
, selectface
, faces
[1]);
1740 /* Make sure the menu title is always displayed with
1741 `msdos-menu-active-face', no matter where the mouse pointer is. */
1742 for (i
= 0; i
< 4; i
++)
1743 title_faces
[i
] = faces
[3];
1746 state
[0].menu
= menu
;
1748 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
1750 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
1751 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
1753 menu
->width
= menu
->submenu
[0]->width
;
1754 state
[0].menu
= menu
->submenu
[0];
1758 state
[0].menu
= menu
;
1760 state
[0].x
= x0
- 1;
1762 state
[0].pane
= onepane
;
1764 mouse_last_x
= -1; /* A hack that forces display. */
1768 if (!mouse_visible
) mouse_on ();
1769 mouse_check_moved ();
1770 if (selected_frame
->mouse_moved
)
1772 selected_frame
->mouse_moved
= 0;
1773 result
= XM_IA_SELECT
;
1774 mouse_get_xy (&x
, &y
);
1775 for (i
= 0; i
< statecount
; i
++)
1776 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
1778 int dy
= y
- state
[i
].y
;
1779 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
1781 if (!state
[i
].menu
->submenu
[dy
])
1782 if (state
[i
].menu
->panenumber
[dy
])
1783 result
= XM_SUCCESS
;
1785 result
= XM_IA_SELECT
;
1786 *pane
= state
[i
].pane
- 1;
1788 /* We hit some part of a menu, so drop extra menus that
1789 have been opened. That does not include an open and
1791 if (i
!= statecount
- 2
1792 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
1793 while (i
!= statecount
- 1)
1797 ScreenUpdate (state
[statecount
].screen_behind
);
1798 xfree (state
[statecount
].screen_behind
);
1800 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
1802 IT_menu_display (state
[i
].menu
,
1806 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
1807 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
1809 ScreenRetrieve (state
[statecount
].screen_behind
1810 = xmalloc (screensize
));
1812 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
1813 state
[statecount
].y
= y
;
1818 IT_menu_display (state
[statecount
- 1].menu
,
1819 state
[statecount
- 1].y
,
1820 state
[statecount
- 1].x
,
1823 for (b
= 0; b
< mouse_button_count
; b
++)
1825 (void) mouse_pressed (b
, &x
, &y
);
1826 if (mouse_released (b
, &x
, &y
))
1832 ScreenUpdate (state
[0].screen_behind
);
1833 while (statecount
--)
1834 xfree (state
[statecount
].screen_behind
);
1838 /* Dispose of a menu. */
1841 XMenuDestroy (Display
*foo
, XMenu
*menu
)
1844 if (menu
->allocated
)
1846 for (i
= 0; i
< menu
->count
; i
++)
1847 if (menu
->submenu
[i
])
1848 XMenuDestroy (foo
, menu
->submenu
[i
]);
1850 xfree (menu
->submenu
);
1851 xfree (menu
->panenumber
);
1857 x_pixel_width (struct frame
*f
)
1859 return FRAME_WIDTH (f
);
1863 x_pixel_height (struct frame
*f
)
1865 return FRAME_HEIGHT (f
);
1867 #endif /* !HAVE_X_WINDOWS */
1869 /* ----------------------- DOS / UNIX conversion --------------------- */
1871 /* Destructively turn backslashes into slashes. */
1874 dostounix_filename (p
)
1885 /* Destructively turn slashes into backslashes. */
1888 unixtodos_filename (p
)
1899 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
1902 getdefdir (drive
, dst
)
1910 regs
.x
.si
= (int) dst
;
1912 intdos (®s
, ®s
);
1913 return !regs
.x
.cflag
;
1916 /* Remove all CR's that are followed by a LF. */
1921 register unsigned char *buf
;
1923 unsigned char *np
= buf
;
1924 unsigned char *startp
= buf
;
1925 unsigned char *endp
= buf
+ n
;
1930 while (buf
< endp
- 1)
1934 if (*(++buf
) != 0x0a)
1945 /* The Emacs root directory as determined by init_environment. */
1947 static char emacsroot
[MAXPATHLEN
];
1950 rootrelativepath (rel
)
1953 static char result
[MAXPATHLEN
+ 10];
1955 strcpy (result
, emacsroot
);
1956 strcat (result
, "/");
1957 strcat (result
, rel
);
1961 /* Define a lot of environment variables if not already defined. Don't
1962 remove anything unless you know what you're doing -- lots of code will
1963 break if one or more of these are missing. */
1966 init_environment (argc
, argv
, skip_args
)
1974 /* Find our root from argv[0]. Assuming argv[0] is, say,
1975 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
1976 root
= alloca (MAXPATHLEN
+ 20);
1977 _fixpath (argv
[0], root
);
1979 len
= strlen (root
);
1980 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
1983 if (len
> 4 && strcmp (root
+ len
- 4, "/bin") == 0)
1984 root
[len
- 4] = '\0';
1986 strcpy (root
, "c:/emacs"); /* Only under debuggers, I think. */
1987 len
= strlen (root
);
1988 strcpy (emacsroot
, root
);
1990 /* We default HOME to our root. */
1991 setenv ("HOME", root
, 0);
1993 /* We default EMACSPATH to root + "/bin". */
1994 strcpy (root
+ len
, "/bin");
1995 setenv ("EMACSPATH", root
, 0);
1997 /* I don't expect anybody to ever use other terminals so the internal
1998 terminal is the default. */
1999 setenv ("TERM", "internal", 0);
2001 #ifdef HAVE_X_WINDOWS
2002 /* Emacs expects DISPLAY to be set. */
2003 setenv ("DISPLAY", "unix:0.0", 0);
2006 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2007 downcase it and mirror the backslashes. */
2008 s
= getenv ("COMSPEC");
2009 if (!s
) s
= "c:/command.com";
2010 t
= alloca (strlen (s
) + 1);
2013 dostounix_filename (t
);
2014 setenv ("SHELL", t
, 0);
2016 /* PATH is also downcased and backslashes mirrored. */
2017 s
= getenv ("PATH");
2019 t
= alloca (strlen (s
) + 3);
2020 /* Current directory is always considered part of MsDos's path but it is
2021 not normally mentioned. Now it is. */
2022 strcat (strcpy (t
, ".;"), s
);
2024 dostounix_filename (t
); /* Not a single file name, but this should work. */
2025 setenv ("PATH", t
, 1);
2027 /* In some sense all dos users have root privileges, so... */
2028 setenv ("USER", "root", 0);
2029 setenv ("NAME", getenv ("USER"), 0);
2031 /* Time zone determined from country code. To make this possible, the
2032 country code may not span more than one time zone. In other words,
2033 in the USA, you lose. */
2035 switch (dos_country_code
)
2037 case 31: /* Belgium */
2038 case 32: /* The Netherlands */
2039 case 33: /* France */
2040 case 34: /* Spain */
2041 case 36: /* Hungary */
2042 case 38: /* Yugoslavia (or what's left of it?) */
2043 case 39: /* Italy */
2044 case 41: /* Switzerland */
2045 case 42: /* Tjekia */
2046 case 45: /* Denmark */
2047 case 46: /* Sweden */
2048 case 47: /* Norway */
2049 case 48: /* Poland */
2050 case 49: /* Germany */
2051 /* Daylight saving from last Sunday in March to last Sunday in
2052 September, both at 2AM. */
2053 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2055 case 44: /* United Kingdom */
2056 case 351: /* Portugal */
2057 case 354: /* Iceland */
2058 setenv ("TZ", "GMT+00", 0);
2060 case 81: /* Japan */
2061 case 82: /* Korea */
2062 setenv ("TZ", "JST-09", 0);
2064 case 90: /* Turkey */
2065 case 358: /* Finland */
2066 setenv ("TZ", "EET-02", 0);
2068 case 972: /* Israel */
2069 /* This is an approximation. (For exact rules, use the
2070 `zoneinfo/israel' file which comes with DJGPP, but you need
2071 to install it in `/usr/share/zoneinfo/' directory first.) */
2072 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2075 init_gettimeofday ();
2080 static int break_stat
; /* BREAK check mode status. */
2081 static int stdin_stat
; /* stdin IOCTL status. */
2083 /* These must be global. */
2084 static _go32_dpmi_seginfo ctrl_break_vector
;
2085 static _go32_dpmi_registers ctrl_break_regs
;
2086 static int ctrlbreakinstalled
= 0;
2088 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2091 ctrl_break_func (regs
)
2092 _go32_dpmi_registers
*regs
;
2098 install_ctrl_break_check ()
2100 if (!ctrlbreakinstalled
)
2102 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2103 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2104 ctrlbreakinstalled
= 1;
2105 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2106 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2108 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2113 * Turn off Dos' Ctrl-C checking and inhibit interpretation of
2114 * control chars by Dos.
2115 * Determine the keyboard type.
2121 union REGS inregs
, outregs
;
2122 static int first_time
= 1;
2124 break_stat
= getcbrk ();
2126 install_ctrl_break_check ();
2131 int86 (0x15, &inregs
, &outregs
);
2132 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2136 if (internal_terminal
2137 #ifdef HAVE_X_WINDOWS
2138 && inhibit_window_system
2142 inregs
.x
.ax
= 0x0021;
2143 int86 (0x33, &inregs
, &outregs
);
2144 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2147 /* Reportedly, the above doesn't work for some mouse drivers. There
2148 is an additional detection method that should work, but might be
2149 a little slower. Use that as an alternative. */
2150 inregs
.x
.ax
= 0x0000;
2151 int86 (0x33, &inregs
, &outregs
);
2152 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2157 have_mouse
= 1; /* enable mouse */
2160 if (outregs
.x
.bx
== 3)
2162 mouse_button_count
= 3;
2163 mouse_button_translate
[0] = 0; /* Left */
2164 mouse_button_translate
[1] = 2; /* Middle */
2165 mouse_button_translate
[2] = 1; /* Right */
2169 mouse_button_count
= 2;
2170 mouse_button_translate
[0] = 0;
2171 mouse_button_translate
[1] = 1;
2173 mouse_position_hook
= &mouse_get_pos
;
2181 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2182 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2183 intdos (&inregs
, &outregs
);
2184 stdin_stat
= outregs
.h
.dl
;
2186 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
2187 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
2188 intdos (&inregs
, &outregs
);
2189 return !outregs
.x
.cflag
;
2192 /* Restore status of standard input and Ctrl-C checking. */
2196 union REGS inregs
, outregs
;
2198 setcbrk (break_stat
);
2201 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
2202 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2203 inregs
.x
.dx
= stdin_stat
;
2204 intdos (&inregs
, &outregs
);
2205 return !outregs
.x
.cflag
;
2209 /* Run command as specified by ARGV in directory DIR.
2210 The command is run with input from TEMPIN, output to
2211 file TEMPOUT and stderr to TEMPERR. */
2213 run_msdos_command (argv
, dir
, tempin
, tempout
, temperr
)
2214 unsigned char **argv
;
2216 int tempin
, tempout
, temperr
;
2218 char *saveargv1
, *saveargv2
, **envv
;
2219 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
2220 int msshell
, result
= -1;
2221 int in
, out
, inbak
, outbak
, errbak
;
2225 /* Get current directory as MSDOS cwd is not per-process. */
2228 cmd
= Ffile_name_nondirectory (build_string (argv
[0]));
2229 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
2230 && !strcmp ("-c", argv
[1]);
2233 saveargv1
= argv
[1];
2234 saveargv2
= argv
[2];
2238 char *p
= alloca (strlen (argv
[2]) + 1);
2240 strcpy (argv
[2] = p
, saveargv2
);
2241 while (*p
&& isspace (*p
))
2243 while (*p
&& !isspace (*p
))
2251 /* Build the environment array. */
2253 extern Lisp_Object Vprocess_environment
;
2254 Lisp_Object tmp
, lst
;
2257 lst
= Vprocess_environment
;
2258 len
= XFASTINT (Flength (lst
));
2260 envv
= alloca ((len
+ 1) * sizeof (char *));
2261 for (i
= 0; i
< len
; i
++)
2265 CHECK_STRING (tmp
, 0);
2266 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
2267 strcpy (envv
[i
], XSTRING (tmp
)->data
);
2269 envv
[len
] = (char *) 0;
2273 chdir (XSTRING (dir
)->data
);
2277 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
2278 goto done
; /* Allocation might fail due to lack of descriptors. */
2281 mouse_get_xy (&x
, &y
);
2283 dos_ttcooked (); /* do it here while 0 = stdin */
2289 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
2302 mouse_moveto (x
, y
);
2309 argv
[1] = saveargv1
;
2310 argv
[2] = saveargv2
;
2318 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
2323 /* ------------------------- Compatibility functions -------------------
2329 * Hostnames for a pc are not really funny,
2330 * but they are used in change log so we emulate the best we can.
2333 gethostname (p
, size
)
2337 char *q
= egetenv ("HOSTNAME");
2344 /* When time zones are set from Ms-Dos too many C-libraries are playing
2345 tricks with time values. We solve this by defining our own version
2346 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2347 once and after each call to `tzset' with TZ changed. That is
2348 accomplished by aliasing tzset to init_gettimeofday. */
2350 static struct tm time_rec
;
2353 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
2361 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
2365 time_rec
.tm_year
= d
.da_year
- 1900;
2366 time_rec
.tm_mon
= d
.da_mon
- 1;
2367 time_rec
.tm_mday
= d
.da_day
;
2370 time_rec
.tm_hour
= t
.ti_hour
;
2371 time_rec
.tm_min
= t
.ti_min
;
2372 time_rec
.tm_sec
= t
.ti_sec
;
2375 tm
.tm_gmtoff
= dos_timezone_offset
;
2377 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
2378 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
2380 /* Ignore tzp; it's obsolescent. */
2386 * A list of unimplemented functions that we silently ignore.
2389 unsigned alarm (s
) unsigned s
; {}
2390 fork () { return 0; }
2391 int kill (x
, y
) int x
, y
; { return -1; }
2393 void volatile pause () {}
2395 setpgrp () {return 0; }
2396 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
2397 sigsetmask (x
) int x
; { return 0; }
2398 unrequest_sigio () {}
2401 #include "sysselect.h"
2403 static struct time last_time
= {120, 120, 120, 120};
2404 static int modeline_time_displayed
= 0;
2406 Lisp_Object Vdos_display_time
;
2412 int sec
, min
, hour
, hund
;
2420 /* Any chance of not getting here 24 hours or more since last time? */
2421 if (hour
== last_time
.ti_hour
2422 && min
== last_time
.ti_min
2423 && sec
== last_time
.ti_sec
)
2426 if (!NILP (Vdos_display_time
))
2429 Lisp_Object dti
= XSYMBOL (Fintern_soft (build_string ("display-time-interval"), Qnil
))->value
;
2430 int delta_time
= ((hour
- last_time
.ti_hour
) * 3600
2431 + (min
- last_time
.ti_min
) * 60
2432 + (sec
- last_time
.ti_sec
));
2434 /* Who knows what the user may put into `display-time-interval'? */
2435 if (!INTEGERP (dti
) || (interval
= XINT (dti
)) <= 0)
2438 /* When it's time to renew the display, fake a `wakeup' call. */
2439 if (!modeline_time_displayed
/* first time */
2440 || delta_time
>= interval
/* or if we were busy for a long time */
2441 || interval
== 1 /* and every `interval' seconds hence */
2442 || interval
== 60 && sec
== 0 /* (usual cases first) */
2443 || (hour
* 3600 + min
* 60 + sec
) % interval
== 0)
2444 call2 (intern ("display-time-filter"), Qnil
,
2445 build_string ("Wake up!\n"));
2447 modeline_time_displayed
= 1;
2449 else if (modeline_time_displayed
)
2451 modeline_time_displayed
= 0;
2452 Fset (intern ("display-time-string"), build_string (""));
2454 /* Force immediate redisplay of modelines. */
2455 update_mode_lines
++;
2456 redisplay_preserve_echo_area ();
2462 /* Only event queue is checked. */
2464 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
2466 SELECT_TYPE
*rfds
, *wfds
, *efds
;
2467 EMACS_TIME
*timeout
;
2470 long timeoutval
, clnow
, cllast
;
2476 check_input
= FD_ISSET (0, rfds
);
2487 /* If we are looking only for the terminal, with no timeout,
2488 just read it and wait -- that's more efficient. */
2492 check_timer (&t
); /* check timer even if some input is pending */
2493 while (!detect_input_pending ());
2497 timeoutval
= EMACS_SECS (*timeout
) * 100 + EMACS_USECS (*timeout
) / 10000;
2499 cllast
= t
.ti_sec
* 100 + t
.ti_hund
;
2501 while (!check_input
|| !detect_input_pending ())
2504 clnow
= t
.ti_sec
* 100 + t
.ti_hund
;
2505 if (clnow
< cllast
) /* time wrap */
2506 timeoutval
-= clnow
+ 6000 - cllast
;
2508 timeoutval
-= clnow
- cllast
;
2509 if (timeoutval
<= 0) /* Stop on timer being cleared */
2521 * Define overlaid functions:
2523 * chdir -> sys_chdir
2524 * tzset -> init_gettimeofday
2525 * abort -> dos_abort
2530 extern int chdir ();
2536 int len
= strlen (path
);
2537 char *tmp
= (char *)path
;
2539 if (*tmp
&& tmp
[1] == ':')
2541 if (getdisk () != tolower (tmp
[0]) - 'a')
2542 setdisk (tolower (tmp
[0]) - 'a');
2543 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
2547 if (len
> 1 && (tmp
[len
- 1] == '/'))
2549 char *tmp1
= (char *) alloca (len
+ 1);
2560 extern void tzset (void);
2563 init_gettimeofday ()
2569 ltm
= gtm
= time (NULL
);
2570 ltm
= mktime (lstm
= localtime (<m
));
2571 gtm
= mktime (gmtime (>m
));
2572 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
2573 time_rec
.tm_isdst
= lstm
->tm_isdst
;
2574 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
2581 dos_abort (file
, line
)
2585 char buffer1
[200], buffer2
[400];
2588 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
2589 for (i
= j
= 0; buffer1
[i
]; i
++) {
2590 buffer2
[j
++] = buffer1
[i
];
2591 buffer2
[j
++] = 0x70;
2593 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
2594 ScreenSetCursor (2, 0);
2602 ScreenSetCursor (10, 0);
2603 cputs ("\r\n\nEmacs aborted!\r\n");
2610 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
2611 staticpro (&recent_doskeys
);
2613 defsubr (&Srecent_doskeys
);
2615 DEFVAR_LISP ("dos-display-time", &Vdos_display_time
,
2616 "*When non-nil, `display-time' is in effect on DOS systems.");
2617 Vdos_display_time
= Qnil
;