(vip-event-key): ignore consp events.
[emacs.git] / src / msdos.c
blob6f175da71a8da101e3c79517d2fdc89ad16ca894
1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995, 1996 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)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Contributed by Morten Welinder */
22 /* New display, keyboard, and mouse control by Kim F. Storm */
24 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
26 #include <config.h>
28 #ifdef MSDOS
29 #include "lisp.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <dos.h>
35 #include "dosfns.h"
36 #include "msdos.h"
37 #include "systime.h"
38 #include "termhooks.h"
39 #include "dispextern.h"
40 #include "termopts.h"
41 #include "frame.h"
42 #include "window.h"
43 #include <go32.h>
44 #include <pc.h>
45 #include <ctype.h>
46 /* #include <process.h> */
47 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
48 #define P_WAIT 1
51 static unsigned long
52 event_timestamp ()
54 struct time t;
55 unsigned long s;
57 gettime (&t);
58 s = t.ti_min;
59 s *= 60;
60 s += t.ti_sec;
61 s *= 1000;
62 s += t.ti_hund * 10;
64 return s;
68 /* ------------------------ Mouse control ---------------------------
70 * Coordinates are in screen positions and zero based.
71 * Mouse buttons are numbered from left to right and also zero based.
74 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
75 static int mouse_visible;
77 static int mouse_last_x;
78 static int mouse_last_y;
80 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
81 static int mouse_button_count;
83 void
84 mouse_on ()
86 union REGS regs;
88 if (have_mouse > 0 && !mouse_visible)
90 if (termscript)
91 fprintf (termscript, "<M_ON>");
92 regs.x.ax = 0x0001;
93 int86 (0x33, &regs, &regs);
94 mouse_visible = 1;
98 void
99 mouse_off ()
101 union REGS regs;
103 if (have_mouse > 0 && mouse_visible)
105 if (termscript)
106 fprintf (termscript, "<M_OFF>");
107 regs.x.ax = 0x0002;
108 int86 (0x33, &regs, &regs);
109 mouse_visible = 0;
113 void
114 mouse_moveto (x, y)
115 int x, y;
117 union REGS regs;
119 if (termscript)
120 fprintf (termscript, "<M_XY=%dx%d>", x, y);
121 regs.x.ax = 0x0004;
122 mouse_last_x = regs.x.cx = x * 8;
123 mouse_last_y = regs.x.dx = y * 8;
124 int86 (0x33, &regs, &regs);
127 static int
128 mouse_pressed (b, xp, yp)
129 int b, *xp, *yp;
131 union REGS regs;
133 if (b >= mouse_button_count)
134 return 0;
135 regs.x.ax = 0x0005;
136 regs.x.bx = mouse_button_translate[b];
137 int86 (0x33, &regs, &regs);
138 if (regs.x.bx)
139 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
140 return (regs.x.bx != 0);
143 static int
144 mouse_released (b, xp, yp)
145 int b, *xp, *yp;
147 union REGS regs;
149 if (b >= mouse_button_count)
150 return 0;
151 regs.x.ax = 0x0006;
152 regs.x.bx = mouse_button_translate[b];
153 int86 (0x33, &regs, &regs);
154 if (regs.x.bx)
155 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
156 return (regs.x.bx != 0);
159 static void
160 mouse_get_xy (int *x, int *y)
162 union REGS regs;
164 regs.x.ax = 0x0003;
165 int86 (0x33, &regs, &regs);
166 *x = regs.x.cx / 8;
167 *y = regs.x.dx / 8;
170 void
171 mouse_get_pos (f, insist, bar_window, part, x, y, time)
172 FRAME_PTR *f;
173 int insist;
174 Lisp_Object *bar_window, *x, *y;
175 enum scroll_bar_part *part;
176 unsigned long *time;
178 int ix, iy;
179 union REGS regs;
181 regs.x.ax = 0x0003;
182 int86 (0x33, &regs, &regs);
183 *f = selected_frame;
184 *bar_window = Qnil;
185 mouse_get_xy (&ix, &iy);
186 selected_frame->mouse_moved = 0;
187 *x = make_number (ix);
188 *y = make_number (iy);
189 *time = event_timestamp ();
192 static void
193 mouse_check_moved ()
195 int x, y;
197 mouse_get_xy (&x, &y);
198 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
199 mouse_last_x = x;
200 mouse_last_y = y;
203 void
204 mouse_init ()
206 union REGS regs;
208 if (termscript)
209 fprintf (termscript, "<M_INIT>");
211 regs.x.ax = 0x0021;
212 int86 (0x33, &regs, &regs);
214 regs.x.ax = 0x0007;
215 regs.x.cx = 0;
216 regs.x.dx = 8 * (ScreenCols () - 1);
217 int86 (0x33, &regs, &regs);
219 regs.x.ax = 0x0008;
220 regs.x.cx = 0;
221 regs.x.dx = 8 * (ScreenRows () - 1);
222 int86 (0x33, &regs, &regs);
224 mouse_moveto (0, 0);
225 mouse_visible = 0;
228 /* ------------------------- Screen control ----------------------
232 static int internal_terminal = 0;
234 #ifndef HAVE_X_WINDOWS
235 extern unsigned char ScreenAttrib;
236 static int screen_face;
237 static int highlight;
239 static int screen_size_X;
240 static int screen_size_Y;
241 static int screen_size;
243 static int current_pos_X;
244 static int current_pos_Y;
245 static int new_pos_X;
246 static int new_pos_Y;
248 static void *startup_screen_buffer;
249 static int startup_screen_size_X;
250 static int startup_screen_size_Y;
251 static int startup_pos_X;
252 static int startup_pos_Y;
253 static unsigned char startup_screen_attrib;
255 static int term_setup_done;
257 /* Similar to the_only_frame. */
258 struct x_output the_only_x_display;
260 /* This is never dereferenced. */
261 Display *x_current_display;
264 #define SCREEN_SET_CURSOR() \
265 if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \
266 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
268 static
269 dos_direct_output (y, x, buf, len)
270 int y;
271 int x;
272 char *buf;
273 int len;
275 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
277 while (--len >= 0) {
278 dosmemput (buf++, 1, t);
279 t += 2;
282 #endif
284 /* Flash the screen as a substitute for BEEPs. */
286 #if (__DJGPP__ < 2)
287 static void
288 do_visible_bell (xorattr)
289 unsigned char xorattr;
291 asm volatile
292 (" movb $1,%%dl
293 visible_bell_0:
294 movl _ScreenPrimary,%%eax
295 call dosmemsetup
296 movl %%eax,%%ebx
297 movl %1,%%ecx
298 movb %0,%%al
299 incl %%ebx
300 visible_bell_1:
301 xorb %%al,%%gs:(%%ebx)
302 addl $2,%%ebx
303 decl %%ecx
304 jne visible_bell_1
305 decb %%dl
306 jne visible_bell_3
307 visible_bell_2:
308 movzwl %%ax,%%eax
309 movzwl %%ax,%%eax
310 movzwl %%ax,%%eax
311 movzwl %%ax,%%eax
312 decw %%cx
313 jne visible_bell_2
314 jmp visible_bell_0
315 visible_bell_3:"
316 : /* no output */
317 : "m" (xorattr), "g" (screen_size)
318 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
321 static void
322 ScreenVisualBell (void)
324 /* This creates an xor-mask that will swap the default fore- and
325 background colors. */
326 do_visible_bell (((the_only_x_display.foreground_pixel
327 ^ the_only_x_display.background_pixel)
328 * 0x11) & 0x7f);
330 #endif
332 #ifndef HAVE_X_WINDOWS
334 /* Set the screen dimensions so that it can show no less than
335 ROWS x COLS frame. */
337 void
338 dos_set_window_size (rows, cols)
339 int *rows, *cols;
341 char video_name[30];
342 Lisp_Object video_mode;
343 int video_mode_value;
344 int have_vga = 0;
345 union REGS regs;
346 int current_rows = ScreenRows (), current_cols = ScreenCols ();
348 if (*rows == current_rows && *cols == current_cols)
349 return;
351 /* Do we have a VGA? */
352 regs.x.ax = 0x1a00;
353 int86 (0x10, &regs, &regs);
354 if (regs.h.al == 0x1a && regs.h.bl > 5 && regs.h.bl < 13)
355 have_vga = 1;
357 mouse_off ();
359 /* If the user specified a special video mode for these dimensions,
360 use that mode. */
361 sprintf (video_name, "screen-dimensions-%dx%d", *rows, *cols);
362 video_mode = XSYMBOL (Fintern_soft (build_string (video_name),
363 Qnil))-> value;
365 if (INTEGERP (video_mode)
366 && (video_mode_value = XINT (video_mode)) > 0)
368 regs.x.ax = video_mode_value;
369 int86 (0x10, &regs, &regs);
370 regs.h.bl = 0;
371 regs.x.ax = 0x1003;
372 int86 (0x10, &regs, &regs);
374 if (have_mouse)
376 /* Must hardware-reset the mouse, or else it won't update
377 its notion of screen dimensions for some non-standard
378 video modes. This is *painfully* slow... */
379 regs.x.ax = 0;
380 int86 (0x33, &regs, &regs);
384 /* Find one of the dimensions supported by standard EGA/VGA
385 which gives us at least the required dimensions. */
387 #if __DJGPP__ > 1
389 else
391 static struct {
392 int rows;
393 int need_vga;
394 } std_dimension[] = {
395 {25, 0},
396 {28, 1},
397 {35, 0},
398 {40, 1},
399 {43, 0},
400 {50, 1}
402 int i = 0;
404 while (i < sizeof (std_dimension) / sizeof (std_dimension[0]))
406 if (std_dimension[i].need_vga <= have_vga
407 && std_dimension[i].rows >= *rows)
409 if (std_dimension[i].rows != current_rows
410 || *cols != current_cols)
411 _set_screen_lines (std_dimension[i].rows);
412 break;
414 i++;
418 #else /* not __DJGPP__ > 1 */
420 else if (*rows <= 25)
422 if (current_rows != 25 || current_cols != 80)
424 regs.x.ax = 3;
425 int86 (0x10, &regs, &regs);
426 regs.x.ax = 0x1101;
427 regs.h.bl = 0;
428 int86 (0x10, &regs, &regs);
429 regs.x.ax = 0x1200;
430 regs.h.bl = 32;
431 int86 (0x10, &regs, &regs);
432 regs.x.ax = 3;
433 int86 (0x10, &regs, &regs);
436 else if (*rows <= 50)
437 if (have_vga && (current_rows != 50 || current_cols != 80)
438 || *rows <= 43 && (current_rows != 43 || current_cols != 80))
440 regs.x.ax = 3;
441 int86 (0x10, &regs, &regs);
442 regs.x.ax = 0x1112;
443 regs.h.bl = 0;
444 int86 (0x10, &regs, &regs);
445 regs.x.ax = 0x1200;
446 regs.h.bl = 32;
447 int86 (0x10, &regs, &regs);
448 regs.x.ax = 0x0100;
449 regs.x.cx = 7;
450 int86 (0x10, &regs, &regs);
452 #endif /* not __DJGPP__ > 1 */
454 if (have_mouse)
456 mouse_init ();
457 mouse_on ();
460 /* Tell the caller what dimensions have been REALLY set. */
461 *rows = ScreenRows ();
462 *cols = ScreenCols ();
465 /* If we write a character in the position where the mouse is,
466 the mouse cursor may need to be refreshed. */
468 static void
469 mouse_off_maybe ()
471 int x, y;
473 if (!mouse_visible)
474 return;
476 mouse_get_xy (&x, &y);
477 if (y != new_pos_Y || x < new_pos_X)
478 return;
480 mouse_off ();
483 static
484 IT_ring_bell ()
486 if (visible_bell)
488 mouse_off ();
489 ScreenVisualBell ();
491 else
493 union REGS inregs, outregs;
494 inregs.h.ah = 2;
495 inregs.h.dl = 7;
496 intdos (&inregs, &outregs);
500 static void
501 IT_set_face (int face)
503 struct face *fp;
504 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
506 if (face == 1 || (face == 0 && highlight))
507 fp = FRAME_MODE_LINE_FACE (foo);
508 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
509 fp = FRAME_DEFAULT_FACE (foo);
510 else
511 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
512 if (termscript)
513 fprintf (termscript, "<FACE:%d:%d>", FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
514 screen_face = face;
515 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
518 static
519 IT_write_glyphs (GLYPH *str, int len)
521 int newface;
522 int ch, l = len;
523 unsigned char *buf, *bp;
525 if (len == 0) return;
527 buf = bp = alloca (len * 2);
529 while (--l >= 0)
531 newface = FAST_GLYPH_FACE (*str);
532 if (newface != screen_face)
533 IT_set_face (newface);
534 ch = FAST_GLYPH_CHAR (*str);
535 *bp++ = (unsigned char)ch;
536 *bp++ = ScreenAttrib;
538 if (termscript)
539 fputc (ch, termscript);
540 str++;
543 mouse_off_maybe ();
544 dosmemput (buf, 2 * len,
545 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
546 new_pos_X += len;
549 static
550 IT_clear_end_of_line (first_unused)
552 char *spaces, *sp;
553 int i, j;
555 IT_set_face (0);
556 if (termscript)
557 fprintf (termscript, "<CLR:EOL>");
558 i = (j = screen_size_X - new_pos_X) * 2;
559 spaces = sp = alloca (i);
561 while (--j >= 0)
563 *sp++ = ' ';
564 *sp++ = ScreenAttrib;
567 mouse_off_maybe ();
568 dosmemput (spaces, i,
569 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
572 static
573 IT_clear_screen (void)
575 if (termscript)
576 fprintf (termscript, "<CLR:SCR>");
577 IT_set_face (0);
578 mouse_off ();
579 ScreenClear ();
580 new_pos_X = new_pos_Y = 0;
583 static
584 IT_clear_to_end (void)
586 if (termscript)
587 fprintf (termscript, "<CLR:EOS>");
589 while (new_pos_Y < screen_size_Y) {
590 new_pos_X = 0;
591 IT_clear_end_of_line (0);
592 new_pos_Y++;
596 static
597 IT_cursor_to (int y, int x)
599 if (termscript)
600 fprintf (termscript, "\n<XY=%dx%d>", x, y);
601 new_pos_X = x;
602 new_pos_Y = y;
605 static
606 IT_reassert_line_highlight (new, vpos)
607 int new, vpos;
609 highlight = new;
610 IT_set_face (0); /* To possibly clear the highlighting. */
613 static
614 IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
616 highlight = new_highlight;
617 IT_set_face (0); /* To possibly clear the highlighting. */
618 IT_cursor_to (vpos, 0);
619 IT_clear_end_of_line (first_unused_hpos);
622 static
623 IT_update_begin ()
625 highlight = 0;
626 IT_set_face (0); /* To possibly clear the highlighting. */
627 screen_face = -1;
630 static
631 IT_update_end ()
635 /* This was more or less copied from xterm.c */
637 static void
638 IT_set_menu_bar_lines (window, n)
639 Lisp_Object window;
640 int n;
642 struct window *w = XWINDOW (window);
644 XSETFASTINT (w->last_modified, 0);
645 XSETFASTINT (w->top, XFASTINT (w->top) + n);
646 XSETFASTINT (w->height, XFASTINT (w->height) - n);
648 /* Handle just the top child in a vertical split. */
649 if (!NILP (w->vchild))
650 IT_set_menu_bar_lines (w->vchild, n);
652 /* Adjust all children in a horizontal split. */
653 for (window = w->hchild; !NILP (window); window = w->next)
655 w = XWINDOW (window);
656 IT_set_menu_bar_lines (window, n);
660 /* IT_set_terminal_modes is called when emacs is started,
661 resumed, and whenever the screen is redrawn! */
663 static
664 IT_set_terminal_modes (void)
666 char *colors;
667 FRAME_PTR f;
668 struct face *fp;
670 if (termscript)
671 fprintf (termscript, "\n<SET_TERM>");
672 highlight = 0;
674 screen_size_X = ScreenCols ();
675 screen_size_Y = ScreenRows ();
676 screen_size = screen_size_X * screen_size_Y;
678 new_pos_X = new_pos_Y = 0;
679 current_pos_X = current_pos_Y = -1;
681 if (term_setup_done)
682 return;
683 term_setup_done = 1;
685 startup_screen_size_X = screen_size_X;
686 startup_screen_size_Y = screen_size_Y;
687 startup_screen_attrib = ScreenAttrib;
689 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
690 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
692 if (termscript)
693 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
694 screen_size_X, screen_size_Y);
697 /* IT_reset_terminal_modes is called when emacs is
698 suspended or killed. */
700 static
701 IT_reset_terminal_modes (void)
703 int display_row_start = (int) ScreenPrimary;
704 int saved_row_len = startup_screen_size_X * 2;
705 int update_row_len = ScreenCols () * 2;
706 int current_rows = ScreenRows ();
707 int to_next_row = update_row_len;
708 unsigned char *saved_row = startup_screen_buffer;
709 int cursor_pos_X = ScreenCols () - 1;
710 int cursor_pos_Y = ScreenRows () - 1;
712 if (termscript)
713 fprintf (termscript, "\n<RESET_TERM>");
715 highlight = 0;
717 if (!term_setup_done)
718 return;
720 mouse_off ();
722 /* We have a situation here.
723 We cannot just do ScreenUpdate(startup_screen_buffer) because
724 the luser could have changed screen dimensions inside Emacs
725 and failed (or didn't want) to restore them before killing
726 Emacs. ScreenUpdate() uses the *current* screen dimensions and
727 thus will happily use memory outside what was allocated for
728 `startup_screen_buffer'.
729 Thus we only restore as much as the current screen dimensions
730 can hold, and clear the rest (if the saved screen is smaller than
731 the current) with the color attribute saved at startup. The cursor
732 is also restored within the visible dimensions. */
734 ScreenAttrib = startup_screen_attrib;
735 ScreenClear ();
737 if (update_row_len > saved_row_len)
738 update_row_len = saved_row_len;
739 if (current_rows > startup_screen_size_Y)
740 current_rows = startup_screen_size_Y;
742 if (termscript)
743 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
744 update_row_len / 2, current_rows);
746 while (current_rows--)
748 dosmemput (saved_row, update_row_len, display_row_start);
749 saved_row += saved_row_len;
750 display_row_start += to_next_row;
752 if (startup_pos_X < cursor_pos_X)
753 cursor_pos_X = startup_pos_X;
754 if (startup_pos_Y < cursor_pos_Y)
755 cursor_pos_Y = startup_pos_Y;
757 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
758 xfree (startup_screen_buffer);
760 term_setup_done = 0;
763 static
764 IT_set_terminal_window (void)
768 void
769 IT_set_frame_parameters (frame, alist)
770 FRAME_PTR frame;
771 Lisp_Object alist;
773 Lisp_Object tail;
774 int redraw;
775 extern unsigned long load_color ();
776 FRAME_PTR f = (FRAME_PTR) &the_only_frame;
778 redraw = 0;
779 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
781 Lisp_Object elt, prop, val;
783 elt = Fcar (tail);
784 prop = Fcar (elt);
785 val = Fcdr (elt);
786 CHECK_SYMBOL (prop, 1);
788 if (EQ (prop, intern ("foreground-color")))
790 unsigned long new_color = load_color (f, val);
791 if (new_color != ~0)
793 FRAME_FOREGROUND_PIXEL (f) = new_color;
794 redraw = 1;
797 else if (EQ (prop, intern ("background-color")))
799 unsigned long new_color = load_color (f, val);
800 if (new_color != ~0)
802 FRAME_BACKGROUND_PIXEL (f) = new_color & ~8;
803 redraw = 1;
806 else if (EQ (prop, intern ("menu-bar-lines")))
808 int new;
809 int old = FRAME_MENU_BAR_LINES (the_only_frame);
811 if (INTEGERP (val))
812 new = XINT (val);
813 else
814 new = 0;
815 FRAME_MENU_BAR_LINES (f) = new;
816 IT_set_menu_bar_lines (the_only_frame.root_window, new - old);
820 if (redraw)
822 recompute_basic_faces (f);
823 Fredraw_frame (Fselected_frame ());
827 #endif /* !HAVE_X_WINDOWS */
830 /* Do we need the internal terminal? */
832 void
833 internal_terminal_init ()
835 char *term = getenv ("TERM");
836 char *colors;
838 #ifdef HAVE_X_WINDOWS
839 if (!inhibit_window_system)
840 return;
841 #endif
843 internal_terminal
844 = (!noninteractive) && term && !strcmp (term, "internal");
846 if (getenv ("EMACSTEST"))
847 termscript = fopen (getenv ("EMACSTEST"), "wt");
849 #ifndef HAVE_X_WINDOWS
850 if (!internal_terminal || inhibit_window_system)
852 the_only_frame.output_method = output_termcap;
853 return;
856 Vwindow_system = intern ("pc");
857 Vwindow_system_version = make_number (1);
859 bzero (&the_only_x_display, sizeof the_only_x_display);
860 the_only_x_display.background_pixel = 7; /* White */
861 the_only_x_display.foreground_pixel = 0; /* Black */
862 colors = getenv ("EMACSCOLORS");
863 if (colors && strlen (colors) >= 2)
865 the_only_x_display.foreground_pixel = colors[0] & 0x07;
866 the_only_x_display.background_pixel = colors[1] & 0x07;
868 the_only_x_display.line_height = 1;
869 the_only_frame.output_data.x = &the_only_x_display;
870 the_only_frame.output_method = output_msdos_raw;
871 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
873 init_frame_faces ((FRAME_PTR) &the_only_frame);
875 ring_bell_hook = IT_ring_bell;
876 write_glyphs_hook = IT_write_glyphs;
877 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
878 clear_to_end_hook = IT_clear_to_end;
879 clear_end_of_line_hook = IT_clear_end_of_line;
880 clear_frame_hook = IT_clear_screen;
881 change_line_highlight_hook = IT_change_line_highlight;
882 update_begin_hook = IT_update_begin;
883 update_end_hook = IT_update_end;
884 reassert_line_highlight_hook = IT_reassert_line_highlight;
886 /* These hooks are called by term.c without being checked. */
887 set_terminal_modes_hook = IT_set_terminal_modes;
888 reset_terminal_modes_hook = IT_reset_terminal_modes;
889 set_terminal_window_hook = IT_set_terminal_window;
890 #endif
893 dos_get_saved_screen (screen, rows, cols)
894 char **screen;
895 int *rows;
896 int *cols;
898 #ifndef HAVE_X_WINDOWS
899 *screen = startup_screen_buffer;
900 *cols = startup_screen_size_X;
901 *rows = startup_screen_size_Y;
902 return 1;
903 #else
904 return 0;
905 #endif
908 /* ----------------------- Keyboard control ----------------------
910 * Keymaps reflect the following keyboard layout:
912 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
913 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
914 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
915 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
916 * SPACE
919 static int extended_kbd; /* 101 (102) keyboard present. */
921 struct dos_keyboard_map
923 char *unshifted;
924 char *shifted;
925 char *alt_gr;
929 static struct dos_keyboard_map us_keyboard = {
930 /* 0 1 2 3 4 5 */
931 /* 01234567890123456789012345678901234567890 12345678901234 */
932 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
933 /* 0123456789012345678901234567890123456789 012345678901234 */
934 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
935 0 /* no Alt-Gr key */
938 static struct dos_keyboard_map fr_keyboard = {
939 /* 0 1 2 3 4 5 */
940 /* 012 3456789012345678901234567890123456789012345678901234 */
941 "ý&‚\",(-Š_€…)= azertyuiop^$ qsdfghjklm—* wxcvbnm;:! ",
942 /* 0123456789012345678901234567890123456789012345678901234 */
943 " 1234567890ø+ AZERTYUIOPùœ QSDFGHJKLM%æ WXCVBN?./õ ",
944 /* 01234567 89012345678901234567890123456789012345678901234 */
945 " ~#{[|`\\^@]} Ï "
948 static struct dos_keyboard_map dk_keyboard = {
949 /* 0 1 2 3 4 5 */
950 /* 0123456789012345678901234567890123456789012345678901234 */
951 "«1234567890+| qwertyuiop†~ asdfghjkl‘›' zxcvbnm,.- ",
952 /* 01 23456789012345678901234567890123456789012345678901234 */
953 "õ!\"#$%&/()=?` QWERTYUIOP�^ ASDFGHJKL’�* ZXCVBNM;:_ ",
954 /* 0123456789012345678901234567890123456789012345678901234 */
955 " @œ$ {[]} | "
958 static struct keyboard_layout_list
960 int country_code;
961 struct dos_keyboard_map *keyboard_map;
962 } keyboard_layout_list[] =
964 1, &us_keyboard,
965 33, &fr_keyboard,
966 45, &dk_keyboard
969 static struct dos_keyboard_map *keyboard;
970 static int keyboard_map_all;
973 dos_set_keyboard (code, always)
974 int code;
975 int always;
977 int i;
979 /* Initialize to US settings, for countries that don't have their own. */
980 keyboard = keyboard_layout_list[0].keyboard_map;
981 keyboard_map_all = always;
982 dos_keyboard_layout = 1;
984 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
985 if (code == keyboard_layout_list[i].country_code)
987 keyboard = keyboard_layout_list[i].keyboard_map;
988 keyboard_map_all = always;
989 dos_keyboard_layout = code;
990 return 1;
992 return 0;
995 #define Ignore 0x0000
996 #define Normal 0x0000 /* normal key - alt changes scan-code */
997 #define FctKey 0x1000 /* func key if c == 0, else c */
998 #define Special 0x2000 /* func key even if c != 0 */
999 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
1000 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
1001 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
1002 #define Grey 0x6000 /* Grey keypad key */
1004 #define Alt 0x0100 /* alt scan-code */
1005 #define Ctrl 0x0200 /* ctrl scan-code */
1006 #define Shift 0x0400 /* shift scan-code */
1008 static struct
1010 unsigned char char_code; /* normal code */
1011 unsigned char meta_code; /* M- code */
1012 unsigned char keypad_code; /* keypad code */
1013 unsigned char editkey_code; /* edit key */
1014 } keypad_translate_map[] = {
1015 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
1016 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
1017 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
1018 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
1019 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
1020 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
1021 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
1022 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
1023 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
1024 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
1025 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
1028 static struct
1030 unsigned char char_code; /* normal code */
1031 unsigned char keypad_code; /* keypad code */
1032 } grey_key_translate_map[] = {
1033 '/', 0xaf, /* kp-decimal */
1034 '*', 0xaa, /* kp-multiply */
1035 '-', 0xad, /* kp-subtract */
1036 '+', 0xab, /* kp-add */
1037 '\r', 0x8d /* kp-enter */
1040 static unsigned short
1041 ibmpc_translate_map[] =
1043 /* --------------- 00 to 0f --------------- */
1044 Normal | 0xff, /* Ctrl Break + Alt-NNN */
1045 Alt | ModFct | 0x1b, /* Escape */
1046 Normal | 1, /* '1' */
1047 Normal | 2, /* '2' */
1048 Normal | 3, /* '3' */
1049 Normal | 4, /* '4' */
1050 Normal | 5, /* '5' */
1051 Normal | 6, /* '6' */
1052 Normal | 7, /* '7' */
1053 Normal | 8, /* '8' */
1054 Normal | 9, /* '9' */
1055 Normal | 10, /* '0' */
1056 Normal | 11, /* '-' */
1057 Normal | 12, /* '=' */
1058 Special | 0x08, /* Backspace */
1059 ModFct | 0x74, /* Tab/Backtab */
1061 /* --------------- 10 to 1f --------------- */
1062 Map | 15, /* 'q' */
1063 Map | 16, /* 'w' */
1064 Map | 17, /* 'e' */
1065 Map | 18, /* 'r' */
1066 Map | 19, /* 't' */
1067 Map | 20, /* 'y' */
1068 Map | 21, /* 'u' */
1069 Map | 22, /* 'i' */
1070 Map | 23, /* 'o' */
1071 Map | 24, /* 'p' */
1072 Map | 25, /* '[' */
1073 Map | 26, /* ']' */
1074 ModFct | 0x0d, /* Return */
1075 Ignore, /* Ctrl */
1076 Map | 30, /* 'a' */
1077 Map | 31, /* 's' */
1079 /* --------------- 20 to 2f --------------- */
1080 Map | 32, /* 'd' */
1081 Map | 33, /* 'f' */
1082 Map | 34, /* 'g' */
1083 Map | 35, /* 'h' */
1084 Map | 36, /* 'j' */
1085 Map | 37, /* 'k' */
1086 Map | 38, /* 'l' */
1087 Map | 39, /* ';' */
1088 Map | 40, /* '\'' */
1089 Map | 0, /* '`' */
1090 Ignore, /* Left shift */
1091 Map | 41, /* '\\' */
1092 Map | 45, /* 'z' */
1093 Map | 46, /* 'x' */
1094 Map | 47, /* 'c' */
1095 Map | 48, /* 'v' */
1097 /* --------------- 30 to 3f --------------- */
1098 Map | 49, /* 'b' */
1099 Map | 50, /* 'n' */
1100 Map | 51, /* 'm' */
1101 Map | 52, /* ',' */
1102 Map | 53, /* '.' */
1103 Map | 54, /* '/' */
1104 Ignore, /* Right shift */
1105 Grey | 1, /* Grey * */
1106 Ignore, /* Alt */
1107 Normal | ' ', /* ' ' */
1108 Ignore, /* Caps Lock */
1109 FctKey | 0xbe, /* F1 */
1110 FctKey | 0xbf, /* F2 */
1111 FctKey | 0xc0, /* F3 */
1112 FctKey | 0xc1, /* F4 */
1113 FctKey | 0xc2, /* F5 */
1115 /* --------------- 40 to 4f --------------- */
1116 FctKey | 0xc3, /* F6 */
1117 FctKey | 0xc4, /* F7 */
1118 FctKey | 0xc5, /* F8 */
1119 FctKey | 0xc6, /* F9 */
1120 FctKey | 0xc7, /* F10 */
1121 Ignore, /* Num Lock */
1122 Ignore, /* Scroll Lock */
1123 KeyPad | 7, /* Home */
1124 KeyPad | 8, /* Up */
1125 KeyPad | 9, /* Page Up */
1126 Grey | 2, /* Grey - */
1127 KeyPad | 4, /* Left */
1128 KeyPad | 5, /* Keypad 5 */
1129 KeyPad | 6, /* Right */
1130 Grey | 3, /* Grey + */
1131 KeyPad | 1, /* End */
1133 /* --------------- 50 to 5f --------------- */
1134 KeyPad | 2, /* Down */
1135 KeyPad | 3, /* Page Down */
1136 KeyPad | 0, /* Insert */
1137 KeyPad | 10, /* Delete */
1138 Shift | FctKey | 0xbe, /* (Shift) F1 */
1139 Shift | FctKey | 0xbf, /* (Shift) F2 */
1140 Shift | FctKey | 0xc0, /* (Shift) F3 */
1141 Shift | FctKey | 0xc1, /* (Shift) F4 */
1142 Shift | FctKey | 0xc2, /* (Shift) F5 */
1143 Shift | FctKey | 0xc3, /* (Shift) F6 */
1144 Shift | FctKey | 0xc4, /* (Shift) F7 */
1145 Shift | FctKey | 0xc5, /* (Shift) F8 */
1146 Shift | FctKey | 0xc6, /* (Shift) F9 */
1147 Shift | FctKey | 0xc7, /* (Shift) F10 */
1148 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1149 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1151 /* --------------- 60 to 6f --------------- */
1152 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1153 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1154 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1155 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1156 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1157 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1158 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1159 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1160 Alt | FctKey | 0xbe, /* (Alt) F1 */
1161 Alt | FctKey | 0xbf, /* (Alt) F2 */
1162 Alt | FctKey | 0xc0, /* (Alt) F3 */
1163 Alt | FctKey | 0xc1, /* (Alt) F4 */
1164 Alt | FctKey | 0xc2, /* (Alt) F5 */
1165 Alt | FctKey | 0xc3, /* (Alt) F6 */
1166 Alt | FctKey | 0xc4, /* (Alt) F7 */
1167 Alt | FctKey | 0xc5, /* (Alt) F8 */
1169 /* --------------- 70 to 7f --------------- */
1170 Alt | FctKey | 0xc6, /* (Alt) F9 */
1171 Alt | FctKey | 0xc7, /* (Alt) F10 */
1172 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1173 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1174 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1175 Ctrl | KeyPad | 1, /* (Ctrl) End */
1176 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1177 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1178 Alt | Map | 1, /* '1' */
1179 Alt | Map | 2, /* '2' */
1180 Alt | Map | 3, /* '3' */
1181 Alt | Map | 4, /* '4' */
1182 Alt | Map | 5, /* '5' */
1183 Alt | Map | 6, /* '6' */
1184 Alt | Map | 7, /* '7' */
1185 Alt | Map | 8, /* '8' */
1187 /* --------------- 80 to 8f --------------- */
1188 Alt | Map | 9, /* '9' */
1189 Alt | Map | 10, /* '0' */
1190 Alt | Map | 11, /* '-' */
1191 Alt | Map | 12, /* '=' */
1192 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1193 FctKey | 0xc8, /* F11 */
1194 FctKey | 0xc9, /* F12 */
1195 Shift | FctKey | 0xc8, /* (Shift) F11 */
1196 Shift | FctKey | 0xc9, /* (Shift) F12 */
1197 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1198 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1199 Alt | FctKey | 0xc8, /* (Alt) F11 */
1200 Alt | FctKey | 0xc9, /* (Alt) F12 */
1201 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1202 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1203 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1205 /* --------------- 90 to 9f --------------- */
1206 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1207 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1208 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1209 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1210 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1211 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1212 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1213 Alt | FctKey | 0x50, /* (Alt) Home */
1214 Alt | FctKey | 0x52, /* (Alt) Up */
1215 Alt | FctKey | 0x55, /* (Alt) Page Up */
1216 Ignore, /* NO KEY */
1217 Alt | FctKey | 0x51, /* (Alt) Left */
1218 Ignore, /* NO KEY */
1219 Alt | FctKey | 0x53, /* (Alt) Right */
1220 Ignore, /* NO KEY */
1221 Alt | FctKey | 0x57, /* (Alt) End */
1223 /* --------------- a0 to af --------------- */
1224 Alt | KeyPad | 2, /* (Alt) Down */
1225 Alt | KeyPad | 3, /* (Alt) Page Down */
1226 Alt | KeyPad | 0, /* (Alt) Insert */
1227 Alt | KeyPad | 10, /* (Alt) Delete */
1228 Alt | Grey | 0, /* (Alt) Grey / */
1229 Alt | FctKey | 0x09, /* (Alt) Tab */
1230 Alt | Grey | 4 /* (Alt) Keypad Enter */
1233 /* These bit-positions corresponds to values returned by BIOS */
1234 #define SHIFT_P 0x0003 /* two bits! */
1235 #define CTRL_P 0x0004
1236 #define ALT_P 0x0008
1237 #define SCRLOCK_P 0x0010
1238 #define NUMLOCK_P 0x0020
1239 #define CAPSLOCK_P 0x0040
1240 #define ALT_GR_P 0x0800
1241 #define SUPER_P 0x4000 /* pseudo */
1242 #define HYPER_P 0x8000 /* pseudo */
1244 static int
1245 dos_get_modifiers (keymask)
1246 int *keymask;
1248 union REGS regs;
1249 int mask;
1250 int modifiers = 0;
1252 /* Calculate modifier bits */
1253 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1254 int86 (0x16, &regs, &regs);
1256 if (!extended_kbd)
1258 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1259 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1261 else
1263 mask = regs.h.al & (SHIFT_P |
1264 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1266 /* Do not break international keyboard support. */
1267 /* When Keyb.Com is loaded, the right Alt key is */
1268 /* used for accessing characters like { and } */
1269 if (regs.h.ah & 2) /* Left ALT pressed ? */
1270 mask |= ALT_P;
1272 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1274 mask |= ALT_GR_P;
1275 if (dos_hyper_key == 1)
1277 mask |= HYPER_P;
1278 modifiers |= hyper_modifier;
1280 else if (dos_super_key == 1)
1282 mask |= SUPER_P;
1283 modifiers |= super_modifier;
1287 if (regs.h.ah & 1) /* Left CTRL pressed
1288 mask |= CTRL_P;
1290 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1292 if (dos_hyper_key == 2)
1294 mask |= HYPER_P;
1295 modifiers |= hyper_modifier;
1297 else if (dos_super_key == 2)
1299 mask |= SUPER_P;
1300 modifiers |= super_modifier;
1302 else
1303 mask |= CTRL_P;
1307 if (mask & SHIFT_P)
1308 modifiers |= shift_modifier;
1309 if (mask & CTRL_P)
1310 modifiers |= ctrl_modifier;
1311 if (mask & ALT_P)
1312 modifiers |= meta_modifier;
1314 if (keymask)
1315 *keymask = mask;
1316 return modifiers;
1319 #define NUM_RECENT_DOSKEYS (100)
1320 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1321 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1322 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1324 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1325 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1326 Each input key receives two values in this vector: first the ASCII code,\n\
1327 and then the scan code.")
1330 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1331 Lisp_Object val;
1333 if (total_doskeys < NUM_RECENT_DOSKEYS)
1334 return Fvector (total_doskeys, keys);
1335 else
1337 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1338 bcopy (keys + recent_doskeys_index,
1339 XVECTOR (val)->contents,
1340 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1341 bcopy (keys,
1342 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1343 recent_doskeys_index * sizeof (Lisp_Object));
1344 return val;
1348 /* Get a char from keyboard. Function keys are put into the event queue. */
1350 static int
1351 dos_rawgetc ()
1353 struct input_event event;
1354 union REGS regs;
1356 #ifndef HAVE_X_WINDOWS
1357 SCREEN_SET_CURSOR ();
1358 if (!mouse_visible) mouse_on ();
1359 #endif
1361 /* The following condition is equivalent to `kbhit ()', except that
1362 it uses the bios to do its job. This pleases DESQview/X. */
1363 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1364 int86 (0x16, &regs, &regs),
1365 (regs.x.flags & 0x40) == 0)
1367 union REGS regs;
1368 register unsigned char c;
1369 int sc, code, mask, kp_mode;
1370 int modifiers;
1372 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1373 int86 (0x16, &regs, &regs);
1374 c = regs.h.al;
1375 sc = regs.h.ah;
1377 total_doskeys += 2;
1378 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1379 = make_number (c);
1380 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1381 recent_doskeys_index = 0;
1382 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1383 = make_number (sc);
1384 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1385 recent_doskeys_index = 0;
1387 modifiers = dos_get_modifiers (&mask);
1389 #ifndef HAVE_X_WINDOWS
1390 if (!NILP (Vdos_display_scancodes))
1392 char buf[11];
1393 sprintf (buf, "%02x:%02x*%04x",
1394 (unsigned) (sc&0xff), (unsigned) c, mask);
1395 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1397 #endif
1399 if (sc == 0xe0)
1401 switch (c)
1403 case 10: /* Ctrl Grey Enter */
1404 code = Ctrl | Grey | 4;
1405 break;
1406 case 13: /* Grey Enter */
1407 code = Grey | 4;
1408 break;
1409 case '/': /* Grey / */
1410 code = Grey | 0;
1411 break;
1412 default:
1413 continue;
1415 c = 0;
1417 else
1419 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1420 continue;
1421 if ((code = ibmpc_translate_map[sc]) == Ignore)
1422 continue;
1425 if (c == 0)
1427 if (code & Alt)
1428 modifiers |= meta_modifier;
1429 if (code & Ctrl)
1430 modifiers |= ctrl_modifier;
1431 if (code & Shift)
1432 modifiers |= shift_modifier;
1435 switch (code & 0xf000)
1437 case ModFct:
1438 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1439 return c;
1440 c = 0; /* Special */
1442 case FctKey:
1443 if (c != 0)
1444 return c;
1446 case Special:
1447 code |= 0xff00;
1448 break;
1450 case Normal:
1451 if (sc == 0)
1453 if (c == 0) /* ctrl-break */
1454 continue;
1455 return c; /* ALT-nnn */
1457 if (!keyboard_map_all)
1459 if (c != ' ')
1460 return c;
1461 code = c;
1462 break;
1465 case Map:
1466 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1467 if (!keyboard_map_all)
1468 return c;
1470 code &= 0xff;
1471 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1472 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1474 if (mask & SHIFT_P)
1476 code = keyboard->shifted[code];
1477 mask -= SHIFT_P;
1478 modifiers &= ~shift_modifier;
1480 else
1481 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1482 code = keyboard->alt_gr[code];
1483 else
1484 code = keyboard->unshifted[code];
1485 break;
1487 case KeyPad:
1488 code &= 0xff;
1489 if (c == 0xe0) /* edit key */
1490 kp_mode = 3;
1491 else
1492 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1493 kp_mode = dos_keypad_mode & 0x03;
1494 else
1495 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1497 switch (kp_mode)
1499 case 0:
1500 if (code == 10 && dos_decimal_point)
1501 return dos_decimal_point;
1502 return keypad_translate_map[code].char_code;
1504 case 1:
1505 code = 0xff00 | keypad_translate_map[code].keypad_code;
1506 break;
1508 case 2:
1509 code = keypad_translate_map[code].meta_code;
1510 modifiers = meta_modifier;
1511 break;
1513 case 3:
1514 code = 0xff00 | keypad_translate_map[code].editkey_code;
1515 break;
1517 break;
1519 case Grey:
1520 code &= 0xff;
1521 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1522 if (dos_keypad_mode & kp_mode)
1523 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1524 else
1525 code = grey_key_translate_map[code].char_code;
1526 break;
1529 make_event:
1530 if (code == 0)
1531 continue;
1533 if (code >= 0x100)
1534 event.kind = non_ascii_keystroke;
1535 else
1536 event.kind = ascii_keystroke;
1537 event.code = code;
1538 event.modifiers = modifiers;
1539 XSETFRAME (event.frame_or_window, selected_frame);
1540 event.timestamp = event_timestamp ();
1541 kbd_buffer_store_event (&event);
1544 if (have_mouse > 0)
1546 int but, press, x, y, ok;
1548 /* Check for mouse movement *before* buttons. */
1549 mouse_check_moved ();
1551 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1552 for (press = 0; press < 2; press++)
1554 int button_num = but;
1556 if (press)
1557 ok = mouse_pressed (but, &x, &y);
1558 else
1559 ok = mouse_released (but, &x, &y);
1560 if (ok)
1562 /* Allow a simultaneous press/release of Mouse-1 and
1563 Mouse-2 to simulate Mouse-3 on two-button mice. */
1564 if (mouse_button_count == 2 && but < 2)
1566 int x2, y2; /* don't clobber original coordinates */
1568 /* If only one button is pressed, wait 100 msec and
1569 check again. This way, Speedy Gonzales isn't
1570 punished, while the slow get their chance. */
1571 if (press && mouse_pressed (1-but, &x2, &y2)
1572 || !press && mouse_released (1-but, &x2, &y2))
1573 button_num = 2;
1574 else
1576 delay (100);
1577 if (press && mouse_pressed (1-but, &x2, &y2)
1578 || !press && mouse_released (1-but, &x2, &y2))
1579 button_num = 2;
1583 event.kind = mouse_click;
1584 event.code = button_num;
1585 event.modifiers = dos_get_modifiers (0)
1586 | (press ? down_modifier : up_modifier);
1587 event.x = x;
1588 event.y = y;
1589 XSETFRAME (event.frame_or_window, selected_frame);
1590 event.timestamp = event_timestamp ();
1591 kbd_buffer_store_event (&event);
1596 return -1;
1599 static int prev_get_char = -1;
1601 /* Return 1 if a key is ready to be read without suspending execution. */
1603 dos_keysns ()
1605 if (prev_get_char != -1)
1606 return 1;
1607 else
1608 return ((prev_get_char = dos_rawgetc ()) != -1);
1611 /* Read a key. Return -1 if no key is ready. */
1613 dos_keyread ()
1615 if (prev_get_char != -1)
1617 int c = prev_get_char;
1618 prev_get_char = -1;
1619 return c;
1621 else
1622 return dos_rawgetc ();
1625 #ifndef HAVE_X_WINDOWS
1626 /* See xterm.c for more info. */
1627 void
1628 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1629 FRAME_PTR f;
1630 register int pix_x, pix_y;
1631 register int *x, *y;
1632 void /* XRectangle */ *bounds;
1633 int noclip;
1635 if (bounds) abort ();
1637 /* Ignore clipping. */
1639 *x = pix_x;
1640 *y = pix_y;
1643 void
1644 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1645 FRAME_PTR f;
1646 register int x, y;
1647 register int *pix_x, *pix_y;
1649 *pix_x = x;
1650 *pix_y = y;
1653 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1654 for now.
1656 Actually, I don't know the meaning of all the parameters of the functions
1657 here -- I only know how they are called by xmenu.c. I could of course
1658 grab the nearest Xlib manual (down the hall, second-to-last door on the
1659 left), but I don't think it's worth the effort. */
1661 static XMenu *
1662 IT_menu_create ()
1664 XMenu *menu;
1666 menu = (XMenu *) xmalloc (sizeof (XMenu));
1667 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1668 return menu;
1671 /* Allocate some (more) memory for MENU ensuring that there is room for one
1672 for item. */
1674 static void
1675 IT_menu_make_room (XMenu *menu)
1677 if (menu->allocated == 0)
1679 int count = menu->allocated = 10;
1680 menu->text = (char **) xmalloc (count * sizeof (char *));
1681 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1682 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1684 else if (menu->allocated == menu->count)
1686 int count = menu->allocated = menu->allocated + 10;
1687 menu->text
1688 = (char **) xrealloc (menu->text, count * sizeof (char *));
1689 menu->submenu
1690 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1691 menu->panenumber
1692 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1696 /* Search the given menu structure for a given pane number. */
1698 static XMenu *
1699 IT_menu_search_pane (XMenu *menu, int pane)
1701 int i;
1702 XMenu *try;
1704 for (i = 0; i < menu->count; i++)
1705 if (menu->submenu[i])
1707 if (pane == menu->panenumber[i])
1708 return menu->submenu[i];
1709 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1710 return try;
1712 return (XMenu *) 0;
1715 /* Determine how much screen space a given menu needs. */
1717 static void
1718 IT_menu_calc_size (XMenu *menu, int *width, int *height)
1720 int i, h2, w2, maxsubwidth, maxheight;
1722 maxsubwidth = 0;
1723 maxheight = menu->count;
1724 for (i = 0; i < menu->count; i++)
1726 if (menu->submenu[i])
1728 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1729 if (w2 > maxsubwidth) maxsubwidth = w2;
1730 if (i + h2 > maxheight) maxheight = i + h2;
1733 *width = menu->width + maxsubwidth;
1734 *height = maxheight;
1737 /* Display MENU at (X,Y) using FACES. */
1739 static void
1740 IT_menu_display (XMenu *menu, int y, int x, int *faces)
1742 int i, j, face, width;
1743 GLYPH *text, *p;
1744 char *q;
1745 int mx, my;
1746 int enabled, mousehere;
1747 int row, col;
1749 width = menu->width;
1750 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1751 ScreenGetCursor (&row, &col);
1752 mouse_get_xy (&mx, &my);
1753 IT_update_begin ();
1754 for (i = 0; i < menu->count; i++)
1756 IT_cursor_to (y + i, x);
1757 enabled
1758 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
1759 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
1760 face = faces[enabled + mousehere * 2];
1761 p = text;
1762 *p++ = FAST_MAKE_GLYPH (' ', face);
1763 for (j = 0, q = menu->text[i]; *q; j++)
1764 *p++ = FAST_MAKE_GLYPH (*q++, face);
1765 for (; j < width; j++)
1766 *p++ = FAST_MAKE_GLYPH (' ', face);
1767 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
1768 IT_write_glyphs (text, width + 2);
1770 IT_update_end ();
1771 IT_cursor_to (row, col);
1772 xfree (text);
1775 /* --------------------------- X Menu emulation ---------------------- */
1777 /* Report availability of menus. */
1780 have_menus_p ()
1782 return 1;
1785 /* Create a brand new menu structure. */
1787 XMenu *
1788 XMenuCreate (Display *foo1, Window foo2, char *foo3)
1790 return IT_menu_create ();
1793 /* Create a new pane and place it on the outer-most level. It is not
1794 clear that it should be placed out there, but I don't know what else
1795 to do. */
1798 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
1800 int len;
1802 if (!enable)
1803 abort ();
1805 IT_menu_make_room (menu);
1806 menu->submenu[menu->count] = IT_menu_create ();
1807 menu->text[menu->count] = txt;
1808 menu->panenumber[menu->count] = ++menu->panecount;
1809 menu->count++;
1810 if ((len = strlen (txt)) > menu->width)
1811 menu->width = len;
1812 return menu->panecount;
1815 /* Create a new item in a menu pane. */
1818 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1819 int foo, char *txt, int enable)
1821 int len;
1823 if (pane)
1824 if (!(menu = IT_menu_search_pane (menu, pane)))
1825 return XM_FAILURE;
1826 IT_menu_make_room (menu);
1827 menu->submenu[menu->count] = (XMenu *) 0;
1828 menu->text[menu->count] = txt;
1829 menu->panenumber[menu->count] = enable;
1830 menu->count++;
1831 if ((len = strlen (txt)) > menu->width)
1832 menu->width = len;
1833 return XM_SUCCESS;
1836 /* Decide where the menu would be placed if requested at (X,Y). */
1838 void
1839 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
1840 int *ulx, int *uly, int *width, int *height)
1842 IT_menu_calc_size (menu, width, height);
1843 *ulx = x + 1;
1844 *uly = y;
1845 *width += 2;
1848 struct IT_menu_state
1850 void *screen_behind;
1851 XMenu *menu;
1852 int pane;
1853 int x, y;
1857 /* Display menu, wait for user's response, and return that response. */
1860 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
1861 int x0, int y0, unsigned ButtonMask, char **txt)
1863 struct IT_menu_state *state;
1864 int statecount;
1865 int x, y, i, b;
1866 int screensize;
1867 int faces[4], selectface;
1868 int leave, result, onepane;
1869 int title_faces[4]; /* face to display the menu title */
1871 /* Just in case we got here without a mouse present... */
1872 if (have_mouse <= 0)
1873 return XM_IA_SELECT;
1875 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
1876 screensize = screen_size * 2;
1877 faces[0]
1878 = compute_glyph_face (&the_only_frame,
1879 face_name_id_number
1880 (&the_only_frame,
1881 intern ("msdos-menu-passive-face")),
1883 faces[1]
1884 = compute_glyph_face (&the_only_frame,
1885 face_name_id_number
1886 (&the_only_frame,
1887 intern ("msdos-menu-active-face")),
1889 selectface
1890 = face_name_id_number (&the_only_frame, intern ("msdos-menu-select-face"));
1891 faces[2] = compute_glyph_face (&the_only_frame, selectface, faces[0]);
1892 faces[3] = compute_glyph_face (&the_only_frame, selectface, faces[1]);
1894 /* Make sure the menu title is always displayed with
1895 `msdos-menu-active-face', no matter where the mouse pointer is. */
1896 for (i = 0; i < 4; i++)
1897 title_faces[i] = faces[3];
1899 statecount = 1;
1900 state[0].menu = menu;
1901 mouse_off ();
1902 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
1904 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
1905 if ((onepane = menu->count == 1 && menu->submenu[0]))
1907 menu->width = menu->submenu[0]->width;
1908 state[0].menu = menu->submenu[0];
1910 else
1912 state[0].menu = menu;
1914 state[0].x = x0 - 1;
1915 state[0].y = y0;
1916 state[0].pane = onepane;
1918 mouse_last_x = -1; /* A hack that forces display. */
1919 leave = 0;
1920 while (!leave)
1922 if (!mouse_visible) mouse_on ();
1923 mouse_check_moved ();
1924 if (selected_frame->mouse_moved)
1926 selected_frame->mouse_moved = 0;
1927 result = XM_IA_SELECT;
1928 mouse_get_xy (&x, &y);
1929 for (i = 0; i < statecount; i++)
1930 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
1932 int dy = y - state[i].y;
1933 if (0 <= dy && dy < state[i].menu->count)
1935 if (!state[i].menu->submenu[dy])
1936 if (state[i].menu->panenumber[dy])
1937 result = XM_SUCCESS;
1938 else
1939 result = XM_IA_SELECT;
1940 *pane = state[i].pane - 1;
1941 *selidx = dy;
1942 /* We hit some part of a menu, so drop extra menus that
1943 have been opened. That does not include an open and
1944 active submenu. */
1945 if (i != statecount - 2
1946 || state[i].menu->submenu[dy] != state[i+1].menu)
1947 while (i != statecount - 1)
1949 statecount--;
1950 mouse_off ();
1951 ScreenUpdate (state[statecount].screen_behind);
1952 xfree (state[statecount].screen_behind);
1954 if (i == statecount - 1 && state[i].menu->submenu[dy])
1956 IT_menu_display (state[i].menu,
1957 state[i].y,
1958 state[i].x,
1959 faces);
1960 state[statecount].menu = state[i].menu->submenu[dy];
1961 state[statecount].pane = state[i].menu->panenumber[dy];
1962 mouse_off ();
1963 ScreenRetrieve (state[statecount].screen_behind
1964 = xmalloc (screensize));
1965 state[statecount].x
1966 = state[i].x + state[i].menu->width + 2;
1967 state[statecount].y = y;
1968 statecount++;
1972 IT_menu_display (state[statecount - 1].menu,
1973 state[statecount - 1].y,
1974 state[statecount - 1].x,
1975 faces);
1977 for (b = 0; b < mouse_button_count; b++)
1979 (void) mouse_pressed (b, &x, &y);
1980 if (mouse_released (b, &x, &y))
1981 leave = 1;
1985 mouse_off ();
1986 ScreenUpdate (state[0].screen_behind);
1987 while (statecount--)
1988 xfree (state[statecount].screen_behind);
1989 return result;
1992 /* Dispose of a menu. */
1994 void
1995 XMenuDestroy (Display *foo, XMenu *menu)
1997 int i;
1998 if (menu->allocated)
2000 for (i = 0; i < menu->count; i++)
2001 if (menu->submenu[i])
2002 XMenuDestroy (foo, menu->submenu[i]);
2003 xfree (menu->text);
2004 xfree (menu->submenu);
2005 xfree (menu->panenumber);
2007 xfree (menu);
2011 x_pixel_width (struct frame *f)
2013 return FRAME_WIDTH (f);
2017 x_pixel_height (struct frame *f)
2019 return FRAME_HEIGHT (f);
2021 #endif /* !HAVE_X_WINDOWS */
2023 /* ----------------------- DOS / UNIX conversion --------------------- */
2025 /* Destructively turn backslashes into slashes. */
2027 void
2028 dostounix_filename (p)
2029 register char *p;
2031 while (*p)
2033 if (*p == '\\')
2034 *p = '/';
2035 p++;
2039 /* Destructively turn slashes into backslashes. */
2041 void
2042 unixtodos_filename (p)
2043 register char *p;
2045 while (*p)
2047 if (*p == '/')
2048 *p = '\\';
2049 p++;
2053 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
2056 getdefdir (drive, dst)
2057 int drive;
2058 char *dst;
2060 union REGS regs;
2062 *dst++ = '/';
2063 regs.h.dl = drive;
2064 regs.x.si = (int) dst;
2065 regs.h.ah = 0x47;
2066 intdos (&regs, &regs);
2067 return !regs.x.cflag;
2070 /* Remove all CR's that are followed by a LF. */
2073 crlf_to_lf (n, buf)
2074 register int n;
2075 register unsigned char *buf;
2077 unsigned char *np = buf;
2078 unsigned char *startp = buf;
2079 unsigned char *endp = buf + n;
2080 unsigned char c;
2082 if (n == 0)
2083 return n;
2084 while (buf < endp - 1)
2086 if (*buf == 0x0d)
2088 if (*(++buf) != 0x0a)
2089 *np++ = 0x0d;
2091 else
2092 *np++ = *buf++;
2094 if (buf < endp)
2095 *np++ = *buf++;
2096 return np - startp;
2099 /* The Emacs root directory as determined by init_environment. */
2101 static char emacsroot[MAXPATHLEN];
2103 char *
2104 rootrelativepath (rel)
2105 char *rel;
2107 static char result[MAXPATHLEN + 10];
2109 strcpy (result, emacsroot);
2110 strcat (result, "/");
2111 strcat (result, rel);
2112 return result;
2115 /* Define a lot of environment variables if not already defined. Don't
2116 remove anything unless you know what you're doing -- lots of code will
2117 break if one or more of these are missing. */
2119 void
2120 init_environment (argc, argv, skip_args)
2121 int argc;
2122 char **argv;
2123 int skip_args;
2125 char *s, *t, *root;
2126 int len;
2128 /* Find our root from argv[0]. Assuming argv[0] is, say,
2129 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
2130 root = alloca (MAXPATHLEN + 20);
2131 _fixpath (argv[0], root);
2132 strlwr (root);
2133 len = strlen (root);
2134 while (len > 0 && root[len] != '/' && root[len] != ':')
2135 len--;
2136 root[len] = '\0';
2137 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
2138 root[len - 4] = '\0';
2139 else
2140 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
2141 len = strlen (root);
2142 strcpy (emacsroot, root);
2144 /* We default HOME to our root. */
2145 setenv ("HOME", root, 0);
2147 /* We default EMACSPATH to root + "/bin". */
2148 strcpy (root + len, "/bin");
2149 setenv ("EMACSPATH", root, 0);
2151 /* I don't expect anybody to ever use other terminals so the internal
2152 terminal is the default. */
2153 setenv ("TERM", "internal", 0);
2155 #ifdef HAVE_X_WINDOWS
2156 /* Emacs expects DISPLAY to be set. */
2157 setenv ("DISPLAY", "unix:0.0", 0);
2158 #endif
2160 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2161 downcase it and mirror the backslashes. */
2162 s = getenv ("COMSPEC");
2163 if (!s) s = "c:/command.com";
2164 t = alloca (strlen (s) + 1);
2165 strcpy (t, s);
2166 strlwr (t);
2167 dostounix_filename (t);
2168 setenv ("SHELL", t, 0);
2170 /* PATH is also downcased and backslashes mirrored. */
2171 s = getenv ("PATH");
2172 if (!s) s = "";
2173 t = alloca (strlen (s) + 3);
2174 /* Current directory is always considered part of MsDos's path but it is
2175 not normally mentioned. Now it is. */
2176 strcat (strcpy (t, ".;"), s);
2177 strlwr (t);
2178 dostounix_filename (t); /* Not a single file name, but this should work. */
2179 setenv ("PATH", t, 1);
2181 /* In some sense all dos users have root privileges, so... */
2182 setenv ("USER", "root", 0);
2183 setenv ("NAME", getenv ("USER"), 0);
2185 /* Time zone determined from country code. To make this possible, the
2186 country code may not span more than one time zone. In other words,
2187 in the USA, you lose. */
2188 if (!getenv ("TZ"))
2189 switch (dos_country_code)
2191 case 31: /* Belgium */
2192 case 32: /* The Netherlands */
2193 case 33: /* France */
2194 case 34: /* Spain */
2195 case 36: /* Hungary */
2196 case 38: /* Yugoslavia (or what's left of it?) */
2197 case 39: /* Italy */
2198 case 41: /* Switzerland */
2199 case 42: /* Tjekia */
2200 case 45: /* Denmark */
2201 case 46: /* Sweden */
2202 case 47: /* Norway */
2203 case 48: /* Poland */
2204 case 49: /* Germany */
2205 /* Daylight saving from last Sunday in March to last Sunday in
2206 September, both at 2AM. */
2207 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2208 break;
2209 case 44: /* United Kingdom */
2210 case 351: /* Portugal */
2211 case 354: /* Iceland */
2212 setenv ("TZ", "GMT+00", 0);
2213 break;
2214 case 81: /* Japan */
2215 case 82: /* Korea */
2216 setenv ("TZ", "JST-09", 0);
2217 break;
2218 case 90: /* Turkey */
2219 case 358: /* Finland */
2220 setenv ("TZ", "EET-02", 0);
2221 break;
2222 case 972: /* Israel */
2223 /* This is an approximation. (For exact rules, use the
2224 `zoneinfo/israel' file which comes with DJGPP, but you need
2225 to install it in `/usr/share/zoneinfo/' directory first.) */
2226 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2227 break;
2229 init_gettimeofday ();
2234 static int break_stat; /* BREAK check mode status. */
2235 static int stdin_stat; /* stdin IOCTL status. */
2237 /* These must be global. */
2238 static _go32_dpmi_seginfo ctrl_break_vector;
2239 static _go32_dpmi_registers ctrl_break_regs;
2240 static int ctrlbreakinstalled = 0;
2242 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2244 void
2245 ctrl_break_func (regs)
2246 _go32_dpmi_registers *regs;
2248 Vquit_flag = Qt;
2251 void
2252 install_ctrl_break_check ()
2254 if (!ctrlbreakinstalled)
2256 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2257 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2258 ctrlbreakinstalled = 1;
2259 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2260 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2261 &ctrl_break_regs);
2262 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2266 /* Turn off Dos' Ctrl-C checking and inhibit interpretation of
2267 control chars by DOS. Determine the keyboard type. */
2270 dos_ttraw ()
2272 union REGS inregs, outregs;
2273 static int first_time = 1;
2275 break_stat = getcbrk ();
2276 setcbrk (0);
2277 install_ctrl_break_check ();
2279 if (first_time)
2281 inregs.h.ah = 0xc0;
2282 int86 (0x15, &inregs, &outregs);
2283 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2285 have_mouse = 0;
2287 if (internal_terminal
2288 #ifdef HAVE_X_WINDOWS
2289 && inhibit_window_system
2290 #endif
2293 inregs.x.ax = 0x0021;
2294 int86 (0x33, &inregs, &outregs);
2295 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2296 if (!have_mouse)
2298 /* Reportedly, the above doesn't work for some mouse drivers. There
2299 is an additional detection method that should work, but might be
2300 a little slower. Use that as an alternative. */
2301 inregs.x.ax = 0x0000;
2302 int86 (0x33, &inregs, &outregs);
2303 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2306 if (have_mouse)
2308 have_mouse = 1; /* enable mouse */
2309 mouse_visible = 0;
2311 if (outregs.x.bx == 3)
2313 mouse_button_count = 3;
2314 mouse_button_translate[0] = 0; /* Left */
2315 mouse_button_translate[1] = 2; /* Middle */
2316 mouse_button_translate[2] = 1; /* Right */
2318 else
2320 mouse_button_count = 2;
2321 mouse_button_translate[0] = 0;
2322 mouse_button_translate[1] = 1;
2324 mouse_position_hook = &mouse_get_pos;
2325 mouse_init ();
2329 first_time = 0;
2332 inregs.x.ax = 0x4400; /* Get IOCTL status. */
2333 inregs.x.bx = 0x00; /* 0 = stdin. */
2334 intdos (&inregs, &outregs);
2335 stdin_stat = outregs.h.dl;
2337 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
2338 inregs.x.ax = 0x4401; /* Set IOCTL status */
2339 intdos (&inregs, &outregs);
2340 return !outregs.x.cflag;
2343 /* Restore status of standard input and Ctrl-C checking. */
2346 dos_ttcooked ()
2348 union REGS inregs, outregs;
2350 setcbrk (break_stat);
2351 mouse_off ();
2353 inregs.x.ax = 0x4401; /* Set IOCTL status. */
2354 inregs.x.bx = 0x00; /* 0 = stdin. */
2355 inregs.x.dx = stdin_stat;
2356 intdos (&inregs, &outregs);
2357 return !outregs.x.cflag;
2361 /* Run command as specified by ARGV in directory DIR.
2362 The command is run with input from TEMPIN, output to
2363 file TEMPOUT and stderr to TEMPERR. */
2366 run_msdos_command (argv, dir, tempin, tempout, temperr)
2367 unsigned char **argv;
2368 Lisp_Object dir;
2369 int tempin, tempout, temperr;
2371 char *saveargv1, *saveargv2, **envv;
2372 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
2373 int msshell, result = -1;
2374 int in, out, inbak, outbak, errbak;
2375 int x, y;
2376 Lisp_Object cmd;
2378 /* Get current directory as MSDOS cwd is not per-process. */
2379 getwd (oldwd);
2381 cmd = Ffile_name_nondirectory (build_string (argv[0]));
2382 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
2383 && !strcmp ("-c", argv[1]);
2384 if (msshell)
2386 saveargv1 = argv[1];
2387 saveargv2 = argv[2];
2388 argv[1] = "/c";
2389 if (argv[2])
2391 char *p = alloca (strlen (argv[2]) + 1);
2393 strcpy (argv[2] = p, saveargv2);
2394 while (*p && isspace (*p))
2395 p++;
2396 while (*p && !isspace (*p))
2397 if (*p == '/')
2398 *p++ = '\\';
2399 else
2400 p++;
2404 /* Build the environment array. */
2406 extern Lisp_Object Vprocess_environment;
2407 Lisp_Object tmp, lst;
2408 int i, len;
2410 lst = Vprocess_environment;
2411 len = XFASTINT (Flength (lst));
2413 envv = alloca ((len + 1) * sizeof (char *));
2414 for (i = 0; i < len; i++)
2416 tmp = Fcar (lst);
2417 lst = Fcdr (lst);
2418 CHECK_STRING (tmp, 0);
2419 envv[i] = alloca (XSTRING (tmp)->size + 1);
2420 strcpy (envv[i], XSTRING (tmp)->data);
2422 envv[len] = (char *) 0;
2425 if (STRINGP (dir))
2426 chdir (XSTRING (dir)->data);
2427 inbak = dup (0);
2428 outbak = dup (1);
2429 errbak = dup (2);
2430 if (inbak < 0 || outbak < 0 || errbak < 0)
2431 goto done; /* Allocation might fail due to lack of descriptors. */
2433 if (have_mouse > 0)
2434 mouse_get_xy (&x, &y);
2436 dos_ttcooked (); /* do it here while 0 = stdin */
2438 dup2 (tempin, 0);
2439 dup2 (tempout, 1);
2440 dup2 (temperr, 2);
2442 result = spawnve (P_WAIT, argv[0], argv, envv);
2444 dup2 (inbak, 0);
2445 dup2 (outbak, 1);
2446 dup2 (errbak, 2);
2447 close (inbak);
2448 close (outbak);
2449 close (errbak);
2451 dos_ttraw ();
2452 if (have_mouse > 0)
2454 mouse_init ();
2455 mouse_moveto (x, y);
2458 done:
2459 chdir (oldwd);
2460 if (msshell)
2462 argv[1] = saveargv1;
2463 argv[2] = saveargv2;
2465 return result;
2468 croak (badfunc)
2469 char *badfunc;
2471 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
2472 reset_sys_modes ();
2473 exit (1);
2476 /* ------------------------- Compatibility functions -------------------
2477 * gethostname
2478 * gettimeofday
2481 /* Hostnames for a pc are not really funny,
2482 but they are used in change log so we emulate the best we can. */
2484 gethostname (p, size)
2485 char *p;
2486 int size;
2488 char *q = egetenv ("HOSTNAME");
2490 if (!q) q = "pc";
2491 strcpy (p, q);
2492 return 0;
2495 /* When time zones are set from Ms-Dos too many C-libraries are playing
2496 tricks with time values. We solve this by defining our own version
2497 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2498 once and after each call to `tzset' with TZ changed. That is
2499 accomplished by aliasing tzset to init_gettimeofday. */
2501 static struct tm time_rec;
2504 gettimeofday (struct timeval *tp, struct timezone *tzp)
2506 if (tp)
2508 struct time t;
2509 struct tm tm;
2511 gettime (&t);
2512 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
2514 struct date d;
2515 getdate (&d);
2516 time_rec.tm_year = d.da_year - 1900;
2517 time_rec.tm_mon = d.da_mon - 1;
2518 time_rec.tm_mday = d.da_day;
2521 time_rec.tm_hour = t.ti_hour;
2522 time_rec.tm_min = t.ti_min;
2523 time_rec.tm_sec = t.ti_sec;
2525 tm = time_rec;
2526 tm.tm_gmtoff = dos_timezone_offset;
2528 tp->tv_sec = mktime (&tm); /* may modify tm */
2529 tp->tv_usec = t.ti_hund * (1000000 / 100);
2531 /* Ignore tzp; it's obsolescent. */
2532 return 0;
2537 * A list of unimplemented functions that we silently ignore.
2540 unsigned alarm (s) unsigned s; {}
2541 fork () { return 0; }
2542 int kill (x, y) int x, y; { return -1; }
2543 nice (p) int p; {}
2544 void volatile pause () {}
2545 request_sigio () {}
2546 setpgrp () {return 0; }
2547 setpriority (x,y,z) int x,y,z; { return 0; }
2548 sigsetmask (x) int x; { return 0; }
2549 sigblock (mask) int mask; { return 0; }
2550 unrequest_sigio () {}
2552 #ifndef HAVE_SELECT
2553 #include "sysselect.h"
2555 static struct time last_time = {120, 120, 120, 120};
2556 static int modeline_time_displayed = 0;
2558 Lisp_Object Vdos_display_time;
2560 static void
2561 check_timer (t)
2562 struct time *t;
2564 int sec, min, hour, hund;
2566 gettime (t);
2567 sec = t->ti_sec;
2568 hund = t->ti_hund;
2569 hour = t->ti_hour;
2570 min = t->ti_min;
2572 /* Any chance of not getting here 24 hours or more since last time? */
2573 if (hour == last_time.ti_hour
2574 && min == last_time.ti_min
2575 && sec == last_time.ti_sec)
2576 return;
2578 if (!NILP (Vdos_display_time))
2580 int interval;
2581 Lisp_Object dti = XSYMBOL (Fintern_soft (build_string ("display-time-interval"), Qnil))->value;
2582 int delta_time = ((hour - last_time.ti_hour) * 3600
2583 + (min - last_time.ti_min) * 60
2584 + (sec - last_time.ti_sec));
2586 /* Who knows what the user may put into `display-time-interval'? */
2587 if (!INTEGERP (dti) || (interval = XINT (dti)) <= 0)
2588 interval = 60;
2590 /* When it's time to renew the display, fake a `wakeup' call. */
2591 if (!modeline_time_displayed /* first time */
2592 || delta_time >= interval /* or if we were busy for a long time */
2593 || interval == 1 /* and every `interval' seconds hence */
2594 || interval == 60 && sec == 0 /* (usual cases first) */
2595 || (hour * 3600 + min * 60 + sec) % interval == 0)
2596 call2 (intern ("display-time-filter"), Qnil,
2597 build_string ("Wake up!\n"));
2599 modeline_time_displayed = 1;
2601 else if (modeline_time_displayed)
2603 modeline_time_displayed = 0;
2604 Fset (intern ("display-time-string"), build_string (""));
2606 /* Force immediate redisplay of modelines. */
2607 update_mode_lines++;
2608 redisplay_preserve_echo_area ();
2611 last_time = *t;
2614 #ifndef EMACS_TIME_ZERO_OR_NEG_P
2615 #define EMACS_TIME_ZERO_OR_NEG_P(time) \
2616 ((long)(time).tv_sec < 0 \
2617 || ((time).tv_sec == 0 \
2618 && (long)(time).tv_usec <= 0))
2619 #endif
2622 /* Only event queue is checked. */
2624 sys_select (nfds, rfds, wfds, efds, timeout)
2625 int nfds;
2626 SELECT_TYPE *rfds, *wfds, *efds;
2627 EMACS_TIME *timeout;
2629 int check_input;
2630 struct time t;
2632 check_input = 0;
2633 if (rfds)
2635 check_input = FD_ISSET (0, rfds);
2636 FD_ZERO (rfds);
2638 if (wfds)
2639 FD_ZERO (wfds);
2640 if (efds)
2641 FD_ZERO (efds);
2643 if (nfds != 1)
2644 abort ();
2646 /* If we are looking only for the terminal, with no timeout,
2647 just read it and wait -- that's more efficient. */
2648 if (!timeout)
2651 check_timer (&t); /* check timer even if some input is pending */
2652 while (!detect_input_pending ());
2654 else
2656 EMACS_TIME clnow, cllast, cldiff;
2658 check_timer (&t);
2659 EMACS_SET_SECS_USECS (cllast, t.ti_sec, t.ti_hund * 10000L);
2661 while (!check_input || !detect_input_pending ())
2663 check_timer (&t);
2664 EMACS_SET_SECS_USECS (clnow, t.ti_sec, t.ti_hund * 10000L);
2665 EMACS_SUB_TIME (cldiff, clnow, cllast);
2667 /* When seconds wrap around, we assume that no more than
2668 1 minute passed since last `check_timer'. */
2669 if (EMACS_TIME_NEG_P (cldiff))
2670 EMACS_SET_SECS (cldiff, EMACS_SECS (cldiff) + 60);
2671 EMACS_SUB_TIME (*timeout, *timeout, cldiff);
2673 /* Stop when timeout value crosses zero. */
2674 if (EMACS_TIME_ZERO_OR_NEG_P (*timeout))
2675 return 0;
2676 cllast = clnow;
2680 FD_SET (0, rfds);
2681 return 1;
2683 #endif
2686 * Define overlaid functions:
2688 * chdir -> sys_chdir
2689 * tzset -> init_gettimeofday
2690 * abort -> dos_abort
2693 #ifdef chdir
2694 #undef chdir
2695 extern int chdir ();
2698 sys_chdir (path)
2699 const char* path;
2701 int len = strlen (path);
2702 char *tmp = (char *)path;
2704 if (*tmp && tmp[1] == ':')
2706 if (getdisk () != tolower (tmp[0]) - 'a')
2707 setdisk (tolower (tmp[0]) - 'a');
2708 tmp += 2; /* strip drive: KFS 1995-07-06 */
2709 len -= 2;
2712 if (len > 1 && (tmp[len - 1] == '/'))
2714 char *tmp1 = (char *) alloca (len + 1);
2715 strcpy (tmp1, tmp);
2716 tmp1[len - 1] = 0;
2717 tmp = tmp1;
2719 return chdir (tmp);
2721 #endif
2723 #ifdef tzset
2724 #undef tzset
2725 extern void tzset (void);
2727 void
2728 init_gettimeofday ()
2730 time_t ltm, gtm;
2731 struct tm *lstm;
2733 tzset ();
2734 ltm = gtm = time (NULL);
2735 ltm = mktime (lstm = localtime (&ltm));
2736 gtm = mktime (gmtime (&gtm));
2737 time_rec.tm_hour = 99; /* force gettimeofday to get date */
2738 time_rec.tm_isdst = lstm->tm_isdst;
2739 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
2741 #endif
2743 #ifdef abort
2744 #undef abort
2745 void
2746 dos_abort (file, line)
2747 char *file;
2748 int line;
2750 char buffer1[200], buffer2[400];
2751 int i, j;
2753 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
2754 for (i = j = 0; buffer1[i]; i++) {
2755 buffer2[j++] = buffer1[i];
2756 buffer2[j++] = 0x70;
2758 dosmemput (buffer2, j, (int)ScreenPrimary);
2759 ScreenSetCursor (2, 0);
2760 abort ();
2762 #else
2763 void
2764 abort ()
2766 dos_ttcooked ();
2767 ScreenSetCursor (10, 0);
2768 cputs ("\r\n\nEmacs aborted!\r\n");
2769 exit (2);
2771 #endif
2773 syms_of_msdos ()
2775 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
2776 staticpro (&recent_doskeys);
2778 defsubr (&Srecent_doskeys);
2780 DEFVAR_LISP ("dos-display-time", &Vdos_display_time,
2781 "*When non-nil, `display-time' is in effect on DOS systems.");
2782 Vdos_display_time = Qnil;
2785 #endif /* MSDOS */