]> code.delx.au - gnu-emacs/blob - src/msdos.c
(check_timer): get rid of the DOS-specific menubar clock
[gnu-emacs] / 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
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
780
781 \f
782 /* ----------------------- Keyboard control ----------------------
783 *
784 * Keymaps reflect the following keyboard layout:
785 *
786 * 0 1 2 3 4 5 6 7 8 9 10 11 12 BS
787 * TAB 15 16 17 18 19 20 21 22 23 24 25 26 (41)
788 * CLOK 30 31 32 33 34 35 36 37 38 39 40 (41) RET
789 * SH () 45 46 47 48 49 50 51 52 53 54 SHIFT
790 * SPACE
791 */
792
793 static int extended_kbd; /* 101 (102) keyboard present. */
794
795 struct dos_keyboard_map
796 {
797 char *unshifted;
798 char *shifted;
799 char *alt_gr;
800 };
801
802
803 static struct dos_keyboard_map us_keyboard = {
804 /* 0 1 2 3 4 5 */
805 /* 01234567890123456789012345678901234567890 12345678901234 */
806 "`1234567890-= qwertyuiop[] asdfghjkl;'\\ zxcvbnm,./ ",
807 /* 0123456789012345678901234567890123456789 012345678901234 */
808 "~!@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"| ZXCVBNM<>? ",
809 0 /* no Alt-Gr key */
810 };
811
812 static struct dos_keyboard_map fr_keyboard = {
813 /* 0 1 2 3 4 5 */
814 /* 012 3456789012345678901234567890123456789012345678901234 */
815 "ý&\82\",(-\8a_\80\85)= azertyuiop^$ qsdfghjklm\97* wxcvbnm;:! ",
816 /* 0123456789012345678901234567890123456789012345678901234 */
817 " 1234567890ø+ AZERTYUIOPù\9c QSDFGHJKLM%æ WXCVBN?./õ ",
818 /* 01234567 89012345678901234567890123456789012345678901234 */
819 " ~#{[|`\\^@]} Ï "
820 };
821
822 static struct dos_keyboard_map dk_keyboard = {
823 /* 0 1 2 3 4 5 */
824 /* 0123456789012345678901234567890123456789012345678901234 */
825 "«1234567890+| qwertyuiop\86~ asdfghjkl\91\9b' zxcvbnm,.- ",
826 /* 01 23456789012345678901234567890123456789012345678901234 */
827 "õ!\"#$%&/()=?` QWERTYUIOP\8f^ ASDFGHJKL\92\9d* ZXCVBNM;:_ ",
828 /* 0123456789012345678901234567890123456789012345678901234 */
829 " @\9c$ {[]} | "
830 };
831
832 static struct keyboard_layout_list
833 {
834 int country_code;
835 struct dos_keyboard_map *keyboard_map;
836 } keyboard_layout_list[] =
837 {
838 1, &us_keyboard,
839 33, &fr_keyboard,
840 45, &dk_keyboard
841 };
842
843 static struct dos_keyboard_map *keyboard;
844 static int keyboard_map_all;
845
846 int
847 dos_set_keyboard (code, always)
848 int code;
849 int always;
850 {
851 int i;
852
853 /* Initialize to US settings, for countries that don't have their own. */
854 keyboard = keyboard_layout_list[0].keyboard_map;
855 keyboard_map_all = always;
856 dos_keyboard_layout = 1;
857
858 for (i = 0; i < (sizeof (keyboard_layout_list)/sizeof (struct keyboard_layout_list)); i++)
859 if (code == keyboard_layout_list[i].country_code)
860 {
861 keyboard = keyboard_layout_list[i].keyboard_map;
862 keyboard_map_all = always;
863 dos_keyboard_layout = code;
864 return 1;
865 }
866 return 0;
867 }
868 \f
869 #define Ignore 0x0000
870 #define Normal 0x0000 /* normal key - alt changes scan-code */
871 #define FctKey 0x1000 /* func key if c == 0, else c */
872 #define Special 0x2000 /* func key even if c != 0 */
873 #define ModFct 0x3000 /* special if mod-keys, else 'c' */
874 #define Map 0x4000 /* alt scan-code, map to unshift/shift key */
875 #define KeyPad 0x5000 /* map to insert/kp-0 depending on c == 0xe0 */
876 #define Grey 0x6000 /* Grey keypad key */
877
878 #define Alt 0x0100 /* alt scan-code */
879 #define Ctrl 0x0200 /* ctrl scan-code */
880 #define Shift 0x0400 /* shift scan-code */
881
882 static struct
883 {
884 unsigned char char_code; /* normal code */
885 unsigned char meta_code; /* M- code */
886 unsigned char keypad_code; /* keypad code */
887 unsigned char editkey_code; /* edit key */
888 } keypad_translate_map[] = {
889 '0', '0', 0xb0, /* kp-0 */ 0x63, /* insert */
890 '1', '1', 0xb1, /* kp-1 */ 0x57, /* end */
891 '2', '2', 0xb2, /* kp-2 */ 0x54, /* down */
892 '3', '3', 0xb3, /* kp-3 */ 0x56, /* next */
893 '4', '4', 0xb4, /* kp-4 */ 0x51, /* left */
894 '5', '5', 0xb5, /* kp-5 */ 0xb5, /* kp-5 */
895 '6', '6', 0xb6, /* kp-6 */ 0x53, /* right */
896 '7', '7', 0xb7, /* kp-7 */ 0x50, /* home */
897 '8', '8', 0xb8, /* kp-8 */ 0x52, /* up */
898 '9', '9', 0xb9, /* kp-9 */ 0x55, /* prior */
899 '.', '-', 0xae, /* kp-decimal */ 0xff /* delete */
900 };
901
902 static struct
903 {
904 unsigned char char_code; /* normal code */
905 unsigned char keypad_code; /* keypad code */
906 } grey_key_translate_map[] = {
907 '/', 0xaf, /* kp-decimal */
908 '*', 0xaa, /* kp-multiply */
909 '-', 0xad, /* kp-subtract */
910 '+', 0xab, /* kp-add */
911 '\r', 0x8d /* kp-enter */
912 };
913
914 static unsigned short
915 ibmpc_translate_map[] =
916 {
917 /* --------------- 00 to 0f --------------- */
918 Normal | 0xff, /* Ctrl Break + Alt-NNN */
919 Alt | ModFct | 0x1b, /* Escape */
920 Normal | 1, /* '1' */
921 Normal | 2, /* '2' */
922 Normal | 3, /* '3' */
923 Normal | 4, /* '4' */
924 Normal | 5, /* '5' */
925 Normal | 6, /* '6' */
926 Normal | 7, /* '7' */
927 Normal | 8, /* '8' */
928 Normal | 9, /* '9' */
929 Normal | 10, /* '0' */
930 Normal | 11, /* '-' */
931 Normal | 12, /* '=' */
932 Special | 0x08, /* Backspace */
933 ModFct | 0x74, /* Tab/Backtab */
934
935 /* --------------- 10 to 1f --------------- */
936 Map | 15, /* 'q' */
937 Map | 16, /* 'w' */
938 Map | 17, /* 'e' */
939 Map | 18, /* 'r' */
940 Map | 19, /* 't' */
941 Map | 20, /* 'y' */
942 Map | 21, /* 'u' */
943 Map | 22, /* 'i' */
944 Map | 23, /* 'o' */
945 Map | 24, /* 'p' */
946 Map | 25, /* '[' */
947 Map | 26, /* ']' */
948 ModFct | 0x0d, /* Return */
949 Ignore, /* Ctrl */
950 Map | 30, /* 'a' */
951 Map | 31, /* 's' */
952
953 /* --------------- 20 to 2f --------------- */
954 Map | 32, /* 'd' */
955 Map | 33, /* 'f' */
956 Map | 34, /* 'g' */
957 Map | 35, /* 'h' */
958 Map | 36, /* 'j' */
959 Map | 37, /* 'k' */
960 Map | 38, /* 'l' */
961 Map | 39, /* ';' */
962 Map | 40, /* '\'' */
963 Map | 0, /* '`' */
964 Ignore, /* Left shift */
965 Map | 41, /* '\\' */
966 Map | 45, /* 'z' */
967 Map | 46, /* 'x' */
968 Map | 47, /* 'c' */
969 Map | 48, /* 'v' */
970
971 /* --------------- 30 to 3f --------------- */
972 Map | 49, /* 'b' */
973 Map | 50, /* 'n' */
974 Map | 51, /* 'm' */
975 Map | 52, /* ',' */
976 Map | 53, /* '.' */
977 Map | 54, /* '/' */
978 Ignore, /* Right shift */
979 Grey | 1, /* Grey * */
980 Ignore, /* Alt */
981 Normal | ' ', /* ' ' */
982 Ignore, /* Caps Lock */
983 FctKey | 0xbe, /* F1 */
984 FctKey | 0xbf, /* F2 */
985 FctKey | 0xc0, /* F3 */
986 FctKey | 0xc1, /* F4 */
987 FctKey | 0xc2, /* F5 */
988
989 /* --------------- 40 to 4f --------------- */
990 FctKey | 0xc3, /* F6 */
991 FctKey | 0xc4, /* F7 */
992 FctKey | 0xc5, /* F8 */
993 FctKey | 0xc6, /* F9 */
994 FctKey | 0xc7, /* F10 */
995 Ignore, /* Num Lock */
996 Ignore, /* Scroll Lock */
997 KeyPad | 7, /* Home */
998 KeyPad | 8, /* Up */
999 KeyPad | 9, /* Page Up */
1000 Grey | 2, /* Grey - */
1001 KeyPad | 4, /* Left */
1002 KeyPad | 5, /* Keypad 5 */
1003 KeyPad | 6, /* Right */
1004 Grey | 3, /* Grey + */
1005 KeyPad | 1, /* End */
1006
1007 /* --------------- 50 to 5f --------------- */
1008 KeyPad | 2, /* Down */
1009 KeyPad | 3, /* Page Down */
1010 KeyPad | 0, /* Insert */
1011 KeyPad | 10, /* Delete */
1012 Shift | FctKey | 0xbe, /* (Shift) F1 */
1013 Shift | FctKey | 0xbf, /* (Shift) F2 */
1014 Shift | FctKey | 0xc0, /* (Shift) F3 */
1015 Shift | FctKey | 0xc1, /* (Shift) F4 */
1016 Shift | FctKey | 0xc2, /* (Shift) F5 */
1017 Shift | FctKey | 0xc3, /* (Shift) F6 */
1018 Shift | FctKey | 0xc4, /* (Shift) F7 */
1019 Shift | FctKey | 0xc5, /* (Shift) F8 */
1020 Shift | FctKey | 0xc6, /* (Shift) F9 */
1021 Shift | FctKey | 0xc7, /* (Shift) F10 */
1022 Ctrl | FctKey | 0xbe, /* (Ctrl) F1 */
1023 Ctrl | FctKey | 0xbf, /* (Ctrl) F2 */
1024
1025 /* --------------- 60 to 6f --------------- */
1026 Ctrl | FctKey | 0xc0, /* (Ctrl) F3 */
1027 Ctrl | FctKey | 0xc1, /* (Ctrl) F4 */
1028 Ctrl | FctKey | 0xc2, /* (Ctrl) F5 */
1029 Ctrl | FctKey | 0xc3, /* (Ctrl) F6 */
1030 Ctrl | FctKey | 0xc4, /* (Ctrl) F7 */
1031 Ctrl | FctKey | 0xc5, /* (Ctrl) F8 */
1032 Ctrl | FctKey | 0xc6, /* (Ctrl) F9 */
1033 Ctrl | FctKey | 0xc7, /* (Ctrl) F10 */
1034 Alt | FctKey | 0xbe, /* (Alt) F1 */
1035 Alt | FctKey | 0xbf, /* (Alt) F2 */
1036 Alt | FctKey | 0xc0, /* (Alt) F3 */
1037 Alt | FctKey | 0xc1, /* (Alt) F4 */
1038 Alt | FctKey | 0xc2, /* (Alt) F5 */
1039 Alt | FctKey | 0xc3, /* (Alt) F6 */
1040 Alt | FctKey | 0xc4, /* (Alt) F7 */
1041 Alt | FctKey | 0xc5, /* (Alt) F8 */
1042
1043 /* --------------- 70 to 7f --------------- */
1044 Alt | FctKey | 0xc6, /* (Alt) F9 */
1045 Alt | FctKey | 0xc7, /* (Alt) F10 */
1046 Ctrl | FctKey | 0x6d, /* (Ctrl) Sys Rq */
1047 Ctrl | KeyPad | 4, /* (Ctrl) Left */
1048 Ctrl | KeyPad | 6, /* (Ctrl) Right */
1049 Ctrl | KeyPad | 1, /* (Ctrl) End */
1050 Ctrl | KeyPad | 3, /* (Ctrl) Page Down */
1051 Ctrl | KeyPad | 7, /* (Ctrl) Home */
1052 Alt | Map | 1, /* '1' */
1053 Alt | Map | 2, /* '2' */
1054 Alt | Map | 3, /* '3' */
1055 Alt | Map | 4, /* '4' */
1056 Alt | Map | 5, /* '5' */
1057 Alt | Map | 6, /* '6' */
1058 Alt | Map | 7, /* '7' */
1059 Alt | Map | 8, /* '8' */
1060
1061 /* --------------- 80 to 8f --------------- */
1062 Alt | Map | 9, /* '9' */
1063 Alt | Map | 10, /* '0' */
1064 Alt | Map | 11, /* '-' */
1065 Alt | Map | 12, /* '=' */
1066 Ctrl | KeyPad | 9, /* (Ctrl) Page Up */
1067 FctKey | 0xc8, /* F11 */
1068 FctKey | 0xc9, /* F12 */
1069 Shift | FctKey | 0xc8, /* (Shift) F11 */
1070 Shift | FctKey | 0xc9, /* (Shift) F12 */
1071 Ctrl | FctKey | 0xc8, /* (Ctrl) F11 */
1072 Ctrl | FctKey | 0xc9, /* (Ctrl) F12 */
1073 Alt | FctKey | 0xc8, /* (Alt) F11 */
1074 Alt | FctKey | 0xc9, /* (Alt) F12 */
1075 Ctrl | KeyPad | 8, /* (Ctrl) Up */
1076 Ctrl | Grey | 2, /* (Ctrl) Grey - */
1077 Ctrl | KeyPad | 5, /* (Ctrl) Keypad 5 */
1078
1079 /* --------------- 90 to 9f --------------- */
1080 Ctrl | Grey | 3, /* (Ctrl) Grey + */
1081 Ctrl | KeyPad | 2, /* (Ctrl) Down */
1082 Ctrl | KeyPad | 0, /* (Ctrl) Insert */
1083 Ctrl | KeyPad | 10, /* (Ctrl) Delete */
1084 Ctrl | FctKey | 0x09, /* (Ctrl) Tab */
1085 Ctrl | Grey | 0, /* (Ctrl) Grey / */
1086 Ctrl | Grey | 1, /* (Ctrl) Grey * */
1087 Alt | FctKey | 0x50, /* (Alt) Home */
1088 Alt | FctKey | 0x52, /* (Alt) Up */
1089 Alt | FctKey | 0x55, /* (Alt) Page Up */
1090 Ignore, /* NO KEY */
1091 Alt | FctKey | 0x51, /* (Alt) Left */
1092 Ignore, /* NO KEY */
1093 Alt | FctKey | 0x53, /* (Alt) Right */
1094 Ignore, /* NO KEY */
1095 Alt | FctKey | 0x57, /* (Alt) End */
1096
1097 /* --------------- a0 to af --------------- */
1098 Alt | KeyPad | 2, /* (Alt) Down */
1099 Alt | KeyPad | 3, /* (Alt) Page Down */
1100 Alt | KeyPad | 0, /* (Alt) Insert */
1101 Alt | KeyPad | 10, /* (Alt) Delete */
1102 Alt | Grey | 0, /* (Alt) Grey / */
1103 Alt | FctKey | 0x09, /* (Alt) Tab */
1104 Alt | Grey | 4 /* (Alt) Keypad Enter */
1105 };
1106 \f
1107 /* These bit-positions corresponds to values returned by BIOS */
1108 #define SHIFT_P 0x0003 /* two bits! */
1109 #define CTRL_P 0x0004
1110 #define ALT_P 0x0008
1111 #define SCRLOCK_P 0x0010
1112 #define NUMLOCK_P 0x0020
1113 #define CAPSLOCK_P 0x0040
1114 #define ALT_GR_P 0x0800
1115 #define SUPER_P 0x4000 /* pseudo */
1116 #define HYPER_P 0x8000 /* pseudo */
1117
1118 static int
1119 dos_get_modifiers (keymask)
1120 int *keymask;
1121 {
1122 union REGS regs;
1123 int mask;
1124 int modifiers = 0;
1125
1126 /* Calculate modifier bits */
1127 regs.h.ah = extended_kbd ? 0x12 : 0x02;
1128 int86 (0x16, &regs, &regs);
1129
1130 if (!extended_kbd)
1131 {
1132 mask = regs.h.al & (SHIFT_P | CTRL_P | ALT_P |
1133 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1134 }
1135 else
1136 {
1137 mask = regs.h.al & (SHIFT_P |
1138 SCRLOCK_P | NUMLOCK_P | CAPSLOCK_P);
1139
1140 /* Do not break international keyboard support. */
1141 /* When Keyb.Com is loaded, the right Alt key is */
1142 /* used for accessing characters like { and } */
1143 if (regs.h.ah & 2) /* Left ALT pressed ? */
1144 mask |= ALT_P;
1145
1146 if ((regs.h.ah & 8) != 0) /* Right ALT pressed ? */
1147 {
1148 mask |= ALT_GR_P;
1149 if (dos_hyper_key == 1)
1150 {
1151 mask |= HYPER_P;
1152 modifiers |= hyper_modifier;
1153 }
1154 else if (dos_super_key == 1)
1155 {
1156 mask |= SUPER_P;
1157 modifiers |= super_modifier;
1158 }
1159 }
1160
1161 if (regs.h.ah & 1) /* Left CTRL pressed
1162 mask |= CTRL_P;
1163
1164 if (regs.h.ah & 4) /* Right CTRL pressed ? */
1165 {
1166 if (dos_hyper_key == 2)
1167 {
1168 mask |= HYPER_P;
1169 modifiers |= hyper_modifier;
1170 }
1171 else if (dos_super_key == 2)
1172 {
1173 mask |= SUPER_P;
1174 modifiers |= super_modifier;
1175 }
1176 else
1177 mask |= CTRL_P;
1178 }
1179 }
1180
1181 if (mask & SHIFT_P)
1182 modifiers |= shift_modifier;
1183 if (mask & CTRL_P)
1184 modifiers |= ctrl_modifier;
1185 if (mask & ALT_P)
1186 modifiers |= meta_modifier;
1187
1188 if (keymask)
1189 *keymask = mask;
1190 return modifiers;
1191 }
1192
1193 #define NUM_RECENT_DOSKEYS (100)
1194 int recent_doskeys_index; /* Index for storing next element into recent_doskeys */
1195 int total_doskeys; /* Total number of elements stored into recent_doskeys */
1196 Lisp_Object recent_doskeys; /* A vector, holding the last 100 keystrokes */
1197
1198 DEFUN ("recent-doskeys", Frecent_doskeys, Srecent_doskeys, 0, 0, 0,
1199 "Return vector of last 100 keyboard input values seen in dos_rawgetc.\n\
1200 Each input key receives two values in this vector: first the ASCII code,\n\
1201 and then the scan code.")
1202 ()
1203 {
1204 Lisp_Object *keys = XVECTOR (recent_doskeys)->contents;
1205 Lisp_Object val;
1206
1207 if (total_doskeys < NUM_RECENT_DOSKEYS)
1208 return Fvector (total_doskeys, keys);
1209 else
1210 {
1211 val = Fvector (NUM_RECENT_DOSKEYS, keys);
1212 bcopy (keys + recent_doskeys_index,
1213 XVECTOR (val)->contents,
1214 (NUM_RECENT_DOSKEYS - recent_doskeys_index) * sizeof (Lisp_Object));
1215 bcopy (keys,
1216 XVECTOR (val)->contents + NUM_RECENT_DOSKEYS - recent_doskeys_index,
1217 recent_doskeys_index * sizeof (Lisp_Object));
1218 return val;
1219 }
1220 }
1221
1222 /* Get a char from keyboard. Function keys are put into the event queue. */
1223 static int
1224 dos_rawgetc ()
1225 {
1226 struct input_event event;
1227 union REGS regs;
1228
1229 #ifndef HAVE_X_WINDOWS
1230 SCREEN_SET_CURSOR ();
1231 if (!mouse_visible) mouse_on ();
1232 #endif
1233
1234 /* The following condition is equivalent to `kbhit ()', except that
1235 it uses the bios to do its job. This pleases DESQview/X. */
1236 while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
1237 int86 (0x16, &regs, &regs),
1238 (regs.x.flags & 0x40) == 0)
1239 {
1240 union REGS regs;
1241 register unsigned char c;
1242 int sc, code, mask, kp_mode;
1243 int modifiers;
1244
1245 regs.h.ah = extended_kbd ? 0x10 : 0x00;
1246 int86 (0x16, &regs, &regs);
1247 c = regs.h.al;
1248 sc = regs.h.ah;
1249
1250 total_doskeys += 2;
1251 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1252 = make_number (c);
1253 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1254 recent_doskeys_index = 0;
1255 XVECTOR (recent_doskeys)->contents[recent_doskeys_index++]
1256 = make_number (sc);
1257 if (recent_doskeys_index == NUM_RECENT_DOSKEYS)
1258 recent_doskeys_index = 0;
1259
1260 modifiers = dos_get_modifiers (&mask);
1261
1262 #ifndef HAVE_X_WINDOWS
1263 if (!NILP (Vdos_display_scancodes))
1264 {
1265 char buf[10];
1266 sprintf (buf, "%02x:%02x*%04x",
1267 (unsigned) (sc&0xff), (unsigned) c, mask);
1268 dos_direct_output (screen_size_Y - 2, screen_size_X - 12, buf, 10);
1269 }
1270 #endif
1271
1272 if (sc == 0xe0)
1273 {
1274 switch (c)
1275 {
1276 case 10: /* Ctrl Grey Enter */
1277 code = Ctrl | Grey | 4;
1278 break;
1279 case 13: /* Grey Enter */
1280 code = Grey | 4;
1281 break;
1282 case '/': /* Grey / */
1283 code = Grey | 0;
1284 break;
1285 default:
1286 continue;
1287 };
1288 c = 0;
1289 }
1290 else
1291 {
1292 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
1293 continue;
1294 if ((code = ibmpc_translate_map[sc]) == Ignore)
1295 continue;
1296 }
1297
1298 if (c == 0)
1299 {
1300 if (code & Alt)
1301 modifiers |= meta_modifier;
1302 if (code & Ctrl)
1303 modifiers |= ctrl_modifier;
1304 if (code & Shift)
1305 modifiers |= shift_modifier;
1306 }
1307
1308 switch (code & 0xf000)
1309 {
1310 case ModFct:
1311 if (c && !(mask & (SHIFT_P | ALT_P | CTRL_P | HYPER_P | SUPER_P)))
1312 return c;
1313 c = 0; /* Special */
1314
1315 case FctKey:
1316 if (c != 0)
1317 return c;
1318
1319 case Special:
1320 code |= 0xff00;
1321 break;
1322
1323 case Normal:
1324 if (sc == 0)
1325 {
1326 if (c == 0) /* ctrl-break */
1327 continue;
1328 return c; /* ALT-nnn */
1329 }
1330 if (!keyboard_map_all)
1331 {
1332 if (c != ' ')
1333 return c;
1334 code = c;
1335 break;
1336 }
1337
1338 case Map:
1339 if (c && !(mask & ALT_P) && !((mask & SHIFT_P) && (mask & CTRL_P)))
1340 if (!keyboard_map_all)
1341 return c;
1342
1343 code &= 0xff;
1344 if (mask & ALT_P && code <= 10 && code > 0 && dos_keypad_mode & 0x200)
1345 mask |= SHIFT_P; /* ALT-1 => M-! etc. */
1346
1347 if (mask & SHIFT_P)
1348 {
1349 code = keyboard->shifted[code];
1350 mask -= SHIFT_P;
1351 modifiers &= ~shift_modifier;
1352 }
1353 else
1354 if ((mask & ALT_GR_P) && keyboard->alt_gr && keyboard->alt_gr[code] != ' ')
1355 code = keyboard->alt_gr[code];
1356 else
1357 code = keyboard->unshifted[code];
1358 break;
1359
1360 case KeyPad:
1361 code &= 0xff;
1362 if (c == 0xe0) /* edit key */
1363 kp_mode = 3;
1364 else
1365 if ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) /* numlock on */
1366 kp_mode = dos_keypad_mode & 0x03;
1367 else
1368 kp_mode = (dos_keypad_mode >> 4) & 0x03;
1369
1370 switch (kp_mode)
1371 {
1372 case 0:
1373 if (code == 10 && dos_decimal_point)
1374 return dos_decimal_point;
1375 return keypad_translate_map[code].char_code;
1376
1377 case 1:
1378 code = 0xff00 | keypad_translate_map[code].keypad_code;
1379 break;
1380
1381 case 2:
1382 code = keypad_translate_map[code].meta_code;
1383 modifiers = meta_modifier;
1384 break;
1385
1386 case 3:
1387 code = 0xff00 | keypad_translate_map[code].editkey_code;
1388 break;
1389 }
1390 break;
1391
1392 case Grey:
1393 code &= 0xff;
1394 kp_mode = ((mask & (NUMLOCK_P|CTRL_P|SHIFT_P|ALT_P)) == NUMLOCK_P) ? 0x04 : 0x40;
1395 if (dos_keypad_mode & kp_mode)
1396 code = 0xff00 | grey_key_translate_map[code].keypad_code;
1397 else
1398 code = grey_key_translate_map[code].char_code;
1399 break;
1400 }
1401
1402 make_event:
1403 if (code == 0)
1404 continue;
1405
1406 if (code >= 0x100)
1407 event.kind = non_ascii_keystroke;
1408 else
1409 event.kind = ascii_keystroke;
1410 event.code = code;
1411 event.modifiers = modifiers;
1412 XSETFRAME (event.frame_or_window, selected_frame);
1413 event.timestamp = event_timestamp ();
1414 kbd_buffer_store_event (&event);
1415 }
1416
1417 if (have_mouse > 0)
1418 {
1419 int but, press, x, y, ok;
1420
1421 /* Check for mouse movement *before* buttons. */
1422 mouse_check_moved ();
1423
1424 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
1425 for (press = 0; press < 2; press++)
1426 {
1427 if (press)
1428 ok = mouse_pressed (but, &x, &y);
1429 else
1430 ok = mouse_released (but, &x, &y);
1431 if (ok)
1432 {
1433 event.kind = mouse_click;
1434 event.code = but;
1435 event.modifiers = dos_get_modifiers (0)
1436 | (press ? down_modifier : up_modifier);
1437 event.x = x;
1438 event.y = y;
1439 XSETFRAME (event.frame_or_window, selected_frame);
1440 event.timestamp = event_timestamp ();
1441 kbd_buffer_store_event (&event);
1442 }
1443 }
1444 }
1445
1446 return -1;
1447 }
1448
1449 static int prev_get_char = -1;
1450
1451 /* Return 1 if a key is ready to be read without suspending execution. */
1452 dos_keysns ()
1453 {
1454 if (prev_get_char != -1)
1455 return 1;
1456 else
1457 return ((prev_get_char = dos_rawgetc ()) != -1);
1458 }
1459
1460 /* Read a key. Return -1 if no key is ready. */
1461 dos_keyread ()
1462 {
1463 if (prev_get_char != -1)
1464 {
1465 int c = prev_get_char;
1466 prev_get_char = -1;
1467 return c;
1468 }
1469 else
1470 return dos_rawgetc ();
1471 }
1472 \f
1473 #ifndef HAVE_X_WINDOWS
1474 /* See xterm.c for more info. */
1475 void
1476 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1477 FRAME_PTR f;
1478 register int pix_x, pix_y;
1479 register int *x, *y;
1480 void /* XRectangle */ *bounds;
1481 int noclip;
1482 {
1483 if (bounds) abort ();
1484
1485 /* Ignore clipping. */
1486
1487 *x = pix_x;
1488 *y = pix_y;
1489 }
1490
1491 void
1492 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1493 FRAME_PTR f;
1494 register int x, y;
1495 register int *pix_x, *pix_y;
1496 {
1497 *pix_x = x;
1498 *pix_y = y;
1499 }
1500 \f
1501 /* Simulation of X's menus. Nothing too fancy here -- just make it work
1502 for now.
1503
1504 Actually, I don't know the meaning of all the parameters of the functions
1505 here -- I only know how they are called by xmenu.c. I could of course
1506 grab the nearest Xlib manual (down the hall, second-to-last door on the
1507 left), but I don't think it's worth the effort. */
1508
1509 static XMenu *
1510 IT_menu_create ()
1511 {
1512 XMenu *menu;
1513
1514 menu = (XMenu *) xmalloc (sizeof (XMenu));
1515 menu->allocated = menu->count = menu->panecount = menu->width = 0;
1516 return menu;
1517 }
1518
1519 /* Allocate some (more) memory for MENU ensuring that there is room for one
1520 for item. */
1521
1522 static void
1523 IT_menu_make_room (XMenu *menu)
1524 {
1525 if (menu->allocated == 0)
1526 {
1527 int count = menu->allocated = 10;
1528 menu->text = (char **) xmalloc (count * sizeof (char *));
1529 menu->submenu = (XMenu **) xmalloc (count * sizeof (XMenu *));
1530 menu->panenumber = (int *) xmalloc (count * sizeof (int));
1531 }
1532 else if (menu->allocated == menu->count)
1533 {
1534 int count = menu->allocated = menu->allocated + 10;
1535 menu->text
1536 = (char **) xrealloc (menu->text, count * sizeof (char *));
1537 menu->submenu
1538 = (XMenu **) xrealloc (menu->submenu, count * sizeof (XMenu *));
1539 menu->panenumber
1540 = (int *) xrealloc (menu->panenumber, count * sizeof (int));
1541 }
1542 }
1543
1544 /* Search the given menu structure for a given pane number. */
1545
1546 static XMenu *
1547 IT_menu_search_pane (XMenu *menu, int pane)
1548 {
1549 int i;
1550 XMenu *try;
1551
1552 for (i = 0; i < menu->count; i++)
1553 if (menu->submenu[i])
1554 {
1555 if (pane == menu->panenumber[i])
1556 return menu->submenu[i];
1557 if ((try = IT_menu_search_pane (menu->submenu[i], pane)))
1558 return try;
1559 }
1560 return (XMenu *) 0;
1561 }
1562
1563 /* Determine how much screen space a given menu needs. */
1564
1565 static void
1566 IT_menu_calc_size (XMenu *menu, int *width, int *height)
1567 {
1568 int i, h2, w2, maxsubwidth, maxheight;
1569
1570 maxsubwidth = 0;
1571 maxheight = menu->count;
1572 for (i = 0; i < menu->count; i++)
1573 {
1574 if (menu->submenu[i])
1575 {
1576 IT_menu_calc_size (menu->submenu[i], &w2, &h2);
1577 if (w2 > maxsubwidth) maxsubwidth = w2;
1578 if (i + h2 > maxheight) maxheight = i + h2;
1579 }
1580 }
1581 *width = menu->width + maxsubwidth;
1582 *height = maxheight;
1583 }
1584
1585 /* Display MENU at (X,Y) using FACES. */
1586
1587 static void
1588 IT_menu_display (XMenu *menu, int y, int x, int *faces)
1589 {
1590 int i, j, face, width;
1591 GLYPH *text, *p;
1592 char *q;
1593 int mx, my;
1594 int enabled, mousehere;
1595 int row, col;
1596
1597 width = menu->width;
1598 text = (GLYPH *) xmalloc ((width + 2) * sizeof (GLYPH));
1599 ScreenGetCursor (&row, &col);
1600 mouse_get_xy (&mx, &my);
1601 IT_update_begin ();
1602 for (i = 0; i < menu->count; i++)
1603 {
1604 IT_cursor_to (y + i, x);
1605 enabled
1606 = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
1607 mousehere = (y + i == my && x <= mx && mx < x + width + 2);
1608 face = faces[enabled + mousehere * 2];
1609 p = text;
1610 *p++ = FAST_MAKE_GLYPH (' ', face);
1611 for (j = 0, q = menu->text[i]; *q; j++)
1612 *p++ = FAST_MAKE_GLYPH (*q++, face);
1613 for (; j < width; j++)
1614 *p++ = FAST_MAKE_GLYPH (' ', face);
1615 *p++ = FAST_MAKE_GLYPH (menu->submenu[i] ? 16 : ' ', face);
1616 IT_write_glyphs (text, width + 2);
1617 }
1618 IT_update_end ();
1619 IT_cursor_to (row, col);
1620 xfree (text);
1621 }
1622
1623 /* --------------------------- X Menu emulation ---------------------- */
1624
1625 /* Create a brand new menu structure. */
1626
1627 XMenu *
1628 XMenuCreate (Display *foo1, Window foo2, char *foo3)
1629 {
1630 return IT_menu_create ();
1631 }
1632
1633 /* Create a new pane and place it on the outer-most level. It is not
1634 clear that it should be placed out there, but I don't know what else
1635 to do. */
1636
1637 int
1638 XMenuAddPane (Display *foo, XMenu *menu, char *txt, int enable)
1639 {
1640 int len;
1641
1642 if (!enable)
1643 abort ();
1644
1645 IT_menu_make_room (menu);
1646 menu->submenu[menu->count] = IT_menu_create ();
1647 menu->text[menu->count] = txt;
1648 menu->panenumber[menu->count] = ++menu->panecount;
1649 menu->count++;
1650 if ((len = strlen (txt)) > menu->width)
1651 menu->width = len;
1652 return menu->panecount;
1653 }
1654
1655 /* Create a new item in a menu pane. */
1656
1657 int
1658 XMenuAddSelection (Display *bar, XMenu *menu, int pane,
1659 int foo, char *txt, int enable)
1660 {
1661 int len;
1662
1663 if (pane)
1664 if (!(menu = IT_menu_search_pane (menu, pane)))
1665 return XM_FAILURE;
1666 IT_menu_make_room (menu);
1667 menu->submenu[menu->count] = (XMenu *) 0;
1668 menu->text[menu->count] = txt;
1669 menu->panenumber[menu->count] = enable;
1670 menu->count++;
1671 if ((len = strlen (txt)) > menu->width)
1672 menu->width = len;
1673 return XM_SUCCESS;
1674 }
1675
1676 /* Decide where the menu would be placed if requested at (X,Y). */
1677
1678 void
1679 XMenuLocate (Display *foo0, XMenu *menu, int foo1, int foo2, int x, int y,
1680 int *ulx, int *uly, int *width, int *height)
1681 {
1682 IT_menu_calc_size (menu, width, height);
1683 *ulx = x + 1;
1684 *uly = y;
1685 *width += 2;
1686 }
1687
1688 struct IT_menu_state
1689 {
1690 void *screen_behind;
1691 XMenu *menu;
1692 int pane;
1693 int x, y;
1694 };
1695
1696
1697 /* Display menu, wait for user's response, and return that response. */
1698
1699 int
1700 XMenuActivate (Display *foo, XMenu *menu, int *pane, int *selidx,
1701 int x0, int y0, unsigned ButtonMask, char **txt)
1702 {
1703 struct IT_menu_state *state;
1704 int statecount;
1705 int x, y, i, b;
1706 int screensize;
1707 int faces[4], selectface;
1708 int leave, result, onepane;
1709
1710 /* Just in case we got here without a mouse present... */
1711 if (have_mouse <= 0)
1712 return XM_IA_SELECT;
1713
1714 state = alloca (menu->panecount * sizeof (struct IT_menu_state));
1715 screensize = screen_size * 2;
1716 faces[0]
1717 = compute_glyph_face (&the_only_frame,
1718 face_name_id_number
1719 (&the_only_frame,
1720 intern ("msdos-menu-passive-face")),
1721 0);
1722 faces[1]
1723 = compute_glyph_face (&the_only_frame,
1724 face_name_id_number
1725 (&the_only_frame,
1726 intern ("msdos-menu-active-face")),
1727 0);
1728 selectface
1729 = face_name_id_number (&the_only_frame, intern ("msdos-menu-select-face"));
1730 faces[2] = compute_glyph_face (&the_only_frame, selectface, faces[0]);
1731 faces[3] = compute_glyph_face (&the_only_frame, selectface, faces[1]);
1732
1733 statecount = 1;
1734 state[0].menu = menu;
1735 mouse_off ();
1736 ScreenRetrieve (state[0].screen_behind = xmalloc (screensize));
1737
1738 IT_menu_display (menu, y0 - 1, x0 - 1, faces); /* display the menu title */
1739 if ((onepane = menu->count == 1 && menu->submenu[0]))
1740 {
1741 menu->width = menu->submenu[0]->width;
1742 state[0].menu = menu->submenu[0];
1743 }
1744 else
1745 {
1746 state[0].menu = menu;
1747 }
1748 state[0].x = x0 - 1;
1749 state[0].y = y0;
1750 state[0].pane = onepane;
1751
1752 mouse_last_x = -1; /* A hack that forces display. */
1753 leave = 0;
1754 while (!leave)
1755 {
1756 if (!mouse_visible) mouse_on ();
1757 mouse_check_moved ();
1758 if (selected_frame->mouse_moved)
1759 {
1760 selected_frame->mouse_moved = 0;
1761 result = XM_IA_SELECT;
1762 mouse_get_xy (&x, &y);
1763 for (i = 0; i < statecount; i++)
1764 if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
1765 {
1766 int dy = y - state[i].y;
1767 if (0 <= dy && dy < state[i].menu->count)
1768 {
1769 if (!state[i].menu->submenu[dy])
1770 if (state[i].menu->panenumber[dy])
1771 result = XM_SUCCESS;
1772 else
1773 result = XM_IA_SELECT;
1774 *pane = state[i].pane - 1;
1775 *selidx = dy;
1776 /* We hit some part of a menu, so drop extra menues that
1777 have been opened. That does not include an open and
1778 active submenu. */
1779 if (i != statecount - 2
1780 || state[i].menu->submenu[dy] != state[i+1].menu)
1781 while (i != statecount - 1)
1782 {
1783 statecount--;
1784 mouse_off ();
1785 ScreenUpdate (state[statecount].screen_behind);
1786 xfree (state[statecount].screen_behind);
1787 }
1788 if (i == statecount - 1 && state[i].menu->submenu[dy])
1789 {
1790 IT_menu_display (state[i].menu,
1791 state[i].y,
1792 state[i].x,
1793 faces);
1794 state[statecount].menu = state[i].menu->submenu[dy];
1795 state[statecount].pane = state[i].menu->panenumber[dy];
1796 mouse_off ();
1797 ScreenRetrieve (state[statecount].screen_behind
1798 = xmalloc (screensize));
1799 state[statecount].x
1800 = state[i].x + state[i].menu->width + 2;
1801 state[statecount].y = y;
1802 statecount++;
1803 }
1804 }
1805 }
1806 IT_menu_display (state[statecount - 1].menu,
1807 state[statecount - 1].y,
1808 state[statecount - 1].x,
1809 faces);
1810 }
1811 for (b = 0; b < mouse_button_count; b++)
1812 {
1813 (void) mouse_pressed (b, &x, &y);
1814 if (mouse_released (b, &x, &y))
1815 leave = 1;
1816 }
1817 }
1818
1819 mouse_off ();
1820 ScreenUpdate (state[0].screen_behind);
1821 while (statecount--)
1822 xfree (state[statecount].screen_behind);
1823 return result;
1824 }
1825
1826 /* Dispose of a menu. */
1827
1828 void
1829 XMenuDestroy (Display *foo, XMenu *menu)
1830 {
1831 int i;
1832 if (menu->allocated)
1833 {
1834 for (i = 0; i < menu->count; i++)
1835 if (menu->submenu[i])
1836 XMenuDestroy (foo, menu->submenu[i]);
1837 xfree (menu->text);
1838 xfree (menu->submenu);
1839 xfree (menu->panenumber);
1840 }
1841 xfree (menu);
1842 }
1843
1844 int
1845 x_pixel_width (struct frame *f)
1846 {
1847 return FRAME_WIDTH (f);
1848 }
1849
1850 int
1851 x_pixel_height (struct frame *f)
1852 {
1853 return FRAME_HEIGHT (f);
1854 }
1855 #endif /* !HAVE_X_WINDOWS */
1856
1857
1858 /* ----------------------- DOS / UNIX conversion --------------------- */
1859
1860 /* Destructively turn backslashes into slashes. */
1861
1862 void
1863 dostounix_filename (p)
1864 register char *p;
1865 {
1866 while (*p)
1867 {
1868 if (*p == '\\')
1869 *p = '/';
1870 p++;
1871 }
1872 }
1873
1874 /* Destructively turn slashes into backslashes. */
1875
1876 void
1877 unixtodos_filename (p)
1878 register char *p;
1879 {
1880 while (*p)
1881 {
1882 if (*p == '/')
1883 *p = '\\';
1884 p++;
1885 }
1886 }
1887
1888 /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
1889
1890 int
1891 getdefdir (drive, dst)
1892 int drive;
1893 char *dst;
1894 {
1895 union REGS regs;
1896
1897 *dst++ = '/';
1898 regs.h.dl = drive;
1899 regs.x.si = (int) dst;
1900 regs.h.ah = 0x47;
1901 intdos (&regs, &regs);
1902 return !regs.x.cflag;
1903 }
1904
1905 /* Remove all CR's that are followed by a LF. */
1906
1907 int
1908 crlf_to_lf (n, buf)
1909 register int n;
1910 register unsigned char *buf;
1911 {
1912 unsigned char *np = buf;
1913 unsigned char *startp = buf;
1914 unsigned char *endp = buf + n;
1915 unsigned char c;
1916
1917 if (n == 0)
1918 return n;
1919 while (buf < endp - 1)
1920 {
1921 if (*buf == 0x0d)
1922 {
1923 if (*(++buf) != 0x0a)
1924 *np++ = 0x0d;
1925 }
1926 else
1927 *np++ = *buf++;
1928 }
1929 if (buf < endp)
1930 *np++ = *buf++;
1931 return np - startp;
1932 }
1933 \f
1934 /* The Emacs root directory as determined by init_environment. */
1935
1936 static char emacsroot[MAXPATHLEN];
1937
1938 char *
1939 rootrelativepath (rel)
1940 char *rel;
1941 {
1942 static char result[MAXPATHLEN + 10];
1943
1944 strcpy (result, emacsroot);
1945 strcat (result, "/");
1946 strcat (result, rel);
1947 return result;
1948 }
1949
1950 /* Define a lot of environment variables if not already defined. Don't
1951 remove anything unless you know what you're doing -- lots of code will
1952 break if one or more of these are missing. */
1953
1954 void
1955 init_environment (argc, argv, skip_args)
1956 int argc;
1957 char **argv;
1958 int skip_args;
1959 {
1960 char *s, *t, *root;
1961 int len;
1962
1963 /* Find our root from argv[0]. Assuming argv[0] is, say,
1964 "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
1965 root = alloca (MAXPATHLEN + 20);
1966 _fixpath (argv[0], root);
1967 strlwr (root);
1968 len = strlen (root);
1969 while (len > 0 && root[len] != '/' && root[len] != ':')
1970 len--;
1971 root[len] = '\0';
1972 if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
1973 root[len - 4] = '\0';
1974 else
1975 strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
1976 len = strlen (root);
1977 strcpy (emacsroot, root);
1978
1979 /* We default HOME to our root. */
1980 setenv ("HOME", root, 0);
1981
1982 /* We default EMACSPATH to root + "/bin". */
1983 strcpy (root + len, "/bin");
1984 setenv ("EMACSPATH", root, 0);
1985
1986 /* I don't expect anybody to ever use other terminals so the internal
1987 terminal is the default. */
1988 setenv ("TERM", "internal", 0);
1989
1990 #ifdef HAVE_X_WINDOWS
1991 /* Emacs expects DISPLAY to be set. */
1992 setenv ("DISPLAY", "unix:0.0", 0);
1993 #endif
1994
1995 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
1996 downcase it and mirror the backslashes. */
1997 s = getenv ("COMSPEC");
1998 if (!s) s = "c:/command.com";
1999 t = alloca (strlen (s) + 1);
2000 strcpy (t, s);
2001 strlwr (t);
2002 dostounix_filename (t);
2003 setenv ("SHELL", t, 0);
2004
2005 /* PATH is also downcased and backslashes mirrored. */
2006 s = getenv ("PATH");
2007 if (!s) s = "";
2008 t = alloca (strlen (s) + 3);
2009 /* Current directory is always considered part of MsDos's path but it is
2010 not normally mentioned. Now it is. */
2011 strcat (strcpy (t, ".;"), s);
2012 strlwr (t);
2013 dostounix_filename (t); /* Not a single file name, but this should work. */
2014 setenv ("PATH", t, 1);
2015
2016 /* In some sense all dos users have root privileges, so... */
2017 setenv ("USER", "root", 0);
2018 setenv ("NAME", getenv ("USER"), 0);
2019
2020 /* Time zone determined from country code. To make this possible, the
2021 country code may not span more than one time zone. In other words,
2022 in the USA, you lose. */
2023 if (!getenv ("TZ"))
2024 switch (dos_country_code)
2025 {
2026 case 31: /* Belgium */
2027 case 32: /* The Netherlands */
2028 case 33: /* France */
2029 case 34: /* Spain */
2030 case 36: /* Hungary */
2031 case 38: /* Yugoslavia (or what's left of it?) */
2032 case 39: /* Italy */
2033 case 41: /* Switzerland */
2034 case 42: /* Tjekia */
2035 case 45: /* Denmark */
2036 case 46: /* Sweden */
2037 case 47: /* Norway */
2038 case 48: /* Poland */
2039 case 49: /* Germany */
2040 /* Daylight saving from last Sunday in March to last Sunday in
2041 September, both at 2AM. */
2042 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
2043 break;
2044 case 44: /* United Kingdom */
2045 case 351: /* Portugal */
2046 case 354: /* Iceland */
2047 setenv ("TZ", "GMT+00", 0);
2048 break;
2049 case 81: /* Japan */
2050 case 82: /* Korea */
2051 setenv ("TZ", "JST-09", 0);
2052 break;
2053 case 90: /* Turkey */
2054 case 358: /* Finland */
2055 setenv ("TZ", "EET-02", 0);
2056 break;
2057 case 972: /* Israel */
2058 /* This is an approximation. (For exact rules, use the
2059 `zoneinfo/israel' file which comes with DJGPP, but you need
2060 to install it in `/usr/share/zoneinfo/' directory first.) */
2061 setenv ("TZ", "IST-02IDT-03,M4.1.6/00:00,M9.5.6/01:00", 0);
2062 break;
2063 }
2064 init_gettimeofday ();
2065 }
2066
2067 \f
2068
2069 static int break_stat; /* BREAK check mode status. */
2070 static int stdin_stat; /* stdin IOCTL status. */
2071
2072 /* These must be global. */
2073 static _go32_dpmi_seginfo ctrl_break_vector;
2074 static _go32_dpmi_registers ctrl_break_regs;
2075 static int ctrlbreakinstalled = 0;
2076
2077 /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
2078
2079 void
2080 ctrl_break_func (regs)
2081 _go32_dpmi_registers *regs;
2082 {
2083 Vquit_flag = Qt;
2084 }
2085
2086 void
2087 install_ctrl_break_check ()
2088 {
2089 if (!ctrlbreakinstalled)
2090 {
2091 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
2092 was compiler with Djgpp 1.11 maintenance level 5 or later! */
2093 ctrlbreakinstalled = 1;
2094 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
2095 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
2096 &ctrl_break_regs);
2097 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
2098 }
2099 }
2100
2101 /*
2102 * Turn off Dos' Ctrl-C checking and inhibit interpretation of
2103 * control chars by Dos.
2104 * Determine the keyboard type.
2105 */
2106
2107 int
2108 dos_ttraw ()
2109 {
2110 union REGS inregs, outregs;
2111 static int first_time = 1;
2112
2113 break_stat = getcbrk ();
2114 setcbrk (0);
2115 install_ctrl_break_check ();
2116
2117 if (first_time)
2118 {
2119 inregs.h.ah = 0xc0;
2120 int86 (0x15, &inregs, &outregs);
2121 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
2122
2123 have_mouse = 0;
2124
2125 if (internal_terminal
2126 #ifdef HAVE_X_WINDOWS
2127 && inhibit_window_system
2128 #endif
2129 )
2130 {
2131 inregs.x.ax = 0x0021;
2132 int86 (0x33, &inregs, &outregs);
2133 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2134 if (!have_mouse)
2135 {
2136 /* Reportedly, the above doesn't work for some mouse drivers. There
2137 is an additional detection method that should work, but might be
2138 a little slower. Use that as an alternative. */
2139 inregs.x.ax = 0x0000;
2140 int86 (0x33, &inregs, &outregs);
2141 have_mouse = (outregs.x.ax & 0xffff) == 0xffff;
2142 }
2143
2144 if (have_mouse)
2145 {
2146 have_mouse = 1; /* enable mouse */
2147 mouse_visible = 0;
2148
2149 if (outregs.x.bx == 3)
2150 {
2151 mouse_button_count = 3;
2152 mouse_button_translate[0] = 0; /* Left */
2153 mouse_button_translate[1] = 2; /* Middle */
2154 mouse_button_translate[2] = 1; /* Right */
2155 }
2156 else
2157 {
2158 mouse_button_count = 2;
2159 mouse_button_translate[0] = 0;
2160 mouse_button_translate[1] = 1;
2161 }
2162 mouse_position_hook = &mouse_get_pos;
2163 mouse_init ();
2164 }
2165 }
2166
2167 first_time = 0;
2168 }
2169
2170 inregs.x.ax = 0x4400; /* Get IOCTL status. */
2171 inregs.x.bx = 0x00; /* 0 = stdin. */
2172 intdos (&inregs, &outregs);
2173 stdin_stat = outregs.h.dl;
2174
2175 inregs.x.dx = stdin_stat | 0x0020; /* raw mode */
2176 inregs.x.ax = 0x4401; /* Set IOCTL status */
2177 intdos (&inregs, &outregs);
2178 return !outregs.x.cflag;
2179 }
2180
2181 /* Restore status of standard input and Ctrl-C checking. */
2182 int
2183 dos_ttcooked ()
2184 {
2185 union REGS inregs, outregs;
2186
2187 setcbrk (break_stat);
2188 mouse_off ();
2189
2190 inregs.x.ax = 0x4401; /* Set IOCTL status. */
2191 inregs.x.bx = 0x00; /* 0 = stdin. */
2192 inregs.x.dx = stdin_stat;
2193 intdos (&inregs, &outregs);
2194 return !outregs.x.cflag;
2195 }
2196
2197 \f
2198 /* Run command as specified by ARGV in directory DIR.
2199 The command is run with input from TEMPIN, output to
2200 file TEMPOUT and stderr to TEMPERR. */
2201 int
2202 run_msdos_command (argv, dir, tempin, tempout, temperr)
2203 unsigned char **argv;
2204 Lisp_Object dir;
2205 int tempin, tempout, temperr;
2206 {
2207 char *saveargv1, *saveargv2, **envv;
2208 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
2209 int msshell, result = -1;
2210 int in, out, inbak, outbak, errbak;
2211 int x, y;
2212 Lisp_Object cmd;
2213
2214 /* Get current directory as MSDOS cwd is not per-process. */
2215 getwd (oldwd);
2216
2217 cmd = Ffile_name_nondirectory (build_string (argv[0]));
2218 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
2219 && !strcmp ("-c", argv[1]);
2220 if (msshell)
2221 {
2222 saveargv1 = argv[1];
2223 saveargv2 = argv[2];
2224 argv[1] = "/c";
2225 if (argv[2])
2226 {
2227 char *p = alloca (strlen (argv[2]) + 1);
2228
2229 strcpy (argv[2] = p, saveargv2);
2230 while (*p && isspace (*p))
2231 p++;
2232 while (*p && !isspace (*p))
2233 if (*p == '/')
2234 *p++ = '\\';
2235 else
2236 p++;
2237 }
2238 }
2239
2240 /* Build the environment array. */
2241 {
2242 extern Lisp_Object Vprocess_environment;
2243 Lisp_Object tmp, lst;
2244 int i, len;
2245
2246 lst = Vprocess_environment;
2247 len = XFASTINT (Flength (lst));
2248
2249 envv = alloca ((len + 1) * sizeof (char *));
2250 for (i = 0; i < len; i++)
2251 {
2252 tmp = Fcar (lst);
2253 lst = Fcdr (lst);
2254 CHECK_STRING (tmp, 0);
2255 envv[i] = alloca (XSTRING (tmp)->size + 1);
2256 strcpy (envv[i], XSTRING (tmp)->data);
2257 }
2258 envv[len] = (char *) 0;
2259 }
2260
2261 if (STRINGP (dir))
2262 chdir (XSTRING (dir)->data);
2263 inbak = dup (0);
2264 outbak = dup (1);
2265 errbak = dup (2);
2266 if (inbak < 0 || outbak < 0 || errbak < 0)
2267 goto done; /* Allocation might fail due to lack of descriptors. */
2268
2269 if (have_mouse > 0)
2270 mouse_get_xy (&x, &y);
2271
2272 dos_ttcooked (); /* do it here while 0 = stdin */
2273
2274 dup2 (tempin, 0);
2275 dup2 (tempout, 1);
2276 dup2 (temperr, 2);
2277
2278 result = spawnve (P_WAIT, argv[0], argv, envv);
2279
2280 dup2 (inbak, 0);
2281 dup2 (outbak, 1);
2282 dup2 (errbak, 2);
2283 close (inbak);
2284 close (outbak);
2285 close (errbak);
2286
2287 dos_ttraw ();
2288 if (have_mouse > 0)
2289 {
2290 mouse_init ();
2291 mouse_moveto (x, y);
2292 }
2293
2294 done:
2295 chdir (oldwd);
2296 if (msshell)
2297 {
2298 argv[1] = saveargv1;
2299 argv[2] = saveargv2;
2300 }
2301 return result;
2302 }
2303
2304 croak (badfunc)
2305 char *badfunc;
2306 {
2307 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
2308 reset_sys_modes ();
2309 exit (1);
2310 }
2311
2312
2313 /* ------------------------- Compatibility functions -------------------
2314 * gethostname
2315 * gettimeofday
2316 */
2317
2318 /*
2319 * Hostnames for a pc are not really funny,
2320 * but they are used in change log so we emulate the best we can.
2321 */
2322
2323 gethostname (p, size)
2324 char *p;
2325 int size;
2326 {
2327 char *q = egetenv ("HOSTNAME");
2328
2329 if (!q) q = "pc";
2330 strcpy (p, q);
2331 return 0;
2332 }
2333
2334 /* When time zones are set from Ms-Dos too many C-libraries are playing
2335 tricks with time values. We solve this by defining our own version
2336 of `gettimeofday' bypassing GO32. Our version needs to be initialized
2337 once and after each call to `tzset' with TZ changed. That is
2338 accomplished by aliasing tzset to init_gettimeofday. */
2339
2340 static struct tm time_rec;
2341
2342 int
2343 gettimeofday (struct timeval *tp, struct timezone *tzp)
2344 {
2345 if (tp)
2346 {
2347 struct time t;
2348 struct tm tm;
2349
2350 gettime (&t);
2351 if (t.ti_hour < time_rec.tm_hour) /* midnight wrap */
2352 {
2353 struct date d;
2354 getdate (&d);
2355 time_rec.tm_year = d.da_year - 1900;
2356 time_rec.tm_mon = d.da_mon - 1;
2357 time_rec.tm_mday = d.da_day;
2358 }
2359
2360 time_rec.tm_hour = t.ti_hour;
2361 time_rec.tm_min = t.ti_min;
2362 time_rec.tm_sec = t.ti_sec;
2363
2364 tm = time_rec;
2365 tm.tm_gmtoff = dos_timezone_offset;
2366
2367 tp->tv_sec = mktime (&tm); /* may modify tm */
2368 tp->tv_usec = t.ti_hund * (1000000 / 100);
2369 }
2370 /* Ignore tzp; it's obsolescent. */
2371 return 0;
2372 }
2373
2374
2375 /*
2376 * A list of unimplemented functions that we silently ignore.
2377 */
2378
2379 unsigned alarm (s) unsigned s; {}
2380 fork () { return 0; }
2381 int kill (x, y) int x, y; { return -1; }
2382 nice (p) int p; {}
2383 void volatile pause () {}
2384 request_sigio () {}
2385 setpgrp () {return 0; }
2386 setpriority (x,y,z) int x,y,z; { return 0; }
2387 sigsetmask (x) int x; { return 0; }
2388 unrequest_sigio () {}
2389
2390 #ifndef HAVE_SELECT
2391 #include "sysselect.h"
2392
2393 static struct time last_time = {120, 120, 120, 120};
2394 static int modeline_time_displayed = 0;
2395
2396 Lisp_Object Vdos_display_time;
2397
2398 static void
2399 check_timer (t)
2400 struct time *t;
2401 {
2402 int sec, min, hour, hund;
2403
2404 gettime (t);
2405 sec = t->ti_sec;
2406 hund = t->ti_hund;
2407 hour = t->ti_hour;
2408 min = t->ti_min;
2409
2410 /* Any chance of not getting here 24 hours or more since last time? */
2411 if (hour == last_time.ti_hour
2412 && min == last_time.ti_min
2413 && sec == last_time.ti_sec)
2414 return;
2415
2416 if (!NILP (Vdos_display_time))
2417 {
2418 int interval;
2419 Lisp_Object dti = XSYMBOL (Fintern_soft (build_string ("display-time-interval"), Qnil))->value;
2420 int delta_time = ((hour - last_time.ti_hour) * 3600
2421 + (min - last_time.ti_min) * 60
2422 + (sec - last_time.ti_sec));
2423
2424 /* Who knows what the user may put into `display-time-interval'? */
2425 if (!INTEGERP (dti) || (interval = XINT (dti)) <= 0)
2426 interval = 60;
2427
2428 /* When it's time to renew the display, fake a `wakeup' call. */
2429 if (!modeline_time_displayed /* first time */
2430 || delta_time >= interval /* or if we were busy for a long time */
2431 || interval == 1 /* and every `interval' seconds hence */
2432 || interval == 60 && sec == 0 /* (usual cases first) */
2433 || (hour * 3600 + min * 60 + sec) % interval == 0)
2434 call2 (intern ("display-time-filter"), Qnil,
2435 build_string ("Wake up!\n"));
2436
2437 modeline_time_displayed = 1;
2438 }
2439 else if (modeline_time_displayed)
2440 {
2441 modeline_time_displayed = 0;
2442 Fset (intern ("display-time-string"), build_string (""));
2443
2444 /* Force immediate redisplay of modelines. */
2445 update_mode_lines++;
2446 redisplay_preserve_echo_area ();
2447 }
2448
2449 last_time = *t;
2450 }
2451
2452 /* Only event queue is checked. */
2453 int
2454 sys_select (nfds, rfds, wfds, efds, timeout)
2455 int nfds;
2456 SELECT_TYPE *rfds, *wfds, *efds;
2457 EMACS_TIME *timeout;
2458 {
2459 int check_input;
2460 long timeoutval, clnow, cllast;
2461 struct time t;
2462
2463 check_input = 0;
2464 if (rfds)
2465 {
2466 check_input = FD_ISSET (0, rfds);
2467 FD_ZERO (rfds);
2468 }
2469 if (wfds)
2470 FD_ZERO (wfds);
2471 if (efds)
2472 FD_ZERO (efds);
2473
2474 if (nfds != 1)
2475 abort ();
2476
2477 /* If we are looking only for the terminal, with no timeout,
2478 just read it and wait -- that's more efficient. */
2479 if (!timeout)
2480 {
2481 do
2482 check_timer (&t); /* check timer even if some input is pending */
2483 while (!detect_input_pending ());
2484 }
2485 else
2486 {
2487 timeoutval = EMACS_SECS (*timeout) * 100 + EMACS_USECS (*timeout) / 10000;
2488 check_timer (&t);
2489 cllast = t.ti_sec * 100 + t.ti_hund;
2490
2491 while (!check_input || !detect_input_pending ())
2492 {
2493 check_timer (&t);
2494 clnow = t.ti_sec * 100 + t.ti_hund;
2495 if (clnow < cllast) /* time wrap */
2496 timeoutval -= clnow + 6000 - cllast;
2497 else
2498 timeoutval -= clnow - cllast;
2499 if (timeoutval <= 0) /* Stop on timer being cleared */
2500 return 0;
2501 cllast = clnow;
2502 }
2503 }
2504
2505 FD_SET (0, rfds);
2506 return 1;
2507 }
2508 #endif
2509
2510 /*
2511 * Define overlayed functions:
2512 *
2513 * chdir -> sys_chdir
2514 * tzset -> init_gettimeofday
2515 * abort -> dos_abort
2516 */
2517
2518 #ifdef chdir
2519 #undef chdir
2520 extern int chdir ();
2521
2522 int
2523 sys_chdir (path)
2524 const char* path;
2525 {
2526 int len = strlen (path);
2527 char *tmp = (char *)path;
2528
2529 if (*tmp && tmp[1] == ':')
2530 {
2531 if (getdisk () != tolower (tmp[0]) - 'a')
2532 setdisk (tolower (tmp[0]) - 'a');
2533 tmp += 2; /* strip drive: KFS 1995-07-06 */
2534 len -= 2;
2535 }
2536
2537 if (len > 1 && (tmp[len - 1] == '/'))
2538 {
2539 char *tmp1 = (char *) alloca (len + 1);
2540 strcpy (tmp1, tmp);
2541 tmp1[len - 1] = 0;
2542 tmp = tmp1;
2543 }
2544 return chdir (tmp);
2545 }
2546 #endif
2547
2548 #ifdef tzset
2549 #undef tzset
2550 extern void tzset (void);
2551
2552 void
2553 init_gettimeofday ()
2554 {
2555 time_t ltm, gtm;
2556 struct tm *lstm;
2557
2558 tzset ();
2559 ltm = gtm = time (NULL);
2560 ltm = mktime (lstm = localtime (&ltm));
2561 gtm = mktime (gmtime (&gtm));
2562 time_rec.tm_hour = 99; /* force gettimeofday to get date */
2563 time_rec.tm_isdst = lstm->tm_isdst;
2564 dos_timezone_offset = time_rec.tm_gmtoff = (int)(gtm - ltm) / 60;
2565 }
2566 #endif
2567
2568 #ifdef abort
2569 #undef abort
2570 void
2571 dos_abort (file, line)
2572 char *file;
2573 int line;
2574 {
2575 char buffer1[200], buffer2[400];
2576 int i, j;
2577
2578 sprintf (buffer1, "<EMACS FATAL ERROR IN %s LINE %d>", file, line);
2579 for (i = j = 0; buffer1[i]; i++) {
2580 buffer2[j++] = buffer1[i];
2581 buffer2[j++] = 0x70;
2582 }
2583 dosmemput (buffer2, j, (int)ScreenPrimary);
2584 ScreenSetCursor (2, 0);
2585 abort ();
2586 }
2587 #else
2588 void
2589 abort ()
2590 {
2591 dos_ttcooked ();
2592 ScreenSetCursor (10, 0);
2593 cputs ("\r\n\nEmacs aborted!\r\n");
2594 exit (2);
2595 }
2596 #endif
2597
2598 syms_of_msdos ()
2599 {
2600 recent_doskeys = Fmake_vector (make_number (NUM_RECENT_DOSKEYS), Qnil);
2601 staticpro (&recent_doskeys);
2602
2603 defsubr (&Srecent_doskeys);
2604
2605 DEFVAR_LISP ("dos-display-time", &Vdos_display_time,
2606 "*When non-nil, `display-time' is in effect on DOS systems.");
2607 Vdos_display_time = Qnil;
2608 }
2609
2610 #endif /* MSDOS */