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