Comment fixes.
[bpt/emacs.git] / src / msdos.c
1 /* MS-DOS specific C utilities.
2 Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
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.
10
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.
15
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. */
19
20 /* Contributed by Morten Welinder */
21 /* New display, keyboard, and mouse control by Kim F. Storm */
22
23 /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
24
25 #include <config.h>
26
27 #ifdef MSDOS
28 #include "lisp.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <sys/param.h>
32 #include <sys/time.h>
33 #include <dos.h>
34 #include "dosfns.h"
35 #include "msdos.h"
36 #include "systime.h"
37 #include "termhooks.h"
38 #include "dispextern.h"
39 #include "termopts.h"
40 #include "frame.h"
41 #include "window.h"
42 #include <go32.h>
43 #include <pc.h>
44 #include <ctype.h>
45 /* #include <process.h> */
46 /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
47 #define P_WAIT 1
48
49
50 static unsigned long
51 event_timestamp ()
52 {
53 struct time t;
54 unsigned long s;
55
56 gettime (&t);
57 s = t.ti_min;
58 s *= 60;
59 s += t.ti_sec;
60 s *= 1000;
61 s += t.ti_hund * 10;
62
63 return s;
64 }
65
66 \f
67 /* ------------------------ Mouse control ---------------------------
68 *
69 * Coordinates are in screen positions and zero based.
70 * Mouse buttons are numbered from left to right and also zero based.
71 */
72
73 int have_mouse; /* 0: no, 1: enabled, -1: disabled */
74 static int mouse_visible;
75
76 static int mouse_last_x;
77 static int mouse_last_y;
78
79 static int mouse_button_translate[NUM_MOUSE_BUTTONS];
80 static int mouse_button_count;
81
82 void
83 mouse_on ()
84 {
85 union REGS regs;
86
87 if (have_mouse > 0 && !mouse_visible)
88 {
89 if (termscript)
90 fprintf (termscript, "<M_ON>");
91 regs.x.ax = 0x0001;
92 int86 (0x33, &regs, &regs);
93 mouse_visible = 1;
94 }
95 }
96
97 void
98 mouse_off ()
99 {
100 union REGS regs;
101
102 if (have_mouse > 0 && mouse_visible)
103 {
104 if (termscript)
105 fprintf (termscript, "<M_OFF>");
106 regs.x.ax = 0x0002;
107 int86 (0x33, &regs, &regs);
108 mouse_visible = 0;
109 }
110 }
111
112 void
113 mouse_moveto (x, y)
114 int x, y;
115 {
116 union REGS regs;
117
118 if (termscript)
119 fprintf (termscript, "<M_XY=%dx%d>", x, y);
120 regs.x.ax = 0x0004;
121 mouse_last_x = regs.x.cx = x * 8;
122 mouse_last_y = regs.x.dx = y * 8;
123 int86 (0x33, &regs, &regs);
124 }
125
126 static int
127 mouse_pressed (b, xp, yp)
128 int b, *xp, *yp;
129 {
130 union REGS regs;
131
132 if (b >= mouse_button_count)
133 return 0;
134 regs.x.ax = 0x0005;
135 regs.x.bx = mouse_button_translate[b];
136 int86 (0x33, &regs, &regs);
137 if (regs.x.bx)
138 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
139 return (regs.x.bx != 0);
140 }
141
142 static int
143 mouse_released (b, xp, yp)
144 int b, *xp, *yp;
145 {
146 union REGS regs;
147
148 if (b >= mouse_button_count)
149 return 0;
150 regs.x.ax = 0x0006;
151 regs.x.bx = mouse_button_translate[b];
152 int86 (0x33, &regs, &regs);
153 if (regs.x.bx)
154 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
155 return (regs.x.bx != 0);
156 }
157
158 static void
159 mouse_get_xy (int *x, int *y)
160 {
161 union REGS regs;
162
163 regs.x.ax = 0x0003;
164 int86 (0x33, &regs, &regs);
165 *x = regs.x.cx / 8;
166 *y = regs.x.dx / 8;
167 }
168
169 void
170 mouse_get_pos (f, insist, bar_window, part, x, y, time)
171 FRAME_PTR *f;
172 int insist;
173 Lisp_Object *bar_window, *x, *y;
174 enum scroll_bar_part *part;
175 unsigned long *time;
176 {
177 int ix, iy;
178 union REGS regs;
179
180 regs.x.ax = 0x0003;
181 int86 (0x33, &regs, &regs);
182 *f = selected_frame;
183 *bar_window = Qnil;
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 ();
189 }
190
191 static void
192 mouse_check_moved ()
193 {
194 int x, y;
195
196 mouse_get_xy (&x, &y);
197 selected_frame->mouse_moved |= (x != mouse_last_x || y != mouse_last_y);
198 mouse_last_x = x;
199 mouse_last_y = y;
200 }
201
202 void
203 mouse_init ()
204 {
205 union REGS regs;
206
207 if (termscript)
208 fprintf (termscript, "<M_INIT>");
209
210 regs.x.ax = 0x0021;
211 int86 (0x33, &regs, &regs);
212
213 regs.x.ax = 0x0007;
214 regs.x.cx = 0;
215 regs.x.dx = 8 * (ScreenCols () - 1);
216 int86 (0x33, &regs, &regs);
217
218 regs.x.ax = 0x0008;
219 regs.x.cx = 0;
220 regs.x.dx = 8 * (ScreenRows () - 1);
221 int86 (0x33, &regs, &regs);
222
223 mouse_moveto (0, 0);
224 mouse_visible = 0;
225 }
226 \f
227 /* ------------------------- Screen control ----------------------
228 *
229 */
230
231 static int internal_terminal = 0;
232
233 #ifndef HAVE_X_WINDOWS
234 extern unsigned char ScreenAttrib;
235 static int screen_face;
236 static int highlight;
237
238 static int screen_size_X;
239 static int screen_size_Y;
240 static int screen_size;
241
242 static int current_pos_X;
243 static int current_pos_Y;
244 static int new_pos_X;
245 static int new_pos_Y;
246
247 static void *startup_screen_buffer;
248 static int startup_screen_size_X;
249 static int startup_screen_size_Y;
250 static int startup_pos_X;
251 static int startup_pos_Y;
252 static unsigned char startup_screen_attrib;
253
254 static int term_setup_done;
255
256 /* Similar to the_only_frame. */
257 struct x_output the_only_x_display;
258
259 /* This is never dereferenced. */
260 Display *x_current_display;
261
262
263 #define SCREEN_SET_CURSOR() \
264 if (current_pos_X != new_pos_X || current_pos_Y != new_pos_Y) \
265 ScreenSetCursor (current_pos_Y = new_pos_Y, current_pos_X = new_pos_X)
266
267 static
268 dos_direct_output (y, x, buf, len)
269 int y;
270 int x;
271 char *buf;
272 int len;
273 {
274 int t = (int) ScreenPrimary + 2 * (x + y * screen_size_X);
275
276 while (--len >= 0) {
277 dosmemput (buf++, 1, t);
278 t += 2;
279 }
280 }
281 #endif
282
283 /* Flash the screen as a substitute for BEEPs. */
284
285 #if (__DJGPP__ < 2)
286 static void
287 do_visible_bell (xorattr)
288 unsigned char xorattr;
289 {
290 asm volatile
291 (" movb $1,%%dl
292 visible_bell_0:
293 movl _ScreenPrimary,%%eax
294 call dosmemsetup
295 movl %%eax,%%ebx
296 movl %1,%%ecx
297 movb %0,%%al
298 incl %%ebx
299 visible_bell_1:
300 xorb %%al,%%gs:(%%ebx)
301 addl $2,%%ebx
302 decl %%ecx
303 jne visible_bell_1
304 decb %%dl
305 jne visible_bell_3
306 visible_bell_2:
307 movzwl %%ax,%%eax
308 movzwl %%ax,%%eax
309 movzwl %%ax,%%eax
310 movzwl %%ax,%%eax
311 decw %%cx
312 jne visible_bell_2
313 jmp visible_bell_0
314 visible_bell_3:"
315 : /* no output */
316 : "m" (xorattr), "g" (screen_size)
317 : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
318 }
319
320 static void
321 ScreenVisualBell (void)
322 {
323 /* This creates an xor-mask that will swap the default fore- and
324 background colors. */
325 do_visible_bell (((the_only_x_display.foreground_pixel
326 ^ the_only_x_display.background_pixel)
327 * 0x11) & 0x7f);
328 }
329 #endif
330
331 #ifndef HAVE_X_WINDOWS
332
333 /*
334 * If we write a character in the position where the mouse is,
335 * the mouse cursor may need to be refreshed.
336 */
337
338 static void
339 mouse_off_maybe ()
340 {
341 int x, y;
342
343 if (!mouse_visible)
344 return;
345
346 mouse_get_xy (&x, &y);
347 if (y != new_pos_Y || x < new_pos_X)
348 return;
349
350 mouse_off ();
351 }
352
353 static
354 IT_ring_bell ()
355 {
356 if (visible_bell)
357 {
358 mouse_off ();
359 ScreenVisualBell ();
360 }
361 else
362 {
363 union REGS inregs, outregs;
364 inregs.h.ah = 2;
365 inregs.h.dl = 7;
366 intdos (&inregs, &outregs);
367 }
368 }
369
370 static void
371 IT_set_face (int face)
372 {
373 struct face *fp;
374 extern struct face *intern_face (/* FRAME_PTR, struct face * */);
375
376 if (face == 1 || (face == 0 && highlight))
377 fp = FRAME_MODE_LINE_FACE (foo);
378 else if (face <= 0 || face >= FRAME_N_COMPUTED_FACES (foo))
379 fp = FRAME_DEFAULT_FACE (foo);
380 else
381 fp = intern_face (selected_frame, FRAME_COMPUTED_FACES (foo)[face]);
382 if (termscript)
383 fprintf (termscript, "<FACE:%d:%d>", FACE_FOREGROUND (fp), FACE_BACKGROUND (fp));
384 screen_face = face;
385 ScreenAttrib = (FACE_BACKGROUND (fp) << 4) | FACE_FOREGROUND (fp);
386 }
387
388 static
389 IT_write_glyphs (GLYPH *str, int len)
390 {
391 int newface;
392 int ch, l = len;
393 unsigned char *buf, *bp;
394
395 if (len == 0) return;
396
397 buf = bp = alloca (len * 2);
398
399 while (--l >= 0)
400 {
401 newface = FAST_GLYPH_FACE (*str);
402 if (newface != screen_face)
403 IT_set_face (newface);
404 ch = FAST_GLYPH_CHAR (*str);
405 *bp++ = (unsigned char)ch;
406 *bp++ = ScreenAttrib;
407
408 if (termscript)
409 fputc (ch, termscript);
410 str++;
411 }
412
413 mouse_off_maybe ();
414 dosmemput (buf, 2 * len,
415 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
416 new_pos_X += len;
417 }
418
419 static
420 IT_clear_end_of_line (first_unused)
421 {
422 char *spaces, *sp;
423 int i, j;
424
425 IT_set_face (0);
426 if (termscript)
427 fprintf (termscript, "<CLR:EOL>");
428 i = (j = screen_size_X - new_pos_X) * 2;
429 spaces = sp = alloca (i);
430
431 while (--j >= 0)
432 {
433 *sp++ = ' ';
434 *sp++ = ScreenAttrib;
435 }
436
437 mouse_off_maybe ();
438 dosmemput (spaces, i,
439 (int)ScreenPrimary + 2 * (new_pos_X + screen_size_X * new_pos_Y));
440 }
441
442 static
443 IT_clear_screen (void)
444 {
445 if (termscript)
446 fprintf (termscript, "<CLR:SCR>");
447 IT_set_face (0);
448 mouse_off ();
449 ScreenClear ();
450 new_pos_X = new_pos_Y = 0;
451 }
452
453 static
454 IT_clear_to_end (void)
455 {
456 if (termscript)
457 fprintf (termscript, "<CLR:EOS>");
458
459 while (new_pos_Y < screen_size_Y) {
460 new_pos_X = 0;
461 IT_clear_end_of_line (0);
462 new_pos_Y++;
463 }
464 }
465
466 static
467 IT_cursor_to (int y, int x)
468 {
469 if (termscript)
470 fprintf (termscript, "\n<XY=%dx%d>", x, y);
471 new_pos_X = x;
472 new_pos_Y = y;
473 }
474
475 static
476 IT_reassert_line_highlight (new, vpos)
477 int new, vpos;
478 {
479 highlight = new;
480 IT_set_face (0); /* To possibly clear the highlighting. */
481 }
482
483 static
484 IT_change_line_highlight (new_highlight, vpos, first_unused_hpos)
485 {
486 highlight = new_highlight;
487 IT_set_face (0); /* To possibly clear the highlighting. */
488 IT_cursor_to (vpos, 0);
489 IT_clear_end_of_line (first_unused_hpos);
490 }
491
492 static
493 IT_update_begin ()
494 {
495 highlight = 0;
496 IT_set_face (0); /* To possibly clear the highlighting. */
497 screen_face = -1;
498 }
499
500 static
501 IT_update_end ()
502 {
503 }
504
505 /* This was more or less copied from xterm.c */
506 static void
507 IT_set_menu_bar_lines (window, n)
508 Lisp_Object window;
509 int n;
510 {
511 struct window *w = XWINDOW (window);
512
513 XSETFASTINT (w->last_modified, 0);
514 XSETFASTINT (w->top, XFASTINT (w->top) + n);
515 XSETFASTINT (w->height, XFASTINT (w->height) - n);
516
517 /* Handle just the top child in a vertical split. */
518 if (!NILP (w->vchild))
519 IT_set_menu_bar_lines (w->vchild, n);
520
521 /* Adjust all children in a horizontal split. */
522 for (window = w->hchild; !NILP (window); window = w->next)
523 {
524 w = XWINDOW (window);
525 IT_set_menu_bar_lines (window, n);
526 }
527 }
528
529 /*
530 * IT_set_terminal_modes is called when emacs is started,
531 * resumed, and whenever the screen is redrawn!
532 */
533
534 static
535 IT_set_terminal_modes (void)
536 {
537 char *colors;
538 FRAME_PTR f;
539 struct face *fp;
540
541 if (termscript)
542 fprintf (termscript, "\n<SET_TERM>");
543 highlight = 0;
544
545 screen_size_X = ScreenCols ();
546 screen_size_Y = ScreenRows ();
547 screen_size = screen_size_X * screen_size_Y;
548
549 new_pos_X = new_pos_Y = 0;
550 current_pos_X = current_pos_Y = -1;
551
552 if (term_setup_done)
553 return;
554 term_setup_done = 1;
555
556 startup_screen_size_X = screen_size_X;
557 startup_screen_size_Y = screen_size_Y;
558 startup_screen_attrib = ScreenAttrib;
559
560 ScreenGetCursor (&startup_pos_Y, &startup_pos_X);
561 ScreenRetrieve (startup_screen_buffer = xmalloc (screen_size * 2));
562
563 if (termscript)
564 fprintf (termscript, "<SCREEN SAVED (dimensions=%dx%d)>\n",
565 screen_size_X, screen_size_Y);
566 }
567
568 /*
569 * IT_reset_terminal_modes is called when emacs is
570 * suspended or killed.
571 */
572
573 static
574 IT_reset_terminal_modes (void)
575 {
576 int display_row_start = (int) ScreenPrimary;
577 int saved_row_len = startup_screen_size_X * 2;
578 int update_row_len = ScreenCols () * 2;
579 int current_rows = ScreenRows ();
580 int to_next_row = update_row_len;
581 unsigned char *saved_row = startup_screen_buffer;
582 int cursor_pos_X = ScreenCols () - 1;
583 int cursor_pos_Y = ScreenRows () - 1;
584
585 if (termscript)
586 fprintf (termscript, "\n<RESET_TERM>");
587
588 highlight = 0;
589
590 if (!term_setup_done)
591 return;
592
593 mouse_off ();
594
595 /* We have a situation here.
596 We cannot just do ScreenUpdate(startup_screen_buffer) because
597 the luser could have changed screen dimensions inside Emacs
598 and failed (or didn't want) to restore them before killing
599 Emacs. ScreenUpdate() uses the *current* screen dimensions and
600 thus will happily use memory outside what was allocated for
601 `startup_screen_buffer'.
602 Thus we only restore as much as the current screen dimensions
603 can hold, and clear the rest (if the saved screen is smaller than
604 the current) with the color attribute saved at startup. The cursor
605 is also restored within the visible dimensions. */
606
607 ScreenAttrib = startup_screen_attrib;
608 ScreenClear ();
609
610 if (update_row_len > saved_row_len)
611 update_row_len = saved_row_len;
612 if (current_rows > startup_screen_size_Y)
613 current_rows = startup_screen_size_Y;
614
615 if (termscript)
616 fprintf (termscript, "<SCREEN RESTORED (dimensions=%dx%d)>\n",
617 update_row_len / 2, current_rows);
618
619 while (current_rows--)
620 {
621 dosmemput (saved_row, update_row_len, display_row_start);
622 saved_row += saved_row_len;
623 display_row_start += to_next_row;
624 }
625 if (startup_pos_X < cursor_pos_X)
626 cursor_pos_X = startup_pos_X;
627 if (startup_pos_Y < cursor_pos_Y)
628 cursor_pos_Y = startup_pos_Y;
629
630 ScreenSetCursor (cursor_pos_Y, cursor_pos_X);
631 xfree (startup_screen_buffer);
632
633 term_setup_done = 0;
634 }
635
636 static
637 IT_set_terminal_window (void)
638 {
639 }
640
641 void
642 IT_set_frame_parameters (frame, alist)
643 FRAME_PTR frame;
644 Lisp_Object alist;
645 {
646 Lisp_Object tail;
647 int redraw;
648 extern unsigned long load_color ();
649 FRAME_PTR f = (FRAME_PTR) &the_only_frame;
650
651 redraw = 0;
652 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
653 {
654 Lisp_Object elt, prop, val;
655
656 elt = Fcar (tail);
657 prop = Fcar (elt);
658 val = Fcdr (elt);
659 CHECK_SYMBOL (prop, 1);
660
661 if (EQ (prop, intern ("foreground-color")))
662 {
663 unsigned long new_color = load_color (f, val);
664 if (new_color != ~0)
665 {
666 FRAME_FOREGROUND_PIXEL (f) = new_color;
667 redraw = 1;
668 }
669 }
670 else if (EQ (prop, intern ("background-color")))
671 {
672 unsigned long new_color = load_color (f, val);
673 if (new_color != ~0)
674 {
675 FRAME_BACKGROUND_PIXEL (f) = new_color & ~8;
676 redraw = 1;
677 }
678 }
679 else if (EQ (prop, intern ("menu-bar-lines")))
680 {
681 int new;
682 int old = FRAME_MENU_BAR_LINES (the_only_frame);
683
684 if (INTEGERP (val))
685 new = XINT (val);
686 else
687 new = 0;
688 FRAME_MENU_BAR_LINES (f) = new;
689 IT_set_menu_bar_lines (the_only_frame.root_window, new - old);
690 }
691 }
692
693 if (redraw)
694 {
695 recompute_basic_faces (f);
696 Fredraw_frame (Fselected_frame ());
697 }
698 }
699
700 #endif /* !HAVE_X_WINDOWS */
701
702
703 /* Do we need the internal terminal? */
704 void
705 internal_terminal_init ()
706 {
707 char *term = getenv ("TERM");
708 char *colors;
709
710 #ifdef HAVE_X_WINDOWS
711 if (!inhibit_window_system)
712 return;
713 #endif
714
715 internal_terminal
716 = (!noninteractive) && term && !strcmp (term, "internal");
717
718 if (getenv ("EMACSTEST"))
719 termscript = fopen (getenv ("EMACSTEST"), "wt");
720
721 #ifndef HAVE_X_WINDOWS
722 if (!internal_terminal || inhibit_window_system)
723 {
724 the_only_frame.output_method = output_termcap;
725 return;
726 }
727
728 Vwindow_system = intern ("pc");
729 Vwindow_system_version = make_number (1);
730
731 bzero (&the_only_x_display, sizeof the_only_x_display);
732 the_only_x_display.background_pixel = 7; /* White */
733 the_only_x_display.foreground_pixel = 0; /* Black */
734 colors = getenv ("EMACSCOLORS");
735 if (colors && strlen (colors) >= 2)
736 {
737 the_only_x_display.foreground_pixel = colors[0] & 0x07;
738 the_only_x_display.background_pixel = colors[1] & 0x07;
739 }
740 the_only_x_display.line_height = 1;
741 the_only_frame.output_data.x = &the_only_x_display;
742 the_only_frame.output_method = output_msdos_raw;
743 the_only_x_display.font = (XFontStruct *)1; /* must *not* be zero */
744
745 init_frame_faces ((FRAME_PTR) &the_only_frame);
746
747 ring_bell_hook = IT_ring_bell;
748 write_glyphs_hook = IT_write_glyphs;
749 cursor_to_hook = raw_cursor_to_hook = IT_cursor_to;
750 clear_to_end_hook = IT_clear_to_end;
751 clear_end_of_line_hook = IT_clear_end_of_line;
752 clear_frame_hook = IT_clear_screen;
753 change_line_highlight_hook = IT_change_line_highlight;
754 update_begin_hook = IT_update_begin;
755 update_end_hook = IT_update_end;
756 reassert_line_highlight_hook = IT_reassert_line_highlight;
757
758 /* These hooks are called by term.c without being checked. */
759 set_terminal_modes_hook = IT_set_terminal_modes;
760 reset_terminal_modes_hook = IT_reset_terminal_modes;
761 set_terminal_window_hook = IT_set_terminal_window;
762 #endif
763 }
764
765 dos_get_saved_screen (screen, rows, cols)
766 char **screen;
767 int *rows;
768 int *cols;
769 {
770 #ifndef HAVE_X_WINDOWS
771 *screen = startup_screen_buffer;
772 *cols = startup_screen_size_X;
773 *rows = startup_screen_size_Y;
774 return 1;
775 #else
776 return 0;
777 #endif
778 }
779 \f
780 /* ----------------------- Keyboard control ----------------------
781 *
782 * Keymaps reflect the following keyboard layout:
783 *
784 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
785 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
786 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
787 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
788 * SPACE
789 */
790
791 static int extended_kbd; /* 101 (102) keyboard present. */
792
793 struct dos_keyboard_map
794 {
795 char *unshifted;
796 char *shifted;
797 char *alt_gr;
798 };
799
800
801 static struct dos_keyboard_map us_keyboard = {
802 /* 0 1 2 3 4 5 */
803 /* 01234567890123456789012345678901234567890 12345678901234 */
804 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
805 /* 0123456789012345678901234567890123456789 012345678901234 */
806 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
807 0 /* no Alt-Gr key */
808 };
809
810 static struct dos_keyboard_map fr_keyboard = {
811 /* 0 1 2 3 4 5 */
812 /* 012 3456789012345678901234567890123456789012345678901234 */
813 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
814 /* 0123456789012345678901234567890123456789012345678901234 */
815 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
816 /* 01234567 89012345678901234567890123456789012345678901234 */
817 " ~#{[|`\\^@]} Ï "
818 };
819
820 static struct dos_keyboard_map dk_keyboard = {
821 /* 0 1 2 3 4 5 */
822 /* 0123456789012345678901234567890123456789012345678901234 */
823 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
824 /* 01 23456789012345678901234567890123456789012345678901234 */
825 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
826 /* 0123456789012345678901234567890123456789012345678901234 */
827 " @\9c$ {[]} | "
828 };
829
830 static struct keyboard_layout_list
831 {
832 int country_code;
833 struct dos_keyboard_map *keyboard_map;
834 } keyboard_layout_list[] =
835 {
836 1, &us_keyboard,
837 33, &fr_keyboard,
838 45, &dk_keyboard
839 };
840
841 static struct dos_keyboard_map *keyboard;
842 static int keyboard_map_all;
843
844 int
845 dos_set_keyboard (code, always)
846 int code;
847 int always;
848 {
849 int i;
850
851 /* Initialize to US settings, for countries that don't have their own. */
852 keyboard = keyboard_layout_list[0].keyboard_map;
853 keyboard_map_all = always;
854 dos_keyboard_layout = 1;
855
856 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
857 if (code == keyboard_layout_list[i].country_code)
858 {
859 keyboard = keyboard_layout_list[i].keyboard_map;
860 keyboard_map_all = always;
861 dos_keyboard_layout = code;
862 return 1;
863 }
864 return 0;
865 }
866 \f
867 #define Ignore 0x0000
868 #define Normal 0x0000 /* normal key - alt changes scan-code */
869 #define FctKey 0x1000 /* func key if c == 0, else c */
870 #define Special 0x2000 /* func key even if c != 0 */
871 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
872 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
873 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
874 #define Grey 0x6000 /* Grey keypad key */
875
876 #define Alt 0x0100 /* alt scan-code */
877 #define Ctrl 0x0200 /* ctrl scan-code */
878 #define Shift 0x0400 /* shift scan-code */
879
880 static struct
881 {
882 unsigned char char_code; /* normal code */
883 unsigned char meta_code; /* M- code */
884 unsigned char keypad_code; /* keypad code */
885 unsigned char editkey_code; /* edit key */
886 } keypad_translate_map[] = {
887 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
888 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
889 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
890 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
891 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
892 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
893 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
894 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
895 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
896 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
897 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
898 };
899
900 static struct
901 {
902 unsigned char char_code; /* normal code */
903 unsigned char keypad_code; /* keypad code */
904 } grey_key_translate_map[] = {
905 '/', 0xaf, /* kp-decimal */
906 '*', 0xaa, /* kp-multiply */
907 '-', 0xad, /* kp-subtract */
908 '+', 0xab, /* kp-add */
909 '\r', 0x8d /* kp-enter */
910 };
911
912 static unsigned short
913 ibmpc_translate_map[] =
914 {
915 /* --------------- 00 to 0f --------------- */
916 Normal | 0xff, /* Ctrl Break + Alt-NNN */
917 Alt | ModFct | 0x1b, /* Escape */
918 Normal | 1, /* '1' */
919 Normal | 2, /* '2' */
920 Normal | 3, /* '3' */
921 Normal | 4, /* '4' */
922 Normal | 5, /* '5' */
923 Normal | 6, /* '6' */
924 Normal | 7, /* '7' */
925 Normal | 8, /* '8' */
926 Normal | 9, /* '9' */
927 Normal | 10, /* '0' */
928 Normal | 11, /* '-' */
929 Normal | 12, /* '=' */
930 Special | 0x08, /* Backspace */
931 ModFct | 0x74, /* Tab/Backtab */
932
933 /* --------------- 10 to 1f --------------- */
934 Map | 15, /* 'q' */
935 Map | 16, /* 'w' */
936 Map | 17, /* 'e' */
937 Map | 18, /* 'r' */
938 Map | 19, /* 't' */
939 Map | 20, /* 'y' */
940 Map | 21, /* 'u' */
941 Map | 22, /* 'i' */
942 Map | 23, /* 'o' */
943 Map | 24, /* 'p' */
944 Map | 25, /* '[' */
945 Map | 26, /* ']' */
946 ModFct | 0x0d, /* Return */
947 Ignore, /* Ctrl */
948 Map | 30, /* 'a' */
949 Map | 31, /* 's' */
950
951 /* --------------- 20 to 2f --------------- */
952 Map | 32, /* 'd' */
953 Map | 33, /* 'f' */
954 Map | 34, /* 'g' */
955 Map | 35, /* 'h' */
956 Map | 36, /* 'j' */
957 Map | 37, /* 'k' */
958 Map | 38, /* 'l' */
959 Map | 39, /* ';' */
960 Map | 40, /* '\'' */
961 Map | 0, /* '`' */
962 Ignore, /* Left shift */
963 Map | 41, /* '\\' */
964 Map | 45, /* 'z' */
965 Map | 46, /* 'x' */
966 Map | 47, /* 'c' */
967 Map | 48, /* 'v' */
968
969 /* --------------- 30 to 3f --------------- */
970 Map | 49, /* 'b' */
971 Map | 50, /* 'n' */
972 Map | 51, /* 'm' */
973 Map | 52, /* ',' */
974 Map | 53, /* '.' */
975 Map | 54, /* '/' */
976 Ignore, /* Right shift */
977 Grey | 1, /* Grey * */
978 Ignore, /* Alt */
979 Normal | ' ', /* ' ' */
980 Ignore, /* Caps Lock */
981 FctKey | 0xbe, /* F1 */
982 FctKey | 0xbf, /* F2 */
983 FctKey | 0xc0, /* F3 */
984 FctKey | 0xc1, /* F4 */
985 FctKey | 0xc2, /* F5 */
986
987 /* --------------- 40 to 4f --------------- */
988 FctKey | 0xc3, /* F6 */
989 FctKey | 0xc4, /* F7 */
990 FctKey | 0xc5, /* F8 */
991 FctKey | 0xc6, /* F9 */
992 FctKey | 0xc7, /* F10 */
993 Ignore, /* Num Lock */
994 Ignore, /* Scroll Lock */
995 KeyPad | 7, /* Home */
996 KeyPad | 8, /* Up */
997 KeyPad | 9, /* Page Up */
998 Grey | 2, /* Grey - */
999 KeyPad | 4, /* Left */
1000 KeyPad | 5, /* Keypad 5 */
1001 KeyPad | 6, /* Right */
1002 Grey | 3, /* Grey + */
1003 KeyPad | 1, /* End */
1004
1005 /* --------------- 50 to 5f --------------- */
1006 KeyPad | 2, /* Down */
1007 KeyPad | 3, /* Page Down */
1008 KeyPad | 0, /* Insert */
1009 KeyPad | 10, /* Delete */
1010 Shift | FctKey | 0xbe, /* (Shift) F1 */
1011 Shift | FctKey | 0xbf, /* (Shift) F2 */
1012 Shift | FctKey | 0xc0, /* (Shift) F3 */
1013 Shift | FctKey | 0xc1, /* (Shift) F4 */
1014 Shift | FctKey | 0xc2, /* (Shift) F5 */
1015 Shift | FctKey | 0xc3, /* (Shift) F6 */
1016 Shift | FctKey | 0xc4, /* (Shift) F7 */
1017 Shift | FctKey | 0xc5, /* (Shift) F8 */
1018 Shift | FctKey | 0xc6, /* (Shift) F9 */
1019 Shift | FctKey | 0xc7, /* (Shift) F10 */
1020 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1021 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1022
1023 /* --------------- 60 to 6f --------------- */
1024 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1025 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1026 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1027 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1028 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1029 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1030 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1031 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1032 Alt | FctKey | 0xbe, /* (Alt) F1 */
1033 Alt | FctKey | 0xbf, /* (Alt) F2 */
1034 Alt | FctKey | 0xc0, /* (Alt) F3 */
1035 Alt | FctKey | 0xc1, /* (Alt) F4 */
1036 Alt | FctKey | 0xc2, /* (Alt) F5 */
1037 Alt | FctKey | 0xc3, /* (Alt) F6 */
1038 Alt | FctKey | 0xc4, /* (Alt) F7 */
1039 Alt | FctKey | 0xc5, /* (Alt) F8 */
1040
1041 /* --------------- 70 to 7f --------------- */
1042 Alt | FctKey | 0xc6, /* (Alt) F9 */
1043 Alt | FctKey | 0xc7, /* (Alt) F10 */
1044 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1045 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1046 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1047 Ctrl | KeyPad | 1, /* (Ctrl) End */
1048 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1049 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1050 Alt | Map | 1, /* '1' */
1051 Alt | Map | 2, /* '2' */
1052 Alt | Map | 3, /* '3' */
1053 Alt | Map | 4, /* '4' */
1054 Alt | Map | 5, /* '5' */
1055 Alt | Map | 6, /* '6' */
1056 Alt | Map | 7, /* '7' */
1057 Alt | Map | 8, /* '8' */
1058
1059 /* --------------- 80 to 8f --------------- */
1060 Alt | Map | 9, /* '9' */
1061 Alt | Map | 10, /* '0' */
1062 Alt | Map | 11, /* '-' */
1063 Alt | Map | 12, /* '=' */
1064 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1065 FctKey | 0xc8, /* F11 */
1066 FctKey | 0xc9, /* F12 */
1067 Shift | FctKey | 0xc8, /* (Shift) F11 */
1068 Shift | FctKey | 0xc9, /* (Shift) F12 */
1069 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1070 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1071 Alt | FctKey | 0xc8, /* (Alt) F11 */
1072 Alt | FctKey | 0xc9, /* (Alt) F12 */
1073 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1074 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1075 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1076
1077 /* --------------- 90 to 9f --------------- */
1078 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1079 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1080 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1081 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1082 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1083 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1084 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1085 Alt | FctKey | 0x50, /* (Alt) Home */
1086 Alt | FctKey | 0x52, /* (Alt) Up */
1087 Alt | FctKey | 0x55, /* (Alt) Page Up */
1088 Ignore, /* NO KEY */
1089 Alt | FctKey | 0x51, /* (Alt) Left */
1090 Ignore, /* NO KEY */
1091 Alt | FctKey | 0x53, /* (Alt) Right */
1092 Ignore, /* NO KEY */
1093 Alt | FctKey | 0x57, /* (Alt) End */
1094
1095 /* --------------- a0 to af --------------- */
1096 Alt | KeyPad | 2, /* (Alt) Down */
1097 Alt | KeyPad | 3, /* (Alt) Page Down */
1098 Alt | KeyPad | 0, /* (Alt) Insert */
1099 Alt | KeyPad | 10, /* (Alt) Delete */
1100 Alt | Grey | 0, /* (Alt) Grey / */
1101 Alt | FctKey | 0x09, /* (Alt) Tab */
1102 Alt | Grey | 4 /* (Alt) Keypad Enter */
1103 };
1104 \f
1105 /* These bit-positions corresponds to values returned by BIOS */
1106 #define SHIFT_P 0x0003 /* two bits! */
1107 #define CTRL_P 0x0004
1108 #define ALT_P 0x0008
1109 #define SCRLOCK_P 0x0010
1110 #define NUMLOCK_P 0x0020
1111 #define CAPSLOCK_P 0x0040
1112 #define ALT_GR_P 0x0800
1113 #define SUPER_P 0x4000 /* pseudo */
1114 #define HYPER_P 0x8000 /* pseudo */
1115
1116 static int
1117 dos_get_modifiers (keymask)
1118 int *keymask;
1119 {
1120 union REGS regs;
1121 int mask;
1122 int modifiers = 0;
1123
1124 /* Calculate modifier bits */
1125 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1126 int86 (0x16, &regs, &regs);
1127
1128 if (!extended_kbd)
1129 {
1130 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1131 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1132 }
1133 else
1134 {
1135 mask = regs.h.al & (SHIFT_P |
1136 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1137
1138 /* Do not break international keyboard support. */
1139 /* When Keyb.Com is loaded, the right Alt key is */
1140 /* used for accessing characters like { and } */
1141 if (regs.h.ah & 2) /* Left ALT pressed ? */
1142 mask |= ALT_P;
1143
1144 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1145 {
1146 mask |= ALT_GR_P;
1147 if (dos_hyper_key == 1)
1148 {
1149 mask |= HYPER_P;
1150 modifiers |= hyper_modifier;
1151 }
1152 else if (dos_super_key == 1)
1153 {
1154 mask |= SUPER_P;
1155 modifiers |= super_modifier;
1156 }
1157 }
1158
1159 if (regs.h.ah & 1) /* Left CTRL pressed
1160 mask |= CTRL_P;
1161
1162 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1163 {
1164 if (dos_hyper_key == 2)
1165 {
1166 mask |= HYPER_P;
1167 modifiers |= hyper_modifier;
1168 }
1169 else if (dos_super_key == 2)
1170 {
1171 mask |= SUPER_P;
1172 modifiers |= super_modifier;
1173 }
1174 else
1175 mask |= CTRL_P;
1176 }
1177 }
1178
1179 if (mask & SHIFT_P)
1180 modifiers |= shift_modifier;
1181 if (mask & CTRL_P)
1182 modifiers |= ctrl_modifier;
1183 if (mask & ALT_P)
1184 modifiers |= meta_modifier;
1185
1186 if (keymask)
1187 *keymask = mask;
1188 return modifiers;
1189 }
1190
1191 #define NUM_RECENT_DOSKEYS (100)
1192 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1193 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1194 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1195
1196 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1197 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1198 Each input key receives two values in this vector: first the ASCII code,\n\
1199 and then the scan code.")
1200 ()
1201 {
1202 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1203 Lisp_Object val;
1204
1205 if (total_doskeys < NUM_RECENT_DOSKEYS)
1206 return Fvector (total_doskeys, keys);
1207 else
1208 {
1209 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1210 bcopy (keys + recent_doskeys_index,
1211 XVECTOR (val)->contents,
1212 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1213 bcopy (keys,
1214 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1215 recent_doskeys_index * sizeof (Lisp_Object));
1216 return val;
1217 }
1218 }
1219
1220 /* Get a char from keyboard. Function keys are put into the event queue. */
1221 static int
1222 dos_rawgetc ()
1223 {
1224 struct input_event event;
1225 union REGS regs;
1226
1227 #ifndef HAVE_X_WINDOWS
1228 SCREEN_SET_CURSOR ();
1229 if (!mouse_visible) mouse_on ();
1230 #endif
1231
1232 /* The following condition is equivalent to `kbhit ()', except that
1233 it uses the bios to do its job. This pleases DESQview/X. */
1234 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1235 int86 (0x16, &regs, &regs),
1236 (regs.x.flags & 0x40) == 0)
1237 {
1238 union REGS regs;
1239 register unsigned char c;
1240 int sc, code, mask, kp_mode;
1241 int modifiers;
1242
1243 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1244 int86 (0x16, &regs, &regs);
1245 c = regs.h.al;
1246 sc = regs.h.ah;
1247
1248 total_doskeys += 2;
1249 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1250 = make_number (c);
1251 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1252 recent_doskeys_index = 0;
1253 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1254 = make_number (sc);
1255 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1256 recent_doskeys_index = 0;
1257
1258 modifiers = dos_get_modifiers (&mask);
1259
1260 #ifndef HAVE_X_WINDOWS
1261 if (!NILP (Vdos_display_scancodes))
1262 {
1263 char buf[10];
1264 sprintf (buf, "%02x:%02x*%04x",
1265 (unsigned) (sc&0xff), (unsigned) c, mask);
1266 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1267 }
1268 #endif
1269
1270 if (sc == 0xe0)
1271 {
1272 switch (c)
1273 {
1274 case 10: /* Ctrl Grey Enter */
1275 code = Ctrl | Grey | 4;
1276 break;
1277 case 13: /* Grey Enter */
1278 code = Grey | 4;
1279 break;
1280 case '/': /* Grey / */
1281 code = Grey | 0;
1282 break;
1283 default:
1284 continue;
1285 };
1286 c = 0;
1287 }
1288 else
1289 {
1290 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1291 continue;
1292 if ((code = ibmpc_translate_map[sc]) == Ignore)
1293 continue;
1294 }
1295
1296 if (c == 0)
1297 {
1298 if (code & Alt)
1299 modifiers |= meta_modifier;
1300 if (code & Ctrl)
1301 modifiers |= ctrl_modifier;
1302 if (code & Shift)
1303 modifiers |= shift_modifier;
1304 }
1305
1306 switch (code & 0xf000)
1307 {
1308 case ModFct:
1309 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1310 return c;
1311 c = 0; /* Special */
1312
1313 case FctKey:
1314 if (c != 0)
1315 return c;
1316
1317 case Special:
1318 code |= 0xff00;
1319 break;
1320
1321 case Normal:
1322 if (sc == 0)
1323 {
1324 if (c == 0) /* ctrl-break */
1325 continue;
1326 return c; /* ALT-nnn */
1327 }
1328 if (!keyboard_map_all)
1329 {
1330 if (c != ' ')
1331 return c;
1332 code = c;
1333 break;
1334 }
1335
1336 case Map:
1337 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1338 if (!keyboard_map_all)
1339 return c;
1340
1341 code &= 0xff;
1342 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1343 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1344
1345 if (mask & SHIFT_P)
1346 {
1347 code = keyboard->shifted[code];
1348 mask -= SHIFT_P;
1349 modifiers &= ~shift_modifier;
1350 }
1351 else
1352 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1353 code = keyboard->alt_gr[code];
1354 else
1355 code = keyboard->unshifted[code];
1356 break;
1357
1358 case KeyPad:
1359 code &= 0xff;
1360 if (c == 0xe0) /* edit key */
1361 kp_mode = 3;
1362 else
1363 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1364 kp_mode = dos_keypad_mode & 0x03;
1365 else
1366 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1367
1368 switch (kp_mode)
1369 {
1370 case 0:
1371 if (code == 10 && dos_decimal_point)
1372 return dos_decimal_point;
1373 return keypad_translate_map[code].char_code;
1374
1375 case 1:
1376 code = 0xff00 | keypad_translate_map[code].keypad_code;
1377 break;
1378
1379 case 2:
1380 code = keypad_translate_map[code].meta_code;
1381 modifiers = meta_modifier;
1382 break;
1383
1384 case 3:
1385 code = 0xff00 | keypad_translate_map[code].editkey_code;
1386 break;
1387 }
1388 break;
1389
1390 case Grey:
1391 code &= 0xff;
1392 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1393 if (dos_keypad_mode & kp_mode)
1394 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1395 else
1396 code = grey_key_translate_map[code].char_code;
1397 break;
1398 }
1399
1400 make_event:
1401 if (code == 0)
1402 continue;
1403
1404 if (code >= 0x100)
1405 event.kind = non_ascii_keystroke;
1406 else
1407 event.kind = ascii_keystroke;
1408 event.code = code;
1409 event.modifiers = modifiers;
1410 XSETFRAME (event.frame_or_window, selected_frame);
1411 event.timestamp = event_timestamp ();
1412 kbd_buffer_store_event (&event);
1413 }
1414
1415 if (have_mouse > 0)
1416 {
1417 int but, press, x, y, ok;
1418
1419 /* Check for mouse movement *before* buttons. */
1420 mouse_check_moved ();
1421
1422 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1423 for (press = 0; press < 2; press++)
1424 {
1425 if (press)
1426 ok = mouse_pressed (but, &x, &y);
1427 else
1428 ok = mouse_released (but, &x, &y);
1429 if (ok)
1430 {
1431 event.kind = mouse_click;
1432 event.code = but;
1433 event.modifiers = dos_get_modifiers (0)
1434 | (press ? down_modifier : up_modifier);
1435 event.x = x;
1436 event.y = y;
1437 XSETFRAME (event.frame_or_window, selected_frame);
1438 event.timestamp = event_timestamp ();
1439 kbd_buffer_store_event (&event);
1440 }
1441 }
1442 }
1443
1444 return -1;
1445 }
1446
1447 static int prev_get_char = -1;
1448
1449 /* Return 1 if a key is ready to be read without suspending execution. */
1450 dos_keysns ()
1451 {
1452 if (prev_get_char != -1)
1453 return 1;
1454 else
1455 return ((prev_get_char = dos_rawgetc ()) != -1);
1456 }
1457
1458 /* Read a key. Return -1 if no key is ready. */
1459 dos_keyread ()
1460 {
1461 if (prev_get_char != -1)
1462 {
1463 int c = prev_get_char;
1464 prev_get_char = -1;
1465 return c;
1466 }
1467 else
1468 return dos_rawgetc ();
1469 }
1470 \f
1471 #ifndef HAVE_X_WINDOWS
1472 /* See xterm.c for more info. */
1473 void
1474 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1475 FRAME_PTR f;
1476 register int pix_x, pix_y;
1477 register int *x, *y;
1478 void /* XRectangle */ *bounds;
1479 int noclip;
1480 {
1481 if (bounds) abort ();
1482
1483 /* Ignore clipping. */
1484
1485 *x = pix_x;
1486 *y = pix_y;
1487 }
1488
1489 void
1490 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1491 FRAME_PTR f;
1492 register int x, y;
1493 register int *pix_x, *pix_y;
1494 {
1495 *pix_x = x;
1496 *pix_y = y;
1497 }
1498 \f
1499 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1500 for now.
1501
1502 Actually, I don't know the meaning of all the parameters of the functions
1503 here -- I only know how they are called by xmenu.c. I could of course
1504 grab the nearest Xlib manual (down the hall, second-to-last door on the
1505 left), but I don't think it's worth the effort. */
1506
1507 static XMenu *
1508 IT_menu_create ()
1509 {
1510 XMenu *menu;
1511
1512 menu = (XMenu *) xmalloc (sizeof (XMenu));
1513 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1514 return menu;
1515 }
1516
1517 /* Allocate some (more) memory for MENU ensuring that there is room for one
1518 for item. */
1519
1520 static void
1521 IT_menu_make_room (XMenu *menu)
1522 {
1523 if (menu->allocated == 0)
1524 {
1525 int count = menu->allocated = 10;
1526 menu->text = (char **) xmalloc (count * sizeof (char *));
1527 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1528 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1529 }
1530 else if (menu->allocated == menu->count)
1531 {
1532 int count = menu->allocated = menu->allocated + 10;
1533 menu->text
1534 = (char **) xrealloc (menu->text, count * sizeof (char *));
1535 menu->submenu
1536 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1537 menu->panenumber
1538 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1539 }
1540 }
1541
1542 /* Search the given menu structure for a given pane number. */
1543
1544 static XMenu *
1545 IT_menu_search_pane (XMenu *menu, int pane)
1546 {
1547 int i;
1548 XMenu *try;
1549
1550 for (i = 0; i < menu->count; i++)
1551 if (menu->submenu[i])
1552 {
1553 if (pane == menu->panenumber[i])
1554 return menu->submenu[i];
1555 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1556 return try;
1557 }
1558 return (XMenu *) 0;
1559 }
1560
1561 /* Determine how much screen space a given menu needs. */
1562
1563 static void
1564 IT_menu_calc_size (XMenu *menu, int *width, int *height)
1565 {
1566 int i, h2, w2, maxsubwidth, maxheight;
1567
1568 maxsubwidth = 0;
1569 maxheight = menu->count;
1570 for (i = 0; i < menu->count; i++)
1571 {
1572 if (menu->submenu[i])
1573 {
1574 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1575 if (w2 > maxsubwidth) maxsubwidth = w2;
1576 if (i + h2 > maxheight) maxheight = i + h2;
1577 }
1578 }
1579 *width = menu->width + maxsubwidth;
1580 *height = maxheight;
1581 }
1582
1583 /* Display MENU at (X,Y) using FACES. */
1584
1585 static void
1586 IT_menu_display (XMenu *menu, int y, int x, int *faces)
1587 {
1588 int i, j, face, width;
1589 GLYPH *text, *p;
1590 char *q;
1591 int mx, my;
1592 int enabled, mousehere;
1593 int row, col;
1594
1595 width = menu->width;
1596 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1597 ScreenGetCursor (&row, &col);
1598 mouse_get_xy (&mx, &my);
1599 IT_update_begin ();
1600 for (i = 0; i < menu->count; i++)
1601 {
1602 IT_cursor_to (y + i, x);
1603 enabled
1604 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
1605 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
1606 face = faces[enabled + mousehere * 2];
1607 p = text;
1608 *p++ = FAST_MAKE_GLYPH (' ', face);
1609 for (j = 0, q = menu->text[i]; *q; j++)
1610 *p++ = FAST_MAKE_GLYPH (*q++, face);
1611 for (; j < width; j++)
1612 *p++ = FAST_MAKE_GLYPH (' ', face);
1613 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
1614 IT_write_glyphs (text, width + 2);
1615 }
1616 IT_update_end ();
1617 IT_cursor_to (row, col);
1618 xfree (text);
1619 }
1620 \f
1621 /* --------------------------- X Menu emulation ---------------------- */
1622
1623 /* Report availability of menus. */
1624
1625 int
1626 have_menus_p ()
1627 {
1628 return 1;
1629 }
1630
1631 /* Create a brand new menu structure. */
1632
1633 XMenu *
1634 XMenuCreate (Display *foo1, Window foo2, char *foo3)
1635 {
1636 return IT_menu_create ();
1637 }
1638
1639 /* Create a new pane and place it on the outer-most level. It is not
1640 clear that it should be placed out there, but I don't know what else
1641 to do. */
1642
1643 int
1644 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
1645 {
1646 int len;
1647
1648 if (!enable)
1649 abort ();
1650
1651 IT_menu_make_room (menu);
1652 menu->submenu[menu->count] = IT_menu_create ();
1653 menu->text[menu->count] = txt;
1654 menu->panenumber[menu->count] = ++menu->panecount;
1655 menu->count++;
1656 if ((len = strlen (txt)) > menu->width)
1657 menu->width = len;
1658 return menu->panecount;
1659 }
1660
1661 /* Create a new item in a menu pane. */
1662
1663 int
1664 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1665 int foo, char *txt, int enable)
1666 {
1667 int len;
1668
1669 if (pane)
1670 if (!(menu = IT_menu_search_pane (menu, pane)))
1671 return XM_FAILURE;
1672 IT_menu_make_room (menu);
1673 menu->submenu[menu->count] = (XMenu *) 0;
1674 menu->text[menu->count] = txt;
1675 menu->panenumber[menu->count] = enable;
1676 menu->count++;
1677 if ((len = strlen (txt)) > menu->width)
1678 menu->width = len;
1679 return XM_SUCCESS;
1680 }
1681
1682 /* Decide where the menu would be placed if requested at (X,Y). */
1683
1684 void
1685 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
1686 int *ulx, int *uly, int *width, int *height)
1687 {
1688 IT_menu_calc_size (menu, width, height);
1689 *ulx = x + 1;
1690 *uly = y;
1691 *width += 2;
1692 }
1693
1694 struct IT_menu_state
1695 {
1696 void *screen_behind;
1697 XMenu *menu;
1698 int pane;
1699 int x, y;
1700 };
1701
1702
1703 /* Display menu, wait for user's response, and return that response. */
1704
1705 int
1706 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
1707 int x0, int y0, unsigned ButtonMask, char **txt)
1708 {
1709 struct IT_menu_state *state;
1710 int statecount;
1711 int x, y, i, b;
1712 int screensize;
1713 int faces[4], selectface;
1714 int leave, result, onepane;
1715 int title_faces[4]; /* face to display the menu title */
1716
1717 /* Just in case we got here without a mouse present... */
1718 if (have_mouse <= 0)
1719 return XM_IA_SELECT;
1720
1721 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
1722 screensize = screen_size * 2;
1723 faces[0]
1724 = compute_glyph_face (&the_only_frame,
1725 face_name_id_number
1726 (&the_only_frame,
1727 intern ("msdos-menu-passive-face")),
1728 0);
1729 faces[1]
1730 = compute_glyph_face (&the_only_frame,
1731 face_name_id_number
1732 (&the_only_frame,
1733 intern ("msdos-menu-active-face")),
1734 0);
1735 selectface
1736 = face_name_id_number (&the_only_frame, intern ("msdos-menu-select-face"));
1737 faces[2] = compute_glyph_face (&the_only_frame, selectface, faces[0]);
1738 faces[3] = compute_glyph_face (&the_only_frame, selectface, faces[1]);
1739
1740 /* Make sure the menu title is always displayed with
1741 `msdos-menu-active-face', no matter where the mouse pointer is. */
1742 for (i = 0; i < 4; i++)
1743 title_faces[i] = faces[3];
1744
1745 statecount = 1;
1746 state[0].menu = menu;
1747 mouse_off ();
1748 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
1749
1750 IT_menu_display (menu, y0 - 1, x0 - 1, title_faces); /* display menu title */
1751 if ((onepane = menu->count == 1 && menu->submenu[0]))
1752 {
1753 menu->width = menu->submenu[0]->width;
1754 state[0].menu = menu->submenu[0];
1755 }
1756 else
1757 {
1758 state[0].menu = menu;
1759 }
1760 state[0].x = x0 - 1;
1761 state[0].y = y0;
1762 state[0].pane = onepane;
1763
1764 mouse_last_x = -1; /* A hack that forces display. */
1765 leave = 0;
1766 while (!leave)
1767 {
1768 if (!mouse_visible) mouse_on ();
1769 mouse_check_moved ();
1770 if (selected_frame->mouse_moved)
1771 {
1772 selected_frame->mouse_moved = 0;
1773 result = XM_IA_SELECT;
1774 mouse_get_xy (&x, &y);
1775 for (i = 0; i < statecount; i++)
1776 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
1777 {
1778 int dy = y - state[i].y;
1779 if (0 <= dy && dy < state[i].menu->count)
1780 {
1781 if (!state[i].menu->submenu[dy])
1782 if (state[i].menu->panenumber[dy])
1783 result = XM_SUCCESS;
1784 else
1785 result = XM_IA_SELECT;
1786 *pane = state[i].pane - 1;
1787 *selidx = dy;
1788 /* We hit some part of a menu, so drop extra menus that
1789 have been opened. That does not include an open and
1790 active submenu. */
1791 if (i != statecount - 2
1792 || state[i].menu->submenu[dy] != state[i+1].menu)
1793 while (i != statecount - 1)
1794 {
1795 statecount--;
1796 mouse_off ();
1797 ScreenUpdate (state[statecount].screen_behind);
1798 xfree (state[statecount].screen_behind);
1799 }
1800 if (i == statecount - 1 && state[i].menu->submenu[dy])
1801 {
1802 IT_menu_display (state[i].menu,
1803 state[i].y,
1804 state[i].x,
1805 faces);
1806 state[statecount].menu = state[i].menu->submenu[dy];
1807 state[statecount].pane = state[i].menu->panenumber[dy];
1808 mouse_off ();
1809 ScreenRetrieve (state[statecount].screen_behind
1810 = xmalloc (screensize));
1811 state[statecount].x
1812 = state[i].x + state[i].menu->width + 2;
1813 state[statecount].y = y;
1814 statecount++;
1815 }
1816 }
1817 }
1818 IT_menu_display (state[statecount - 1].menu,
1819 state[statecount - 1].y,
1820 state[statecount - 1].x,
1821 faces);
1822 }
1823 for (b = 0; b < mouse_button_count; b++)
1824 {
1825 (void) mouse_pressed (b, &x, &y);
1826 if (mouse_released (b, &x, &y))
1827 leave = 1;
1828 }
1829 }
1830
1831 mouse_off ();
1832 ScreenUpdate (state[0].screen_behind);
1833 while (statecount--)
1834 xfree (state[statecount].screen_behind);
1835 return result;
1836 }
1837
1838 /* Dispose of a menu. */
1839
1840 void
1841 XMenuDestroy (Display *foo, XMenu *menu)
1842 {
1843 int i;
1844 if (menu->allocated)
1845 {
1846 for (i = 0; i < menu->count; i++)
1847 if (menu->submenu[i])
1848 XMenuDestroy (foo, menu->submenu[i]);
1849 xfree (menu->text);
1850 xfree (menu->submenu);
1851 xfree (menu->panenumber);
1852 }
1853 xfree (menu);
1854 }
1855
1856 int
1857 x_pixel_width (struct frame *f)
1858 {
1859 return FRAME_WIDTH (f);
1860 }
1861
1862 int
1863 x_pixel_height (struct frame *f)
1864 {
1865 return FRAME_HEIGHT (f);
1866 }
1867 #endif /* !HAVE_X_WINDOWS */
1868 \f
1869 /* ----------------------- DOS / UNIX conversion --------------------- */
1870
1871 /* Destructively turn backslashes into slashes. */
1872
1873 void
1874 dostounix_filename (p)
1875 register char *p;
1876 {
1877 while (*p)
1878 {
1879 if (*p == '\\')
1880 *p = '/';
1881 p++;
1882 }
1883 }
1884
1885 /* Destructively turn slashes into backslashes. */
1886
1887 void
1888 unixtodos_filename (p)
1889 register char *p;
1890 {
1891 while (*p)
1892 {
1893 if (*p == '/')
1894 *p = '\\';
1895 p++;
1896 }
1897 }
1898
1899 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
1900
1901 int
1902 getdefdir (drive, dst)
1903 int drive;
1904 char *dst;
1905 {
1906 union REGS regs;
1907
1908 *dst++ = '/';
1909 regs.h.dl = drive;
1910 regs.x.si = (int) dst;
1911 regs.h.ah = 0x47;
1912 intdos (&regs, &regs);
1913 return !regs.x.cflag;
1914 }
1915
1916 /* Remove all CR's that are followed by a LF. */
1917
1918 int
1919 crlf_to_lf (n, buf)
1920 register int n;
1921 register unsigned char *buf;
1922 {
1923 unsigned char *np = buf;
1924 unsigned char *startp = buf;
1925 unsigned char *endp = buf + n;
1926 unsigned char c;
1927
1928 if (n == 0)
1929 return n;
1930 while (buf < endp - 1)
1931 {
1932 if (*buf == 0x0d)
1933 {
1934 if (*(++buf) != 0x0a)
1935 *np++ = 0x0d;
1936 }
1937 else
1938 *np++ = *buf++;
1939 }
1940 if (buf < endp)
1941 *np++ = *buf++;
1942 return np - startp;
1943 }
1944 \f
1945 /* The Emacs root directory as determined by init_environment. */
1946
1947 static char emacsroot[MAXPATHLEN];
1948
1949 char *
1950 rootrelativepath (rel)
1951 char *rel;
1952 {
1953 static char result[MAXPATHLEN + 10];
1954
1955 strcpy (result, emacsroot);
1956 strcat (result, "/");
1957 strcat (result, rel);
1958 return result;
1959 }
1960
1961 /* Define a lot of environment variables if not already defined. Don't
1962 remove anything unless you know what you're doing -- lots of code will
1963 break if one or more of these are missing. */
1964
1965 void
1966 init_environment (argc, argv, skip_args)
1967 int argc;
1968 char **argv;
1969 int skip_args;
1970 {
1971 char *s, *t, *root;
1972 int len;
1973
1974 /* Find our root from argv[0]. Assuming argv[0] is, say,
1975 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
1976 root = alloca (MAXPATHLEN + 20);
1977 _fixpath (argv[0], root);
1978 strlwr (root);
1979 len = strlen (root);
1980 while (len > 0 && root[len] != '/' && root[len] != ':')
1981 len--;
1982 root[len] = '\0';
1983 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
1984 root[len - 4] = '\0';
1985 else
1986 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
1987 len = strlen (root);
1988 strcpy (emacsroot, root);
1989
1990 /* We default HOME to our root. */
1991 setenv ("HOME", root, 0);
1992
1993 /* We default EMACSPATH to root + "/bin". */
1994 strcpy (root + len, "/bin");
1995 setenv ("EMACSPATH", root, 0);
1996
1997 /* I don't expect anybody to ever use other terminals so the internal
1998 terminal is the default. */
1999 setenv ("TERM", "internal", 0);
2000
2001 #ifdef HAVE_X_WINDOWS
2002 /* Emacs expects DISPLAY to be set. */
2003 setenv ("DISPLAY", "unix:0.0", 0);
2004 #endif
2005
2006 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
2007 downcase it and mirror the backslashes. */
2008 s = getenv ("COMSPEC");
2009 if (!s) s = "c:/command.com";
2010 t = alloca (strlen (s) + 1);
2011 strcpy (t, s);
2012 strlwr (t);
2013 dostounix_filename (t);
2014 setenv ("SHELL", t, 0);
2015
2016 /* PATH is also downcased and backslashes mirrored. */
2017 s = getenv ("PATH");
2018 if (!s) s = "";
2019 t = alloca (strlen (s) + 3);
2020 /* Current directory is always considered part of MsDos's path but it is
2021 not normally mentioned. Now it is. */
2022 strcat (strcpy (t, ".;"), s);
2023 strlwr (t);
2024 dostounix_filename (t); /* Not a single file name, but this should work. */
2025 setenv ("PATH", t, 1);
2026
2027 /* In some sense all dos users have root privileges, so... */
2028 setenv ("USER", "root", 0);
2029 setenv ("NAME", getenv ("USER"), 0);
2030
2031 /* Time zone determined from country code. To make this possible, the
2032 country code may not span more than one time zone. In other words,
2033 in the USA, you lose. */
2034 if (!getenv ("TZ"))
2035 switch (dos_country_code)
2036 {
2037 case 31: /* Belgium */
2038 case 32: /* The Netherlands */
2039 case 33: /* France */
2040 case 34: /* Spain */
2041 case 36: /* Hungary */
2042 case 38: /* Yugoslavia (or what's left of it?) */
2043 case 39: /* Italy */
2044 case 41: /* Switzerland */
2045 case 42: /* Tjekia */
2046 case 45: /* Denmark */
2047 case 46: /* Sweden */
2048 case 47: /* Norway */
2049 case 48: /* Poland */
2050 case 49: /* Germany */
2051 /* Daylight saving from last Sunday in March to last Sunday in
2052 September, both at 2AM. */
2053 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2054 break;
2055 case 44: /* United Kingdom */
2056 case 351: /* Portugal */
2057 case 354: /* Iceland */
2058 setenv ("TZ", "GMT+00", 0);
2059 break;
2060 case 81: /* Japan */
2061 case 82: /* Korea */
2062 setenv ("TZ", "JST-09", 0);
2063 break;
2064 case 90: /* Turkey */
2065 case 358: /* Finland */
2066 setenv ("TZ", "EET-02", 0);
2067 break;
2068 case 972: /* Israel */
2069 /* This is an approximation. (For exact rules, use the
2070 `zoneinfo/israel' file which comes with DJGPP, but you need
2071 to install it in `/usr/share/zoneinfo/' directory first.) */
2072 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2073 break;
2074 }
2075 init_gettimeofday ();
2076 }
2077
2078 \f
2079
2080 static int break_stat; /* BREAK check mode status. */
2081 static int stdin_stat; /* stdin IOCTL status. */
2082
2083 /* These must be global. */
2084 static _go32_dpmi_seginfo ctrl_break_vector;
2085 static _go32_dpmi_registers ctrl_break_regs;
2086 static int ctrlbreakinstalled = 0;
2087
2088 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2089
2090 void
2091 ctrl_break_func (regs)
2092 _go32_dpmi_registers *regs;
2093 {
2094 Vquit_flag = Qt;
2095 }
2096
2097 void
2098 install_ctrl_break_check ()
2099 {
2100 if (!ctrlbreakinstalled)
2101 {
2102 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2103 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2104 ctrlbreakinstalled = 1;
2105 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2106 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2107 &ctrl_break_regs);
2108 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2109 }
2110 }
2111
2112 /*
2113 * Turn off Dos' Ctrl-C checking and inhibit interpretation of
2114 * control chars by Dos.
2115 * Determine the keyboard type.
2116 */
2117
2118 int
2119 dos_ttraw ()
2120 {
2121 union REGS inregs, outregs;
2122 static int first_time = 1;
2123
2124 break_stat = getcbrk ();
2125 setcbrk (0);
2126 install_ctrl_break_check ();
2127
2128 if (first_time)
2129 {
2130 inregs.h.ah = 0xc0;
2131 int86 (0x15, &inregs, &outregs);
2132 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2133
2134 have_mouse = 0;
2135
2136 if (internal_terminal
2137 #ifdef HAVE_X_WINDOWS
2138 && inhibit_window_system
2139 #endif
2140 )
2141 {
2142 inregs.x.ax = 0x0021;
2143 int86 (0x33, &inregs, &outregs);
2144 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2145 if (!have_mouse)
2146 {
2147 /* Reportedly, the above doesn't work for some mouse drivers. There
2148 is an additional detection method that should work, but might be
2149 a little slower. Use that as an alternative. */
2150 inregs.x.ax = 0x0000;
2151 int86 (0x33, &inregs, &outregs);
2152 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2153 }
2154
2155 if (have_mouse)
2156 {
2157 have_mouse = 1; /* enable mouse */
2158 mouse_visible = 0;
2159
2160 if (outregs.x.bx == 3)
2161 {
2162 mouse_button_count = 3;
2163 mouse_button_translate[0] = 0; /* Left */
2164 mouse_button_translate[1] = 2; /* Middle */
2165 mouse_button_translate[2] = 1; /* Right */
2166 }
2167 else
2168 {
2169 mouse_button_count = 2;
2170 mouse_button_translate[0] = 0;
2171 mouse_button_translate[1] = 1;
2172 }
2173 mouse_position_hook = &mouse_get_pos;
2174 mouse_init ();
2175 }
2176 }
2177
2178 first_time = 0;
2179 }
2180
2181 inregs.x.ax = 0x4400; /* Get IOCTL status. */
2182 inregs.x.bx = 0x00; /* 0 = stdin. */
2183 intdos (&inregs, &outregs);
2184 stdin_stat = outregs.h.dl;
2185
2186 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
2187 inregs.x.ax = 0x4401; /* Set IOCTL status */
2188 intdos (&inregs, &outregs);
2189 return !outregs.x.cflag;
2190 }
2191
2192 /* Restore status of standard input and Ctrl-C checking. */
2193 int
2194 dos_ttcooked ()
2195 {
2196 union REGS inregs, outregs;
2197
2198 setcbrk (break_stat);
2199 mouse_off ();
2200
2201 inregs.x.ax = 0x4401; /* Set IOCTL status. */
2202 inregs.x.bx = 0x00; /* 0 = stdin. */
2203 inregs.x.dx = stdin_stat;
2204 intdos (&inregs, &outregs);
2205 return !outregs.x.cflag;
2206 }
2207
2208 \f
2209 /* Run command as specified by ARGV in directory DIR.
2210 The command is run with input from TEMPIN, output to
2211 file TEMPOUT and stderr to TEMPERR. */
2212 int
2213 run_msdos_command (argv, dir, tempin, tempout, temperr)
2214 unsigned char **argv;
2215 Lisp_Object dir;
2216 int tempin, tempout, temperr;
2217 {
2218 char *saveargv1, *saveargv2, **envv;
2219 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
2220 int msshell, result = -1;
2221 int in, out, inbak, outbak, errbak;
2222 int x, y;
2223 Lisp_Object cmd;
2224
2225 /* Get current directory as MSDOS cwd is not per-process. */
2226 getwd (oldwd);
2227
2228 cmd = Ffile_name_nondirectory (build_string (argv[0]));
2229 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
2230 && !strcmp ("-c", argv[1]);
2231 if (msshell)
2232 {
2233 saveargv1 = argv[1];
2234 saveargv2 = argv[2];
2235 argv[1] = "/c";
2236 if (argv[2])
2237 {
2238 char *p = alloca (strlen (argv[2]) + 1);
2239
2240 strcpy (argv[2] = p, saveargv2);
2241 while (*p && isspace (*p))
2242 p++;
2243 while (*p && !isspace (*p))
2244 if (*p == '/')
2245 *p++ = '\\';
2246 else
2247 p++;
2248 }
2249 }
2250
2251 /* Build the environment array. */
2252 {
2253 extern Lisp_Object Vprocess_environment;
2254 Lisp_Object tmp, lst;
2255 int i, len;
2256
2257 lst = Vprocess_environment;
2258 len = XFASTINT (Flength (lst));
2259
2260 envv = alloca ((len + 1) * sizeof (char *));
2261 for (i = 0; i < len; i++)
2262 {
2263 tmp = Fcar (lst);
2264 lst = Fcdr (lst);
2265 CHECK_STRING (tmp, 0);
2266 envv[i] = alloca (XSTRING (tmp)->size + 1);
2267 strcpy (envv[i], XSTRING (tmp)->data);
2268 }
2269 envv[len] = (char *) 0;
2270 }
2271
2272 if (STRINGP (dir))
2273 chdir (XSTRING (dir)->data);
2274 inbak = dup (0);
2275 outbak = dup (1);
2276 errbak = dup (2);
2277 if (inbak < 0 || outbak < 0 || errbak < 0)
2278 goto done; /* Allocation might fail due to lack of descriptors. */
2279
2280 if (have_mouse > 0)
2281 mouse_get_xy (&x, &y);
2282
2283 dos_ttcooked (); /* do it here while 0 = stdin */
2284
2285 dup2 (tempin, 0);
2286 dup2 (tempout, 1);
2287 dup2 (temperr, 2);
2288
2289 result = spawnve (P_WAIT, argv[0], argv, envv);
2290
2291 dup2 (inbak, 0);
2292 dup2 (outbak, 1);
2293 dup2 (errbak, 2);
2294 close (inbak);
2295 close (outbak);
2296 close (errbak);
2297
2298 dos_ttraw ();
2299 if (have_mouse > 0)
2300 {
2301 mouse_init ();
2302 mouse_moveto (x, y);
2303 }
2304
2305 done:
2306 chdir (oldwd);
2307 if (msshell)
2308 {
2309 argv[1] = saveargv1;
2310 argv[2] = saveargv2;
2311 }
2312 return result;
2313 }
2314
2315 croak (badfunc)
2316 char *badfunc;
2317 {
2318 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
2319 reset_sys_modes ();
2320 exit (1);
2321 }
2322 \f
2323 /* ------------------------- Compatibility functions -------------------
2324 * gethostname
2325 * gettimeofday
2326 */
2327
2328 /*
2329 * Hostnames for a pc are not really funny,
2330 * but they are used in change log so we emulate the best we can.
2331 */
2332
2333 gethostname (p, size)
2334 char *p;
2335 int size;
2336 {
2337 char *q = egetenv ("HOSTNAME");
2338
2339 if (!q) q = "pc";
2340 strcpy (p, q);
2341 return 0;
2342 }
2343
2344 /* When time zones are set from Ms-Dos too many C-libraries are playing
2345 tricks with time values. We solve this by defining our own version
2346 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2347 once and after each call to `tzset' with TZ changed. That is
2348 accomplished by aliasing tzset to init_gettimeofday. */
2349
2350 static struct tm time_rec;
2351
2352 int
2353 gettimeofday (struct timeval *tp, struct timezone *tzp)
2354 {
2355 if (tp)
2356 {
2357 struct time t;
2358 struct tm tm;
2359
2360 gettime (&t);
2361 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
2362 {
2363 struct date d;
2364 getdate (&d);
2365 time_rec.tm_year = d.da_year - 1900;
2366 time_rec.tm_mon = d.da_mon - 1;
2367 time_rec.tm_mday = d.da_day;
2368 }
2369
2370 time_rec.tm_hour = t.ti_hour;
2371 time_rec.tm_min = t.ti_min;
2372 time_rec.tm_sec = t.ti_sec;
2373
2374 tm = time_rec;
2375 tm.tm_gmtoff = dos_timezone_offset;
2376
2377 tp->tv_sec = mktime (&tm); /* may modify tm */
2378 tp->tv_usec = t.ti_hund * (1000000 / 100);
2379 }
2380 /* Ignore tzp; it's obsolescent. */
2381 return 0;
2382 }
2383
2384
2385 /*
2386 * A list of unimplemented functions that we silently ignore.
2387 */
2388
2389 unsigned alarm (s) unsigned s; {}
2390 fork () { return 0; }
2391 int kill (x, y) int x, y; { return -1; }
2392 nice (p) int p; {}
2393 void volatile pause () {}
2394 request_sigio () {}
2395 setpgrp () {return 0; }
2396 setpriority (x,y,z) int x,y,z; { return 0; }
2397 sigsetmask (x) int x; { return 0; }
2398 unrequest_sigio () {}
2399
2400 #ifndef HAVE_SELECT
2401 #include "sysselect.h"
2402
2403 static struct time last_time = {120, 120, 120, 120};
2404 static int modeline_time_displayed = 0;
2405
2406 Lisp_Object Vdos_display_time;
2407
2408 static void
2409 check_timer (t)
2410 struct time *t;
2411 {
2412 int sec, min, hour, hund;
2413
2414 gettime (t);
2415 sec = t->ti_sec;
2416 hund = t->ti_hund;
2417 hour = t->ti_hour;
2418 min = t->ti_min;
2419
2420 /* Any chance of not getting here 24 hours or more since last time? */
2421 if (hour == last_time.ti_hour
2422 && min == last_time.ti_min
2423 && sec == last_time.ti_sec)
2424 return;
2425
2426 if (!NILP (Vdos_display_time))
2427 {
2428 int interval;
2429 Lisp_Object dti = XSYMBOL (Fintern_soft (build_string ("display-time-interval"), Qnil))->value;
2430 int delta_time = ((hour - last_time.ti_hour) * 3600
2431 + (min - last_time.ti_min) * 60
2432 + (sec - last_time.ti_sec));
2433
2434 /* Who knows what the user may put into `display-time-interval'? */
2435 if (!INTEGERP (dti) || (interval = XINT (dti)) <= 0)
2436 interval = 60;
2437
2438 /* When it's time to renew the display, fake a `wakeup' call. */
2439 if (!modeline_time_displayed /* first time */
2440 || delta_time >= interval /* or if we were busy for a long time */
2441 || interval == 1 /* and every `interval' seconds hence */
2442 || interval == 60 && sec == 0 /* (usual cases first) */
2443 || (hour * 3600 + min * 60 + sec) % interval == 0)
2444 call2 (intern ("display-time-filter"), Qnil,
2445 build_string ("Wake up!\n"));
2446
2447 modeline_time_displayed = 1;
2448 }
2449 else if (modeline_time_displayed)
2450 {
2451 modeline_time_displayed = 0;
2452 Fset (intern ("display-time-string"), build_string (""));
2453
2454 /* Force immediate redisplay of modelines. */
2455 update_mode_lines++;
2456 redisplay_preserve_echo_area ();
2457 }
2458
2459 last_time = *t;
2460 }
2461
2462 /* Only event queue is checked. */
2463 int
2464 sys_select (nfds, rfds, wfds, efds, timeout)
2465 int nfds;
2466 SELECT_TYPE *rfds, *wfds, *efds;
2467 EMACS_TIME *timeout;
2468 {
2469 int check_input;
2470 long timeoutval, clnow, cllast;
2471 struct time t;
2472
2473 check_input = 0;
2474 if (rfds)
2475 {
2476 check_input = FD_ISSET (0, rfds);
2477 FD_ZERO (rfds);
2478 }
2479 if (wfds)
2480 FD_ZERO (wfds);
2481 if (efds)
2482 FD_ZERO (efds);
2483
2484 if (nfds != 1)
2485 abort ();
2486
2487 /* If we are looking only for the terminal, with no timeout,
2488 just read it and wait -- that's more efficient. */
2489 if (!timeout)
2490 {
2491 do
2492 check_timer (&t); /* check timer even if some input is pending */
2493 while (!detect_input_pending ());
2494 }
2495 else
2496 {
2497 timeoutval = EMACS_SECS (*timeout) * 100 + EMACS_USECS (*timeout) / 10000;
2498 check_timer (&t);
2499 cllast = t.ti_sec * 100 + t.ti_hund;
2500
2501 while (!check_input || !detect_input_pending ())
2502 {
2503 check_timer (&t);
2504 clnow = t.ti_sec * 100 + t.ti_hund;
2505 if (clnow < cllast) /* time wrap */
2506 timeoutval -= clnow + 6000 - cllast;
2507 else
2508 timeoutval -= clnow - cllast;
2509 if (timeoutval <= 0) /* Stop on timer being cleared */
2510 return 0;
2511 cllast = clnow;
2512 }
2513 }
2514
2515 FD_SET (0, rfds);
2516 return 1;
2517 }
2518 #endif
2519
2520 /*
2521 * Define overlaid functions:
2522 *
2523 * chdir -> sys_chdir
2524 * tzset -> init_gettimeofday
2525 * abort -> dos_abort
2526 */
2527
2528 #ifdef chdir
2529 #undef chdir
2530 extern int chdir ();
2531
2532 int
2533 sys_chdir (path)
2534 const char* path;
2535 {
2536 int len = strlen (path);
2537 char *tmp = (char *)path;
2538
2539 if (*tmp && tmp[1] == ':')
2540 {
2541 if (getdisk () != tolower (tmp[0]) - 'a')
2542 setdisk (tolower (tmp[0]) - 'a');
2543 tmp += 2; /* strip drive: KFS 1995-07-06 */
2544 len -= 2;
2545 }
2546
2547 if (len > 1 && (tmp[len - 1] == '/'))
2548 {
2549 char *tmp1 = (char *) alloca (len + 1);
2550 strcpy (tmp1, tmp);
2551 tmp1[len - 1] = 0;
2552 tmp = tmp1;
2553 }
2554 return chdir (tmp);
2555 }
2556 #endif
2557
2558 #ifdef tzset
2559 #undef tzset
2560 extern void tzset (void);
2561
2562 void
2563 init_gettimeofday ()
2564 {
2565 time_t ltm, gtm;
2566 struct tm *lstm;
2567
2568 tzset ();
2569 ltm = gtm = time (NULL);
2570 ltm = mktime (lstm = localtime (&ltm));
2571 gtm = mktime (gmtime (&gtm));
2572 time_rec.tm_hour = 99; /* force gettimeofday to get date */
2573 time_rec.tm_isdst = lstm->tm_isdst;
2574 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
2575 }
2576 #endif
2577
2578 #ifdef abort
2579 #undef abort
2580 void
2581 dos_abort (file, line)
2582 char *file;
2583 int line;
2584 {
2585 char buffer1[200], buffer2[400];
2586 int i, j;
2587
2588 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
2589 for (i = j = 0; buffer1[i]; i++) {
2590 buffer2[j++] = buffer1[i];
2591 buffer2[j++] = 0x70;
2592 }
2593 dosmemput (buffer2, j, (int)ScreenPrimary);
2594 ScreenSetCursor (2, 0);
2595 abort ();
2596 }
2597 #else
2598 void
2599 abort ()
2600 {
2601 dos_ttcooked ();
2602 ScreenSetCursor (10, 0);
2603 cputs ("\r\n\nEmacs aborted!\r\n");
2604 exit (2);
2605 }
2606 #endif
2607
2608 syms_of_msdos ()
2609 {
2610 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
2611 staticpro (&recent_doskeys);
2612
2613 defsubr (&Srecent_doskeys);
2614
2615 DEFVAR_LISP ("dos-display-time", &Vdos_display_time,
2616 "*When non-nil, `display-time' is in effect on DOS systems.");
2617 Vdos_display_time = Qnil;
2618 }
2619
2620 #endif /* MSDOS */