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