1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994 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
;
253 static int term_setup_done
;
255 /* Similar to the_only_frame. */
256 struct x_display the_only_x_display
;
258 /* This is never dereferenced. */
259 Display
*x_current_display
;
262 #define SCREEN_SET_CURSOR() \
263 if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \
264 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
267 dos_direct_output (y
, x
, buf
, len
)
273 int t
= (int) ScreenPrimary
+ 2 * (x
+ y
* screen_size_X
);
276 dosmemput (buf
++, 1, t
);
282 /* Flash the screen as a substitute for BEEPs. */
286 do_visible_bell (xorattr
)
287 unsigned char xorattr
;
292 movl _ScreenPrimary,%%eax
299 xorb %%al,%%gs:(%%ebx)
315 : "m" (xorattr
), "g" (screen_size
)
316 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
320 ScreenVisualBell (void)
322 /* This creates an xor-mask that will swap the default fore- and
323 background colors. */
324 do_visible_bell (((the_only_x_display
.foreground_pixel
325 ^ the_only_x_display
.background_pixel
)
330 #ifndef HAVE_X_WINDOWS
333 * If we write a character in the position where the mouse is,
334 * the mouse cursor may need to be refreshed.
345 mouse_get_xy (&x
, &y
);
346 if (y
!= new_pos_Y
|| x
< new_pos_X
)
362 union REGS inregs
, outregs
;
365 intdos (&inregs
, &outregs
);
370 IT_set_face (int face
)
373 extern struct face
*intern_face (/* FRAME_PTR, struct face * */);
375 if (face
== 1 || (face
== 0 && highlight
))
376 fp
= FRAME_MODE_LINE_FACE (foo
);
377 else if (face
<= 0 || face
>= FRAME_N_COMPUTED_FACES (foo
))
378 fp
= FRAME_DEFAULT_FACE (foo
);
380 fp
= intern_face (selected_frame
, FRAME_COMPUTED_FACES (foo
)[face
]);
382 fprintf (termscript
, "<FACE:%d:%d>", FACE_FOREGROUND (fp
), FACE_BACKGROUND (fp
));
384 ScreenAttrib
= (FACE_BACKGROUND (fp
) << 4) | FACE_FOREGROUND (fp
);
388 IT_write_glyphs (GLYPH
*str
, int len
)
392 unsigned char *buf
, *bp
;
394 if (len
== 0) return;
396 buf
= bp
= alloca (len
* 2);
400 newface
= FAST_GLYPH_FACE (*str
);
401 if (newface
!= screen_face
)
402 IT_set_face (newface
);
403 ch
= FAST_GLYPH_CHAR (*str
);
404 *bp
++ = (unsigned char)ch
;
405 *bp
++ = ScreenAttrib
;
408 fputc (ch
, termscript
);
413 dosmemput (buf
, 2 * len
,
414 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
419 IT_clear_end_of_line (first_unused
)
426 fprintf (termscript
, "<CLR:EOL>");
427 i
= (j
= screen_size_X
- new_pos_X
) * 2;
428 spaces
= sp
= alloca (i
);
433 *sp
++ = ScreenAttrib
;
437 dosmemput (spaces
, i
,
438 (int)ScreenPrimary
+ 2 * (new_pos_X
+ screen_size_X
* new_pos_Y
));
442 IT_clear_screen (void)
445 fprintf (termscript
, "<CLR:SCR>");
449 new_pos_X
= new_pos_Y
= 0;
453 IT_clear_to_end (void)
456 fprintf (termscript
, "<CLR:EOS>");
458 while (new_pos_Y
< screen_size_Y
) {
460 IT_clear_end_of_line (0);
466 IT_cursor_to (int y
, int x
)
469 fprintf (termscript
, "\n<XY=%dx%d>", x
, y
);
475 IT_reassert_line_highlight (new, vpos
)
479 IT_set_face (0); /* To possibly clear the highlighting. */
483 IT_change_line_highlight (new_highlight
, vpos
, first_unused_hpos
)
485 highlight
= new_highlight
;
486 IT_set_face (0); /* To possibly clear the highlighting. */
487 IT_cursor_to (vpos
, 0);
488 IT_clear_end_of_line (first_unused_hpos
);
495 IT_set_face (0); /* To possibly clear the highlighting. */
504 /* This was more or less copied from xterm.c */
506 IT_set_menu_bar_lines (window
, n
)
510 struct window
*w
= XWINDOW (window
);
512 XSETFASTINT (w
->top
, XFASTINT (w
->top
) + n
);
513 XSETFASTINT (w
->height
, XFASTINT (w
->height
) - n
);
515 /* Handle just the top child in a vertical split. */
516 if (!NILP (w
->vchild
))
517 IT_set_menu_bar_lines (w
->vchild
, n
);
519 /* Adjust all children in a horizontal split. */
520 for (window
= w
->hchild
; !NILP (window
); window
= w
->next
)
522 w
= XWINDOW (window
);
523 IT_set_menu_bar_lines (window
, n
);
528 * IT_set_terminal_modes is called when emacs is started,
529 * resumed, and whenever the screen is redrawn!
533 IT_set_terminal_modes (void)
540 fprintf (termscript
, "\n<SET_TERM>");
543 screen_size_X
= ScreenCols ();
544 screen_size_Y
= ScreenRows ();
545 screen_size
= screen_size_X
* screen_size_Y
;
547 new_pos_X
= new_pos_Y
= 0;
548 current_pos_X
= current_pos_Y
= -1;
554 startup_screen_size_X
= screen_size_X
;
555 startup_screen_size_Y
= screen_size_Y
;
557 ScreenGetCursor (&startup_pos_Y
, &startup_pos_X
);
558 ScreenRetrieve (startup_screen_buffer
= xmalloc (screen_size
* 2));
561 fprintf (termscript
, "<SCREEN SAVED>\n");
565 * IT_reset_terminal_modes is called when emacs is
566 * suspended or killed.
570 IT_reset_terminal_modes (void)
573 fprintf (termscript
, "\n<RESET_TERM>");
577 if (!term_setup_done
)
580 ScreenUpdate (startup_screen_buffer
);
581 ScreenSetCursor (startup_pos_Y
, startup_pos_X
);
582 xfree (startup_screen_buffer
);
585 fprintf (termscript
, "<SCREEN RESTORED>\n");
591 IT_set_terminal_window (void)
596 IT_set_frame_parameters (frame
, alist
)
602 extern unsigned long load_color ();
603 FRAME_PTR f
= (FRAME_PTR
) &the_only_frame
;
606 for (tail
= alist
; CONSP (tail
); tail
= Fcdr (tail
))
608 Lisp_Object elt
, prop
, val
;
613 CHECK_SYMBOL (prop
, 1);
615 if (EQ (prop
, intern ("foreground-color")))
617 unsigned long new_color
= load_color (f
, val
);
620 FRAME_FOREGROUND_PIXEL (f
) = new_color
;
624 else if (EQ (prop
, intern ("background-color")))
626 unsigned long new_color
= load_color (f
, val
);
629 FRAME_BACKGROUND_PIXEL (f
) = new_color
& ~8;
633 else if (EQ (prop
, intern ("menu-bar-lines")))
636 int old
= FRAME_MENU_BAR_LINES (the_only_frame
);
642 FRAME_MENU_BAR_LINES (f
) = new;
643 IT_set_menu_bar_lines (the_only_frame
.root_window
, new - old
);
649 recompute_basic_faces (f
);
650 Fredraw_frame (Fselected_frame ());
654 #endif /* !HAVE_X_WINDOWS */
657 /* Do we need the internal terminal? */
659 internal_terminal_init ()
661 char *term
= getenv ("TERM");
664 #ifdef HAVE_X_WINDOWS
665 if (!inhibit_window_system
)
670 = (!noninteractive
) && term
&& !strcmp (term
, "internal");
672 if (getenv ("EMACSTEST"))
673 termscript
= fopen (getenv ("EMACSTEST"), "wt");
675 #ifndef HAVE_X_WINDOWS
676 if (!internal_terminal
|| inhibit_window_system
)
678 the_only_frame
.output_method
= output_termcap
;
682 Vwindow_system
= intern ("pc");
683 Vwindow_system_version
= make_number (1);
685 bzero (&the_only_x_display
, sizeof the_only_x_display
);
686 the_only_x_display
.background_pixel
= 7; /* White */
687 the_only_x_display
.foreground_pixel
= 0; /* Black */
688 colors
= getenv ("EMACSCOLORS");
689 if (colors
&& strlen (colors
) >= 2)
691 the_only_x_display
.foreground_pixel
= colors
[0] & 0x07;
692 the_only_x_display
.background_pixel
= colors
[1] & 0x07;
694 the_only_x_display
.line_height
= 1;
695 the_only_frame
.display
.x
= &the_only_x_display
;
696 the_only_frame
.output_method
= output_msdos_raw
;
698 init_frame_faces ((FRAME_PTR
) &the_only_frame
);
700 ring_bell_hook
= IT_ring_bell
;
701 write_glyphs_hook
= IT_write_glyphs
;
702 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
703 clear_to_end_hook
= IT_clear_to_end
;
704 clear_end_of_line_hook
= IT_clear_end_of_line
;
705 clear_frame_hook
= IT_clear_screen
;
706 change_line_highlight_hook
= IT_change_line_highlight
;
707 update_begin_hook
= IT_update_begin
;
708 update_end_hook
= IT_update_end
;
709 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
711 /* These hooks are called by term.c without being checked. */
712 set_terminal_modes_hook
= IT_set_terminal_modes
;
713 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
714 set_terminal_window_hook
= IT_set_terminal_window
;
718 dos_get_saved_screen (screen
, rows
, cols
)
723 #ifndef HAVE_X_WINDOWS
724 *screen
= startup_screen_buffer
;
725 *cols
= startup_screen_size_X
;
726 *rows
= startup_screen_size_Y
;
735 /* ----------------------- Keyboard control ----------------------
737 * Keymaps reflect the following keyboard layout:
739 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
740 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
741 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
742 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
746 static int extended_kbd
; /* 101 (102) keyboard present. */
748 struct dos_keyboard_map
756 static struct dos_keyboard_map us_keyboard
= {
758 /* 01234567890123456789012345678901234567890 12345678901234 */
759 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
760 /* 0123456789012345678901234567890123456789 012345678901234 */
761 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
762 0 /* no Alt-Gr key */
765 static struct dos_keyboard_map fr_keyboard
= {
767 /* 012 3456789012345678901234567890123456789012345678901234 */
768 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
769 /* 0123456789012345678901234567890123456789012345678901234 */
770 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
771 /* 01234567 89012345678901234567890123456789012345678901234 */
775 static struct dos_keyboard_map dk_keyboard
= {
777 /* 0123456789012345678901234567890123456789012345678901234 */
778 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
779 /* 01 23456789012345678901234567890123456789012345678901234 */
780 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
781 /* 0123456789012345678901234567890123456789012345678901234 */
785 static struct keyboard_layout_list
788 struct dos_keyboard_map
*keyboard_map
;
789 } keyboard_layout_list
[] =
796 static struct dos_keyboard_map
*keyboard
;
797 static int keyboard_map_all
;
800 dos_set_keyboard (code
, always
)
805 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
806 if (code
== keyboard_layout_list
[i
].country_code
)
808 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
809 keyboard_map_all
= always
;
810 dos_keyboard_layout
= code
;
816 #define Ignore 0x0000
817 #define Normal 0x0000 /* normal key - alt changes scan-code */
818 #define FctKey 0x1000 /* func key if c == 0, else c */
819 #define Special 0x2000 /* func key even if c != 0 */
820 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
821 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
822 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
823 #define Grey 0x6000 /* Grey keypad key */
825 #define Alt 0x0100 /* alt scan-code */
826 #define Ctrl 0x0200 /* ctrl scan-code */
827 #define Shift 0x0400 /* shift scan-code */
831 unsigned char char_code
; /* normal code */
832 unsigned char meta_code
; /* M- code */
833 unsigned char keypad_code
; /* keypad code */
834 unsigned char editkey_code
; /* edit key */
835 } keypad_translate_map
[] = {
836 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
837 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
838 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
839 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
840 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
841 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
842 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
843 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
844 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
845 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
846 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
851 unsigned char char_code
; /* normal code */
852 unsigned char keypad_code
; /* keypad code */
853 } grey_key_translate_map
[] = {
854 '/', 0xaf, /* kp-decimal */
855 '*', 0xaa, /* kp-multiply */
856 '-', 0xad, /* kp-subtract */
857 '+', 0xab, /* kp-add */
858 '\r', 0x8d /* kp-enter */
861 static unsigned short
862 ibmpc_translate_map
[] =
864 /* --------------- 00 to 0f --------------- */
865 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
866 Alt
| ModFct
| 0x1b, /* Escape */
867 Normal
| 1, /* '1' */
868 Normal
| 2, /* '2' */
869 Normal
| 3, /* '3' */
870 Normal
| 4, /* '4' */
871 Normal
| 5, /* '5' */
872 Normal
| 6, /* '6' */
873 Normal
| 7, /* '7' */
874 Normal
| 8, /* '8' */
875 Normal
| 9, /* '9' */
876 Normal
| 10, /* '0' */
877 Normal
| 11, /* '-' */
878 Normal
| 12, /* '=' */
879 Special
| 0x08, /* Backspace */
880 ModFct
| 0x74, /* Tab/Backtab */
882 /* --------------- 10 to 1f --------------- */
895 ModFct
| 0x0d, /* Return */
900 /* --------------- 20 to 2f --------------- */
911 Ignore
, /* Left shift */
918 /* --------------- 30 to 3f --------------- */
925 Ignore
, /* Right shift */
926 Grey
| 1, /* Grey * */
928 Normal
| ' ', /* ' ' */
929 Ignore
, /* Caps Lock */
930 FctKey
| 0xbe, /* F1 */
931 FctKey
| 0xbf, /* F2 */
932 FctKey
| 0xc0, /* F3 */
933 FctKey
| 0xc1, /* F4 */
934 FctKey
| 0xc2, /* F5 */
936 /* --------------- 40 to 4f --------------- */
937 FctKey
| 0xc3, /* F6 */
938 FctKey
| 0xc4, /* F7 */
939 FctKey
| 0xc5, /* F8 */
940 FctKey
| 0xc6, /* F9 */
941 FctKey
| 0xc7, /* F10 */
942 Ignore
, /* Num Lock */
943 Ignore
, /* Scroll Lock */
944 KeyPad
| 7, /* Home */
946 KeyPad
| 9, /* Page Up */
947 Grey
| 2, /* Grey - */
948 KeyPad
| 4, /* Left */
949 KeyPad
| 5, /* Keypad 5 */
950 KeyPad
| 6, /* Right */
951 Grey
| 3, /* Grey + */
952 KeyPad
| 1, /* End */
954 /* --------------- 50 to 5f --------------- */
955 KeyPad
| 2, /* Down */
956 KeyPad
| 3, /* Page Down */
957 KeyPad
| 0, /* Insert */
958 KeyPad
| 10, /* Delete */
959 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
960 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
961 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
962 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
963 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
964 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
965 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
966 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
967 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
968 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
969 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
970 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
972 /* --------------- 60 to 6f --------------- */
973 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
974 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
975 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
976 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
977 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
978 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
979 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
980 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
981 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
982 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
983 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
984 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
985 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
986 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
987 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
988 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
990 /* --------------- 70 to 7f --------------- */
991 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
992 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
993 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
994 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
995 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
996 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
997 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
998 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
999 Alt
| Map
| 1, /* '1' */
1000 Alt
| Map
| 2, /* '2' */
1001 Alt
| Map
| 3, /* '3' */
1002 Alt
| Map
| 4, /* '4' */
1003 Alt
| Map
| 5, /* '5' */
1004 Alt
| Map
| 6, /* '6' */
1005 Alt
| Map
| 7, /* '7' */
1006 Alt
| Map
| 8, /* '8' */
1008 /* --------------- 80 to 8f --------------- */
1009 Alt
| Map
| 9, /* '9' */
1010 Alt
| Map
| 10, /* '0' */
1011 Alt
| Map
| 11, /* '-' */
1012 Alt
| Map
| 12, /* '=' */
1013 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1014 FctKey
| 0xc8, /* F11 */
1015 FctKey
| 0xc9, /* F12 */
1016 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1017 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1018 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1019 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1020 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1021 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1022 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1023 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1024 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1026 /* --------------- 90 to 9f --------------- */
1027 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1028 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1029 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1030 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1031 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1032 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1033 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1034 Alt
| FctKey
| 0x50, /* (Alt) Home */
1035 Alt
| FctKey
| 0x52, /* (Alt) Up */
1036 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1037 Ignore
, /* NO KEY */
1038 Alt
| FctKey
| 0x51, /* (Alt) Left */
1039 Ignore
, /* NO KEY */
1040 Alt
| FctKey
| 0x53, /* (Alt) Right */
1041 Ignore
, /* NO KEY */
1042 Alt
| FctKey
| 0x57, /* (Alt) End */
1044 /* --------------- a0 to af --------------- */
1045 Alt
| KeyPad
| 2, /* (Alt) Down */
1046 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1047 Alt
| KeyPad
| 0, /* (Alt) Insert */
1048 Alt
| KeyPad
| 10, /* (Alt) Delete */
1049 Alt
| Grey
| 0, /* (Alt) Grey / */
1050 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1051 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1054 /* These bit-positions corresponds to values returned by BIOS */
1055 #define SHIFT_P 0x0003 /* two bits! */
1056 #define CTRL_P 0x0004
1057 #define ALT_P 0x0008
1058 #define SCRLOCK_P 0x0010
1059 #define NUMLOCK_P 0x0020
1060 #define CAPSLOCK_P 0x0040
1061 #define ALT_GR_P 0x0800
1062 #define SUPER_P 0x4000 /* pseudo */
1063 #define HYPER_P 0x8000 /* pseudo */
1066 dos_get_modifiers (keymask
)
1073 /* Calculate modifier bits */
1074 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1075 int86 (0x16, ®s
, ®s
);
1079 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1080 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1084 mask
= regs
.h
.al
& (SHIFT_P
|
1085 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1087 /* Do not break international keyboard support. */
1088 /* When Keyb.Com is loaded, the right Alt key is */
1089 /* used for accessing characters like { and } */
1090 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1093 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1096 if (dos_hyper_key
== 1)
1099 modifiers
|= hyper_modifier
;
1101 else if (dos_super_key
== 1)
1104 modifiers
|= super_modifier
;
1108 if (regs
.h
.ah
& 1) /* Left CTRL pressed
1111 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1113 if (dos_hyper_key
== 2)
1116 modifiers
|= hyper_modifier
;
1118 else if (dos_super_key
== 2)
1121 modifiers
|= super_modifier
;
1129 modifiers
|= shift_modifier
;
1131 modifiers
|= ctrl_modifier
;
1133 modifiers
|= meta_modifier
;
1140 #define NUM_RECENT_DOSKEYS (100)
1141 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1142 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1143 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1145 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1146 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1147 Each input key receives two values in this vector: first the ASCII code,\n\
1148 and then the scan code.")
1151 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1154 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1155 return Fvector (total_doskeys
, keys
);
1158 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1159 bcopy (keys
+ recent_doskeys_index
,
1160 XVECTOR (val
)->contents
,
1161 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1163 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1164 recent_doskeys_index
* sizeof (Lisp_Object
));
1169 /* Get a char from keyboard. Function keys are put into the event queue. */
1173 struct input_event event
;
1176 #ifndef HAVE_X_WINDOWS
1177 SCREEN_SET_CURSOR ();
1178 if (!mouse_visible
) mouse_on ();
1181 /* The following condition is equivalent to `kbhit ()', except that
1182 it uses the bios to do its job. This pleases DESQview/X. */
1183 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1184 int86 (0x16, ®s
, ®s
),
1185 (regs
.x
.flags
& 0x40) == 0)
1188 register unsigned char c
;
1189 int sc
, code
, mask
, kp_mode
;
1192 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1193 int86 (0x16, ®s
, ®s
);
1198 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1200 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1201 recent_doskeys_index
= 0;
1202 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1204 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1205 recent_doskeys_index
= 0;
1207 modifiers
= dos_get_modifiers (&mask
);
1209 #ifndef HAVE_X_WINDOWS
1210 if (!NILP (Vdos_display_scancodes
))
1213 sprintf (buf
, "%02x:%02x*%04x",
1214 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1215 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1223 case 10: /* Ctrl Grey Enter */
1224 code
= Ctrl
| Grey
| 4;
1226 case 13: /* Grey Enter */
1229 case '/': /* Grey / */
1239 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1241 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1248 modifiers
|= meta_modifier
;
1250 modifiers
|= ctrl_modifier
;
1252 modifiers
|= shift_modifier
;
1255 switch (code
& 0xf000)
1258 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1260 c
= 0; /* Special */
1273 if (c
== 0) /* ctrl-break */
1275 return c
; /* ALT-nnn */
1277 if (!keyboard_map_all
)
1286 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1287 if (!keyboard_map_all
)
1291 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1292 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1296 code
= keyboard
->shifted
[code
];
1298 modifiers
&= ~shift_modifier
;
1301 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1302 code
= keyboard
->alt_gr
[code
];
1304 code
= keyboard
->unshifted
[code
];
1309 if (c
== 0xe0) /* edit key */
1312 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1313 kp_mode
= dos_keypad_mode
& 0x03;
1315 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1320 if (code
== 10 && dos_decimal_point
)
1321 return dos_decimal_point
;
1322 return keypad_translate_map
[code
].char_code
;
1325 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1329 code
= keypad_translate_map
[code
].meta_code
;
1330 modifiers
= meta_modifier
;
1334 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1341 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1342 if (dos_keypad_mode
& kp_mode
)
1343 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1345 code
= grey_key_translate_map
[code
].char_code
;
1354 event
.kind
= non_ascii_keystroke
;
1356 event
.kind
= ascii_keystroke
;
1358 event
.modifiers
= modifiers
;
1359 XSETFRAME (event
.frame_or_window
, selected_frame
);
1360 event
.timestamp
= event_timestamp ();
1361 kbd_buffer_store_event (&event
);
1366 int but
, press
, x
, y
, ok
;
1368 /* Check for mouse movement *before* buttons. */
1369 mouse_check_moved ();
1371 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1372 for (press
= 0; press
< 2; press
++)
1375 ok
= mouse_pressed (but
, &x
, &y
);
1377 ok
= mouse_released (but
, &x
, &y
);
1380 event
.kind
= mouse_click
;
1382 event
.modifiers
= dos_get_modifiers (0)
1383 | (press
? down_modifier
: up_modifier
);
1386 XSETFRAME (event
.frame_or_window
, selected_frame
);
1387 event
.timestamp
= event_timestamp ();
1388 kbd_buffer_store_event (&event
);
1396 static int prev_get_char
= -1;
1398 /* Return 1 if a key is ready to be read without suspending execution. */
1401 if (prev_get_char
!= -1)
1404 return ((prev_get_char
= dos_rawgetc ()) != -1);
1407 /* Read a key. Return -1 if no key is ready. */
1410 if (prev_get_char
!= -1)
1412 int c
= prev_get_char
;
1417 return dos_rawgetc ();
1420 #ifndef HAVE_X_WINDOWS
1421 /* See xterm.c for more info. */
1423 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1425 register int pix_x
, pix_y
;
1426 register int *x
, *y
;
1427 void /* XRectangle */ *bounds
;
1430 if (bounds
) abort ();
1432 /* Ignore clipping. */
1439 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1442 register int *pix_x
, *pix_y
;
1448 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1451 Actually, I don't know the meaning of all the parameters of the functions
1452 here -- I only know how they are called by xmenu.c. I could of course
1453 grab the nearest Xlib manual (down the hall, second-to-last door on the
1454 left), but I don't think it's worth the effort. */
1461 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1462 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1466 /* Allocate some (more) memory for MENU ensuring that there is room for one
1470 IT_menu_make_room (XMenu
*menu
)
1472 if (menu
->allocated
== 0)
1474 int count
= menu
->allocated
= 10;
1475 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1476 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1477 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1479 else if (menu
->allocated
== menu
->count
)
1481 int count
= menu
->allocated
= menu
->allocated
+ 10;
1483 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1485 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1487 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1491 /* Search the given menu structure for a given pane number. */
1494 IT_menu_search_pane (XMenu
*menu
, int pane
)
1499 for (i
= 0; i
< menu
->count
; i
++)
1500 if (menu
->submenu
[i
])
1502 if (pane
== menu
->panenumber
[i
])
1503 return menu
->submenu
[i
];
1504 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1510 /* Determine how much screen space a given menu needs. */
1513 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1515 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1518 maxheight
= menu
->count
;
1519 for (i
= 0; i
< menu
->count
; i
++)
1521 if (menu
->submenu
[i
])
1523 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1524 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1525 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1528 *width
= menu
->width
+ maxsubwidth
;
1529 *height
= maxheight
;
1532 /* Display MENU at (X,Y) using FACES. */
1535 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1537 int i
, j
, face
, width
;
1541 int enabled
, mousehere
;
1544 width
= menu
->width
;
1545 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1546 ScreenGetCursor (&row
, &col
);
1547 mouse_get_xy (&mx
, &my
);
1549 for (i
= 0; i
< menu
->count
; i
++)
1551 IT_cursor_to (y
+ i
, x
);
1553 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1554 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1555 face
= faces
[enabled
+ mousehere
* 2];
1557 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1558 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
1559 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
1560 for (; j
< width
; j
++)
1561 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1562 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
1563 IT_write_glyphs (text
, width
+ 2);
1566 IT_cursor_to (row
, col
);
1570 /* --------------------------- X Menu emulation ---------------------- */
1572 /* Create a brand new menu structure. */
1575 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
1577 return IT_menu_create ();
1580 /* Create a new pane and place it on the outer-most level. It is not
1581 clear that it should be placed out there, but I don't know what else
1585 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
1592 IT_menu_make_room (menu
);
1593 menu
->submenu
[menu
->count
] = IT_menu_create ();
1594 menu
->text
[menu
->count
] = txt
;
1595 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
1597 if ((len
= strlen (txt
)) > menu
->width
)
1599 return menu
->panecount
;
1602 /* Create a new item in a menu pane. */
1605 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
1606 int foo
, char *txt
, int enable
)
1611 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
1613 IT_menu_make_room (menu
);
1614 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
1615 menu
->text
[menu
->count
] = txt
;
1616 menu
->panenumber
[menu
->count
] = enable
;
1618 if ((len
= strlen (txt
)) > menu
->width
)
1623 /* Decide where the menu would be placed if requested at (X,Y). */
1626 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
1627 int *ulx
, int *uly
, int *width
, int *height
)
1629 if (menu
->count
== 1 && menu
->submenu
[0])
1630 /* Special case: the menu consists of only one pane. */
1631 IT_menu_calc_size (menu
->submenu
[0], width
, height
);
1633 IT_menu_calc_size (menu
, width
, height
);
1639 struct IT_menu_state
1641 void *screen_behind
;
1648 /* Display menu, wait for user's response, and return that response. */
1651 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
1652 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
1654 struct IT_menu_state
*state
;
1658 int faces
[4], selectface
;
1659 int leave
, result
, onepane
;
1661 /* Just in case we got here without a mouse present... */
1662 if (have_mouse
<= 0)
1663 return XM_IA_SELECT
;
1665 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
1666 screensize
= screen_size
* 2;
1668 = compute_glyph_face (&the_only_frame
,
1671 intern ("msdos-menu-passive-face")),
1674 = compute_glyph_face (&the_only_frame
,
1677 intern ("msdos-menu-active-face")),
1680 = face_name_id_number (&the_only_frame
, intern ("msdos-menu-select-face"));
1681 faces
[2] = compute_glyph_face (&the_only_frame
, selectface
, faces
[0]);
1682 faces
[3] = compute_glyph_face (&the_only_frame
, selectface
, faces
[1]);
1685 state
[0].menu
= menu
;
1687 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
1688 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
1690 menu
->width
= menu
->submenu
[0]->width
;
1691 state
[0].menu
= menu
->submenu
[0];
1695 state
[0].menu
= menu
;
1697 state
[0].x
= x0
- 1;
1699 state
[0].pane
= onepane
;
1701 mouse_last_x
= -1; /* A hack that forces display. */
1705 if (!mouse_visible
) mouse_on ();
1706 mouse_check_moved ();
1707 if (selected_frame
->mouse_moved
)
1709 selected_frame
->mouse_moved
= 0;
1710 result
= XM_IA_SELECT
;
1711 mouse_get_xy (&x
, &y
);
1712 for (i
= 0; i
< statecount
; i
++)
1713 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
1715 int dy
= y
- state
[i
].y
;
1716 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
1718 if (!state
[i
].menu
->submenu
[dy
])
1719 if (state
[i
].menu
->panenumber
[dy
])
1720 result
= XM_SUCCESS
;
1722 result
= XM_IA_SELECT
;
1723 *pane
= state
[i
].pane
- 1;
1725 /* We hit some part of a menu, so drop extra menues that
1726 have been opened. That does not include an open and
1728 if (i
!= statecount
- 2
1729 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
1730 while (i
!= statecount
- 1)
1734 ScreenUpdate (state
[statecount
].screen_behind
);
1735 xfree (state
[statecount
].screen_behind
);
1737 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
1739 IT_menu_display (state
[i
].menu
,
1743 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
1744 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
1746 ScreenRetrieve (state
[statecount
].screen_behind
1747 = xmalloc (screensize
));
1749 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
1750 state
[statecount
].y
= y
;
1755 IT_menu_display (state
[statecount
- 1].menu
,
1756 state
[statecount
- 1].y
,
1757 state
[statecount
- 1].x
,
1760 for (b
= 0; b
< mouse_button_count
; b
++)
1762 (void) mouse_pressed (b
, &x
, &y
);
1763 if (mouse_released (b
, &x
, &y
))
1769 ScreenUpdate (state
[0].screen_behind
);
1770 while (statecount
--)
1771 xfree (state
[statecount
].screen_behind
);
1775 /* Dispose of a menu. */
1778 XMenuDestroy (Display
*foo
, XMenu
*menu
)
1781 if (menu
->allocated
)
1783 for (i
= 0; i
< menu
->count
; i
++)
1784 if (menu
->submenu
[i
])
1785 XMenuDestroy (foo
, menu
->submenu
[i
]);
1787 xfree (menu
->submenu
);
1788 xfree (menu
->panenumber
);
1794 x_pixel_width (struct frame
*f
)
1796 return FRAME_WIDTH (f
);
1800 x_pixel_height (struct frame
*f
)
1802 return FRAME_HEIGHT (f
);
1804 #endif /* !HAVE_X_WINDOWS */
1807 /* ----------------------- DOS / UNIX conversion --------------------- */
1809 /* Destructively turn backslashes into slashes. */
1812 dostounix_filename (p
)
1823 /* Destructively turn slashes into backslashes. */
1826 unixtodos_filename (p
)
1837 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
1840 getdefdir (drive
, dst
)
1848 regs
.x
.si
= (int) dst
;
1850 intdos (®s
, ®s
);
1851 return !regs
.x
.cflag
;
1854 /* Remove all CR's that are followed by a LF. */
1859 register unsigned char *buf
;
1861 unsigned char *np
= buf
;
1862 unsigned char *startp
= buf
;
1863 unsigned char *endp
= buf
+ n
;
1868 while (buf
< endp
- 1)
1872 if (*(++buf
) != 0x0a)
1883 /* The Emacs root directory as determined by init_environment. */
1885 static char emacsroot
[MAXPATHLEN
];
1888 rootrelativepath (rel
)
1891 static char result
[MAXPATHLEN
+ 10];
1893 strcpy (result
, emacsroot
);
1894 strcat (result
, "/");
1895 strcat (result
, rel
);
1899 /* Define a lot of environment variables if not already defined. Don't
1900 remove anything unless you know what you're doing -- lots of code will
1901 break if one or more of these are missing. */
1904 init_environment (argc
, argv
, skip_args
)
1912 /* Find our root from argv[0]. Assuming argv[0] is, say,
1913 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
1914 root
= alloca (MAXPATHLEN
+ 20);
1915 _fixpath (argv
[0], root
);
1917 len
= strlen (root
);
1918 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
1921 if (len
> 4 && strcmp (root
+ len
- 4, "/bin") == 0)
1922 root
[len
- 4] = '\0';
1924 strcpy (root
, "c:/emacs"); /* Only under debuggers, I think. */
1925 len
= strlen (root
);
1926 strcpy (emacsroot
, root
);
1928 /* We default HOME to our root. */
1929 setenv ("HOME", root
, 0);
1931 /* We default EMACSPATH to root + "/bin". */
1932 strcpy (root
+ len
, "/bin");
1933 setenv ("EMACSPATH", root
, 0);
1935 /* I don't expect anybody to ever use other terminals so the internal
1936 terminal is the default. */
1937 setenv ("TERM", "internal", 0);
1939 #ifdef HAVE_X_WINDOWS
1940 /* Emacs expects DISPLAY to be set. */
1941 setenv ("DISPLAY", "unix:0.0", 0);
1944 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
1945 downcase it and mirror the backslashes. */
1946 s
= getenv ("COMSPEC");
1947 if (!s
) s
= "c:/command.com";
1948 t
= alloca (strlen (s
) + 1);
1951 dostounix_filename (t
);
1952 setenv ("SHELL", t
, 0);
1954 /* PATH is also downcased and backslashes mirrored. */
1955 s
= getenv ("PATH");
1957 t
= alloca (strlen (s
) + 3);
1958 /* Current directory is always considered part of MsDos's path but it is
1959 not normally mentioned. Now it is. */
1960 strcat (strcpy (t
, ".;"), s
);
1962 dostounix_filename (t
); /* Not a single file name, but this should work. */
1963 setenv ("PATH", t
, 1);
1965 /* In some sense all dos users have root privileges, so... */
1966 setenv ("USER", "root", 0);
1967 setenv ("NAME", getenv ("USER"), 0);
1969 /* Time zone determined from country code. To make this possible, the
1970 country code may not span more than one time zone. In other words,
1971 in the USA, you lose. */
1973 switch (dos_country_code
)
1975 case 31: /* Belgium */
1976 case 32: /* The Netherlands */
1977 case 33: /* France */
1978 case 34: /* Spain */
1979 case 36: /* Hungary */
1980 case 38: /* Yugoslavia (or what's left of it?) */
1981 case 39: /* Italy */
1982 case 41: /* Switzerland */
1983 case 42: /* Tjekia */
1984 case 45: /* Denmark */
1985 case 46: /* Sweden */
1986 case 47: /* Norway */
1987 case 48: /* Poland */
1988 case 49: /* Germany */
1989 /* Daylight saving from last Sunday in March to last Sunday in
1990 September, both at 2AM. */
1991 setenv ("TZ", "MET" /* "-01METDST-02,M3.5.0/02:00,M9.5.0/02:00" */, 0);
1993 case 44: /* United Kingdom */
1994 case 351: /* Portugal */
1995 case 354: /* Iceland */
1996 setenv ("TZ", "GMT" /* "+00" */, 0);
1998 case 81: /* Japan */
1999 case 82: /* Korea */
2000 setenv ("TZ", "JST" /* "-09" */, 0);
2002 case 90: /* Turkey */
2003 case 358: /* Finland */
2004 case 972: /* Israel */
2005 setenv ("TZ", "EET" /* "-02" */, 0);
2012 static int break_stat
; /* BREAK check mode status. */
2013 static int stdin_stat
; /* stdin IOCTL status. */
2015 /* These must be global. */
2016 static _go32_dpmi_seginfo ctrl_break_vector
;
2017 static _go32_dpmi_registers ctrl_break_regs
;
2018 static int ctrlbreakinstalled
= 0;
2020 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2023 ctrl_break_func (regs
)
2024 _go32_dpmi_registers
*regs
;
2030 install_ctrl_break_check ()
2032 if (!ctrlbreakinstalled
)
2034 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2035 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2036 ctrlbreakinstalled
= 1;
2037 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2038 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2040 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2045 * Turn off Dos' Ctrl-C checking and inhibit interpretation of
2046 * control chars by Dos.
2047 * Determine the keyboard type.
2053 union REGS inregs
, outregs
;
2054 static int first_time
= 1;
2056 break_stat
= getcbrk ();
2058 install_ctrl_break_check ();
2063 int86 (0x15, &inregs
, &outregs
);
2064 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2068 if (internal_terminal
2069 #ifdef HAVE_X_WINDOWS
2070 && inhibit_window_system
2074 inregs
.x
.ax
= 0x0021;
2075 int86 (0x33, &inregs
, &outregs
);
2076 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2079 /* Reportedly, the above doesn't work for some mouse drivers. There
2080 is an additional detection method that should work, but might be
2081 a little slower. Use that as an alternative. */
2082 inregs
.x
.ax
= 0x0000;
2083 int86 (0x33, &inregs
, &outregs
);
2084 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2089 have_mouse
= 1; /* enable mouse */
2092 if (outregs
.x
.bx
== 3)
2094 mouse_button_count
= 3;
2095 mouse_button_translate
[0] = 0; /* Left */
2096 mouse_button_translate
[1] = 2; /* Middle */
2097 mouse_button_translate
[2] = 1; /* Right */
2101 mouse_button_count
= 2;
2102 mouse_button_translate
[0] = 0;
2103 mouse_button_translate
[1] = 1;
2105 mouse_position_hook
= &mouse_get_pos
;
2113 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2114 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2115 intdos (&inregs
, &outregs
);
2116 stdin_stat
= outregs
.h
.dl
;
2118 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
2119 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
2120 intdos (&inregs
, &outregs
);
2121 return !outregs
.x
.cflag
;
2124 /* Restore status of standard input and Ctrl-C checking. */
2128 union REGS inregs
, outregs
;
2130 setcbrk (break_stat
);
2133 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
2134 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2135 inregs
.x
.dx
= stdin_stat
;
2136 intdos (&inregs
, &outregs
);
2137 return !outregs
.x
.cflag
;
2141 /* Run command as specified by ARGV in directory DIR.
2142 The command is run with input from TEMPIN and output to file TEMPOUT. */
2144 run_msdos_command (argv
, dir
, tempin
, tempout
)
2145 unsigned char **argv
;
2147 int tempin
, tempout
;
2149 char *saveargv1
, *saveargv2
, **envv
;
2150 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
2151 int msshell
, result
= -1;
2152 int in
, out
, inbak
, outbak
, errbak
;
2156 /* Get current directory as MSDOS cwd is not per-process. */
2159 cmd
= Ffile_name_nondirectory (build_string (argv
[0]));
2160 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
2161 && !strcmp ("-c", argv
[1]);
2164 saveargv1
= argv
[1];
2165 saveargv2
= argv
[2];
2169 char *p
= alloca (strlen (argv
[2]) + 1);
2171 strcpy (argv
[2] = p
, saveargv2
);
2172 while (*p
&& isspace (*p
))
2174 while (*p
&& !isspace (*p
))
2182 /* Build the environment array. */
2184 extern Lisp_Object Vprocess_environment
;
2185 Lisp_Object tmp
, lst
;
2188 lst
= Vprocess_environment
;
2189 len
= XFASTINT (Flength (lst
));
2191 envv
= alloca ((len
+ 1) * sizeof (char *));
2192 for (i
= 0; i
< len
; i
++)
2196 CHECK_STRING (tmp
, 0);
2197 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
2198 strcpy (envv
[i
], XSTRING (tmp
)->data
);
2200 envv
[len
] = (char *) 0;
2204 chdir (XSTRING (dir
)->data
);
2208 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
2209 goto done
; /* Allocation might fail due to lack of descriptors. */
2212 mouse_get_xy (&x
, &y
);
2214 dos_ttcooked (); /* do it here while 0 = stdin */
2220 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
2233 mouse_moveto (x
, y
);
2240 argv
[1] = saveargv1
;
2241 argv
[2] = saveargv2
;
2249 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
2255 /* ------------------------- Compatibility functions -------------------
2261 * Hostnames for a pc are not really funny,
2262 * but they are used in change log so we emulate the best we can.
2265 gethostname (p
, size
)
2269 char *q
= egetenv ("HOSTNAME");
2276 /* When time zones are set from Ms-Dos too may C-libraries are playing
2277 tricks with time values. We solve this by defining our own version
2278 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2279 once and after each call to `tzset' with TZ changed. That is
2280 accomplished by aliasing tzset to init_gettimeofday. */
2282 static struct tm time_rec
;
2285 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
2293 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
2297 time_rec
.tm_year
= d
.da_year
- 1900;
2298 time_rec
.tm_mon
= d
.da_mon
- 1;
2299 time_rec
.tm_mday
= d
.da_day
;
2302 time_rec
.tm_hour
= t
.ti_hour
;
2303 time_rec
.tm_min
= t
.ti_min
;
2304 time_rec
.tm_sec
= t
.ti_sec
;
2307 tm
.tm_gmtoff
= dos_timezone_offset
;
2309 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
2310 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
2312 /* Ignore tzp; it's obsolescent. */
2318 * A list of unimplemented functions that we silently ignore.
2321 unsigned alarm (s
) unsigned s
; {}
2322 fork () { return 0; }
2323 int kill (x
, y
) int x
, y
; { return -1; }
2325 void volatile pause () {}
2327 setpgrp () {return 0; }
2328 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
2329 sigsetmask (x
) int x
; { return 0; }
2330 unrequest_sigio () {}
2332 int run_dos_timer_hooks
= 0;
2335 #include "sysselect.h"
2337 static int last_ti_sec
= -1;
2345 if (t
->ti_sec
== last_ti_sec
)
2347 last_ti_sec
= t
->ti_sec
;
2349 if (!NILP (Vdos_menubar_clock
))
2353 int min
= t
->ti_min
;
2354 int hour
= t
->ti_hour
;
2356 if (dos_timezone_offset
)
2358 int tz
= dos_timezone_offset
;
2366 if ((hour
-= (tz
/ 60)) < 0)
2372 if ((dos_country_info
[0x11] & 0x01) == 0) /* 12 hour clock */
2375 if (hour
== 0) hour
= 12;
2378 len
= sprintf (clock_str
, "%2d.%02d.%02d", hour
, min
, t
->ti_sec
);
2379 dos_direct_output (0, screen_size_X
- len
- 1, clock_str
, len
);
2382 if (!NILP (Vdos_timer_hooks
))
2383 run_dos_timer_hooks
++;
2386 /* Only event queue is checked. */
2388 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
2390 SELECT_TYPE
*rfds
, *wfds
, *efds
;
2391 EMACS_TIME
*timeout
;
2394 long timeoutval
, clnow
, cllast
;
2400 check_input
= FD_ISSET (0, rfds
);
2411 /* If we are looking only for the terminal, with no timeout,
2412 just read it and wait -- that's more efficient. */
2415 while (! detect_input_pending ())
2420 timeoutval
= EMACS_SECS (*timeout
) * 100 + EMACS_USECS (*timeout
) / 10000;
2422 cllast
= t
.ti_sec
* 100 + t
.ti_hund
;
2424 while (!check_input
|| !detect_input_pending ())
2427 clnow
= t
.ti_sec
* 100 + t
.ti_hund
;
2428 if (clnow
< cllast
) /* time wrap */
2429 timeoutval
-= clnow
+ 6000 - cllast
;
2431 timeoutval
-= clnow
- cllast
;
2432 if (timeoutval
<= 0) /* Stop on timer being cleared */
2444 * Define overlayed functions:
2446 * chdir -> sys_chdir
2447 * tzset -> init_gettimeofday
2448 * abort -> dos_abort
2453 extern int chdir ();
2459 int len
= strlen (path
);
2460 char *tmp
= (char *)path
;
2462 if (*tmp
&& tmp
[1] == ':')
2464 if (getdisk () != tolower (tmp
[0]) - 'a')
2465 setdisk (tolower (tmp
[0]) - 'a');
2466 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
2470 if (len
> 1 && (tmp
[len
- 1] == '/'))
2472 char *tmp1
= (char *) alloca (len
+ 1);
2483 extern void tzset (void);
2486 init_gettimeofday ()
2492 ltm
= gtm
= time (NULL
);
2493 ltm
= mktime (lstm
= localtime (<m
));
2494 gtm
= mktime (gmtime (>m
));
2495 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
2496 time_rec
.tm_isdst
= lstm
->tm_isdst
;
2497 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
2504 dos_abort (file
, line
)
2508 char buffer1
[200], buffer2
[400];
2511 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
2512 for (i
= j
= 0; buffer1
[i
]; i
++) {
2513 buffer2
[j
++] = buffer1
[i
];
2514 buffer2
[j
++] = 0x70;
2516 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
2517 ScreenSetCursor (2, 0);
2524 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
2525 staticpro (&recent_doskeys
);
2527 defsubr (&Srecent_doskeys
);