1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* Contributed by Morten Welinder */
21 /* New display, keyboard, and mouse control by Kim F. Storm */
23 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
31 #include <sys/param.h>
37 #include "termhooks.h"
38 #include "dispextern.h"
45 /* #include <process.h> */
46 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
67 /* ------------------------ Mouse control ---------------------------
69 * Coordinates are in screen positions and zero based.
70 * Mouse buttons are numbered from left to right and also zero based.
73 int have_mouse
; /* 0: no, 1: enabled, -1: disabled */
74 static int mouse_visible
;
76 static int mouse_last_x
;
77 static int mouse_last_y
;
79 static int mouse_button_translate
[NUM_MOUSE_BUTTONS
];
80 static int mouse_button_count
;
87 if (have_mouse
> 0 && !mouse_visible
)
90 fprintf (termscript
, "<M_ON>");
92 int86 (0x33, ®s
, ®s
);
102 if (have_mouse
> 0 && mouse_visible
)
105 fprintf (termscript
, "<M_OFF>");
107 int86 (0x33, ®s
, ®s
);
119 fprintf (termscript
, "<M_XY=%dx%d>", x
, y
);
121 mouse_last_x
= regs
.x
.cx
= x
* 8;
122 mouse_last_y
= regs
.x
.dx
= y
* 8;
123 int86 (0x33, ®s
, ®s
);
127 mouse_pressed (b
, xp
, yp
)
132 if (b
>= mouse_button_count
)
135 regs
.x
.bx
= mouse_button_translate
[b
];
136 int86 (0x33, ®s
, ®s
);
138 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
139 return (regs
.x
.bx
!= 0);
143 mouse_released (b
, xp
, yp
)
148 if (b
>= mouse_button_count
)
151 regs
.x
.bx
= mouse_button_translate
[b
];
152 int86 (0x33, ®s
, ®s
);
154 *xp
= regs
.x
.cx
/ 8, *yp
= regs
.x
.dx
/ 8;
155 return (regs
.x
.bx
!= 0);
159 mouse_get_xy (int *x
, int *y
)
164 int86 (0x33, ®s
, ®s
);
170 mouse_get_pos (f
, insist
, bar_window
, part
, x
, y
, time
)
173 Lisp_Object
*bar_window
, *x
, *y
;
174 enum scroll_bar_part
*part
;
181 int86 (0x33, ®s
, ®s
);
184 mouse_get_xy (&ix
, &iy
);
185 selected_frame
->mouse_moved
= 0;
186 *x
= make_number (ix
);
187 *y
= make_number (iy
);
188 *time
= event_timestamp ();
196 mouse_get_xy (&x
, &y
);
197 selected_frame
->mouse_moved
|= (x
!= mouse_last_x
|| y
!= mouse_last_y
);
208 fprintf (termscript
, "<M_INIT>");
211 int86 (0x33, ®s
, ®s
);
215 regs
.x
.dx
= 8 * (ScreenCols () - 1);
216 int86 (0x33, ®s
, ®s
);
220 regs
.x
.dx
= 8 * (ScreenRows () - 1);
221 int86 (0x33, ®s
, ®s
);
227 /* ------------------------- Screen control ----------------------
231 static int internal_terminal
= 0;
233 #ifndef HAVE_X_WINDOWS
234 extern unsigned char ScreenAttrib
;
235 static int screen_face
;
236 static int highlight
;
238 static int screen_size_X
;
239 static int screen_size_Y
;
240 static int screen_size
;
242 static int current_pos_X
;
243 static int current_pos_Y
;
244 static int new_pos_X
;
245 static int new_pos_Y
;
247 static void *startup_screen_buffer
;
248 static int startup_screen_size_X
;
249 static int startup_screen_size_Y
;
250 static int startup_pos_X
;
251 static int startup_pos_Y
;
253 static int term_setup_done
;
255 /* Similar to the_only_frame. */
256 struct x_output 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
.output_data
.x
= &the_only_x_display
;
696 the_only_frame
.output_method
= output_msdos_raw
;
697 the_only_x_display
.font
= (XFontStruct
*)1; /* must *not* be zero */
699 init_frame_faces ((FRAME_PTR
) &the_only_frame
);
701 ring_bell_hook
= IT_ring_bell
;
702 write_glyphs_hook
= IT_write_glyphs
;
703 cursor_to_hook
= raw_cursor_to_hook
= IT_cursor_to
;
704 clear_to_end_hook
= IT_clear_to_end
;
705 clear_end_of_line_hook
= IT_clear_end_of_line
;
706 clear_frame_hook
= IT_clear_screen
;
707 change_line_highlight_hook
= IT_change_line_highlight
;
708 update_begin_hook
= IT_update_begin
;
709 update_end_hook
= IT_update_end
;
710 reassert_line_highlight_hook
= IT_reassert_line_highlight
;
712 /* These hooks are called by term.c without being checked. */
713 set_terminal_modes_hook
= IT_set_terminal_modes
;
714 reset_terminal_modes_hook
= IT_reset_terminal_modes
;
715 set_terminal_window_hook
= IT_set_terminal_window
;
719 dos_get_saved_screen (screen
, rows
, cols
)
724 #ifndef HAVE_X_WINDOWS
725 *screen
= startup_screen_buffer
;
726 *cols
= startup_screen_size_X
;
727 *rows
= startup_screen_size_Y
;
736 /* ----------------------- Keyboard control ----------------------
738 * Keymaps reflect the following keyboard layout:
740 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
741 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
742 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
743 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
747 static int extended_kbd
; /* 101 (102) keyboard present. */
749 struct dos_keyboard_map
757 static struct dos_keyboard_map us_keyboard
= {
759 /* 01234567890123456789012345678901234567890 12345678901234 */
760 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
761 /* 0123456789012345678901234567890123456789 012345678901234 */
762 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
763 0 /* no Alt-Gr key */
766 static struct dos_keyboard_map fr_keyboard
= {
768 /* 012 3456789012345678901234567890123456789012345678901234 */
769 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
770 /* 0123456789012345678901234567890123456789012345678901234 */
771 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
772 /* 01234567 89012345678901234567890123456789012345678901234 */
776 static struct dos_keyboard_map dk_keyboard
= {
778 /* 0123456789012345678901234567890123456789012345678901234 */
779 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
780 /* 01 23456789012345678901234567890123456789012345678901234 */
781 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
782 /* 0123456789012345678901234567890123456789012345678901234 */
786 static struct keyboard_layout_list
789 struct dos_keyboard_map
*keyboard_map
;
790 } keyboard_layout_list
[] =
797 static struct dos_keyboard_map
*keyboard
;
798 static int keyboard_map_all
;
801 dos_set_keyboard (code
, always
)
807 /* Initialize to US settings, for countries that don't have their own. */
808 keyboard
= keyboard_layout_list
[0].keyboard_map
;
809 keyboard_map_all
= always
;
810 dos_keyboard_layout
= 1;
812 for (i
= 0; i
< (sizeof (keyboard_layout_list
)/sizeof (struct keyboard_layout_list
)); i
++)
813 if (code
== keyboard_layout_list
[i
].country_code
)
815 keyboard
= keyboard_layout_list
[i
].keyboard_map
;
816 keyboard_map_all
= always
;
817 dos_keyboard_layout
= code
;
823 #define Ignore 0x0000
824 #define Normal 0x0000 /* normal key - alt changes scan-code */
825 #define FctKey 0x1000 /* func key if c == 0, else c */
826 #define Special 0x2000 /* func key even if c != 0 */
827 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
828 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
829 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
830 #define Grey 0x6000 /* Grey keypad key */
832 #define Alt 0x0100 /* alt scan-code */
833 #define Ctrl 0x0200 /* ctrl scan-code */
834 #define Shift 0x0400 /* shift scan-code */
838 unsigned char char_code
; /* normal code */
839 unsigned char meta_code
; /* M- code */
840 unsigned char keypad_code
; /* keypad code */
841 unsigned char editkey_code
; /* edit key */
842 } keypad_translate_map
[] = {
843 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
844 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
845 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
846 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
847 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
848 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
849 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
850 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
851 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
852 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
853 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
858 unsigned char char_code
; /* normal code */
859 unsigned char keypad_code
; /* keypad code */
860 } grey_key_translate_map
[] = {
861 '/', 0xaf, /* kp-decimal */
862 '*', 0xaa, /* kp-multiply */
863 '-', 0xad, /* kp-subtract */
864 '+', 0xab, /* kp-add */
865 '\r', 0x8d /* kp-enter */
868 static unsigned short
869 ibmpc_translate_map
[] =
871 /* --------------- 00 to 0f --------------- */
872 Normal
| 0xff, /* Ctrl Break + Alt-NNN */
873 Alt
| ModFct
| 0x1b, /* Escape */
874 Normal
| 1, /* '1' */
875 Normal
| 2, /* '2' */
876 Normal
| 3, /* '3' */
877 Normal
| 4, /* '4' */
878 Normal
| 5, /* '5' */
879 Normal
| 6, /* '6' */
880 Normal
| 7, /* '7' */
881 Normal
| 8, /* '8' */
882 Normal
| 9, /* '9' */
883 Normal
| 10, /* '0' */
884 Normal
| 11, /* '-' */
885 Normal
| 12, /* '=' */
886 Special
| 0x08, /* Backspace */
887 ModFct
| 0x74, /* Tab/Backtab */
889 /* --------------- 10 to 1f --------------- */
902 ModFct
| 0x0d, /* Return */
907 /* --------------- 20 to 2f --------------- */
918 Ignore
, /* Left shift */
925 /* --------------- 30 to 3f --------------- */
932 Ignore
, /* Right shift */
933 Grey
| 1, /* Grey * */
935 Normal
| ' ', /* ' ' */
936 Ignore
, /* Caps Lock */
937 FctKey
| 0xbe, /* F1 */
938 FctKey
| 0xbf, /* F2 */
939 FctKey
| 0xc0, /* F3 */
940 FctKey
| 0xc1, /* F4 */
941 FctKey
| 0xc2, /* F5 */
943 /* --------------- 40 to 4f --------------- */
944 FctKey
| 0xc3, /* F6 */
945 FctKey
| 0xc4, /* F7 */
946 FctKey
| 0xc5, /* F8 */
947 FctKey
| 0xc6, /* F9 */
948 FctKey
| 0xc7, /* F10 */
949 Ignore
, /* Num Lock */
950 Ignore
, /* Scroll Lock */
951 KeyPad
| 7, /* Home */
953 KeyPad
| 9, /* Page Up */
954 Grey
| 2, /* Grey - */
955 KeyPad
| 4, /* Left */
956 KeyPad
| 5, /* Keypad 5 */
957 KeyPad
| 6, /* Right */
958 Grey
| 3, /* Grey + */
959 KeyPad
| 1, /* End */
961 /* --------------- 50 to 5f --------------- */
962 KeyPad
| 2, /* Down */
963 KeyPad
| 3, /* Page Down */
964 KeyPad
| 0, /* Insert */
965 KeyPad
| 10, /* Delete */
966 Shift
| FctKey
| 0xbe, /* (Shift) F1 */
967 Shift
| FctKey
| 0xbf, /* (Shift) F2 */
968 Shift
| FctKey
| 0xc0, /* (Shift) F3 */
969 Shift
| FctKey
| 0xc1, /* (Shift) F4 */
970 Shift
| FctKey
| 0xc2, /* (Shift) F5 */
971 Shift
| FctKey
| 0xc3, /* (Shift) F6 */
972 Shift
| FctKey
| 0xc4, /* (Shift) F7 */
973 Shift
| FctKey
| 0xc5, /* (Shift) F8 */
974 Shift
| FctKey
| 0xc6, /* (Shift) F9 */
975 Shift
| FctKey
| 0xc7, /* (Shift) F10 */
976 Ctrl
| FctKey
| 0xbe, /* (Ctrl) F1 */
977 Ctrl
| FctKey
| 0xbf, /* (Ctrl) F2 */
979 /* --------------- 60 to 6f --------------- */
980 Ctrl
| FctKey
| 0xc0, /* (Ctrl) F3 */
981 Ctrl
| FctKey
| 0xc1, /* (Ctrl) F4 */
982 Ctrl
| FctKey
| 0xc2, /* (Ctrl) F5 */
983 Ctrl
| FctKey
| 0xc3, /* (Ctrl) F6 */
984 Ctrl
| FctKey
| 0xc4, /* (Ctrl) F7 */
985 Ctrl
| FctKey
| 0xc5, /* (Ctrl) F8 */
986 Ctrl
| FctKey
| 0xc6, /* (Ctrl) F9 */
987 Ctrl
| FctKey
| 0xc7, /* (Ctrl) F10 */
988 Alt
| FctKey
| 0xbe, /* (Alt) F1 */
989 Alt
| FctKey
| 0xbf, /* (Alt) F2 */
990 Alt
| FctKey
| 0xc0, /* (Alt) F3 */
991 Alt
| FctKey
| 0xc1, /* (Alt) F4 */
992 Alt
| FctKey
| 0xc2, /* (Alt) F5 */
993 Alt
| FctKey
| 0xc3, /* (Alt) F6 */
994 Alt
| FctKey
| 0xc4, /* (Alt) F7 */
995 Alt
| FctKey
| 0xc5, /* (Alt) F8 */
997 /* --------------- 70 to 7f --------------- */
998 Alt
| FctKey
| 0xc6, /* (Alt) F9 */
999 Alt
| FctKey
| 0xc7, /* (Alt) F10 */
1000 Ctrl
| FctKey
| 0x6d, /* (Ctrl) Sys Rq */
1001 Ctrl
| KeyPad
| 4, /* (Ctrl) Left */
1002 Ctrl
| KeyPad
| 6, /* (Ctrl) Right */
1003 Ctrl
| KeyPad
| 1, /* (Ctrl) End */
1004 Ctrl
| KeyPad
| 3, /* (Ctrl) Page Down */
1005 Ctrl
| KeyPad
| 7, /* (Ctrl) Home */
1006 Alt
| Map
| 1, /* '1' */
1007 Alt
| Map
| 2, /* '2' */
1008 Alt
| Map
| 3, /* '3' */
1009 Alt
| Map
| 4, /* '4' */
1010 Alt
| Map
| 5, /* '5' */
1011 Alt
| Map
| 6, /* '6' */
1012 Alt
| Map
| 7, /* '7' */
1013 Alt
| Map
| 8, /* '8' */
1015 /* --------------- 80 to 8f --------------- */
1016 Alt
| Map
| 9, /* '9' */
1017 Alt
| Map
| 10, /* '0' */
1018 Alt
| Map
| 11, /* '-' */
1019 Alt
| Map
| 12, /* '=' */
1020 Ctrl
| KeyPad
| 9, /* (Ctrl) Page Up */
1021 FctKey
| 0xc8, /* F11 */
1022 FctKey
| 0xc9, /* F12 */
1023 Shift
| FctKey
| 0xc8, /* (Shift) F11 */
1024 Shift
| FctKey
| 0xc9, /* (Shift) F12 */
1025 Ctrl
| FctKey
| 0xc8, /* (Ctrl) F11 */
1026 Ctrl
| FctKey
| 0xc9, /* (Ctrl) F12 */
1027 Alt
| FctKey
| 0xc8, /* (Alt) F11 */
1028 Alt
| FctKey
| 0xc9, /* (Alt) F12 */
1029 Ctrl
| KeyPad
| 8, /* (Ctrl) Up */
1030 Ctrl
| Grey
| 2, /* (Ctrl) Grey - */
1031 Ctrl
| KeyPad
| 5, /* (Ctrl) Keypad 5 */
1033 /* --------------- 90 to 9f --------------- */
1034 Ctrl
| Grey
| 3, /* (Ctrl) Grey + */
1035 Ctrl
| KeyPad
| 2, /* (Ctrl) Down */
1036 Ctrl
| KeyPad
| 0, /* (Ctrl) Insert */
1037 Ctrl
| KeyPad
| 10, /* (Ctrl) Delete */
1038 Ctrl
| FctKey
| 0x09, /* (Ctrl) Tab */
1039 Ctrl
| Grey
| 0, /* (Ctrl) Grey / */
1040 Ctrl
| Grey
| 1, /* (Ctrl) Grey * */
1041 Alt
| FctKey
| 0x50, /* (Alt) Home */
1042 Alt
| FctKey
| 0x52, /* (Alt) Up */
1043 Alt
| FctKey
| 0x55, /* (Alt) Page Up */
1044 Ignore
, /* NO KEY */
1045 Alt
| FctKey
| 0x51, /* (Alt) Left */
1046 Ignore
, /* NO KEY */
1047 Alt
| FctKey
| 0x53, /* (Alt) Right */
1048 Ignore
, /* NO KEY */
1049 Alt
| FctKey
| 0x57, /* (Alt) End */
1051 /* --------------- a0 to af --------------- */
1052 Alt
| KeyPad
| 2, /* (Alt) Down */
1053 Alt
| KeyPad
| 3, /* (Alt) Page Down */
1054 Alt
| KeyPad
| 0, /* (Alt) Insert */
1055 Alt
| KeyPad
| 10, /* (Alt) Delete */
1056 Alt
| Grey
| 0, /* (Alt) Grey / */
1057 Alt
| FctKey
| 0x09, /* (Alt) Tab */
1058 Alt
| Grey
| 4 /* (Alt) Keypad Enter */
1061 /* These bit-positions corresponds to values returned by BIOS */
1062 #define SHIFT_P 0x0003 /* two bits! */
1063 #define CTRL_P 0x0004
1064 #define ALT_P 0x0008
1065 #define SCRLOCK_P 0x0010
1066 #define NUMLOCK_P 0x0020
1067 #define CAPSLOCK_P 0x0040
1068 #define ALT_GR_P 0x0800
1069 #define SUPER_P 0x4000 /* pseudo */
1070 #define HYPER_P 0x8000 /* pseudo */
1073 dos_get_modifiers (keymask
)
1080 /* Calculate modifier bits */
1081 regs
.h
.ah
= extended_kbd
? 0x12 : 0x02;
1082 int86 (0x16, ®s
, ®s
);
1086 mask
= regs
.h
.al
& (SHIFT_P
| CTRL_P
| ALT_P
|
1087 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1091 mask
= regs
.h
.al
& (SHIFT_P
|
1092 SCRLOCK_P
| NUMLOCK_P
| CAPSLOCK_P
);
1094 /* Do not break international keyboard support. */
1095 /* When Keyb.Com is loaded, the right Alt key is */
1096 /* used for accessing characters like { and } */
1097 if (regs
.h
.ah
& 2) /* Left ALT pressed ? */
1100 if ((regs
.h
.ah
& 8) != 0) /* Right ALT pressed ? */
1103 if (dos_hyper_key
== 1)
1106 modifiers
|= hyper_modifier
;
1108 else if (dos_super_key
== 1)
1111 modifiers
|= super_modifier
;
1115 if (regs
.h
.ah
& 1) /* Left CTRL pressed
1118 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1120 if (dos_hyper_key
== 2)
1123 modifiers
|= hyper_modifier
;
1125 else if (dos_super_key
== 2)
1128 modifiers
|= super_modifier
;
1136 modifiers
|= shift_modifier
;
1138 modifiers
|= ctrl_modifier
;
1140 modifiers
|= meta_modifier
;
1147 #define NUM_RECENT_DOSKEYS (100)
1148 int recent_doskeys_index
; /* Index for storing next element into recent_doskeys */
1149 int total_doskeys
; /* Total number of elements stored into recent_doskeys */
1150 Lisp_Object recent_doskeys
; /* A vector, holding the last 100 keystrokes */
1152 DEFUN ("recent-doskeys", Frecent_doskeys
, Srecent_doskeys
, 0, 0, 0,
1153 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1154 Each input key receives two values in this vector: first the ASCII code,\n\
1155 and then the scan code.")
1158 Lisp_Object
*keys
= XVECTOR (recent_doskeys
)->contents
;
1161 if (total_doskeys
< NUM_RECENT_DOSKEYS
)
1162 return Fvector (total_doskeys
, keys
);
1165 val
= Fvector (NUM_RECENT_DOSKEYS
, keys
);
1166 bcopy (keys
+ recent_doskeys_index
,
1167 XVECTOR (val
)->contents
,
1168 (NUM_RECENT_DOSKEYS
- recent_doskeys_index
) * sizeof (Lisp_Object
));
1170 XVECTOR (val
)->contents
+ NUM_RECENT_DOSKEYS
- recent_doskeys_index
,
1171 recent_doskeys_index
* sizeof (Lisp_Object
));
1176 /* Get a char from keyboard. Function keys are put into the event queue. */
1180 struct input_event event
;
1183 #ifndef HAVE_X_WINDOWS
1184 SCREEN_SET_CURSOR ();
1185 if (!mouse_visible
) mouse_on ();
1188 /* The following condition is equivalent to `kbhit ()', except that
1189 it uses the bios to do its job. This pleases DESQview/X. */
1190 while ((regs
.h
.ah
= extended_kbd
? 0x11 : 0x01),
1191 int86 (0x16, ®s
, ®s
),
1192 (regs
.x
.flags
& 0x40) == 0)
1195 register unsigned char c
;
1196 int sc
, code
, mask
, kp_mode
;
1199 regs
.h
.ah
= extended_kbd
? 0x10 : 0x00;
1200 int86 (0x16, ®s
, ®s
);
1205 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1207 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1208 recent_doskeys_index
= 0;
1209 XVECTOR (recent_doskeys
)->contents
[recent_doskeys_index
++]
1211 if (recent_doskeys_index
== NUM_RECENT_DOSKEYS
)
1212 recent_doskeys_index
= 0;
1214 modifiers
= dos_get_modifiers (&mask
);
1216 #ifndef HAVE_X_WINDOWS
1217 if (!NILP (Vdos_display_scancodes
))
1220 sprintf (buf
, "%02x:%02x*%04x",
1221 (unsigned) (sc
&0xff), (unsigned) c
, mask
);
1222 dos_direct_output (screen_size_Y
- 2, screen_size_X
- 12, buf
, 10);
1230 case 10: /* Ctrl Grey Enter */
1231 code
= Ctrl
| Grey
| 4;
1233 case 13: /* Grey Enter */
1236 case '/': /* Grey / */
1246 if (sc
>= (sizeof (ibmpc_translate_map
) / sizeof (short)))
1248 if ((code
= ibmpc_translate_map
[sc
]) == Ignore
)
1255 modifiers
|= meta_modifier
;
1257 modifiers
|= ctrl_modifier
;
1259 modifiers
|= shift_modifier
;
1262 switch (code
& 0xf000)
1265 if (c
&& !(mask
& (SHIFT_P
| ALT_P
| CTRL_P
| HYPER_P
| SUPER_P
)))
1267 c
= 0; /* Special */
1280 if (c
== 0) /* ctrl-break */
1282 return c
; /* ALT-nnn */
1284 if (!keyboard_map_all
)
1293 if (c
&& !(mask
& ALT_P
) && !((mask
& SHIFT_P
) && (mask
& CTRL_P
)))
1294 if (!keyboard_map_all
)
1298 if (mask
& ALT_P
&& code
<= 10 && code
> 0 && dos_keypad_mode
& 0x200)
1299 mask
|= SHIFT_P
; /* ALT-1 => M-! etc. */
1303 code
= keyboard
->shifted
[code
];
1305 modifiers
&= ~shift_modifier
;
1308 if ((mask
& ALT_GR_P
) && keyboard
->alt_gr
&& keyboard
->alt_gr
[code
] != ' ')
1309 code
= keyboard
->alt_gr
[code
];
1311 code
= keyboard
->unshifted
[code
];
1316 if (c
== 0xe0) /* edit key */
1319 if ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) /* numlock on */
1320 kp_mode
= dos_keypad_mode
& 0x03;
1322 kp_mode
= (dos_keypad_mode
>> 4) & 0x03;
1327 if (code
== 10 && dos_decimal_point
)
1328 return dos_decimal_point
;
1329 return keypad_translate_map
[code
].char_code
;
1332 code
= 0xff00 | keypad_translate_map
[code
].keypad_code
;
1336 code
= keypad_translate_map
[code
].meta_code
;
1337 modifiers
= meta_modifier
;
1341 code
= 0xff00 | keypad_translate_map
[code
].editkey_code
;
1348 kp_mode
= ((mask
& (NUMLOCK_P
|CTRL_P
|SHIFT_P
|ALT_P
)) == NUMLOCK_P
) ? 0x04 : 0x40;
1349 if (dos_keypad_mode
& kp_mode
)
1350 code
= 0xff00 | grey_key_translate_map
[code
].keypad_code
;
1352 code
= grey_key_translate_map
[code
].char_code
;
1361 event
.kind
= non_ascii_keystroke
;
1363 event
.kind
= ascii_keystroke
;
1365 event
.modifiers
= modifiers
;
1366 XSETFRAME (event
.frame_or_window
, selected_frame
);
1367 event
.timestamp
= event_timestamp ();
1368 kbd_buffer_store_event (&event
);
1373 int but
, press
, x
, y
, ok
;
1375 /* Check for mouse movement *before* buttons. */
1376 mouse_check_moved ();
1378 for (but
= 0; but
< NUM_MOUSE_BUTTONS
; but
++)
1379 for (press
= 0; press
< 2; press
++)
1382 ok
= mouse_pressed (but
, &x
, &y
);
1384 ok
= mouse_released (but
, &x
, &y
);
1387 event
.kind
= mouse_click
;
1389 event
.modifiers
= dos_get_modifiers (0)
1390 | (press
? down_modifier
: up_modifier
);
1393 XSETFRAME (event
.frame_or_window
, selected_frame
);
1394 event
.timestamp
= event_timestamp ();
1395 kbd_buffer_store_event (&event
);
1403 static int prev_get_char
= -1;
1405 /* Return 1 if a key is ready to be read without suspending execution. */
1408 if (prev_get_char
!= -1)
1411 return ((prev_get_char
= dos_rawgetc ()) != -1);
1414 /* Read a key. Return -1 if no key is ready. */
1417 if (prev_get_char
!= -1)
1419 int c
= prev_get_char
;
1424 return dos_rawgetc ();
1427 #ifndef HAVE_X_WINDOWS
1428 /* See xterm.c for more info. */
1430 pixel_to_glyph_coords (f
, pix_x
, pix_y
, x
, y
, bounds
, noclip
)
1432 register int pix_x
, pix_y
;
1433 register int *x
, *y
;
1434 void /* XRectangle */ *bounds
;
1437 if (bounds
) abort ();
1439 /* Ignore clipping. */
1446 glyph_to_pixel_coords (f
, x
, y
, pix_x
, pix_y
)
1449 register int *pix_x
, *pix_y
;
1455 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1458 Actually, I don't know the meaning of all the parameters of the functions
1459 here -- I only know how they are called by xmenu.c. I could of course
1460 grab the nearest Xlib manual (down the hall, second-to-last door on the
1461 left), but I don't think it's worth the effort. */
1468 menu
= (XMenu
*) xmalloc (sizeof (XMenu
));
1469 menu
->allocated
= menu
->count
= menu
->panecount
= menu
->width
= 0;
1473 /* Allocate some (more) memory for MENU ensuring that there is room for one
1477 IT_menu_make_room (XMenu
*menu
)
1479 if (menu
->allocated
== 0)
1481 int count
= menu
->allocated
= 10;
1482 menu
->text
= (char **) xmalloc (count
* sizeof (char *));
1483 menu
->submenu
= (XMenu
**) xmalloc (count
* sizeof (XMenu
*));
1484 menu
->panenumber
= (int *) xmalloc (count
* sizeof (int));
1486 else if (menu
->allocated
== menu
->count
)
1488 int count
= menu
->allocated
= menu
->allocated
+ 10;
1490 = (char **) xrealloc (menu
->text
, count
* sizeof (char *));
1492 = (XMenu
**) xrealloc (menu
->submenu
, count
* sizeof (XMenu
*));
1494 = (int *) xrealloc (menu
->panenumber
, count
* sizeof (int));
1498 /* Search the given menu structure for a given pane number. */
1501 IT_menu_search_pane (XMenu
*menu
, int pane
)
1506 for (i
= 0; i
< menu
->count
; i
++)
1507 if (menu
->submenu
[i
])
1509 if (pane
== menu
->panenumber
[i
])
1510 return menu
->submenu
[i
];
1511 if ((try = IT_menu_search_pane (menu
->submenu
[i
], pane
)))
1517 /* Determine how much screen space a given menu needs. */
1520 IT_menu_calc_size (XMenu
*menu
, int *width
, int *height
)
1522 int i
, h2
, w2
, maxsubwidth
, maxheight
;
1525 maxheight
= menu
->count
;
1526 for (i
= 0; i
< menu
->count
; i
++)
1528 if (menu
->submenu
[i
])
1530 IT_menu_calc_size (menu
->submenu
[i
], &w2
, &h2
);
1531 if (w2
> maxsubwidth
) maxsubwidth
= w2
;
1532 if (i
+ h2
> maxheight
) maxheight
= i
+ h2
;
1535 *width
= menu
->width
+ maxsubwidth
;
1536 *height
= maxheight
;
1539 /* Display MENU at (X,Y) using FACES. */
1542 IT_menu_display (XMenu
*menu
, int y
, int x
, int *faces
)
1544 int i
, j
, face
, width
;
1548 int enabled
, mousehere
;
1551 width
= menu
->width
;
1552 text
= (GLYPH
*) xmalloc ((width
+ 2) * sizeof (GLYPH
));
1553 ScreenGetCursor (&row
, &col
);
1554 mouse_get_xy (&mx
, &my
);
1556 for (i
= 0; i
< menu
->count
; i
++)
1558 IT_cursor_to (y
+ i
, x
);
1560 = (!menu
->submenu
[i
] && menu
->panenumber
[i
]) || (menu
->submenu
[i
]);
1561 mousehere
= (y
+ i
== my
&& x
<= mx
&& mx
< x
+ width
+ 2);
1562 face
= faces
[enabled
+ mousehere
* 2];
1564 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1565 for (j
= 0, q
= menu
->text
[i
]; *q
; j
++)
1566 *p
++ = FAST_MAKE_GLYPH (*q
++, face
);
1567 for (; j
< width
; j
++)
1568 *p
++ = FAST_MAKE_GLYPH (' ', face
);
1569 *p
++ = FAST_MAKE_GLYPH (menu
->submenu
[i
] ? 16 : ' ', face
);
1570 IT_write_glyphs (text
, width
+ 2);
1573 IT_cursor_to (row
, col
);
1577 /* --------------------------- X Menu emulation ---------------------- */
1579 /* Create a brand new menu structure. */
1582 XMenuCreate (Display
*foo1
, Window foo2
, char *foo3
)
1584 return IT_menu_create ();
1587 /* Create a new pane and place it on the outer-most level. It is not
1588 clear that it should be placed out there, but I don't know what else
1592 XMenuAddPane (Display
*foo
, XMenu
*menu
, char *txt
, int enable
)
1599 IT_menu_make_room (menu
);
1600 menu
->submenu
[menu
->count
] = IT_menu_create ();
1601 menu
->text
[menu
->count
] = txt
;
1602 menu
->panenumber
[menu
->count
] = ++menu
->panecount
;
1604 if ((len
= strlen (txt
)) > menu
->width
)
1606 return menu
->panecount
;
1609 /* Create a new item in a menu pane. */
1612 XMenuAddSelection (Display
*bar
, XMenu
*menu
, int pane
,
1613 int foo
, char *txt
, int enable
)
1618 if (!(menu
= IT_menu_search_pane (menu
, pane
)))
1620 IT_menu_make_room (menu
);
1621 menu
->submenu
[menu
->count
] = (XMenu
*) 0;
1622 menu
->text
[menu
->count
] = txt
;
1623 menu
->panenumber
[menu
->count
] = enable
;
1625 if ((len
= strlen (txt
)) > menu
->width
)
1630 /* Decide where the menu would be placed if requested at (X,Y). */
1633 XMenuLocate (Display
*foo0
, XMenu
*menu
, int foo1
, int foo2
, int x
, int y
,
1634 int *ulx
, int *uly
, int *width
, int *height
)
1636 if (menu
->count
== 1 && menu
->submenu
[0])
1637 /* Special case: the menu consists of only one pane. */
1638 IT_menu_calc_size (menu
->submenu
[0], width
, height
);
1640 IT_menu_calc_size (menu
, width
, height
);
1646 struct IT_menu_state
1648 void *screen_behind
;
1655 /* Display menu, wait for user's response, and return that response. */
1658 XMenuActivate (Display
*foo
, XMenu
*menu
, int *pane
, int *selidx
,
1659 int x0
, int y0
, unsigned ButtonMask
, char **txt
)
1661 struct IT_menu_state
*state
;
1665 int faces
[4], selectface
;
1666 int leave
, result
, onepane
;
1668 /* Just in case we got here without a mouse present... */
1669 if (have_mouse
<= 0)
1670 return XM_IA_SELECT
;
1672 state
= alloca (menu
->panecount
* sizeof (struct IT_menu_state
));
1673 screensize
= screen_size
* 2;
1675 = compute_glyph_face (&the_only_frame
,
1678 intern ("msdos-menu-passive-face")),
1681 = compute_glyph_face (&the_only_frame
,
1684 intern ("msdos-menu-active-face")),
1687 = face_name_id_number (&the_only_frame
, intern ("msdos-menu-select-face"));
1688 faces
[2] = compute_glyph_face (&the_only_frame
, selectface
, faces
[0]);
1689 faces
[3] = compute_glyph_face (&the_only_frame
, selectface
, faces
[1]);
1692 state
[0].menu
= menu
;
1694 ScreenRetrieve (state
[0].screen_behind
= xmalloc (screensize
));
1695 if ((onepane
= menu
->count
== 1 && menu
->submenu
[0]))
1697 menu
->width
= menu
->submenu
[0]->width
;
1698 state
[0].menu
= menu
->submenu
[0];
1702 state
[0].menu
= menu
;
1704 state
[0].x
= x0
- 1;
1706 state
[0].pane
= onepane
;
1708 mouse_last_x
= -1; /* A hack that forces display. */
1712 if (!mouse_visible
) mouse_on ();
1713 mouse_check_moved ();
1714 if (selected_frame
->mouse_moved
)
1716 selected_frame
->mouse_moved
= 0;
1717 result
= XM_IA_SELECT
;
1718 mouse_get_xy (&x
, &y
);
1719 for (i
= 0; i
< statecount
; i
++)
1720 if (state
[i
].x
<= x
&& x
< state
[i
].x
+ state
[i
].menu
->width
+ 2)
1722 int dy
= y
- state
[i
].y
;
1723 if (0 <= dy
&& dy
< state
[i
].menu
->count
)
1725 if (!state
[i
].menu
->submenu
[dy
])
1726 if (state
[i
].menu
->panenumber
[dy
])
1727 result
= XM_SUCCESS
;
1729 result
= XM_IA_SELECT
;
1730 *pane
= state
[i
].pane
- 1;
1732 /* We hit some part of a menu, so drop extra menues that
1733 have been opened. That does not include an open and
1735 if (i
!= statecount
- 2
1736 || state
[i
].menu
->submenu
[dy
] != state
[i
+1].menu
)
1737 while (i
!= statecount
- 1)
1741 ScreenUpdate (state
[statecount
].screen_behind
);
1742 xfree (state
[statecount
].screen_behind
);
1744 if (i
== statecount
- 1 && state
[i
].menu
->submenu
[dy
])
1746 IT_menu_display (state
[i
].menu
,
1750 state
[statecount
].menu
= state
[i
].menu
->submenu
[dy
];
1751 state
[statecount
].pane
= state
[i
].menu
->panenumber
[dy
];
1753 ScreenRetrieve (state
[statecount
].screen_behind
1754 = xmalloc (screensize
));
1756 = state
[i
].x
+ state
[i
].menu
->width
+ 2;
1757 state
[statecount
].y
= y
;
1762 IT_menu_display (state
[statecount
- 1].menu
,
1763 state
[statecount
- 1].y
,
1764 state
[statecount
- 1].x
,
1767 for (b
= 0; b
< mouse_button_count
; b
++)
1769 (void) mouse_pressed (b
, &x
, &y
);
1770 if (mouse_released (b
, &x
, &y
))
1776 ScreenUpdate (state
[0].screen_behind
);
1777 while (statecount
--)
1778 xfree (state
[statecount
].screen_behind
);
1782 /* Dispose of a menu. */
1785 XMenuDestroy (Display
*foo
, XMenu
*menu
)
1788 if (menu
->allocated
)
1790 for (i
= 0; i
< menu
->count
; i
++)
1791 if (menu
->submenu
[i
])
1792 XMenuDestroy (foo
, menu
->submenu
[i
]);
1794 xfree (menu
->submenu
);
1795 xfree (menu
->panenumber
);
1801 x_pixel_width (struct frame
*f
)
1803 return FRAME_WIDTH (f
);
1807 x_pixel_height (struct frame
*f
)
1809 return FRAME_HEIGHT (f
);
1811 #endif /* !HAVE_X_WINDOWS */
1814 /* ----------------------- DOS / UNIX conversion --------------------- */
1816 /* Destructively turn backslashes into slashes. */
1819 dostounix_filename (p
)
1830 /* Destructively turn slashes into backslashes. */
1833 unixtodos_filename (p
)
1844 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
1847 getdefdir (drive
, dst
)
1855 regs
.x
.si
= (int) dst
;
1857 intdos (®s
, ®s
);
1858 return !regs
.x
.cflag
;
1861 /* Remove all CR's that are followed by a LF. */
1866 register unsigned char *buf
;
1868 unsigned char *np
= buf
;
1869 unsigned char *startp
= buf
;
1870 unsigned char *endp
= buf
+ n
;
1875 while (buf
< endp
- 1)
1879 if (*(++buf
) != 0x0a)
1890 /* The Emacs root directory as determined by init_environment. */
1892 static char emacsroot
[MAXPATHLEN
];
1895 rootrelativepath (rel
)
1898 static char result
[MAXPATHLEN
+ 10];
1900 strcpy (result
, emacsroot
);
1901 strcat (result
, "/");
1902 strcat (result
, rel
);
1906 /* Define a lot of environment variables if not already defined. Don't
1907 remove anything unless you know what you're doing -- lots of code will
1908 break if one or more of these are missing. */
1911 init_environment (argc
, argv
, skip_args
)
1919 /* Find our root from argv[0]. Assuming argv[0] is, say,
1920 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
1921 root
= alloca (MAXPATHLEN
+ 20);
1922 _fixpath (argv
[0], root
);
1924 len
= strlen (root
);
1925 while (len
> 0 && root
[len
] != '/' && root
[len
] != ':')
1928 if (len
> 4 && strcmp (root
+ len
- 4, "/bin") == 0)
1929 root
[len
- 4] = '\0';
1931 strcpy (root
, "c:/emacs"); /* Only under debuggers, I think. */
1932 len
= strlen (root
);
1933 strcpy (emacsroot
, root
);
1935 /* We default HOME to our root. */
1936 setenv ("HOME", root
, 0);
1938 /* We default EMACSPATH to root + "/bin". */
1939 strcpy (root
+ len
, "/bin");
1940 setenv ("EMACSPATH", root
, 0);
1942 /* I don't expect anybody to ever use other terminals so the internal
1943 terminal is the default. */
1944 setenv ("TERM", "internal", 0);
1946 #ifdef HAVE_X_WINDOWS
1947 /* Emacs expects DISPLAY to be set. */
1948 setenv ("DISPLAY", "unix:0.0", 0);
1951 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
1952 downcase it and mirror the backslashes. */
1953 s
= getenv ("COMSPEC");
1954 if (!s
) s
= "c:/command.com";
1955 t
= alloca (strlen (s
) + 1);
1958 dostounix_filename (t
);
1959 setenv ("SHELL", t
, 0);
1961 /* PATH is also downcased and backslashes mirrored. */
1962 s
= getenv ("PATH");
1964 t
= alloca (strlen (s
) + 3);
1965 /* Current directory is always considered part of MsDos's path but it is
1966 not normally mentioned. Now it is. */
1967 strcat (strcpy (t
, ".;"), s
);
1969 dostounix_filename (t
); /* Not a single file name, but this should work. */
1970 setenv ("PATH", t
, 1);
1972 /* In some sense all dos users have root privileges, so... */
1973 setenv ("USER", "root", 0);
1974 setenv ("NAME", getenv ("USER"), 0);
1976 /* Time zone determined from country code. To make this possible, the
1977 country code may not span more than one time zone. In other words,
1978 in the USA, you lose. */
1980 switch (dos_country_code
)
1982 case 31: /* Belgium */
1983 case 32: /* The Netherlands */
1984 case 33: /* France */
1985 case 34: /* Spain */
1986 case 36: /* Hungary */
1987 case 38: /* Yugoslavia (or what's left of it?) */
1988 case 39: /* Italy */
1989 case 41: /* Switzerland */
1990 case 42: /* Tjekia */
1991 case 45: /* Denmark */
1992 case 46: /* Sweden */
1993 case 47: /* Norway */
1994 case 48: /* Poland */
1995 case 49: /* Germany */
1996 /* Daylight saving from last Sunday in March to last Sunday in
1997 September, both at 2AM. */
1998 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2000 case 44: /* United Kingdom */
2001 case 351: /* Portugal */
2002 case 354: /* Iceland */
2003 setenv ("TZ", "GMT+00", 0);
2005 case 81: /* Japan */
2006 case 82: /* Korea */
2007 setenv ("TZ", "JST-09", 0);
2009 case 90: /* Turkey */
2010 case 358: /* Finland */
2011 setenv ("TZ", "EET-02", 0);
2013 case 972: /* Israel */
2014 /* This is an approximation. (For exact rules, use the
2015 `zoneinfo/israel' file which comes with DJGPP, but you need
2016 to install it in `/usr/share/zoneinfo/' directory first.) */
2017 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2020 init_gettimeofday ();
2025 static int break_stat
; /* BREAK check mode status. */
2026 static int stdin_stat
; /* stdin IOCTL status. */
2028 /* These must be global. */
2029 static _go32_dpmi_seginfo ctrl_break_vector
;
2030 static _go32_dpmi_registers ctrl_break_regs
;
2031 static int ctrlbreakinstalled
= 0;
2033 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2036 ctrl_break_func (regs
)
2037 _go32_dpmi_registers
*regs
;
2043 install_ctrl_break_check ()
2045 if (!ctrlbreakinstalled
)
2047 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2048 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2049 ctrlbreakinstalled
= 1;
2050 ctrl_break_vector
.pm_offset
= (int) ctrl_break_func
;
2051 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector
,
2053 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector
);
2058 * Turn off Dos' Ctrl-C checking and inhibit interpretation of
2059 * control chars by Dos.
2060 * Determine the keyboard type.
2066 union REGS inregs
, outregs
;
2067 static int first_time
= 1;
2069 break_stat
= getcbrk ();
2071 install_ctrl_break_check ();
2076 int86 (0x15, &inregs
, &outregs
);
2077 extended_kbd
= (!outregs
.x
.cflag
) && (outregs
.h
.ah
== 0);
2081 if (internal_terminal
2082 #ifdef HAVE_X_WINDOWS
2083 && inhibit_window_system
2087 inregs
.x
.ax
= 0x0021;
2088 int86 (0x33, &inregs
, &outregs
);
2089 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2092 /* Reportedly, the above doesn't work for some mouse drivers. There
2093 is an additional detection method that should work, but might be
2094 a little slower. Use that as an alternative. */
2095 inregs
.x
.ax
= 0x0000;
2096 int86 (0x33, &inregs
, &outregs
);
2097 have_mouse
= (outregs
.x
.ax
& 0xffff) == 0xffff;
2102 have_mouse
= 1; /* enable mouse */
2105 if (outregs
.x
.bx
== 3)
2107 mouse_button_count
= 3;
2108 mouse_button_translate
[0] = 0; /* Left */
2109 mouse_button_translate
[1] = 2; /* Middle */
2110 mouse_button_translate
[2] = 1; /* Right */
2114 mouse_button_count
= 2;
2115 mouse_button_translate
[0] = 0;
2116 mouse_button_translate
[1] = 1;
2118 mouse_position_hook
= &mouse_get_pos
;
2126 inregs
.x
.ax
= 0x4400; /* Get IOCTL status. */
2127 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2128 intdos (&inregs
, &outregs
);
2129 stdin_stat
= outregs
.h
.dl
;
2131 inregs
.x
.dx
= stdin_stat
| 0x0020; /* raw mode */
2132 inregs
.x
.ax
= 0x4401; /* Set IOCTL status */
2133 intdos (&inregs
, &outregs
);
2134 return !outregs
.x
.cflag
;
2137 /* Restore status of standard input and Ctrl-C checking. */
2141 union REGS inregs
, outregs
;
2143 setcbrk (break_stat
);
2146 inregs
.x
.ax
= 0x4401; /* Set IOCTL status. */
2147 inregs
.x
.bx
= 0x00; /* 0 = stdin. */
2148 inregs
.x
.dx
= stdin_stat
;
2149 intdos (&inregs
, &outregs
);
2150 return !outregs
.x
.cflag
;
2154 /* Run command as specified by ARGV in directory DIR.
2155 The command is run with input from TEMPIN and output to file TEMPOUT. */
2157 run_msdos_command (argv
, dir
, tempin
, tempout
)
2158 unsigned char **argv
;
2160 int tempin
, tempout
;
2162 char *saveargv1
, *saveargv2
, **envv
;
2163 char oldwd
[MAXPATHLEN
+ 1]; /* Fixed size is safe on MSDOS. */
2164 int msshell
, result
= -1;
2165 int in
, out
, inbak
, outbak
, errbak
;
2169 /* Get current directory as MSDOS cwd is not per-process. */
2172 cmd
= Ffile_name_nondirectory (build_string (argv
[0]));
2173 msshell
= !NILP (Fmember (cmd
, Fsymbol_value (intern ("msdos-shells"))))
2174 && !strcmp ("-c", argv
[1]);
2177 saveargv1
= argv
[1];
2178 saveargv2
= argv
[2];
2182 char *p
= alloca (strlen (argv
[2]) + 1);
2184 strcpy (argv
[2] = p
, saveargv2
);
2185 while (*p
&& isspace (*p
))
2187 while (*p
&& !isspace (*p
))
2195 /* Build the environment array. */
2197 extern Lisp_Object Vprocess_environment
;
2198 Lisp_Object tmp
, lst
;
2201 lst
= Vprocess_environment
;
2202 len
= XFASTINT (Flength (lst
));
2204 envv
= alloca ((len
+ 1) * sizeof (char *));
2205 for (i
= 0; i
< len
; i
++)
2209 CHECK_STRING (tmp
, 0);
2210 envv
[i
] = alloca (XSTRING (tmp
)->size
+ 1);
2211 strcpy (envv
[i
], XSTRING (tmp
)->data
);
2213 envv
[len
] = (char *) 0;
2217 chdir (XSTRING (dir
)->data
);
2221 if (inbak
< 0 || outbak
< 0 || errbak
< 0)
2222 goto done
; /* Allocation might fail due to lack of descriptors. */
2225 mouse_get_xy (&x
, &y
);
2227 dos_ttcooked (); /* do it here while 0 = stdin */
2233 result
= spawnve (P_WAIT
, argv
[0], argv
, envv
);
2246 mouse_moveto (x
, y
);
2253 argv
[1] = saveargv1
;
2254 argv
[2] = saveargv2
;
2262 fprintf (stderr
, "%s not yet implemented\r\n", badfunc
);
2268 /* ------------------------- Compatibility functions -------------------
2274 * Hostnames for a pc are not really funny,
2275 * but they are used in change log so we emulate the best we can.
2278 gethostname (p
, size
)
2282 char *q
= egetenv ("HOSTNAME");
2289 /* When time zones are set from Ms-Dos too many C-libraries are playing
2290 tricks with time values. We solve this by defining our own version
2291 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2292 once and after each call to `tzset' with TZ changed. That is
2293 accomplished by aliasing tzset to init_gettimeofday. */
2295 static struct tm time_rec
;
2298 gettimeofday (struct timeval
*tp
, struct timezone
*tzp
)
2306 if (t
.ti_hour
< time_rec
.tm_hour
) /* midnight wrap */
2310 time_rec
.tm_year
= d
.da_year
- 1900;
2311 time_rec
.tm_mon
= d
.da_mon
- 1;
2312 time_rec
.tm_mday
= d
.da_day
;
2315 time_rec
.tm_hour
= t
.ti_hour
;
2316 time_rec
.tm_min
= t
.ti_min
;
2317 time_rec
.tm_sec
= t
.ti_sec
;
2320 tm
.tm_gmtoff
= dos_timezone_offset
;
2322 tp
->tv_sec
= mktime (&tm
); /* may modify tm */
2323 tp
->tv_usec
= t
.ti_hund
* (1000000 / 100);
2325 /* Ignore tzp; it's obsolescent. */
2331 * A list of unimplemented functions that we silently ignore.
2334 unsigned alarm (s
) unsigned s
; {}
2335 fork () { return 0; }
2336 int kill (x
, y
) int x
, y
; { return -1; }
2338 void volatile pause () {}
2340 setpgrp () {return 0; }
2341 setpriority (x
,y
,z
) int x
,y
,z
; { return 0; }
2342 sigsetmask (x
) int x
; { return 0; }
2343 unrequest_sigio () {}
2345 int run_dos_timer_hooks
= 0;
2348 #include "sysselect.h"
2350 static int last_ti_sec
= -1;
2351 static int dos_menubar_clock_displayed
= 0;
2359 if (t
->ti_sec
== last_ti_sec
)
2361 last_ti_sec
= t
->ti_sec
;
2363 if (!NILP (Vdos_menubar_clock
))
2367 int min
= t
->ti_min
;
2368 int hour
= t
->ti_hour
;
2370 if (dos_timezone_offset
)
2372 int tz
= dos_timezone_offset
;
2380 if ((hour
-= (tz
/ 60)) < 0)
2386 if ((dos_country_info
[0x11] & 0x01) == 0) /* 12 hour clock */
2389 if (hour
== 0) hour
= 12;
2392 len
= sprintf (clock_str
, "%2d.%02d.%02d", hour
, min
, t
->ti_sec
);
2393 dos_direct_output (0, screen_size_X
- len
- 1, clock_str
, len
);
2394 dos_menubar_clock_displayed
= 1;
2396 else if (dos_menubar_clock_displayed
)
2398 /* Erase last displayed time. */
2399 dos_direct_output (0, screen_size_X
- 9, " ", 8);
2400 dos_menubar_clock_displayed
= 0;
2403 if (!NILP (Vdos_timer_hooks
))
2404 run_dos_timer_hooks
++;
2407 /* Only event queue is checked. */
2409 sys_select (nfds
, rfds
, wfds
, efds
, timeout
)
2411 SELECT_TYPE
*rfds
, *wfds
, *efds
;
2412 EMACS_TIME
*timeout
;
2415 long timeoutval
, clnow
, cllast
;
2421 check_input
= FD_ISSET (0, rfds
);
2432 /* If we are looking only for the terminal, with no timeout,
2433 just read it and wait -- that's more efficient. */
2436 while (! detect_input_pending ())
2441 timeoutval
= EMACS_SECS (*timeout
) * 100 + EMACS_USECS (*timeout
) / 10000;
2443 cllast
= t
.ti_sec
* 100 + t
.ti_hund
;
2445 while (!check_input
|| !detect_input_pending ())
2448 clnow
= t
.ti_sec
* 100 + t
.ti_hund
;
2449 if (clnow
< cllast
) /* time wrap */
2450 timeoutval
-= clnow
+ 6000 - cllast
;
2452 timeoutval
-= clnow
- cllast
;
2453 if (timeoutval
<= 0) /* Stop on timer being cleared */
2465 * Define overlayed functions:
2467 * chdir -> sys_chdir
2468 * tzset -> init_gettimeofday
2469 * abort -> dos_abort
2474 extern int chdir ();
2480 int len
= strlen (path
);
2481 char *tmp
= (char *)path
;
2483 if (*tmp
&& tmp
[1] == ':')
2485 if (getdisk () != tolower (tmp
[0]) - 'a')
2486 setdisk (tolower (tmp
[0]) - 'a');
2487 tmp
+= 2; /* strip drive: KFS 1995-07-06 */
2491 if (len
> 1 && (tmp
[len
- 1] == '/'))
2493 char *tmp1
= (char *) alloca (len
+ 1);
2504 extern void tzset (void);
2507 init_gettimeofday ()
2513 ltm
= gtm
= time (NULL
);
2514 ltm
= mktime (lstm
= localtime (<m
));
2515 gtm
= mktime (gmtime (>m
));
2516 time_rec
.tm_hour
= 99; /* force gettimeofday to get date */
2517 time_rec
.tm_isdst
= lstm
->tm_isdst
;
2518 dos_timezone_offset
= time_rec
.tm_gmtoff
= (int)(gtm
- ltm
) / 60;
2525 dos_abort (file
, line
)
2529 char buffer1
[200], buffer2
[400];
2532 sprintf (buffer1
, "<EMACS FATAL ERROR IN %s LINE %d>", file
, line
);
2533 for (i
= j
= 0; buffer1
[i
]; i
++) {
2534 buffer2
[j
++] = buffer1
[i
];
2535 buffer2
[j
++] = 0x70;
2537 dosmemput (buffer2
, j
, (int)ScreenPrimary
);
2538 ScreenSetCursor (2, 0);
2545 recent_doskeys
= Fmake_vector (make_number (NUM_RECENT_DOSKEYS
), Qnil
);
2546 staticpro (&recent_doskeys
);
2548 defsubr (&Srecent_doskeys
);