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, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
32 #include <sys/param.h>
38 #include "termhooks.h"
39 #include "dispextern.h"
46 /* #include <process.h> */
47 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
68 /* ------------------------ Mouse control ---------------------------
70 * Coordinates are in screen positions and zero based.
71 * Mouse buttons are numbered from left to right and also zero based.
74 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
75 static int mouse_visible
;
77 static int mouse_last_x
;
78 static int mouse_last_y
;
80 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
81 static int mouse_button_count
;
88 if (have_mouse
> 0 && !mouse_visible
)
91 fprintf (termscript
, "<M_ON>");
93 int86 (0x33, ®s
, ®s
);
103 if (have_mouse
> 0 && mouse_visible
)
106 fprintf (termscript
, "<M_OFF>");
108 int86 (0x33, ®s
, ®s
);
120 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
122 mouse_last_x
= regs
.x
.cx
= x
* 8;
123 mouse_last_y
= regs
.x
.dx
= y
* 8;
124 int86 (0x33, ®s
, ®s
);
128 mouse_pressed (b
, xp
, yp
)
133 if (b
>= mouse_button_count
)
136 regs
.x
.bx
= mouse_button_translate
[b
];
137 int86 (0x33, ®s
, ®s
);
139 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
140 return (regs
.x
.bx
!= 0);
144 mouse_released (b
, xp
, yp
)
149 if (b
>= mouse_button_count
)
152 regs
.x
.bx
= mouse_button_translate
[b
];
153 int86 (0x33, ®s
, ®s
);
155 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
156 return (regs
.x
.bx
!= 0);
160 mouse_get_xy (int *x
, int *y
)
165 int86 (0x33, ®s
, ®s
);
171 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
174 Lisp_Object
*bar_window
, *x
, *y
;
175 enum scroll_bar_part
*part
;
182 int86 (0x33, ®s
, ®s
);
185 mouse_get_xy (&ix
, &iy
);
186 selected_frame
->mouse_moved
= 0;
187 *x
= make_number (ix
);
188 *y
= make_number (iy
);
189 *time
= event_timestamp ();
197 mouse_get_xy (&x
, &y
);
198 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
209 fprintf (termscript
, "<M_INIT>");
212 int86 (0x33, ®s
, ®s
);
216 regs
.x
.dx
= 8 * (ScreenCols () - 1);
217 int86 (0x33, ®s
, ®s
);
221 regs
.x
.dx
= 8 * (ScreenRows () - 1);
222 int86 (0x33, ®s
, ®s
);
228 /* ------------------------- Screen control ----------------------
232 static int internal_terminal
= 0;
234 #ifndef HAVE_X_WINDOWS
235 extern unsigned char ScreenAttrib
;
236 static int screen_face
;
237 static int highlight
;
239 static int screen_size_X
;
240 static int screen_size_Y
;
241 static int screen_size
;
243 static int current_pos_X
;
244 static int current_pos_Y
;
245 static int new_pos_X
;
246 static int new_pos_Y
;
248 static void *startup_screen_buffer
;
249 static int startup_screen_size_X
;
250 static int startup_screen_size_Y
;
251 static int startup_pos_X
;
252 static int startup_pos_Y
;
253 static unsigned char startup_screen_attrib
;
255 static int term_setup_done
;
257 /* Similar to the_only_frame. */
258 struct x_output the_only_x_display
;
260 /* This is never dereferenced. */
261 Display
*x_current_display
;
264 #define SCREEN_SET_CURSOR() \
265 if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \
266 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
269 dos_direct_output (y
, x
, buf
, len
)
275 int t
= (int) ScreenPrimary
+ 2 * (x
+ y
* screen_size_X
);
278 dosmemput (buf
++, 1, t
);
284 /* Flash the screen as a substitute for BEEPs. */
288 do_visible_bell (xorattr
)
289 unsigned char xorattr
;
294 movl _ScreenPrimary,%%eax
301 xorb %%al,%%gs:(%%ebx)
317 : "m" (xorattr
), "g" (screen_size
)
318 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
322 ScreenVisualBell (void)
324 /* This creates an xor-mask that will swap the default fore- and
325 background colors. */
326 do_visible_bell (((the_only_x_display
.foreground_pixel
327 ^ the_only_x_display
.background_pixel
)
332 #ifndef HAVE_X_WINDOWS
335 * If we write a character in the position where the mouse is,
336 * the mouse cursor may need to be refreshed.
347 mouse_get_xy (&x
, &y
);
348 if (y
!= new_pos_Y
|| x
< new_pos_X
)
364 union REGS inregs
, outregs
;
367 intdos (&inregs
, &outregs
);
372 IT_set_face (int face
)
375 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
377 if (face
== 1 || (face
== 0 && highlight
))
378 fp
= FRAME_MODE_LINE_FACE (foo
);
379 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
380 fp
= FRAME_DEFAULT_FACE (foo
);
382 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
384 fprintf (termscript
, "<FACE:%d:%d>", FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
386 ScreenAttrib
= (FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
);
390 IT_write_glyphs (GLYPH
*str
, int len
)
394 unsigned char *buf
, *bp
;
396 if (len
== 0) return;
398 buf
= bp
= alloca (len
* 2);
402 newface
= FAST_GLYPH_FACE (*str
);
403 if (newface
!= screen_face
)
404 IT_set_face (newface
);
405 ch
= FAST_GLYPH_CHAR (*str
);
406 *bp
++ = (unsigned char)ch
;
407 *bp
++ = ScreenAttrib
;
410 fputc (ch
, termscript
);
415 dosmemput (buf
, 2 * len
,
416 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
421 IT_clear_end_of_line (first_unused
)
428 fprintf (termscript
, "<CLR:EOL>");
429 i
= (j
= screen_size_X
- new_pos_X
) * 2;
430 spaces
= sp
= alloca (i
);
435 *sp
++ = ScreenAttrib
;
439 dosmemput (spaces
, i
,
440 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
444 IT_clear_screen (void)
447 fprintf (termscript
, "<CLR:SCR>");
451 new_pos_X
= new_pos_Y
= 0;
455 IT_clear_to_end (void)
458 fprintf (termscript
, "<CLR:EOS>");
460 while (new_pos_Y
< screen_size_Y
) {
462 IT_clear_end_of_line (0);
468 IT_cursor_to (int y
, int x
)
471 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
477 IT_reassert_line_highlight (new, vpos
)
481 IT_set_face (0); /* To possibly clear the highlighting. */
485 IT_change_line_highlight (new_highlight
, vpos
, first_unused_hpos
)
487 highlight
= new_highlight
;
488 IT_set_face (0); /* To possibly clear the highlighting. */
489 IT_cursor_to (vpos
, 0);
490 IT_clear_end_of_line (first_unused_hpos
);
497 IT_set_face (0); /* To possibly clear the highlighting. */
506 /* This was more or less copied from xterm.c */
508 IT_set_menu_bar_lines (window
, n
)
512 struct window
*w
= XWINDOW (window
);
514 XSETFASTINT (w
->last_modified
, 0);
515 XSETFASTINT (w
->top
, XFASTINT (w
->top
) + n
);
516 XSETFASTINT (w
->height
, XFASTINT (w
->height
) - n
);
518 /* Handle just the top child in a vertical split. */
519 if (!NILP (w
->vchild
))
520 IT_set_menu_bar_lines (w
->vchild
, n
);
522 /* Adjust all children in a horizontal split. */
523 for (window
= w
->hchild
; !NILP (window
); window
= w
->next
)
525 w
= XWINDOW (window
);
526 IT_set_menu_bar_lines (window
, n
);
531 * IT_set_terminal_modes is called when emacs is started,
532 * resumed, and whenever the screen is redrawn!
536 IT_set_terminal_modes (void)
543 fprintf (termscript
, "\n<SET_TERM>");
546 screen_size_X
= ScreenCols ();
547 screen_size_Y
= ScreenRows ();
548 screen_size
= screen_size_X
* screen_size_Y
;
550 new_pos_X
= new_pos_Y
= 0;
551 current_pos_X
= current_pos_Y
= -1;
557 startup_screen_size_X
= screen_size_X
;
558 startup_screen_size_Y
= screen_size_Y
;
559 startup_screen_attrib
= ScreenAttrib
;
561 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
562 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
565 fprintf (termscript
, "<SCREEN SAVED (dimensions=%dx%d)>\n",
566 screen_size_X
, screen_size_Y
);
570 * IT_reset_terminal_modes is called when emacs is
571 * suspended or killed.
575 IT_reset_terminal_modes (void)
577 int display_row_start
= (int) ScreenPrimary
;
578 int saved_row_len
= startup_screen_size_X
* 2;
579 int update_row_len
= ScreenCols () * 2;
580 int current_rows
= ScreenRows ();
581 int to_next_row
= update_row_len
;
582 unsigned char *saved_row
= startup_screen_buffer
;
583 int cursor_pos_X
= ScreenCols () - 1;
584 int cursor_pos_Y
= ScreenRows () - 1;
587 fprintf (termscript
, "\n<RESET_TERM>");
591 if (!term_setup_done
)
596 /* We have a situation here.
597 We cannot just do ScreenUpdate(startup_screen_buffer) because
598 the luser could have changed screen dimensions inside Emacs
599 and failed (or didn't want) to restore them before killing
600 Emacs. ScreenUpdate() uses the *current* screen dimensions and
601 thus will happily use memory outside what was allocated for
602 `startup_screen_buffer'.
603 Thus we only restore as much as the current screen dimensions
604 can hold, and clear the rest (if the saved screen is smaller than
605 the current) with the color attribute saved at startup. The cursor
606 is also restored within the visible dimensions. */
608 ScreenAttrib
= startup_screen_attrib
;
611 if (update_row_len
> saved_row_len
)
612 update_row_len
= saved_row_len
;
613 if (current_rows
> startup_screen_size_Y
)
614 current_rows
= startup_screen_size_Y
;
617 fprintf (termscript
, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
618 update_row_len
/ 2, current_rows
);
620 while (current_rows
--)
622 dosmemput (saved_row
, update_row_len
, display_row_start
);
623 saved_row
+= saved_row_len
;
624 display_row_start
+= to_next_row
;
626 if (startup_pos_X
< cursor_pos_X
)
627 cursor_pos_X
= startup_pos_X
;
628 if (startup_pos_Y
< cursor_pos_Y
)
629 cursor_pos_Y
= startup_pos_Y
;
631 ScreenSetCursor (cursor_pos_Y
, cursor_pos_X
);
632 xfree (startup_screen_buffer
);
638 IT_set_terminal_window (void)
643 IT_set_frame_parameters (frame
, alist
)
649 extern unsigned long load_color ();
650 FRAME_PTR f
= (FRAME_PTR
) &the_only_frame
;
653 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
655 Lisp_Object elt
, prop
, val
;
660 CHECK_SYMBOL (prop
, 1);
662 if (EQ (prop
, intern ("foreground-color")))
664 unsigned long new_color
= load_color (f
, val
);
667 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
671 else if (EQ (prop
, intern ("background-color")))
673 unsigned long new_color
= load_color (f
, val
);
676 FRAME_BACKGROUND_PIXEL (f
) = new_color
& ~8;
680 else if (EQ (prop
, intern ("menu-bar-lines")))
683 int old
= FRAME_MENU_BAR_LINES (the_only_frame
);
689 FRAME_MENU_BAR_LINES (f
) = new;
690 IT_set_menu_bar_lines (the_only_frame
.root_window
, new - old
);
696 recompute_basic_faces (f
);
697 Fredraw_frame (Fselected_frame ());
701 #endif /* !HAVE_X_WINDOWS */
704 /* Do we need the internal terminal? */
706 internal_terminal_init ()
708 char *term
= getenv ("TERM");
711 #ifdef HAVE_X_WINDOWS
712 if (!inhibit_window_system
)
717 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
719 if (getenv ("EMACSTEST"))
720 termscript
= fopen (getenv ("EMACSTEST"), "wt");
722 #ifndef HAVE_X_WINDOWS
723 if (!internal_terminal
|| inhibit_window_system
)
725 the_only_frame
.output_method
= output_termcap
;
729 Vwindow_system
= intern ("pc");
730 Vwindow_system_version
= make_number (1);
732 bzero (&the_only_x_display
, sizeof the_only_x_display
);
733 the_only_x_display
.background_pixel
= 7; /* White */
734 the_only_x_display
.foreground_pixel
= 0; /* Black */
735 colors
= getenv ("EMACSCOLORS");
736 if (colors
&& strlen (colors
) >= 2)
738 the_only_x_display
.foreground_pixel
= colors
[0] & 0x07;
739 the_only_x_display
.background_pixel
= colors
[1] & 0x07;
741 the_only_x_display
.line_height
= 1;
742 the_only_frame
.output_data
.x
= &the_only_x_display
;
743 the_only_frame
.output_method
= output_msdos_raw
;
744 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
746 init_frame_faces ((FRAME_PTR
) &the_only_frame
);
748 ring_bell_hook
= IT_ring_bell
;
749 write_glyphs_hook
= IT_write_glyphs
;
750 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
751 clear_to_end_hook
= IT_clear_to_end
;
752 clear_end_of_line_hook
= IT_clear_end_of_line
;
753 clear_frame_hook
= IT_clear_screen
;
754 change_line_highlight_hook
= IT_change_line_highlight
;
755 update_begin_hook
= IT_update_begin
;
756 update_end_hook
= IT_update_end
;
757 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
759 /* These hooks are called by term.c without being checked. */
760 set_terminal_modes_hook
= IT_set_terminal_modes
;
761 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
762 set_terminal_window_hook
= IT_set_terminal_window
;
766 dos_get_saved_screen (screen
, rows
, cols
)
771 #ifndef HAVE_X_WINDOWS
772 *screen
= startup_screen_buffer
;
773 *cols
= startup_screen_size_X
;
774 *rows
= startup_screen_size_Y
;
781 /* ----------------------- Keyboard control ----------------------
783 * Keymaps reflect the following keyboard layout:
785 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
786 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
787 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
788 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
792 static int extended_kbd
; /* 101 (102) keyboard present. */
794 struct dos_keyboard_map
802 static struct dos_keyboard_map us_keyboard
= {
804 /* 01234567890123456789012345678901234567890 12345678901234 */
805 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
806 /* 0123456789012345678901234567890123456789 012345678901234 */
807 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
808 0 /* no Alt-Gr key */
811 static struct dos_keyboard_map fr_keyboard
= {
813 /* 012 3456789012345678901234567890123456789012345678901234 */
814 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
815 /* 0123456789012345678901234567890123456789012345678901234 */
816 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
817 /* 01234567 89012345678901234567890123456789012345678901234 */
821 static struct dos_keyboard_map dk_keyboard
= {
823 /* 0123456789012345678901234567890123456789012345678901234 */
824 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
825 /* 01 23456789012345678901234567890123456789012345678901234 */
826 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
827 /* 0123456789012345678901234567890123456789012345678901234 */
831 static struct keyboard_layout_list
834 struct dos_keyboard_map
*keyboard_map
;
835 } keyboard_layout_list
[] =
842 static struct dos_keyboard_map
*keyboard
;
843 static int keyboard_map_all
;
846 dos_set_keyboard (code
, always
)
852 /* Initialize to US settings, for countries that don't have their own. */
853 keyboard
= keyboard_layout_list
[0].keyboard_map
;
854 keyboard_map_all
= always
;
855 dos_keyboard_layout
= 1;
857 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
858 if (code
== keyboard_layout_list
[i
].country_code
)
860 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
861 keyboard_map_all
= always
;
862 dos_keyboard_layout
= code
;
868 #define Ignore 0x0000
869 #define Normal 0x0000 /* normal key - alt changes scan-code */
870 #define FctKey 0x1000 /* func key if c == 0, else c */
871 #define Special 0x2000 /* func key even if c != 0 */
872 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
873 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
874 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
875 #define Grey 0x6000 /* Grey keypad key */
877 #define Alt 0x0100 /* alt scan-code */
878 #define Ctrl 0x0200 /* ctrl scan-code */
879 #define Shift 0x0400 /* shift scan-code */
883 unsigned char char_code
; /* normal code */
884 unsigned char meta_code
; /* M- code */
885 unsigned char keypad_code
; /* keypad code */
886 unsigned char editkey_code
; /* edit key */
887 } keypad_translate_map
[] = {
888 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
889 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
890 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
891 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
892 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
893 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
894 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
895 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
896 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
897 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
898 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
903 unsigned char char_code
; /* normal code */
904 unsigned char keypad_code
; /* keypad code */
905 } grey_key_translate_map
[] = {
906 '/', 0xaf, /* kp-decimal */
907 '*', 0xaa, /* kp-multiply */
908 '-', 0xad, /* kp-subtract */
909 '+', 0xab, /* kp-add */
910 '\r', 0x8d /* kp-enter */
913 static unsigned short
914 ibmpc_translate_map
[] =
916 /* --------------- 00 to 0f --------------- */
917 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
918 Alt
| ModFct
| 0x1b, /* Escape */
919 Normal
| 1, /* '1' */
920 Normal
| 2, /* '2' */
921 Normal
| 3, /* '3' */
922 Normal
| 4, /* '4' */
923 Normal
| 5, /* '5' */
924 Normal
| 6, /* '6' */
925 Normal
| 7, /* '7' */
926 Normal
| 8, /* '8' */
927 Normal
| 9, /* '9' */
928 Normal
| 10, /* '0' */
929 Normal
| 11, /* '-' */
930 Normal
| 12, /* '=' */
931 Special
| 0x08, /* Backspace */
932 ModFct
| 0x74, /* Tab/Backtab */
934 /* --------------- 10 to 1f --------------- */
947 ModFct
| 0x0d, /* Return */
952 /* --------------- 20 to 2f --------------- */
963 Ignore
, /* Left shift */
970 /* --------------- 30 to 3f --------------- */
977 Ignore
, /* Right shift */
978 Grey
| 1, /* Grey * */
980 Normal
| ' ', /* ' ' */
981 Ignore
, /* Caps Lock */
982 FctKey
| 0xbe, /* F1 */
983 FctKey
| 0xbf, /* F2 */
984 FctKey
| 0xc0, /* F3 */
985 FctKey
| 0xc1, /* F4 */
986 FctKey
| 0xc2, /* F5 */
988 /* --------------- 40 to 4f --------------- */
989 FctKey
| 0xc3, /* F6 */
990 FctKey
| 0xc4, /* F7 */
991 FctKey
| 0xc5, /* F8 */
992 FctKey
| 0xc6, /* F9 */
993 FctKey
| 0xc7, /* F10 */
994 Ignore
, /* Num Lock */
995 Ignore
, /* Scroll Lock */
996 KeyPad
| 7, /* Home */
998 KeyPad
| 9, /* Page Up */
999 Grey
| 2, /* Grey - */
1000 KeyPad
| 4, /* Left */
1001 KeyPad
| 5, /* Keypad 5 */
1002 KeyPad
| 6, /* Right */
1003 Grey
| 3, /* Grey + */
1004 KeyPad
| 1, /* End */
1006 /* --------------- 50 to 5f --------------- */
1007 KeyPad
| 2, /* Down */
1008 KeyPad
| 3, /* Page Down */
1009 KeyPad
| 0, /* Insert */
1010 KeyPad
| 10, /* Delete */
1011 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
1012 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
1013 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
1014 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
1015 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
1016 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
1017 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
1018 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
1019 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
1020 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
1021 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
1022 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
1024 /* --------------- 60 to 6f --------------- */
1025 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
1026 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
1027 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
1028 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
1029 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
1030 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
1031 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
1032 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
1033 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
1034 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
1035 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
1036 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
1037 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
1038 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
1039 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
1040 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
1042 /* --------------- 70 to 7f --------------- */
1043 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
1044 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1045 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1046 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1047 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1048 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1049 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1050 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1051 Alt
| Map
| 1, /* '1' */
1052 Alt
| Map
| 2, /* '2' */
1053 Alt
| Map
| 3, /* '3' */
1054 Alt
| Map
| 4, /* '4' */
1055 Alt
| Map
| 5, /* '5' */
1056 Alt
| Map
| 6, /* '6' */
1057 Alt
| Map
| 7, /* '7' */
1058 Alt
| Map
| 8, /* '8' */
1060 /* --------------- 80 to 8f --------------- */
1061 Alt
| Map
| 9, /* '9' */
1062 Alt
| Map
| 10, /* '0' */
1063 Alt
| Map
| 11, /* '-' */
1064 Alt
| Map
| 12, /* '=' */
1065 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1066 FctKey
| 0xc8, /* F11 */
1067 FctKey
| 0xc9, /* F12 */
1068 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1069 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1070 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1071 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1072 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1073 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1074 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1075 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1076 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1078 /* --------------- 90 to 9f --------------- */
1079 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1080 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1081 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1082 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1083 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1084 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1085 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1086 Alt
| FctKey
| 0x50, /* (Alt) Home */
1087 Alt
| FctKey
| 0x52, /* (Alt) Up */
1088 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1089 Ignore
, /* NO KEY */
1090 Alt
| FctKey
| 0x51, /* (Alt) Left */
1091 Ignore
, /* NO KEY */
1092 Alt
| FctKey
| 0x53, /* (Alt) Right */
1093 Ignore
, /* NO KEY */
1094 Alt
| FctKey
| 0x57, /* (Alt) End */
1096 /* --------------- a0 to af --------------- */
1097 Alt
| KeyPad
| 2, /* (Alt) Down */
1098 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1099 Alt
| KeyPad
| 0, /* (Alt) Insert */
1100 Alt
| KeyPad
| 10, /* (Alt) Delete */
1101 Alt
| Grey
| 0, /* (Alt) Grey / */
1102 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1103 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1106 /* These bit-positions corresponds to values returned by BIOS */
1107 #define SHIFT_P 0x0003 /* two bits! */
1108 #define CTRL_P 0x0004
1109 #define ALT_P 0x0008
1110 #define SCRLOCK_P 0x0010
1111 #define NUMLOCK_P 0x0020
1112 #define CAPSLOCK_P 0x0040
1113 #define ALT_GR_P 0x0800
1114 #define SUPER_P 0x4000 /* pseudo */
1115 #define HYPER_P 0x8000 /* pseudo */
1118 dos_get_modifiers (keymask
)
1125 /* Calculate modifier bits */
1126 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1127 int86 (0x16, ®s
, ®s
);
1131 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1132 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1136 mask
= regs
.h
.al
& (SHIFT_P
|
1137 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1139 /* Do not break international keyboard support. */
1140 /* When Keyb.Com is loaded, the right Alt key is */
1141 /* used for accessing characters like { and } */
1142 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1145 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1148 if (dos_hyper_key
== 1)
1151 modifiers
|= hyper_modifier
;
1153 else if (dos_super_key
== 1)
1156 modifiers
|= super_modifier
;
1160 if (regs
.h
.ah
& 1) /* Left CTRL pressed
1163 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1165 if (dos_hyper_key
== 2)
1168 modifiers
|= hyper_modifier
;
1170 else if (dos_super_key
== 2)
1173 modifiers
|= super_modifier
;
1181 modifiers
|= shift_modifier
;
1183 modifiers
|= ctrl_modifier
;
1185 modifiers
|= meta_modifier
;
1192 #define NUM_RECENT_DOSKEYS (100)
1193 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1194 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1195 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1197 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1198 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1199 Each input key receives two values in this vector: first the ASCII code,\n\
1200 and then the scan code.")
1203 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1206 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1207 return Fvector (total_doskeys
, keys
);
1210 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1211 bcopy (keys
+ recent_doskeys_index
,
1212 XVECTOR (val
)->contents
,
1213 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1215 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1216 recent_doskeys_index
* sizeof (Lisp_Object
));
1221 /* Get a char from keyboard. Function keys are put into the event queue. */
1225 struct input_event event
;
1228 #ifndef HAVE_X_WINDOWS
1229 SCREEN_SET_CURSOR ();
1230 if (!mouse_visible
) mouse_on ();
1233 /* The following condition is equivalent to `kbhit ()', except that
1234 it uses the bios to do its job. This pleases DESQview/X. */
1235 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1236 int86 (0x16, ®s
, ®s
),
1237 (regs
.x
.flags
& 0x40) == 0)
1240 register unsigned char c
;
1241 int sc
, code
, mask
, kp_mode
;
1244 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1245 int86 (0x16, ®s
, ®s
);
1250 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1252 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1253 recent_doskeys_index
= 0;
1254 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1256 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1257 recent_doskeys_index
= 0;
1259 modifiers
= dos_get_modifiers (&mask
);
1261 #ifndef HAVE_X_WINDOWS
1262 if (!NILP (Vdos_display_scancodes
))
1265 sprintf (buf
, "%02x:%02x*%04x",
1266 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1267 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1275 case 10: /* Ctrl Grey Enter */
1276 code
= Ctrl
| Grey
| 4;
1278 case 13: /* Grey Enter */
1281 case '/': /* Grey / */
1291 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1293 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1300 modifiers
|= meta_modifier
;
1302 modifiers
|= ctrl_modifier
;
1304 modifiers
|= shift_modifier
;
1307 switch (code
& 0xf000)
1310 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1312 c
= 0; /* Special */
1325 if (c
== 0) /* ctrl-break */
1327 return c
; /* ALT-nnn */
1329 if (!keyboard_map_all
)
1338 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1339 if (!keyboard_map_all
)
1343 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1344 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1348 code
= keyboard
->shifted
[code
];
1350 modifiers
&= ~shift_modifier
;
1353 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1354 code
= keyboard
->alt_gr
[code
];
1356 code
= keyboard
->unshifted
[code
];
1361 if (c
== 0xe0) /* edit key */
1364 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1365 kp_mode
= dos_keypad_mode
& 0x03;
1367 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1372 if (code
== 10 && dos_decimal_point
)
1373 return dos_decimal_point
;
1374 return keypad_translate_map
[code
].char_code
;
1377 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1381 code
= keypad_translate_map
[code
].meta_code
;
1382 modifiers
= meta_modifier
;
1386 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1393 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1394 if (dos_keypad_mode
& kp_mode
)
1395 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1397 code
= grey_key_translate_map
[code
].char_code
;
1406 event
.kind
= non_ascii_keystroke
;
1408 event
.kind
= ascii_keystroke
;
1410 event
.modifiers
= modifiers
;
1411 XSETFRAME (event
.frame_or_window
, selected_frame
);
1412 event
.timestamp
= event_timestamp ();
1413 kbd_buffer_store_event (&event
);
1418 int but
, press
, x
, y
, ok
;
1420 /* Check for mouse movement *before* buttons. */
1421 mouse_check_moved ();
1423 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1424 for (press
= 0; press
< 2; press
++)
1427 ok
= mouse_pressed (but
, &x
, &y
);
1429 ok
= mouse_released (but
, &x
, &y
);
1432 event
.kind
= mouse_click
;
1434 event
.modifiers
= dos_get_modifiers (0)
1435 | (press
? down_modifier
: up_modifier
);
1438 XSETFRAME (event
.frame_or_window
, selected_frame
);
1439 event
.timestamp
= event_timestamp ();
1440 kbd_buffer_store_event (&event
);
1448 static int prev_get_char
= -1;
1450 /* Return 1 if a key is ready to be read without suspending execution. */
1453 if (prev_get_char
!= -1)
1456 return ((prev_get_char
= dos_rawgetc ()) != -1);
1459 /* Read a key. Return -1 if no key is ready. */
1462 if (prev_get_char
!= -1)
1464 int c
= prev_get_char
;
1469 return dos_rawgetc ();
1472 #ifndef HAVE_X_WINDOWS
1473 /* See xterm.c for more info. */
1475 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1477 register int pix_x
, pix_y
;
1478 register int *x
, *y
;
1479 void /* XRectangle */ *bounds
;
1482 if (bounds
) abort ();
1484 /* Ignore clipping. */
1491 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1494 register int *pix_x
, *pix_y
;
1500 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1503 Actually, I don't know the meaning of all the parameters of the functions
1504 here -- I only know how they are called by xmenu.c. I could of course
1505 grab the nearest Xlib manual (down the hall, second-to-last door on the
1506 left), but I don't think it's worth the effort. */
1513 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1514 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1518 /* Allocate some (more) memory for MENU ensuring that there is room for one
1522 IT_menu_make_room (XMenu
*menu
)
1524 if (menu
->allocated
== 0)
1526 int count
= menu
->allocated
= 10;
1527 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1528 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1529 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1531 else if (menu
->allocated
== menu
->count
)
1533 int count
= menu
->allocated
= menu
->allocated
+ 10;
1535 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1537 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1539 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1543 /* Search the given menu structure for a given pane number. */
1546 IT_menu_search_pane (XMenu
*menu
, int pane
)
1551 for (i
= 0; i
< menu
->count
; i
++)
1552 if (menu
->submenu
[i
])
1554 if (pane
== menu
->panenumber
[i
])
1555 return menu
->submenu
[i
];
1556 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1562 /* Determine how much screen space a given menu needs. */
1565 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1567 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1570 maxheight
= menu
->count
;
1571 for (i
= 0; i
< menu
->count
; i
++)
1573 if (menu
->submenu
[i
])
1575 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1576 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1577 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1580 *width
= menu
->width
+ maxsubwidth
;
1581 *height
= maxheight
;
1584 /* Display MENU at (X,Y) using FACES. */
1587 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1589 int i
, j
, face
, width
;
1593 int enabled
, mousehere
;
1596 width
= menu
->width
;
1597 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1598 ScreenGetCursor (&row
, &col
);
1599 mouse_get_xy (&mx
, &my
);
1601 for (i
= 0; i
< menu
->count
; i
++)
1603 IT_cursor_to (y
+ i
, x
);
1605 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1606 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1607 face
= faces
[enabled
+ mousehere
* 2];
1609 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1610 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
1611 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
1612 for (; j
< width
; j
++)
1613 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1614 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
1615 IT_write_glyphs (text
, width
+ 2);
1618 IT_cursor_to (row
, col
);
1622 /* --------------------------- X Menu emulation ---------------------- */
1624 /* Report availability of menus. */
1632 /* Create a brand new menu structure. */
1635 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
1637 return IT_menu_create ();
1640 /* Create a new pane and place it on the outer-most level. It is not
1641 clear that it should be placed out there, but I don't know what else
1645 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
1652 IT_menu_make_room (menu
);
1653 menu
->submenu
[menu
->count
] = IT_menu_create ();
1654 menu
->text
[menu
->count
] = txt
;
1655 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
1657 if ((len
= strlen (txt
)) > menu
->width
)
1659 return menu
->panecount
;
1662 /* Create a new item in a menu pane. */
1665 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
1666 int foo
, char *txt
, int enable
)
1671 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
1673 IT_menu_make_room (menu
);
1674 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
1675 menu
->text
[menu
->count
] = txt
;
1676 menu
->panenumber
[menu
->count
] = enable
;
1678 if ((len
= strlen (txt
)) > menu
->width
)
1683 /* Decide where the menu would be placed if requested at (X,Y). */
1686 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
1687 int *ulx
, int *uly
, int *width
, int *height
)
1689 IT_menu_calc_size (menu
, width
, height
);
1695 struct IT_menu_state
1697 void *screen_behind
;
1704 /* Display menu, wait for user's response, and return that response. */
1707 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
1708 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
1710 struct IT_menu_state
*state
;
1714 int faces
[4], selectface
;
1715 int leave
, result
, onepane
;
1716 int title_faces
[4]; /* face to display the menu title */
1718 /* Just in case we got here without a mouse present... */
1719 if (have_mouse
<= 0)
1720 return XM_IA_SELECT
;
1722 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
1723 screensize
= screen_size
* 2;
1725 = compute_glyph_face (&the_only_frame
,
1728 intern ("msdos-menu-passive-face")),
1731 = compute_glyph_face (&the_only_frame
,
1734 intern ("msdos-menu-active-face")),
1737 = face_name_id_number (&the_only_frame
, intern ("msdos-menu-select-face"));
1738 faces
[2] = compute_glyph_face (&the_only_frame
, selectface
, faces
[0]);
1739 faces
[3] = compute_glyph_face (&the_only_frame
, selectface
, faces
[1]);
1741 /* Make sure the menu title is always displayed with
1742 `msdos-menu-active-face', no matter where the mouse pointer is. */
1743 for (i
= 0; i
< 4; i
++)
1744 title_faces
[i
] = faces
[3];
1747 state
[0].menu
= menu
;
1749 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
1751 IT_menu_display (menu
, y0
- 1, x0
- 1, title_faces
); /* display menu title */
1752 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
1754 menu
->width
= menu
->submenu
[0]->width
;
1755 state
[0].menu
= menu
->submenu
[0];
1759 state
[0].menu
= menu
;
1761 state
[0].x
= x0
- 1;
1763 state
[0].pane
= onepane
;
1765 mouse_last_x
= -1; /* A hack that forces display. */
1769 if (!mouse_visible
) mouse_on ();
1770 mouse_check_moved ();
1771 if (selected_frame
->mouse_moved
)
1773 selected_frame
->mouse_moved
= 0;
1774 result
= XM_IA_SELECT
;
1775 mouse_get_xy (&x
, &y
);
1776 for (i
= 0; i
< statecount
; i
++)
1777 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
1779 int dy
= y
- state
[i
].y
;
1780 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
1782 if (!state
[i
].menu
->submenu
[dy
])
1783 if (state
[i
].menu
->panenumber
[dy
])
1784 result
= XM_SUCCESS
;
1786 result
= XM_IA_SELECT
;
1787 *pane
= state
[i
].pane
- 1;
1789 /* We hit some part of a menu, so drop extra menus that
1790 have been opened. That does not include an open and
1792 if (i
!= statecount
- 2
1793 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
1794 while (i
!= statecount
- 1)
1798 ScreenUpdate (state
[statecount
].screen_behind
);
1799 xfree (state
[statecount
].screen_behind
);
1801 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
1803 IT_menu_display (state
[i
].menu
,
1807 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
1808 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
1810 ScreenRetrieve (state
[statecount
].screen_behind
1811 = xmalloc (screensize
));
1813 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
1814 state
[statecount
].y
= y
;
1819 IT_menu_display (state
[statecount
- 1].menu
,
1820 state
[statecount
- 1].y
,
1821 state
[statecount
- 1].x
,
1824 for (b
= 0; b
< mouse_button_count
; b
++)
1826 (void) mouse_pressed (b
, &x
, &y
);
1827 if (mouse_released (b
, &x
, &y
))
1833 ScreenUpdate (state
[0].screen_behind
);
1834 while (statecount
--)
1835 xfree (state
[statecount
].screen_behind
);
1839 /* Dispose of a menu. */
1842 XMenuDestroy (Display
*foo
, XMenu
*menu
)
1845 if (menu
->allocated
)
1847 for (i
= 0; i
< menu
->count
; i
++)
1848 if (menu
->submenu
[i
])
1849 XMenuDestroy (foo
, menu
->submenu
[i
]);
1851 xfree (menu
->submenu
);
1852 xfree (menu
->panenumber
);
1858 x_pixel_width (struct frame
*f
)
1860 return FRAME_WIDTH (f
);
1864 x_pixel_height (struct frame
*f
)
1866 return FRAME_HEIGHT (f
);
1868 #endif /* !HAVE_X_WINDOWS */
1870 /* ----------------------- DOS / UNIX conversion --------------------- */
1872 /* Destructively turn backslashes into slashes. */
1875 dostounix_filename (p
)
1886 /* Destructively turn slashes into backslashes. */
1889 unixtodos_filename (p
)
1900 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
1903 getdefdir (drive
, dst
)
1911 regs
.x
.si
= (int) dst
;
1913 intdos (®s
, ®s
);
1914 return !regs
.x
.cflag
;
1917 /* Remove all CR's that are followed by a LF. */
1922 register unsigned char *buf
;
1924 unsigned char *np
= buf
;
1925 unsigned char *startp
= buf
;
1926 unsigned char *endp
= buf
+ n
;
1931 while (buf
< endp
- 1)
1935 if (*(++buf
) != 0x0a)
1946 /* The Emacs root directory as determined by init_environment. */
1948 static char emacsroot
[MAXPATHLEN
];
1951 rootrelativepath (rel
)
1954 static char result
[MAXPATHLEN
+ 10];
1956 strcpy (result
, emacsroot
);
1957 strcat (result
, "/");
1958 strcat (result
, rel
);
1962 /* Define a lot of environment variables if not already defined. Don't
1963 remove anything unless you know what you're doing -- lots of code will
1964 break if one or more of these are missing. */
1967 init_environment (argc
, argv
, skip_args
)
1975 /* Find our root from argv[0]. Assuming argv[0] is, say,
1976 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
1977 root
= alloca (MAXPATHLEN
+ 20);
1978 _fixpath (argv
[0], root
);
1980 len
= strlen (root
);
1981 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
1984 if (len
> 4 && strcmp (root
+ len
- 4, "/bin") == 0)
1985 root
[len
- 4] = '\0';
1987 strcpy (root
, "c:/emacs"); /* Only under debuggers, I think. */
1988 len
= strlen (root
);
1989 strcpy (emacsroot
, root
);
1991 /* We default HOME to our root. */
1992 setenv ("HOME", root
, 0);
1994 /* We default EMACSPATH to root + "/bin". */
1995 strcpy (root
+ len
, "/bin");
1996 setenv ("EMACSPATH", root
, 0);
1998 /* I don't expect anybody to ever use other terminals so the internal
1999 terminal is the default. */
2000 setenv ("TERM", "internal", 0);
2002 #ifdef HAVE_X_WINDOWS
2003 /* Emacs expects DISPLAY to be set. */
2004 setenv ("DISPLAY", "unix:0.0", 0);
2007 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2008 downcase it and mirror the backslashes. */
2009 s
= getenv ("COMSPEC");
2010 if (!s
) s
= "c:/command.com";
2011 t
= alloca (strlen (s
) + 1);
2014 dostounix_filename (t
);
2015 setenv ("SHELL", t
, 0);
2017 /* PATH is also downcased and backslashes mirrored. */
2018 s
= getenv ("PATH");
2020 t
= alloca (strlen (s
) + 3);
2021 /* Current directory is always considered part of MsDos's path but it is
2022 not normally mentioned. Now it is. */
2023 strcat (strcpy (t
, ".;"), s
);
2025 dostounix_filename (t
); /* Not a single file name, but this should work. */
2026 setenv ("PATH", t
, 1);
2028 /* In some sense all dos users have root privileges, so... */
2029 setenv ("USER", "root", 0);
2030 setenv ("NAME", getenv ("USER"), 0);
2032 /* Time zone determined from country code. To make this possible, the
2033 country code may not span more than one time zone. In other words,
2034 in the USA, you lose. */
2036 switch (dos_country_code
)
2038 case 31: /* Belgium */
2039 case 32: /* The Netherlands */
2040 case 33: /* France */
2041 case 34: /* Spain */
2042 case 36: /* Hungary */
2043 case 38: /* Yugoslavia (or what's left of it?) */
2044 case 39: /* Italy */
2045 case 41: /* Switzerland */
2046 case 42: /* Tjekia */
2047 case 45: /* Denmark */
2048 case 46: /* Sweden */
2049 case 47: /* Norway */
2050 case 48: /* Poland */
2051 case 49: /* Germany */
2052 /* Daylight saving from last Sunday in March to last Sunday in
2053 September, both at 2AM. */
2054 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2056 case 44: /* United Kingdom */
2057 case 351: /* Portugal */
2058 case 354: /* Iceland */
2059 setenv ("TZ", "GMT+00", 0);
2061 case 81: /* Japan */
2062 case 82: /* Korea */
2063 setenv ("TZ", "JST-09", 0);
2065 case 90: /* Turkey */
2066 case 358: /* Finland */
2067 setenv ("TZ", "EET-02", 0);
2069 case 972: /* Israel */
2070 /* This is an approximation. (For exact rules, use the
2071 `zoneinfo/israel' file which comes with DJGPP, but you need
2072 to install it in `/usr/share/zoneinfo/' directory first.) */
2073 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2076 init_gettimeofday ();
2081 static int break_stat
; /* BREAK check mode status. */
2082 static int stdin_stat
; /* stdin IOCTL status. */
2084 /* These must be global. */
2085 static _go32_dpmi_seginfo ctrl_break_vector
;
2086 static _go32_dpmi_registers ctrl_break_regs
;
2087 static int ctrlbreakinstalled
= 0;
2089 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2092 ctrl_break_func (regs
)
2093 _go32_dpmi_registers
*regs
;
2099 install_ctrl_break_check ()
2101 if (!ctrlbreakinstalled
)
2103 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2104 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2105 ctrlbreakinstalled
= 1;
2106 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2107 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2109 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2114 * Turn off Dos' Ctrl-C checking and inhibit interpretation of
2115 * control chars by Dos.
2116 * Determine the keyboard type.
2122 union REGS inregs
, outregs
;
2123 static int first_time
= 1;
2125 break_stat
= getcbrk ();
2127 install_ctrl_break_check ();
2132 int86 (0x15, &inregs
, &outregs
);
2133 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2137 if (internal_terminal
2138 #ifdef HAVE_X_WINDOWS
2139 && inhibit_window_system
2143 inregs
.x
.ax
= 0x0021;
2144 int86 (0x33, &inregs
, &outregs
);
2145 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2148 /* Reportedly, the above doesn't work for some mouse drivers. There
2149 is an additional detection method that should work, but might be
2150 a little slower. Use that as an alternative. */
2151 inregs
.x
.ax
= 0x0000;
2152 int86 (0x33, &inregs
, &outregs
);
2153 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2158 have_mouse
= 1; /* enable mouse */
2161 if (outregs
.x
.bx
== 3)
2163 mouse_button_count
= 3;
2164 mouse_button_translate
[0] = 0; /* Left */
2165 mouse_button_translate
[1] = 2; /* Middle */
2166 mouse_button_translate
[2] = 1; /* Right */
2170 mouse_button_count
= 2;
2171 mouse_button_translate
[0] = 0;
2172 mouse_button_translate
[1] = 1;
2174 mouse_position_hook
= &mouse_get_pos
;
2182 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2183 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2184 intdos (&inregs
, &outregs
);
2185 stdin_stat
= outregs
.h
.dl
;
2187 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
2188 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
2189 intdos (&inregs
, &outregs
);
2190 return !outregs
.x
.cflag
;
2193 /* Restore status of standard input and Ctrl-C checking. */
2197 union REGS inregs
, outregs
;
2199 setcbrk (break_stat
);
2202 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
2203 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2204 inregs
.x
.dx
= stdin_stat
;
2205 intdos (&inregs
, &outregs
);
2206 return !outregs
.x
.cflag
;
2210 /* Run command as specified by ARGV in directory DIR.
2211 The command is run with input from TEMPIN, output to
2212 file TEMPOUT and stderr to TEMPERR. */
2214 run_msdos_command (argv
, dir
, tempin
, tempout
, temperr
)
2215 unsigned char **argv
;
2217 int tempin
, tempout
, temperr
;
2219 char *saveargv1
, *saveargv2
, **envv
;
2220 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
2221 int msshell
, result
= -1;
2222 int in
, out
, inbak
, outbak
, errbak
;
2226 /* Get current directory as MSDOS cwd is not per-process. */
2229 cmd
= Ffile_name_nondirectory (build_string (argv
[0]));
2230 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
2231 && !strcmp ("-c", argv
[1]);
2234 saveargv1
= argv
[1];
2235 saveargv2
= argv
[2];
2239 char *p
= alloca (strlen (argv
[2]) + 1);
2241 strcpy (argv
[2] = p
, saveargv2
);
2242 while (*p
&& isspace (*p
))
2244 while (*p
&& !isspace (*p
))
2252 /* Build the environment array. */
2254 extern Lisp_Object Vprocess_environment
;
2255 Lisp_Object tmp
, lst
;
2258 lst
= Vprocess_environment
;
2259 len
= XFASTINT (Flength (lst
));
2261 envv
= alloca ((len
+ 1) * sizeof (char *));
2262 for (i
= 0; i
< len
; i
++)
2266 CHECK_STRING (tmp
, 0);
2267 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
2268 strcpy (envv
[i
], XSTRING (tmp
)->data
);
2270 envv
[len
] = (char *) 0;
2274 chdir (XSTRING (dir
)->data
);
2278 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
2279 goto done
; /* Allocation might fail due to lack of descriptors. */
2282 mouse_get_xy (&x
, &y
);
2284 dos_ttcooked (); /* do it here while 0 = stdin */
2290 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
2303 mouse_moveto (x
, y
);
2310 argv
[1] = saveargv1
;
2311 argv
[2] = saveargv2
;
2319 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
2324 /* ------------------------- Compatibility functions -------------------
2330 * Hostnames for a pc are not really funny,
2331 * but they are used in change log so we emulate the best we can.
2334 gethostname (p
, size
)
2338 char *q
= egetenv ("HOSTNAME");
2345 /* When time zones are set from Ms-Dos too many C-libraries are playing
2346 tricks with time values. We solve this by defining our own version
2347 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2348 once and after each call to `tzset' with TZ changed. That is
2349 accomplished by aliasing tzset to init_gettimeofday. */
2351 static struct tm time_rec
;
2354 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
2362 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
2366 time_rec
.tm_year
= d
.da_year
- 1900;
2367 time_rec
.tm_mon
= d
.da_mon
- 1;
2368 time_rec
.tm_mday
= d
.da_day
;
2371 time_rec
.tm_hour
= t
.ti_hour
;
2372 time_rec
.tm_min
= t
.ti_min
;
2373 time_rec
.tm_sec
= t
.ti_sec
;
2376 tm
.tm_gmtoff
= dos_timezone_offset
;
2378 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
2379 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
2381 /* Ignore tzp; it's obsolescent. */
2387 * A list of unimplemented functions that we silently ignore.
2390 unsigned alarm (s
) unsigned s
; {}
2391 fork () { return 0; }
2392 int kill (x
, y
) int x
, y
; { return -1; }
2394 void volatile pause () {}
2396 setpgrp () {return 0; }
2397 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
2398 sigsetmask (x
) int x
; { return 0; }
2399 unrequest_sigio () {}
2402 #include "sysselect.h"
2404 static struct time last_time
= {120, 120, 120, 120};
2405 static int modeline_time_displayed
= 0;
2407 Lisp_Object Vdos_display_time
;
2413 int sec
, min
, hour
, hund
;
2421 /* Any chance of not getting here 24 hours or more since last time? */
2422 if (hour
== last_time
.ti_hour
2423 && min
== last_time
.ti_min
2424 && sec
== last_time
.ti_sec
)
2427 if (!NILP (Vdos_display_time
))
2430 Lisp_Object dti
= XSYMBOL (Fintern_soft (build_string ("display-time-interval"), Qnil
))->value
;
2431 int delta_time
= ((hour
- last_time
.ti_hour
) * 3600
2432 + (min
- last_time
.ti_min
) * 60
2433 + (sec
- last_time
.ti_sec
));
2435 /* Who knows what the user may put into `display-time-interval'? */
2436 if (!INTEGERP (dti
) || (interval
= XINT (dti
)) <= 0)
2439 /* When it's time to renew the display, fake a `wakeup' call. */
2440 if (!modeline_time_displayed
/* first time */
2441 || delta_time
>= interval
/* or if we were busy for a long time */
2442 || interval
== 1 /* and every `interval' seconds hence */
2443 || interval
== 60 && sec
== 0 /* (usual cases first) */
2444 || (hour
* 3600 + min
* 60 + sec
) % interval
== 0)
2445 call2 (intern ("display-time-filter"), Qnil
,
2446 build_string ("Wake up!\n"));
2448 modeline_time_displayed
= 1;
2450 else if (modeline_time_displayed
)
2452 modeline_time_displayed
= 0;
2453 Fset (intern ("display-time-string"), build_string (""));
2455 /* Force immediate redisplay of modelines. */
2456 update_mode_lines
++;
2457 redisplay_preserve_echo_area ();
2463 /* Only event queue is checked. */
2465 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
2467 SELECT_TYPE
*rfds
, *wfds
, *efds
;
2468 EMACS_TIME
*timeout
;
2471 long timeoutval
, clnow
, cllast
;
2477 check_input
= FD_ISSET (0, rfds
);
2488 /* If we are looking only for the terminal, with no timeout,
2489 just read it and wait -- that's more efficient. */
2493 check_timer (&t
); /* check timer even if some input is pending */
2494 while (!detect_input_pending ());
2498 timeoutval
= EMACS_SECS (*timeout
) * 100 + EMACS_USECS (*timeout
) / 10000;
2500 cllast
= t
.ti_sec
* 100 + t
.ti_hund
;
2502 while (!check_input
|| !detect_input_pending ())
2505 clnow
= t
.ti_sec
* 100 + t
.ti_hund
;
2506 if (clnow
< cllast
) /* time wrap */
2507 timeoutval
-= clnow
+ 6000 - cllast
;
2509 timeoutval
-= clnow
- cllast
;
2510 if (timeoutval
<= 0) /* Stop on timer being cleared */
2522 * Define overlaid functions:
2524 * chdir -> sys_chdir
2525 * tzset -> init_gettimeofday
2526 * abort -> dos_abort
2531 extern int chdir ();
2537 int len
= strlen (path
);
2538 char *tmp
= (char *)path
;
2540 if (*tmp
&& tmp
[1] == ':')
2542 if (getdisk () != tolower (tmp
[0]) - 'a')
2543 setdisk (tolower (tmp
[0]) - 'a');
2544 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
2548 if (len
> 1 && (tmp
[len
- 1] == '/'))
2550 char *tmp1
= (char *) alloca (len
+ 1);
2561 extern void tzset (void);
2564 init_gettimeofday ()
2570 ltm
= gtm
= time (NULL
);
2571 ltm
= mktime (lstm
= localtime (<m
));
2572 gtm
= mktime (gmtime (>m
));
2573 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
2574 time_rec
.tm_isdst
= lstm
->tm_isdst
;
2575 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
2582 dos_abort (file
, line
)
2586 char buffer1
[200], buffer2
[400];
2589 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
2590 for (i
= j
= 0; buffer1
[i
]; i
++) {
2591 buffer2
[j
++] = buffer1
[i
];
2592 buffer2
[j
++] = 0x70;
2594 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
2595 ScreenSetCursor (2, 0);
2603 ScreenSetCursor (10, 0);
2604 cputs ("\r\n\nEmacs aborted!\r\n");
2611 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
2612 staticpro (&recent_doskeys
);
2614 defsubr (&Srecent_doskeys
);
2616 DEFVAR_LISP ("dos-display-time", &Vdos_display_time
,
2617 "*When non-nil, `display-time' is in effect on DOS systems.");
2618 Vdos_display_time
= Qnil
;