Finish downcasing mouse_init1, mouse_off,
[bpt/emacs.git] / src / msdos.c
CommitLineData
1b94449f
RS
1/* MS-DOS specific C utilities. Coded by Morten Welinder 1993
2 Copyright (C) 1993 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
21
48984716 22#include <config.h>
1b94449f
RS
23
24#ifdef MSDOS
25#include "lisp.h"
26#include <stdio.h>
27#include <stdlib.h>
28#include <sys/param.h>
29#include <sys/time.h>
30#include <dos.h>
31#include "dosfns.h"
32#include "msdos.h"
33#include "systime.h"
34#include "termhooks.h"
35#include "frame.h"
36#include <go32.h>
37#include <pc.h>
38#include <ctype.h>
39/* #include <process.h> */
40/* Damn that local process.h! Instead we can define P_WAIT ourselves. */
41#define P_WAIT 1
42
43static int break_stat; /* BREAK check mode status. */
44static int stdin_stat; /* stdin IOCTL status. */
45static int extended_kbd; /* 101 (102) keyboard present. */
46
47int have_mouse; /* Mouse present? */
48static int mouse_last_x;
49static int mouse_last_y;
50
51/* Turn off Dos' Ctrl-C checking and inhibit interpretation of control chars
52 by Dos. Determine the keyboard type. */
53int
54dos_ttraw ()
55{
56 union REGS inregs, outregs;
57
58 inregs.h.ah = 0xc0;
59 int86 (0x15, &inregs, &outregs);
60 extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
61
62 break_stat = getcbrk ();
63 setcbrk (0);
64 install_ctrl_break_check ();
65 have_mouse = Mouse_init1 ();
66
67 inregs.x.ax = 0x4400; /* Get IOCTL status. */
68 inregs.x.bx = 0x00; /* 0 = stdin. */
69 intdos (&inregs, &outregs);
70 stdin_stat = outregs.h.dl;
71
72 inregs.x.dx = (outregs.x.dx | 0x0020) & 0x0027; /* raw mode */
73 inregs.h.al = 0x01;
74 intdos (&inregs, &outregs);
75 return !outregs.x.cflag;
76}
77
78/* Restore status of standard input and Ctrl-C checking. */
79int
80dos_ttcooked ()
81{
82 union REGS inregs, outregs;
83
84 setcbrk (break_stat);
85 if (have_mouse) Mouse_off ();
86
87 inregs.x.ax = 0x4401; /* Set IOCTL status. */
88 inregs.x.bx = 0x00; /* 0 = stdin. */
89 inregs.x.dx = stdin_stat;
90 intdos (&inregs, &outregs);
91 return !outregs.x.cflag;
92}
93
94static unsigned short
95ibmpc_translate_map[] =
96{
97 /* --------------- 00 to 0f --------------- */
98 0, /* Ctrl Break */
99 0xff1b, /* Escape */
100 0xffb1, /* Keypad 1 */
101 0xffb2, /* Keypad 2 */
102 0xffb3, /* Keypad 3 */
103 0xffb4, /* Keypad 4 */
104 0xffb5, /* Keypad 5 */
105 0xffb6, /* Keypad 6 */
106 0xffb7, /* Keypad 7 */
107 0xffb8, /* Keypad 8 */
108 0xffb9, /* Keypad 9 */
109 0xffb0, /* Keypad 0 */
110 '-', '=',
111 0xff08, /* Backspace */
112 0xff74, /* (Shift) Tab [Tab doesn't use this table] */
113
114 /* --------------- 10 to 1f --------------- */
115 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
116 0xff8d, /* Keypad Enter */
117 0, /* Ctrl */
118 'a', 's',
119
120 /* --------------- 20 to 2f --------------- */
121 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
122 0, /* Left shift */
123 '\\', 'z', 'x', 'c', 'v',
124
125 /* --------------- 30 to 3f --------------- */
126 'b', 'n', 'm', ',', '.',
127 0xffaf, /* Grey / */
128 0, /* Right shift */
129 0xffaa, /* Grey * */
130 0, /* Alt */
131 ' ',
132 0, /* Caps Lock */
133 0xffbe, /* F1 */
134 0xffbf, /* F2 */
135 0xffc0, /* F3 */
136 0xffc1, /* F4 */
137 0xffc2, /* F5 */
138
139 /* --------------- 40 to 4f --------------- */
140 0xffc3, /* F6 */
141 0xffc4, /* F7 */
142 0xffc5, /* F8 */
143 0xffc6, /* F9 */
144 0xffc7, /* F10 */
145 0, /* Num Lock */
146 0, /* Scroll Lock */
147 0xff50, /* Home */
148 0xff52, /* Up */
149 0xff55, /* Page Up */
150 0xffad, /* Grey - */
151 0xff51, /* Left */
152 0xffb5, /* Keypad 5 */
153 0xff53, /* Right */
154 0xffab, /* Grey + */
155 0xff57, /* End */
156
157 /* --------------- 50 to 5f --------------- */
158 0xff54, /* Down */
159 0xff56, /* Page Down */
160 0xff63, /* Insert */
161 0xffff, /* Delete */
162 0xffbe, /* (Shift) F1 */
163 0xffbf, /* (Shift) F2 */
164 0xffc0, /* (Shift) F3 */
165 0xffc1, /* (Shift) F4 */
166 0xffc2, /* (Shift) F5 */
167 0xffc3, /* (Shift) F6 */
168 0xffc4, /* (Shift) F7 */
169 0xffc5, /* (Shift) F8 */
170 0xffc6, /* (Shift) F9 */
171 0xffc7, /* (Shift) F10 */
172 0xffbe, /* (Ctrl) F1 */
173 0xffbf, /* (Ctrl) F2 */
174
175 /* --------------- 60 to 6f --------------- */
176 0xffc0, /* (Ctrl) F3 */
177 0xffc1, /* (Ctrl) F4 */
178 0xffc2, /* (Ctrl) F5 */
179 0xffc3, /* (Ctrl) F6 */
180 0xffc4, /* (Ctrl) F7 */
181 0xffc5, /* (Ctrl) F8 */
182 0xffc6, /* (Ctrl) F9 */
183 0xffc7, /* (Ctrl) F10 */
184 0xffbe, /* (Alt) F1 */
185 0xffbf, /* (Alt) F2 */
186 0xffc0, /* (Alt) F3 */
187 0xffc1, /* (Alt) F4 */
188 0xffc2, /* (Alt) F5 */
189 0xffc3, /* (Alt) F6 */
190 0xffc4, /* (Alt) F7 */
191 0xffc5, /* (Alt) F8 */
192
193 /* --------------- 70 to 7f --------------- */
194 0xffc6, /* (Alt) F9 */
195 0xffc7, /* (Alt) F10 */
196 0xff6d, /* (Ctrl) Sys Rq */
197 0xff51, /* (Ctrl) Left */
198 0xff53, /* (Ctrl) Right */
199 0xff57, /* (Ctrl) End */
200 0xff56, /* (Ctrl) Page Down */
201 0xff50, /* (Ctrl) Home */
202 '1', '2', '3', '4', '5', '6', '7', '8', /* (Alt) */
203
204 /* --------------- 80 to 8f --------------- */
205 '9', '0', '-', '=', /* (Alt) */
206 0xff55, /* (Ctrl) Page Up */
207 0xffc8, /* F11 */
208 0xffc9, /* F12 */
209 0xffc8, /* (Shift) F11 */
210 0xffc9, /* (Shift) F12 */
211 0xffc8, /* (Ctrl) F11 */
212 0xffc9, /* (Ctrl) F12 */
213 0xffc8, /* (Alt) F11 */
214 0xffc9, /* (Alt) F12 */
215 0xff52, /* (Ctrl) Up */
216 0xffae, /* (Ctrl) Grey - */
217 0xffb5, /* (Ctrl) Keypad 5 */
218
219 /* --------------- 90 to 9f --------------- */
220 0xffab, /* (Ctrl) Grey + */
221 0xff54, /* (Ctrl) Down */
222 0xff63, /* (Ctrl) Insert */
223 0xffff, /* (Ctrl) Delete */
224 0xff09, /* (Ctrl) Tab */
225 0xffaf, /* (Ctrl) Grey / */
226 0xffaa, /* (Ctrl) Grey * */
227 0xff50, /* (Alt) Home */
228 0xff52, /* (Alt) Up */
229 0xff55, /* (Alt) Page Up */
230 0, /* NO KEY */
231 0xff51, /* (Alt) Left */
232 0, /* NO KEY */
233 0xff53, /* (Alt) Right */
234 0, /* NO KEY */
235 0xff57, /* (Alt) End */
236
237 /* --------------- a0 to af --------------- */
238 0xff54, /* (Alt) Down */
239 0xff56, /* (Alt) Page Down */
240 0xff63, /* (Alt) Insert */
241 0xffff, /* (Alt) Delete */
242 0xffaf, /* (Alt) Grey / */
243 0xff09, /* (Alt) Tab */
244 0xff0d /* (Alt) Enter */
245};
246
247/* Get a char from keyboard. Function keys are put into the event queue. */
248static int
249dos_rawgetc ()
250{
251 struct input_event event;
252 struct timeval tv;
253 union REGS regs;
254 int ctrl_p, alt_p, shift_p;
255
256 /* Calculate modifier bits */
257 regs.h.ah = extended_kbd ? 0x12 : 0x02;
258 int86 (0x16, &regs, &regs);
259 ctrl_p = ((regs.h.al & 4) != 0);
260 shift_p = ((regs.h.al & 3) != 0);
261 alt_p = ((extended_kbd ? (regs.h.ah & 2) : (regs.h.al & 8)) != 0);
262
263 while (kbhit ())
264 {
265 union REGS regs;
266 register unsigned char c;
267 int sc, code;
268
269 regs.h.ah = extended_kbd ? 0x10 : 0x00;
270 int86 (0x16, &regs, &regs);
271 c = regs.h.al;
272 sc = regs.h.ah;
273
274 /* Determine from the scan code if a keypad key was pressed. */
275 if (c >= '0' && c <= '9' && sc > 0xb)
276 sc = (c == '0') ? 0xb : (c - '0' + 1), c = 0;
277 else if (sc == 0xe0)
278 {
279 switch (c)
280 {
281 case 10: /* Ctrl Enter */
282 case 13:
283 sc = 0x1c;
284 break;
285 case '.': /* Decimal point or decimal comma */
286 case ',':
287 sc = 0x53;
288 break;
289 case '/':
290 sc = 0x35;
291 break;
292 default:
293 sc = 0;
294 };
295 c = 0;
296 }
297
298 if (c == 0
299 || c == ' '
300 || alt_p
301 || (ctrl_p && shift_p)
302 || (c == 0xe0 && sc != 0) /* Pseudo-key */
303 || sc == 0x37 /* Grey * */
304 || sc == 0x4a /* Grey - */
305 || sc == 0x4e /* Grey + */
306 || sc == 0x0e) /* Back space *key*, not Ctrl-h */
307 {
308 if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
309 code = 0;
310 else
311 code = ibmpc_translate_map[sc];
312 if (code != 0)
313 {
314 if (code >= 0x100)
315 {
316 event.kind = non_ascii_keystroke;
317 event.code = code & 0xff;
318 }
319 else
320 {
321 /* Don't return S- if we don't have to. */
322 if (code >= 'a' && code <= 'z')
323 {
324 c = shift_p ? toupper (code) : code;
325 shift_p = 0;
326 }
327 else
328 if (c == 0) c = code;
329 event.kind = ascii_keystroke;
330 event.code = c;
331 }
332 event.modifiers
333 = (shift_p ? shift_modifier : 0)
334 + (ctrl_p ? ctrl_modifier : 0)
335 + (alt_p ? meta_modifier : 0);
336 /* EMACS == Enter Meta Alt Control Shift */
337 event.frame_or_window = selected_frame;
338 gettimeofday (&tv, NULL);
339 event.timestamp = tv.tv_usec;
340 kbd_buffer_store_event (&event);
341 }
342 } else
343 return c;
344 }
345
346 if (have_mouse)
347 {
348 int but, press, x, y, ok;
349
350 /* Check for mouse movement *before* buttons. */
351 Mouse_check_moved ();
352
353 for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
354 for (press = 0; press < 2; press++)
355 {
356 if (press)
357 ok = Mouse_pressed (but, &x, &y);
358 else
359 ok = Mouse_released (but, &x, &y);
360 if (ok)
361 {
362 event.kind = mouse_click;
363 event.code = but;
364 event.modifiers
365 = (shift_p ? shift_modifier : 0)
366 + (ctrl_p ? ctrl_modifier : 0)
367 + (alt_p ? meta_modifier : 0)
368 + (press ? down_modifier : up_modifier);
369 event.x = x;
370 event.y = y;
371 event.frame_or_window = selected_frame;
372 gettimeofday (&tv, NULL);
373 event.timestamp = tv.tv_usec;
374 kbd_buffer_store_event (&event);
375 }
376 }
377 }
378
379 return -1;
380}
381
382static int prev_get_char = -1;
383
384/* Return 1 if a key is ready to be read without suspending execution. */
385dos_keysns ()
386{
387 if (prev_get_char != -1)
388 return 1;
389 else
390 return ((prev_get_char = dos_rawgetc ()) != -1);
391}
392
393/* Read a key. Return -1 if no key is ready. */
394dos_keyread ()
395{
396 if (prev_get_char != -1)
397 {
398 int c = prev_get_char;
399 prev_get_char = -1;
400 return c;
401 }
402 else
403 return dos_rawgetc ();
404}
405
406/* Hostnames for a pc are not really funny, but they are used in change log
407 so we emulate the best we can. */
408gethostname (p, size)
409 char *p;
410 int size;
411{
412 char *q = egetenv ("HOSTNAME");
413
414 if (!q) q = "pc";
415 strcpy (p, q);
416 return 0;
417}
418
419/* Destructively turn backslashes into slashes. */
420void
421dostounix_filename (p)
422 register char *p;
423{
424 while (*p)
425 {
426 if (*p == '\\')
427 *p = '/';
428 p++;
429 }
430}
431
432/* Destructively turn slashes into backslashes. */
433void
434unixtodos_filename (p)
435 register char *p;
436{
437 while (*p)
438 {
439 if (*p == '/')
440 *p = '\\';
441 p++;
442 }
443}
444
445/* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
446int
447getdefdir (drive, dst)
448 int drive;
449 char *dst;
450{
451 union REGS regs;
452
453 *dst++ = '/';
454 regs.h.dl = drive;
455 regs.x.si = (int) dst;
456 regs.h.ah = 0x47;
457 intdos (&regs, &regs);
458 return !regs.x.cflag;
459}
460
461/* Remove all CR's that are followed by a LF. */
462int
463crlf_to_lf (n, buf)
464 register int n;
465 register unsigned char *buf;
466{
467 unsigned char *np = buf;
468 unsigned char *startp = buf;
469 unsigned char *endp = buf + n;
470 unsigned char c;
471
472 if (n == 0)
473 return n;
474 while (buf < endp)
475 {
476 if (*buf == 0x0d)
477 {
478 if (*(++buf) != 0x0a)
479 *np++ = 0x0d;
480 }
481 else
482 *np++ = *buf++;
483 }
484 return np - startp;
485}
486
487
488/* Run command as specified by ARGV in directory DIR.
489 The command is run with input from TEMPIN and output to file TEMPOUT. */
490int
491run_msdos_command (argv, dir, tempin, tempout)
492 unsigned char **argv;
493 Lisp_Object dir;
494 int tempin, tempout;
495{
496 char *saveargv1, *saveargv2, **envv;
497 char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
498 int msshell, result = -1;
499 int in, out, inbak, outbak, errbak;
500 Lisp_Object cmd;
501
502 /* Get current directory as MSDOS cwd is not per-process. */
503 getwd (oldwd);
504
505 cmd = Ffile_name_nondirectory (build_string (argv[0]));
506 msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
507 && !strcmp ("-c", argv[1]);
508 if (msshell)
509 {
510 saveargv1 = argv[1];
511 argv[1] = "/c";
512 if (argv[2])
513 {
514 saveargv2 = argv[2];
515 unixtodos_filename (argv[2] = strdup (argv[2]));
516 }
517 }
518
519 /* Build the environment array. */
520 {
521 extern Lisp_Object Vprocess_environment;
091d0bdf
KH
522 Lisp_Object tmp, lst;
523 int i, len;
524
525 lst = Vprocess_environment;
526 len = XFASTINT (Flength (lst));
1b94449f
RS
527
528 envv = alloca ((len + 1) * sizeof (char *));
529 for (i = 0; i < len; i++)
530 {
531 tmp = Fcar (lst);
532 lst = Fcdr (lst);
533 CHECK_STRING (tmp, 0);
534 envv[i] = alloca (XSTRING (tmp)->size + 1);
535 strcpy (envv[i], XSTRING (tmp)->data);
536 }
537 envv[len] = (char *) 0;
538 }
539
540 if (XTYPE (dir) == Lisp_String)
541 chdir (XSTRING (dir)->data);
542 inbak = dup (0);
543 outbak = dup (1);
544 errbak = dup (2);
545 if (inbak < 0 || outbak < 0 || errbak < 0)
546 goto done; /* Allocation might fail due to lack of descriptors. */
547 dup2 (tempin, 0);
548 dup2 (tempout, 1);
549 dup2 (tempout, 2);
550 dos_ttcooked ();
551 result = spawnve (P_WAIT, argv[0], argv, envv);
552 dos_ttraw ();
553 dup2 (inbak, 0);
554 dup2 (outbak, 1);
555 dup2 (errbak, 2);
556
557 done:
558 chdir (oldwd);
559 if (msshell)
560 {
561 argv[1] = saveargv1;
562 if (argv[2])
563 {
564 free (argv[2]);
565 argv[2] = saveargv2;
566 }
567 }
568 return result;
569}
570
571
572croak (badfunc)
573 char *badfunc;
574{
575 fprintf (stderr, "%s not yet implemented\r\n", badfunc);
576 reset_sys_modes ();
577 exit (1);
578}
579
580/* A list of unimplemented functions that we silently ignore. */
581unsigned alarm (s) unsigned s; {}
582fork () { return 0; }
583int kill (x, y) int x, y; { return -1; }
584nice (p) int p; {}
585void volatile pause () {}
586request_sigio () {}
587setpgrp () {return 0; }
588setpriority (x,y,z) int x,y,z; { return 0; }
589sigsetmask (x) int x; { return 0; }
590unrequest_sigio () {}
591
592#ifdef chdir
593#undef chdir
594#endif
595
596int
597sys_chdir (path)
598 const char* path;
599{
600 int len = strlen (path);
601 char *tmp = (char *) alloca (len + 1);
602 /* Gotta do this extern here due to the corresponding #define: */
603 extern int chdir ();
604
605 if (*path && path[1] == ':' && (getdisk () != tolower (path[0]) - 'a'))
606 setdisk (tolower (path[0]) - 'a');
607
608 strcpy (tmp, path);
609 if (strcmp (path, "/") && strcmp (path + 1, ":/") && (path[len - 1] == '/'))
610 tmp[len - 1] = 0;
611 return chdir (tmp);
612}
613
614/* Sleep SECS. If KBDOK also return immediately if a key is pressed. */
615void
616sleep_or_kbd_hit (secs, kbdok)
617 int secs, kbdok;
618{
619 long clnow, clthen;
620 struct timeval t;
621
622 gettimeofday (&t, NULL);
623 clnow = t.tv_sec * 100 + t.tv_usec / 10000;
624 clthen = clnow + (100 * secs);
625
626 do
627 {
628 gettimeofday (&t, NULL);
629 clnow = t.tv_sec * 100 + t.tv_usec / 10000;
630 if (kbdok && detect_input_pending ())
631 return;
632 }
633 while (clnow < clthen);
634}
635
636/* Define a lot of environment variables if not already defined. Don't
637 remove anything unless you know what you're doing -- lots of code will
638 break if one or more of these are missing. */
639void
640init_environment (argc, argv, skip_args)
641 int argc;
642 char **argv;
643 int skip_args;
644{
645 char *s, *t;
646
647 /* We default HOME to the directory from which Emacs was started, but with
648 a "/bin" suffix removed. */
649 s = argv[0];
650 t = alloca (strlen (s) + 1);
651 strcpy (t, s);
652 s = t + strlen (t);
653 while (s != t && *s != '/' && *s != ':') s--;
654 if (s == t)
655 t = "c:/emacs"; /* When run under debug32. */
656 else
657 {
658 if (*s == ':') s++;
659 *s = 0;
660 if (s - 4 >= t && strcmp (s - 4, "/bin") == 0)
661 s[strlen (s) - 4] = 0;
662 }
663 setenv ("HOME", t, 0);
664
665 /* We set EMACSPATH to ~/bin (expanded) */
666 s = getenv ("HOME");
667 t = strcpy (alloca (strlen (s) + 6), s);
668 if (s[strlen (s) - 1] != '/') strcat (t, "/");
669 strcat (t, "bin");
670 setenv ("EMACSPATH", t, 0);
671
672 /* I don't expect anybody to ever use other terminals so the internal
673 terminal is the default. */
674 setenv ("TERM", "internal", 0);
675
676 /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
677 downcase it and mirror the backslashes. */
678 s = getenv ("COMSPEC");
679 if (!s) s = "c:/command.com";
680 t = alloca (strlen (s) + 1);
681 strcpy (t, s);
682 strlwr (t);
683 dostounix_filename (t);
684 setenv ("SHELL", t, 0);
685
686 /* PATH is also downcased and backslashes mirrored. */
687 s = getenv ("PATH");
688 if (!s) s = "";
689 t = alloca (strlen (s) + 3);
690 /* Current directory is always considered part of MsDos's path but it is
691 not normally mentioned. Now it is. */
692 strcat (strcpy (t, ".;"), s);
693 strlwr (t);
694 dostounix_filename (t); /* Not a single file name, but this should work. */
695 setenv ("PATH", t, 1);
696
697 /* In some sense all dos users have root privileges, so... */
698 setenv ("USER", "root", 0);
699 setenv ("NAME", getenv ("USER"), 0);
700
701 /* Time zone determined from country code. To make this possible, the
702 country code may not span more than one time zone. In other words,
703 in the USA, you lose. */
704 switch (dos_country_code)
705 {
706 case 31: /* Belgium */
707 case 32: /* The Netherlands */
708 case 33: /* France */
709 case 34: /* Spain */
710 case 36: /* Hungary */
711 case 38: /* Yugoslavia (or what's left of it?) */
712 case 39: /* Italy */
713 case 41: /* Switzerland */
714 case 42: /* Tjekia */
715 case 45: /* Denmark */
716 case 46: /* Sweden */
717 case 47: /* Norway */
718 case 48: /* Poland */
719 case 49: /* Germany */
720 /* Daylight saving from last Sunday in March to last Sunday in
721 September, both at 2AM. */
722 setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
723 break;
724 case 44: /* United Kingdom */
725 case 351: /* Portugal */
726 case 354: /* Iceland */
727 setenv ("TZ", "GMT+00", 0);
728 break;
729 case 81: /* Japan */
730 case 82: /* Korea */
731 setenv ("TZ", "???-09", 0);
732 break;
733 case 90: /* Turkey */
734 case 358: /* Finland */
735 case 972: /* Israel */
736 setenv ("TZ", "EET-02", 0);
737 break;
738 }
739 tzset ();
740}
741
742/* Flash the screen as a substitute for BEEPs. */
743
744static unsigned char _xorattr;
745
746void
747visible_bell (xorattr)
748 unsigned char xorattr;
749{
750 _xorattr = xorattr;
751 asm (" pushl %eax
752 pushl %ebx
753 pushl %ecx
754 pushl %edx
755 movl $1,%edx
756visible_bell_0:
757 movl _ScreenPrimary,%eax
758 call dosmemsetup
759 movl %eax,%ebx
760 call _ScreenRows
761 movl %eax,%ecx
762 call _ScreenCols
763 imull %eax,%ecx
764 movb (__xorattr),%al
765 incl %ebx
766visible_bell_1:
767 xorb %al,%gs:(%ebx)
768 addl $2,%ebx
769 decl %ecx
770 jne visible_bell_1
771 decl %edx
772 jne visible_bell_3
773visible_bell_2:
774 movzwl %ax,%eax
775 movzwl %ax,%eax
776 movzwl %ax,%eax
777 movzwl %ax,%eax
778 decw %cx
779 jne visible_bell_2
780 jmp visible_bell_0
781visible_bell_3:
782 popl %edx
783 popl %ecx
784 popl %ebx
785 popl %eax");
786}
787
788static int internal_terminal = 0;
789#undef fflush
790
791int
792internal_flush (f)
793 FILE *f;
794{
795 static int x;
796 static int y;
797 char c, *cp;
798 int count, i;
799
800 if (internal_terminal && f == stdout)
801 {
802 if (have_mouse) Mouse_off ();
803 cp = stdout->_base;
804 count = stdout->_ptr - stdout->_base;
805 while (count > 0)
806 {
807 switch (c = *cp++)
808 {
809 case 27:
810 switch (*cp++)
811 {
812 case '@':
813 y = *cp++;
814 x = *cp++;
815 count -= 4;
816 break;
817 case 'A':
818 ScreenAttrib = *cp++;
819 count -= 3;
820 break;
821 case 'B':
822 visible_bell (*cp++);
823 count -= 3;
824 break;
825 case 'C':
826 ScreenClear ();
827 x = y = 0;
828 count -= 2;
829 break;
830 case 'E':
831 for (i = ScreenCols () - 1; i >= x; i--)
832 ScreenPutChar (' ', ScreenAttrib, i, y);
833 count -= 2;
834 break;
835 case 'R':
836 x++;
837 count -= 2;
838 break;
839 case 'U':
840 y--;
841 count -= 2;
842 break;
843 case 'X':
844 ScreenAttrib ^= *cp++;
845 count -= 3;
846 break;
847 default:
848 count -= 2;
849 }
850 break;
851 case 8:
852 x--;
853 count--;
854 break;
855 case 13:
856 x = 0;
857 count--;
858 break;
859 case 10:
860 y++;
861 count--;
862 break;
863 default:
864 ScreenPutChar (c, ScreenAttrib, x++, y);
865 count--;
866 }
867 }
868 fpurge (stdout);
869 ScreenSetCursor (y, x);
870 if (have_mouse) Mouse_on ();
871 }
872 else
873 /* This is a call to the original fflush. */
874 fflush (f);
875}
876
877/* Do we need the internal terminal? */
878void
879internal_terminal_init ()
880{
881 char *term = getenv ("TERM");
882
883 internal_terminal
884 = (!noninteractive) && term && !strcmp (term, "internal");
885}
886
887/* These must be global. */
888static _go32_dpmi_seginfo ctrl_break_vector;
889static _go32_dpmi_registers ctrl_break_regs;
890static int ctrlbreakinstalled = 0;
891
892/* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
893void
894ctrl_break_func (regs)
895 _go32_dpmi_registers *regs;
896{
897 Vquit_flag = Qt;
898}
899
900void
901install_ctrl_break_check ()
902{
903 if (!ctrlbreakinstalled)
904 {
905 /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
906 was compiler with Djgpp 1.11 maintenance level 2 or later! */
907 ctrlbreakinstalled = 1;
908 ctrl_break_vector.pm_offset = (int) ctrl_break_func;
909 _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
910 &ctrl_break_regs);
911 _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
912 }
913}
914\f
915
916/* Mouse routines under devellopment follow. Coordinates are in screen
917 positions and zero based. Mouse buttons are numbered from left to
918 right and also zero based. */
919
920static int mouse_button_translate[NUM_MOUSE_BUTTONS];
921static int mouse_button_count;
922
923void
924mouse_init ()
925{
926 union REGS regs;
927
928 regs.x.ax = 0x0007;
929 regs.x.cx = 0;
930 regs.x.dx = 8 * (ScreenCols () - 1);
931 int86 (0x33, &regs, &regs);
932
933 regs.x.ax = 0x0008;
934 regs.x.cx = 0;
935 regs.x.dx = 8 * (ScreenRows () - 1);
936 int86 (0x33, &regs, &regs);
937
938 mouse_moveto (ScreenCols () - 1, ScreenRows () - 1);
939 mouse_on ();
940}
941
942void
943mouse_on ()
944{
945 union REGS regs;
946
947 regs.x.ax = 0x0001;
948 int86 (0x33, &regs, &regs);
949}
950
951void
952mouse_off ()
953{
954 union REGS regs;
955
956 regs.x.ax = 0x0002;
957 int86 (0x33, &regs, &regs);
958}
959
960void
961mouse_moveto (x, y)
962 int x, y;
963{
964 union REGS regs;
965
966 regs.x.ax = 0x0004;
967 mouse_last_x = regs.x.cx = x * 8;
968 mouse_last_y = regs.x.dx = y * 8;
969 int86 (0x33, &regs, &regs);
970}
971
972int
973mouse_pressed (b, xp, yp)
974 int b, *xp, *yp;
975{
976 union REGS regs;
977
978 if (b >= mouse_button_count)
979 return 0;
980 regs.x.ax = 0x0005;
981 regs.x.bx = mouse_button_translate[b];
982 int86 (0x33, &regs, &regs);
983 if (regs.x.bx)
984 *xp = regs.x.cx / 8, *yp = regs.x.dx /8;
985 return (regs.x.bx != 0);
986}
987
988int
989mouse_released (b, xp, yp)
990 int b, *xp, *yp;
991{
992 union REGS regs;
993
994 if (b >= mouse_button_count)
995 return 0;
996 regs.x.ax = 0x0006;
997 regs.x.bx = mouse_button_translate[b];
998 int86 (0x33, &regs, &regs);
999 if (regs.x.bx)
1000 *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
1001 return (regs.x.bx != 0);
1002}
1003
1004void
1005mouse_get_pos (f, bar_window, part, x, y, time)
1006 FRAME_PTR *f;
1007 Lisp_Object *bar_window, *x, *y;
1008 enum scroll_bar_part *part;
1009 unsigned long *time;
1010{
1011 union REGS regs;
1012 struct timeval tv;
1013
1014 regs.x.ax = 0x0003;
1015 int86 (0x33, &regs, &regs);
1016 *f = selected_frame;
1017 *bar_window = Qnil;
1018 gettimeofday (&tv, NULL);
411acee3
RS
1019 *x = make_number (regs.x.cx);
1020 *y = make_number (regs.x.dx);
1b94449f
RS
1021 *time = tv.tv_usec;
1022 mouse_moved = 0;
1023}
1024
1025void
1026mouse_check_moved ()
1027{
1028 union REGS regs;
1029
1030 regs.x.ax = 0x0003;
1031 int86 (0x33, &regs, &regs);
1032 if (regs.x.cx != mouse_last_x || regs.x.dx != mouse_last_y)
1033 {
1034 mouse_moved = 1;
1035 mouse_last_x = regs.x.cx;
1036 mouse_last_y = regs.x.dx;
1037 }
1038}
1039
1040int
1041mouse_init1 ()
1042{
1043 union REGS regs;
1044 int present;
1045
1046 regs.x.ax = 0x0021;
1047 int86 (0x33, &regs, &regs);
1048 present = internal_terminal && (regs.x.ax & 0xffff) == 0xffff;
1049 if (present)
1050 {
1051 if (regs.x.bx == 3)
1052 {
1053 mouse_button_count = 3;
1054 mouse_button_translate[0] = 0; /* Left */
1055 mouse_button_translate[1] = 2; /* Middle */
1056 mouse_button_translate[2] = 1; /* Right */
1057 }
1058 else
1059 {
1060 mouse_button_count = 2;
1061 mouse_button_translate[0] = 0;
1062 mouse_button_translate[1] = 1;
1063 }
1064 mouse_position_hook = &mouse_get_pos;
1065 mouse_init ();
1066 }
1067 return present;
1068}
1069
1070#endif /* MSDOS */