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
;
782 /* ----------------------- Keyboard control ----------------------
784 * Keymaps reflect the following keyboard layout:
786 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
787 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
788 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
789 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
793 static int extended_kbd
; /* 101 (102) keyboard present. */
795 struct dos_keyboard_map
803 static struct dos_keyboard_map us_keyboard
= {
805 /* 01234567890123456789012345678901234567890 12345678901234 */
806 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
807 /* 0123456789012345678901234567890123456789 012345678901234 */
808 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
809 0 /* no Alt-Gr key */
812 static struct dos_keyboard_map fr_keyboard
= {
814 /* 012 3456789012345678901234567890123456789012345678901234 */
815 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
816 /* 0123456789012345678901234567890123456789012345678901234 */
817 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
818 /* 01234567 89012345678901234567890123456789012345678901234 */
822 static struct dos_keyboard_map dk_keyboard
= {
824 /* 0123456789012345678901234567890123456789012345678901234 */
825 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
826 /* 01 23456789012345678901234567890123456789012345678901234 */
827 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
828 /* 0123456789012345678901234567890123456789012345678901234 */
832 static struct keyboard_layout_list
835 struct dos_keyboard_map
*keyboard_map
;
836 } keyboard_layout_list
[] =
843 static struct dos_keyboard_map
*keyboard
;
844 static int keyboard_map_all
;
847 dos_set_keyboard (code
, always
)
853 /* Initialize to US settings, for countries that don't have their own. */
854 keyboard
= keyboard_layout_list
[0].keyboard_map
;
855 keyboard_map_all
= always
;
856 dos_keyboard_layout
= 1;
858 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
859 if (code
== keyboard_layout_list
[i
].country_code
)
861 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
862 keyboard_map_all
= always
;
863 dos_keyboard_layout
= code
;
869 #define Ignore 0x0000
870 #define Normal 0x0000 /* normal key - alt changes scan-code */
871 #define FctKey 0x1000 /* func key if c == 0, else c */
872 #define Special 0x2000 /* func key even if c != 0 */
873 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
874 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
875 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
876 #define Grey 0x6000 /* Grey keypad key */
878 #define Alt 0x0100 /* alt scan-code */
879 #define Ctrl 0x0200 /* ctrl scan-code */
880 #define Shift 0x0400 /* shift scan-code */
884 unsigned char char_code
; /* normal code */
885 unsigned char meta_code
; /* M- code */
886 unsigned char keypad_code
; /* keypad code */
887 unsigned char editkey_code
; /* edit key */
888 } keypad_translate_map
[] = {
889 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
890 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
891 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
892 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
893 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
894 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
895 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
896 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
897 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
898 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
899 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
904 unsigned char char_code
; /* normal code */
905 unsigned char keypad_code
; /* keypad code */
906 } grey_key_translate_map
[] = {
907 '/', 0xaf, /* kp-decimal */
908 '*', 0xaa, /* kp-multiply */
909 '-', 0xad, /* kp-subtract */
910 '+', 0xab, /* kp-add */
911 '\r', 0x8d /* kp-enter */
914 static unsigned short
915 ibmpc_translate_map
[] =
917 /* --------------- 00 to 0f --------------- */
918 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
919 Alt
| ModFct
| 0x1b, /* Escape */
920 Normal
| 1, /* '1' */
921 Normal
| 2, /* '2' */
922 Normal
| 3, /* '3' */
923 Normal
| 4, /* '4' */
924 Normal
| 5, /* '5' */
925 Normal
| 6, /* '6' */
926 Normal
| 7, /* '7' */
927 Normal
| 8, /* '8' */
928 Normal
| 9, /* '9' */
929 Normal
| 10, /* '0' */
930 Normal
| 11, /* '-' */
931 Normal
| 12, /* '=' */
932 Special
| 0x08, /* Backspace */
933 ModFct
| 0x74, /* Tab/Backtab */
935 /* --------------- 10 to 1f --------------- */
948 ModFct
| 0x0d, /* Return */
953 /* --------------- 20 to 2f --------------- */
964 Ignore
, /* Left shift */
971 /* --------------- 30 to 3f --------------- */
978 Ignore
, /* Right shift */
979 Grey
| 1, /* Grey * */
981 Normal
| ' ', /* ' ' */
982 Ignore
, /* Caps Lock */
983 FctKey
| 0xbe, /* F1 */
984 FctKey
| 0xbf, /* F2 */
985 FctKey
| 0xc0, /* F3 */
986 FctKey
| 0xc1, /* F4 */
987 FctKey
| 0xc2, /* F5 */
989 /* --------------- 40 to 4f --------------- */
990 FctKey
| 0xc3, /* F6 */
991 FctKey
| 0xc4, /* F7 */
992 FctKey
| 0xc5, /* F8 */
993 FctKey
| 0xc6, /* F9 */
994 FctKey
| 0xc7, /* F10 */
995 Ignore
, /* Num Lock */
996 Ignore
, /* Scroll Lock */
997 KeyPad
| 7, /* Home */
999 KeyPad
| 9, /* Page Up */
1000 Grey
| 2, /* Grey - */
1001 KeyPad
| 4, /* Left */
1002 KeyPad
| 5, /* Keypad 5 */
1003 KeyPad
| 6, /* Right */
1004 Grey
| 3, /* Grey + */
1005 KeyPad
| 1, /* End */
1007 /* --------------- 50 to 5f --------------- */
1008 KeyPad
| 2, /* Down */
1009 KeyPad
| 3, /* Page Down */
1010 KeyPad
| 0, /* Insert */
1011 KeyPad
| 10, /* Delete */
1012 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1013 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1014 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1015 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1016 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1017 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1018 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1019 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1020 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1021 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1022 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1023 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1025 /* --------------- 60 to 6f --------------- */
1026 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1027 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1028 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1029 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1030 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1031 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1032 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1033 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1034 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1035 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1036 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1037 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1038 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1039 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1040 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1041 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1043 /* --------------- 70 to 7f --------------- */
1044 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1045 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1046 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1047 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1048 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1049 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1050 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1051 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1052 Alt
| Map
| 1, /* '1' */
1053 Alt
| Map
| 2, /* '2' */
1054 Alt
| Map
| 3, /* '3' */
1055 Alt
| Map
| 4, /* '4' */
1056 Alt
| Map
| 5, /* '5' */
1057 Alt
| Map
| 6, /* '6' */
1058 Alt
| Map
| 7, /* '7' */
1059 Alt
| Map
| 8, /* '8' */
1061 /* --------------- 80 to 8f --------------- */
1062 Alt
| Map
| 9, /* '9' */
1063 Alt
| Map
| 10, /* '0' */
1064 Alt
| Map
| 11, /* '-' */
1065 Alt
| Map
| 12, /* '=' */
1066 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1067 FctKey
| 0xc8, /* F11 */
1068 FctKey
| 0xc9, /* F12 */
1069 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1070 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1071 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1072 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1073 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1074 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1075 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1076 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1077 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1079 /* --------------- 90 to 9f --------------- */
1080 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1081 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1082 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1083 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1084 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1085 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1086 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1087 Alt
| FctKey
| 0x50, /* (Alt) Home */
1088 Alt
| FctKey
| 0x52, /* (Alt) Up */
1089 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1090 Ignore
, /* NO KEY */
1091 Alt
| FctKey
| 0x51, /* (Alt) Left */
1092 Ignore
, /* NO KEY */
1093 Alt
| FctKey
| 0x53, /* (Alt) Right */
1094 Ignore
, /* NO KEY */
1095 Alt
| FctKey
| 0x57, /* (Alt) End */
1097 /* --------------- a0 to af --------------- */
1098 Alt
| KeyPad
| 2, /* (Alt) Down */
1099 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1100 Alt
| KeyPad
| 0, /* (Alt) Insert */
1101 Alt
| KeyPad
| 10, /* (Alt) Delete */
1102 Alt
| Grey
| 0, /* (Alt) Grey / */
1103 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1104 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1107 /* These bit-positions corresponds to values returned by BIOS */
1108 #define SHIFT_P 0x0003 /* two bits! */
1109 #define CTRL_P 0x0004
1110 #define ALT_P 0x0008
1111 #define SCRLOCK_P 0x0010
1112 #define NUMLOCK_P 0x0020
1113 #define CAPSLOCK_P 0x0040
1114 #define ALT_GR_P 0x0800
1115 #define SUPER_P 0x4000 /* pseudo */
1116 #define HYPER_P 0x8000 /* pseudo */
1119 dos_get_modifiers (keymask
)
1126 /* Calculate modifier bits */
1127 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1128 int86 (0x16, ®s
, ®s
);
1132 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1133 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1137 mask
= regs
.h
.al
& (SHIFT_P
|
1138 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1140 /* Do not break international keyboard support. */
1141 /* When Keyb.Com is loaded, the right Alt key is */
1142 /* used for accessing characters like { and } */
1143 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1146 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1149 if (dos_hyper_key
== 1)
1152 modifiers
|= hyper_modifier
;
1154 else if (dos_super_key
== 1)
1157 modifiers
|= super_modifier
;
1161 if (regs
.h
.ah
& 1) /* Left CTRL pressed
1164 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1166 if (dos_hyper_key
== 2)
1169 modifiers
|= hyper_modifier
;
1171 else if (dos_super_key
== 2)
1174 modifiers
|= super_modifier
;
1182 modifiers
|= shift_modifier
;
1184 modifiers
|= ctrl_modifier
;
1186 modifiers
|= meta_modifier
;
1193 #define NUM_RECENT_DOSKEYS (100)
1194 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1195 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1196 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1198 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1199 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1200 Each input key receives two values in this vector: first the ASCII code,\n\
1201 and then the scan code.")
1204 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1207 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1208 return Fvector (total_doskeys
, keys
);
1211 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1212 bcopy (keys
+ recent_doskeys_index
,
1213 XVECTOR (val
)->contents
,
1214 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1216 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1217 recent_doskeys_index
* sizeof (Lisp_Object
));
1222 /* Get a char from keyboard. Function keys are put into the event queue. */
1226 struct input_event event
;
1229 #ifndef HAVE_X_WINDOWS
1230 SCREEN_SET_CURSOR ();
1231 if (!mouse_visible
) mouse_on ();
1234 /* The following condition is equivalent to `kbhit ()', except that
1235 it uses the bios to do its job. This pleases DESQview/X. */
1236 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1237 int86 (0x16, ®s
, ®s
),
1238 (regs
.x
.flags
& 0x40) == 0)
1241 register unsigned char c
;
1242 int sc
, code
, mask
, kp_mode
;
1245 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1246 int86 (0x16, ®s
, ®s
);
1251 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1253 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1254 recent_doskeys_index
= 0;
1255 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1257 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1258 recent_doskeys_index
= 0;
1260 modifiers
= dos_get_modifiers (&mask
);
1262 #ifndef HAVE_X_WINDOWS
1263 if (!NILP (Vdos_display_scancodes
))
1266 sprintf (buf
, "%02x:%02x*%04x",
1267 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1268 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1276 case 10: /* Ctrl Grey Enter */
1277 code
= Ctrl
| Grey
| 4;
1279 case 13: /* Grey Enter */
1282 case '/': /* Grey / */
1292 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1294 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1301 modifiers
|= meta_modifier
;
1303 modifiers
|= ctrl_modifier
;
1305 modifiers
|= shift_modifier
;
1308 switch (code
& 0xf000)
1311 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1313 c
= 0; /* Special */
1326 if (c
== 0) /* ctrl-break */
1328 return c
; /* ALT-nnn */
1330 if (!keyboard_map_all
)
1339 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1340 if (!keyboard_map_all
)
1344 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1345 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1349 code
= keyboard
->shifted
[code
];
1351 modifiers
&= ~shift_modifier
;
1354 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1355 code
= keyboard
->alt_gr
[code
];
1357 code
= keyboard
->unshifted
[code
];
1362 if (c
== 0xe0) /* edit key */
1365 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1366 kp_mode
= dos_keypad_mode
& 0x03;
1368 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1373 if (code
== 10 && dos_decimal_point
)
1374 return dos_decimal_point
;
1375 return keypad_translate_map
[code
].char_code
;
1378 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1382 code
= keypad_translate_map
[code
].meta_code
;
1383 modifiers
= meta_modifier
;
1387 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1394 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1395 if (dos_keypad_mode
& kp_mode
)
1396 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1398 code
= grey_key_translate_map
[code
].char_code
;
1407 event
.kind
= non_ascii_keystroke
;
1409 event
.kind
= ascii_keystroke
;
1411 event
.modifiers
= modifiers
;
1412 XSETFRAME (event
.frame_or_window
, selected_frame
);
1413 event
.timestamp
= event_timestamp ();
1414 kbd_buffer_store_event (&event
);
1419 int but
, press
, x
, y
, ok
;
1421 /* Check for mouse movement *before* buttons. */
1422 mouse_check_moved ();
1424 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1425 for (press
= 0; press
< 2; press
++)
1428 ok
= mouse_pressed (but
, &x
, &y
);
1430 ok
= mouse_released (but
, &x
, &y
);
1433 event
.kind
= mouse_click
;
1435 event
.modifiers
= dos_get_modifiers (0)
1436 | (press
? down_modifier
: up_modifier
);
1439 XSETFRAME (event
.frame_or_window
, selected_frame
);
1440 event
.timestamp
= event_timestamp ();
1441 kbd_buffer_store_event (&event
);
1449 static int prev_get_char
= -1;
1451 /* Return 1 if a key is ready to be read without suspending execution. */
1454 if (prev_get_char
!= -1)
1457 return ((prev_get_char
= dos_rawgetc ()) != -1);
1460 /* Read a key. Return -1 if no key is ready. */
1463 if (prev_get_char
!= -1)
1465 int c
= prev_get_char
;
1470 return dos_rawgetc ();
1473 #ifndef HAVE_X_WINDOWS
1474 /* See xterm.c for more info. */
1476 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1478 register int pix_x
, pix_y
;
1479 register int *x
, *y
;
1480 void /* XRectangle */ *bounds
;
1483 if (bounds
) abort ();
1485 /* Ignore clipping. */
1492 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1495 register int *pix_x
, *pix_y
;
1501 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1504 Actually, I don't know the meaning of all the parameters of the functions
1505 here -- I only know how they are called by xmenu.c. I could of course
1506 grab the nearest Xlib manual (down the hall, second-to-last door on the
1507 left), but I don't think it's worth the effort. */
1514 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1515 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1519 /* Allocate some (more) memory for MENU ensuring that there is room for one
1523 IT_menu_make_room (XMenu
*menu
)
1525 if (menu
->allocated
== 0)
1527 int count
= menu
->allocated
= 10;
1528 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1529 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1530 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1532 else if (menu
->allocated
== menu
->count
)
1534 int count
= menu
->allocated
= menu
->allocated
+ 10;
1536 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1538 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1540 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1544 /* Search the given menu structure for a given pane number. */
1547 IT_menu_search_pane (XMenu
*menu
, int pane
)
1552 for (i
= 0; i
< menu
->count
; i
++)
1553 if (menu
->submenu
[i
])
1555 if (pane
== menu
->panenumber
[i
])
1556 return menu
->submenu
[i
];
1557 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1563 /* Determine how much screen space a given menu needs. */
1566 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1568 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1571 maxheight
= menu
->count
;
1572 for (i
= 0; i
< menu
->count
; i
++)
1574 if (menu
->submenu
[i
])
1576 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1577 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1578 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1581 *width
= menu
->width
+ maxsubwidth
;
1582 *height
= maxheight
;
1585 /* Display MENU at (X,Y) using FACES. */
1588 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1590 int i
, j
, face
, width
;
1594 int enabled
, mousehere
;
1597 width
= menu
->width
;
1598 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1599 ScreenGetCursor (&row
, &col
);
1600 mouse_get_xy (&mx
, &my
);
1602 for (i
= 0; i
< menu
->count
; i
++)
1604 IT_cursor_to (y
+ i
, x
);
1606 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1607 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1608 face
= faces
[enabled
+ mousehere
* 2];
1610 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1611 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
1612 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
1613 for (; j
< width
; j
++)
1614 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1615 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
1616 IT_write_glyphs (text
, width
+ 2);
1619 IT_cursor_to (row
, col
);
1623 /* --------------------------- X Menu emulation ---------------------- */
1625 /* Create a brand new menu structure. */
1628 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
1630 return IT_menu_create ();
1633 /* Create a new pane and place it on the outer-most level. It is not
1634 clear that it should be placed out there, but I don't know what else
1638 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
1645 IT_menu_make_room (menu
);
1646 menu
->submenu
[menu
->count
] = IT_menu_create ();
1647 menu
->text
[menu
->count
] = txt
;
1648 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
1650 if ((len
= strlen (txt
)) > menu
->width
)
1652 return menu
->panecount
;
1655 /* Create a new item in a menu pane. */
1658 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
1659 int foo
, char *txt
, int enable
)
1664 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
1666 IT_menu_make_room (menu
);
1667 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
1668 menu
->text
[menu
->count
] = txt
;
1669 menu
->panenumber
[menu
->count
] = enable
;
1671 if ((len
= strlen (txt
)) > menu
->width
)
1676 /* Decide where the menu would be placed if requested at (X,Y). */
1679 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
1680 int *ulx
, int *uly
, int *width
, int *height
)
1682 IT_menu_calc_size (menu
, width
, height
);
1688 struct IT_menu_state
1690 void *screen_behind
;
1697 /* Display menu, wait for user's response, and return that response. */
1700 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
1701 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
1703 struct IT_menu_state
*state
;
1707 int faces
[4], selectface
;
1708 int leave
, result
, onepane
;
1710 /* Just in case we got here without a mouse present... */
1711 if (have_mouse
<= 0)
1712 return XM_IA_SELECT
;
1714 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
1715 screensize
= screen_size
* 2;
1717 = compute_glyph_face (&the_only_frame
,
1720 intern ("msdos-menu-passive-face")),
1723 = compute_glyph_face (&the_only_frame
,
1726 intern ("msdos-menu-active-face")),
1729 = face_name_id_number (&the_only_frame
, intern ("msdos-menu-select-face"));
1730 faces
[2] = compute_glyph_face (&the_only_frame
, selectface
, faces
[0]);
1731 faces
[3] = compute_glyph_face (&the_only_frame
, selectface
, faces
[1]);
1734 state
[0].menu
= menu
;
1736 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
1738 IT_menu_display (menu
, y0
- 1, x0
- 1, faces
); /* display the menu title */
1739 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
1741 menu
->width
= menu
->submenu
[0]->width
;
1742 state
[0].menu
= menu
->submenu
[0];
1746 state
[0].menu
= menu
;
1748 state
[0].x
= x0
- 1;
1750 state
[0].pane
= onepane
;
1752 mouse_last_x
= -1; /* A hack that forces display. */
1756 if (!mouse_visible
) mouse_on ();
1757 mouse_check_moved ();
1758 if (selected_frame
->mouse_moved
)
1760 selected_frame
->mouse_moved
= 0;
1761 result
= XM_IA_SELECT
;
1762 mouse_get_xy (&x
, &y
);
1763 for (i
= 0; i
< statecount
; i
++)
1764 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
1766 int dy
= y
- state
[i
].y
;
1767 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
1769 if (!state
[i
].menu
->submenu
[dy
])
1770 if (state
[i
].menu
->panenumber
[dy
])
1771 result
= XM_SUCCESS
;
1773 result
= XM_IA_SELECT
;
1774 *pane
= state
[i
].pane
- 1;
1776 /* We hit some part of a menu, so drop extra menues that
1777 have been opened. That does not include an open and
1779 if (i
!= statecount
- 2
1780 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
1781 while (i
!= statecount
- 1)
1785 ScreenUpdate (state
[statecount
].screen_behind
);
1786 xfree (state
[statecount
].screen_behind
);
1788 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
1790 IT_menu_display (state
[i
].menu
,
1794 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
1795 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
1797 ScreenRetrieve (state
[statecount
].screen_behind
1798 = xmalloc (screensize
));
1800 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
1801 state
[statecount
].y
= y
;
1806 IT_menu_display (state
[statecount
- 1].menu
,
1807 state
[statecount
- 1].y
,
1808 state
[statecount
- 1].x
,
1811 for (b
= 0; b
< mouse_button_count
; b
++)
1813 (void) mouse_pressed (b
, &x
, &y
);
1814 if (mouse_released (b
, &x
, &y
))
1820 ScreenUpdate (state
[0].screen_behind
);
1821 while (statecount
--)
1822 xfree (state
[statecount
].screen_behind
);
1826 /* Dispose of a menu. */
1829 XMenuDestroy (Display
*foo
, XMenu
*menu
)
1832 if (menu
->allocated
)
1834 for (i
= 0; i
< menu
->count
; i
++)
1835 if (menu
->submenu
[i
])
1836 XMenuDestroy (foo
, menu
->submenu
[i
]);
1838 xfree (menu
->submenu
);
1839 xfree (menu
->panenumber
);
1845 x_pixel_width (struct frame
*f
)
1847 return FRAME_WIDTH (f
);
1851 x_pixel_height (struct frame
*f
)
1853 return FRAME_HEIGHT (f
);
1855 #endif /* !HAVE_X_WINDOWS */
1858 /* ----------------------- DOS / UNIX conversion --------------------- */
1860 /* Destructively turn backslashes into slashes. */
1863 dostounix_filename (p
)
1874 /* Destructively turn slashes into backslashes. */
1877 unixtodos_filename (p
)
1888 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
1891 getdefdir (drive
, dst
)
1899 regs
.x
.si
= (int) dst
;
1901 intdos (®s
, ®s
);
1902 return !regs
.x
.cflag
;
1905 /* Remove all CR's that are followed by a LF. */
1910 register unsigned char *buf
;
1912 unsigned char *np
= buf
;
1913 unsigned char *startp
= buf
;
1914 unsigned char *endp
= buf
+ n
;
1919 while (buf
< endp
- 1)
1923 if (*(++buf
) != 0x0a)
1934 /* The Emacs root directory as determined by init_environment. */
1936 static char emacsroot
[MAXPATHLEN
];
1939 rootrelativepath (rel
)
1942 static char result
[MAXPATHLEN
+ 10];
1944 strcpy (result
, emacsroot
);
1945 strcat (result
, "/");
1946 strcat (result
, rel
);
1950 /* Define a lot of environment variables if not already defined. Don't
1951 remove anything unless you know what you're doing -- lots of code will
1952 break if one or more of these are missing. */
1955 init_environment (argc
, argv
, skip_args
)
1963 /* Find our root from argv[0]. Assuming argv[0] is, say,
1964 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
1965 root
= alloca (MAXPATHLEN
+ 20);
1966 _fixpath (argv
[0], root
);
1968 len
= strlen (root
);
1969 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
1972 if (len
> 4 && strcmp (root
+ len
- 4, "/bin") == 0)
1973 root
[len
- 4] = '\0';
1975 strcpy (root
, "c:/emacs"); /* Only under debuggers, I think. */
1976 len
= strlen (root
);
1977 strcpy (emacsroot
, root
);
1979 /* We default HOME to our root. */
1980 setenv ("HOME", root
, 0);
1982 /* We default EMACSPATH to root + "/bin". */
1983 strcpy (root
+ len
, "/bin");
1984 setenv ("EMACSPATH", root
, 0);
1986 /* I don't expect anybody to ever use other terminals so the internal
1987 terminal is the default. */
1988 setenv ("TERM", "internal", 0);
1990 #ifdef HAVE_X_WINDOWS
1991 /* Emacs expects DISPLAY to be set. */
1992 setenv ("DISPLAY", "unix:0.0", 0);
1995 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
1996 downcase it and mirror the backslashes. */
1997 s
= getenv ("COMSPEC");
1998 if (!s
) s
= "c:/command.com";
1999 t
= alloca (strlen (s
) + 1);
2002 dostounix_filename (t
);
2003 setenv ("SHELL", t
, 0);
2005 /* PATH is also downcased and backslashes mirrored. */
2006 s
= getenv ("PATH");
2008 t
= alloca (strlen (s
) + 3);
2009 /* Current directory is always considered part of MsDos's path but it is
2010 not normally mentioned. Now it is. */
2011 strcat (strcpy (t
, ".;"), s
);
2013 dostounix_filename (t
); /* Not a single file name, but this should work. */
2014 setenv ("PATH", t
, 1);
2016 /* In some sense all dos users have root privileges, so... */
2017 setenv ("USER", "root", 0);
2018 setenv ("NAME", getenv ("USER"), 0);
2020 /* Time zone determined from country code. To make this possible, the
2021 country code may not span more than one time zone. In other words,
2022 in the USA, you lose. */
2024 switch (dos_country_code
)
2026 case 31: /* Belgium */
2027 case 32: /* The Netherlands */
2028 case 33: /* France */
2029 case 34: /* Spain */
2030 case 36: /* Hungary */
2031 case 38: /* Yugoslavia (or what's left of it?) */
2032 case 39: /* Italy */
2033 case 41: /* Switzerland */
2034 case 42: /* Tjekia */
2035 case 45: /* Denmark */
2036 case 46: /* Sweden */
2037 case 47: /* Norway */
2038 case 48: /* Poland */
2039 case 49: /* Germany */
2040 /* Daylight saving from last Sunday in March to last Sunday in
2041 September, both at 2AM. */
2042 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2044 case 44: /* United Kingdom */
2045 case 351: /* Portugal */
2046 case 354: /* Iceland */
2047 setenv ("TZ", "GMT+00", 0);
2049 case 81: /* Japan */
2050 case 82: /* Korea */
2051 setenv ("TZ", "JST-09", 0);
2053 case 90: /* Turkey */
2054 case 358: /* Finland */
2055 setenv ("TZ", "EET-02", 0);
2057 case 972: /* Israel */
2058 /* This is an approximation. (For exact rules, use the
2059 `zoneinfo/israel' file which comes with DJGPP, but you need
2060 to install it in `/usr/share/zoneinfo/' directory first.) */
2061 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2064 init_gettimeofday ();
2069 static int break_stat
; /* BREAK check mode status. */
2070 static int stdin_stat
; /* stdin IOCTL status. */
2072 /* These must be global. */
2073 static _go32_dpmi_seginfo ctrl_break_vector
;
2074 static _go32_dpmi_registers ctrl_break_regs
;
2075 static int ctrlbreakinstalled
= 0;
2077 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2080 ctrl_break_func (regs
)
2081 _go32_dpmi_registers
*regs
;
2087 install_ctrl_break_check ()
2089 if (!ctrlbreakinstalled
)
2091 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2092 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2093 ctrlbreakinstalled
= 1;
2094 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2095 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2097 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2102 * Turn off Dos' Ctrl-C checking and inhibit interpretation of
2103 * control chars by Dos.
2104 * Determine the keyboard type.
2110 union REGS inregs
, outregs
;
2111 static int first_time
= 1;
2113 break_stat
= getcbrk ();
2115 install_ctrl_break_check ();
2120 int86 (0x15, &inregs
, &outregs
);
2121 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2125 if (internal_terminal
2126 #ifdef HAVE_X_WINDOWS
2127 && inhibit_window_system
2131 inregs
.x
.ax
= 0x0021;
2132 int86 (0x33, &inregs
, &outregs
);
2133 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2136 /* Reportedly, the above doesn't work for some mouse drivers. There
2137 is an additional detection method that should work, but might be
2138 a little slower. Use that as an alternative. */
2139 inregs
.x
.ax
= 0x0000;
2140 int86 (0x33, &inregs
, &outregs
);
2141 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2146 have_mouse
= 1; /* enable mouse */
2149 if (outregs
.x
.bx
== 3)
2151 mouse_button_count
= 3;
2152 mouse_button_translate
[0] = 0; /* Left */
2153 mouse_button_translate
[1] = 2; /* Middle */
2154 mouse_button_translate
[2] = 1; /* Right */
2158 mouse_button_count
= 2;
2159 mouse_button_translate
[0] = 0;
2160 mouse_button_translate
[1] = 1;
2162 mouse_position_hook
= &mouse_get_pos
;
2170 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2171 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2172 intdos (&inregs
, &outregs
);
2173 stdin_stat
= outregs
.h
.dl
;
2175 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
2176 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
2177 intdos (&inregs
, &outregs
);
2178 return !outregs
.x
.cflag
;
2181 /* Restore status of standard input and Ctrl-C checking. */
2185 union REGS inregs
, outregs
;
2187 setcbrk (break_stat
);
2190 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
2191 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2192 inregs
.x
.dx
= stdin_stat
;
2193 intdos (&inregs
, &outregs
);
2194 return !outregs
.x
.cflag
;
2198 /* Run command as specified by ARGV in directory DIR.
2199 The command is run with input from TEMPIN, output to
2200 file TEMPOUT and stderr to TEMPERR. */
2202 run_msdos_command (argv
, dir
, tempin
, tempout
, temperr
)
2203 unsigned char **argv
;
2205 int tempin
, tempout
, temperr
;
2207 char *saveargv1
, *saveargv2
, **envv
;
2208 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
2209 int msshell
, result
= -1;
2210 int in
, out
, inbak
, outbak
, errbak
;
2214 /* Get current directory as MSDOS cwd is not per-process. */
2217 cmd
= Ffile_name_nondirectory (build_string (argv
[0]));
2218 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
2219 && !strcmp ("-c", argv
[1]);
2222 saveargv1
= argv
[1];
2223 saveargv2
= argv
[2];
2227 char *p
= alloca (strlen (argv
[2]) + 1);
2229 strcpy (argv
[2] = p
, saveargv2
);
2230 while (*p
&& isspace (*p
))
2232 while (*p
&& !isspace (*p
))
2240 /* Build the environment array. */
2242 extern Lisp_Object Vprocess_environment
;
2243 Lisp_Object tmp
, lst
;
2246 lst
= Vprocess_environment
;
2247 len
= XFASTINT (Flength (lst
));
2249 envv
= alloca ((len
+ 1) * sizeof (char *));
2250 for (i
= 0; i
< len
; i
++)
2254 CHECK_STRING (tmp
, 0);
2255 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
2256 strcpy (envv
[i
], XSTRING (tmp
)->data
);
2258 envv
[len
] = (char *) 0;
2262 chdir (XSTRING (dir
)->data
);
2266 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
2267 goto done
; /* Allocation might fail due to lack of descriptors. */
2270 mouse_get_xy (&x
, &y
);
2272 dos_ttcooked (); /* do it here while 0 = stdin */
2278 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
2291 mouse_moveto (x
, y
);
2298 argv
[1] = saveargv1
;
2299 argv
[2] = saveargv2
;
2307 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
2313 /* ------------------------- Compatibility functions -------------------
2319 * Hostnames for a pc are not really funny,
2320 * but they are used in change log so we emulate the best we can.
2323 gethostname (p
, size
)
2327 char *q
= egetenv ("HOSTNAME");
2334 /* When time zones are set from Ms-Dos too many C-libraries are playing
2335 tricks with time values. We solve this by defining our own version
2336 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2337 once and after each call to `tzset' with TZ changed. That is
2338 accomplished by aliasing tzset to init_gettimeofday. */
2340 static struct tm time_rec
;
2343 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
2351 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
2355 time_rec
.tm_year
= d
.da_year
- 1900;
2356 time_rec
.tm_mon
= d
.da_mon
- 1;
2357 time_rec
.tm_mday
= d
.da_day
;
2360 time_rec
.tm_hour
= t
.ti_hour
;
2361 time_rec
.tm_min
= t
.ti_min
;
2362 time_rec
.tm_sec
= t
.ti_sec
;
2365 tm
.tm_gmtoff
= dos_timezone_offset
;
2367 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
2368 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
2370 /* Ignore tzp; it's obsolescent. */
2376 * A list of unimplemented functions that we silently ignore.
2379 unsigned alarm (s
) unsigned s
; {}
2380 fork () { return 0; }
2381 int kill (x
, y
) int x
, y
; { return -1; }
2383 void volatile pause () {}
2385 setpgrp () {return 0; }
2386 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
2387 sigsetmask (x
) int x
; { return 0; }
2388 unrequest_sigio () {}
2391 #include "sysselect.h"
2393 static struct time last_time
= {120, 120, 120, 120};
2394 static int modeline_time_displayed
= 0;
2396 Lisp_Object Vdos_display_time
;
2402 int sec
, min
, hour
, hund
;
2410 /* Any chance of not getting here 24 hours or more since last time? */
2411 if (hour
== last_time
.ti_hour
2412 && min
== last_time
.ti_min
2413 && sec
== last_time
.ti_sec
)
2416 if (!NILP (Vdos_display_time
))
2419 Lisp_Object dti
= XSYMBOL (Fintern_soft (build_string ("display-time-interval"), Qnil
))->value
;
2420 int delta_time
= ((hour
- last_time
.ti_hour
) * 3600
2421 + (min
- last_time
.ti_min
) * 60
2422 + (sec
- last_time
.ti_sec
));
2424 /* Who knows what the user may put into `display-time-interval'? */
2425 if (!INTEGERP (dti
) || (interval
= XINT (dti
)) <= 0)
2428 /* When it's time to renew the display, fake a `wakeup' call. */
2429 if (!modeline_time_displayed
/* first time */
2430 || delta_time
>= interval
/* or if we were busy for a long time */
2431 || interval
== 1 /* and every `interval' seconds hence */
2432 || interval
== 60 && sec
== 0 /* (usual cases first) */
2433 || (hour
* 3600 + min
* 60 + sec
) % interval
== 0)
2434 call2 (intern ("display-time-filter"), Qnil
,
2435 build_string ("Wake up!\n"));
2437 modeline_time_displayed
= 1;
2439 else if (modeline_time_displayed
)
2441 modeline_time_displayed
= 0;
2442 Fset (intern ("display-time-string"), build_string (""));
2444 /* Force immediate redisplay of modelines. */
2445 update_mode_lines
++;
2446 redisplay_preserve_echo_area ();
2452 /* Only event queue is checked. */
2454 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
2456 SELECT_TYPE
*rfds
, *wfds
, *efds
;
2457 EMACS_TIME
*timeout
;
2460 long timeoutval
, clnow
, cllast
;
2466 check_input
= FD_ISSET (0, rfds
);
2477 /* If we are looking only for the terminal, with no timeout,
2478 just read it and wait -- that's more efficient. */
2482 check_timer (&t
); /* check timer even if some input is pending */
2483 while (!detect_input_pending ());
2487 timeoutval
= EMACS_SECS (*timeout
) * 100 + EMACS_USECS (*timeout
) / 10000;
2489 cllast
= t
.ti_sec
* 100 + t
.ti_hund
;
2491 while (!check_input
|| !detect_input_pending ())
2494 clnow
= t
.ti_sec
* 100 + t
.ti_hund
;
2495 if (clnow
< cllast
) /* time wrap */
2496 timeoutval
-= clnow
+ 6000 - cllast
;
2498 timeoutval
-= clnow
- cllast
;
2499 if (timeoutval
<= 0) /* Stop on timer being cleared */
2511 * Define overlayed functions:
2513 * chdir -> sys_chdir
2514 * tzset -> init_gettimeofday
2515 * abort -> dos_abort
2520 extern int chdir ();
2526 int len
= strlen (path
);
2527 char *tmp
= (char *)path
;
2529 if (*tmp
&& tmp
[1] == ':')
2531 if (getdisk () != tolower (tmp
[0]) - 'a')
2532 setdisk (tolower (tmp
[0]) - 'a');
2533 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
2537 if (len
> 1 && (tmp
[len
- 1] == '/'))
2539 char *tmp1
= (char *) alloca (len
+ 1);
2550 extern void tzset (void);
2553 init_gettimeofday ()
2559 ltm
= gtm
= time (NULL
);
2560 ltm
= mktime (lstm
= localtime (<m
));
2561 gtm
= mktime (gmtime (>m
));
2562 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
2563 time_rec
.tm_isdst
= lstm
->tm_isdst
;
2564 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
2571 dos_abort (file
, line
)
2575 char buffer1
[200], buffer2
[400];
2578 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
2579 for (i
= j
= 0; buffer1
[i
]; i
++) {
2580 buffer2
[j
++] = buffer1
[i
];
2581 buffer2
[j
++] = 0x70;
2583 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
2584 ScreenSetCursor (2, 0);
2592 ScreenSetCursor (10, 0);
2593 cputs ("\r\n\nEmacs aborted!\r\n");
2600 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
2601 staticpro (&recent_doskeys
);
2603 defsubr (&Srecent_doskeys
);
2605 DEFVAR_LISP ("dos-display-time", &Vdos_display_time
,
2606 "*When non-nil, `display-time' is in effect on DOS systems.");
2607 Vdos_display_time
= Qnil
;