]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/fhandler_console.cc
* fhandler_console.cc (fhandler_console::fixup_after_exec): Fix error message.
[newlib-cygwin.git] / winsup / cygwin / fhandler_console.cc
1 /* fhandler_console.cc
2
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include <sys/termios.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <wingdi.h>
17 #include <winuser.h>
18 #include <wincon.h>
19 #include <winnls.h>
20 #include <ctype.h>
21 #include <sys/cygwin.h>
22 #include "cygerrno.h"
23 #include "security.h"
24 #include "path.h"
25 #include "fhandler.h"
26 #include "dtable.h"
27 #include "cygheap.h"
28 #include "sigproc.h"
29 #include "pinfo.h"
30 #include "shared_info.h"
31 #include "cygthread.h"
32 #include "cygtls.h"
33
34 #define CONVERT_LIMIT 16384
35
36 static bool
37 cp_convert (UINT destcp, char *dest, UINT srccp, const char *src, DWORD size)
38 {
39 if (!size)
40 /* no action */;
41 else if (destcp == srccp)
42 {
43 if (dest != src)
44 memcpy (dest, src, size);
45 }
46 else
47 {
48 WCHAR wbuffer[CONVERT_LIMIT]; /* same size as the maximum input, s.b. */
49 if (!MultiByteToWideChar (srccp, 0, src, size, wbuffer, sizeof (wbuffer)))
50 return false;
51 if (!WideCharToMultiByte (destcp, 0, wbuffer, size, dest, size,
52 NULL, NULL))
53 return false;
54 }
55 return true;
56 }
57
58 /*
59 * Scroll the screen context.
60 * x1, y1 - ul corner
61 * x2, y2 - dr corner
62 * xn, yn - new ul corner
63 * Negative values represents current screen dimensions
64 */
65
66 #define srTop (dev_state->info.winTop + dev_state->scroll_region.Top)
67 #define srBottom ((dev_state->scroll_region.Bottom < 0) ? dev_state->info.winBottom : dev_state->info.winTop + dev_state->scroll_region.Bottom)
68
69 #define use_tty ISSTATE (myself, PID_USETTY)
70
71 const char * get_nonascii_key (INPUT_RECORD&, char *);
72
73 static console_state NO_COPY *shared_console_info;
74
75 dev_console NO_COPY *fhandler_console::dev_state;
76
77 /* Allocate and initialize the shared record for the current console.
78 Returns a pointer to shared_console_info. */
79 tty_min *
80 fhandler_console::get_tty_stuff (int flags = 0)
81 {
82 if (dev_state)
83 return &shared_console_info->tty_min_state;
84
85 shared_console_info =
86 (console_state *) open_shared (NULL, 0, cygheap->console_h,
87 sizeof (*shared_console_info),
88 SH_SHARED_CONSOLE);
89 dev_state = &shared_console_info->dev_state;
90
91 ProtectHandleINH (cygheap->console_h);
92 if (!shared_console_info->tty_min_state.ntty)
93 {
94 shared_console_info->tty_min_state.setntty (TTY_CONSOLE);
95 shared_console_info->tty_min_state.setsid (myself->sid);
96 myself->set_ctty (&shared_console_info->tty_min_state, flags, NULL);
97
98 dev_state->scroll_region.Bottom = -1;
99 dev_state->dwLastCursorPosition.X = -1;
100 dev_state->dwLastCursorPosition.Y = -1;
101 dev_state->default_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
102 dev_state->underline_color = FOREGROUND_GREEN | FOREGROUND_BLUE;
103 dev_state->dim_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
104 dev_state->meta_mask = LEFT_ALT_PRESSED;
105 /* Set the mask that determines if an input keystroke is modified by
106 META. We set this based on the keyboard layout language loaded
107 for the current thread. The left <ALT> key always generates
108 META, but the right <ALT> key only generates META if we are using
109 an English keyboard because many "international" keyboards
110 replace common shell symbols ('[', '{', etc.) with accented
111 language-specific characters (umlaut, accent grave, etc.). On
112 these keyboards right <ALT> (called AltGr) is used to produce the
113 shell symbols and should not be interpreted as META. */
114 if (PRIMARYLANGID (LOWORD (GetKeyboardLayout (0))) == LANG_ENGLISH)
115 dev_state->meta_mask |= RIGHT_ALT_PRESSED;
116 }
117
118 return &shared_console_info->tty_min_state;
119 }
120
121 void
122 set_console_ctty ()
123 {
124 (void) fhandler_console::get_tty_stuff ();
125 }
126
127 /* Return the tty structure associated with a given tty number. If the
128 tty number is < 0, just return a dummy record. */
129 tty_min *
130 tty_list::get_tty (int n)
131 {
132 static tty_min nada;
133 if (n == TTY_CONSOLE)
134 return fhandler_console::get_tty_stuff ();
135 else if (n >= 0)
136 return &cygwin_shared->tty.ttys[n];
137 else
138 return &nada;
139 }
140
141
142 /* Determine if a console is associated with this process prior to a spawn.
143 If it is, then we'll return 1. If the console has been initialized, then
144 set it into a more friendly state for non-cygwin apps. */
145 int __stdcall
146 set_console_state_for_spawn ()
147 {
148 HANDLE h = CreateFile ("CONIN$", GENERIC_READ, FILE_SHARE_WRITE,
149 &sec_none_nih, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
150 NULL);
151
152 if (h == INVALID_HANDLE_VALUE)
153 return 0;
154
155 if (shared_console_info != NULL)
156 {
157 /* ACK. Temporarily define for use in TTYSETF macro */
158 SetConsoleMode (h, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
159 shared_console_info->tty_min_state.rstcons (true);
160 }
161
162 CloseHandle (h);
163 return 1;
164 }
165
166 /* The results of GetConsoleCP() and GetConsoleOutputCP() cannot be
167 cached, because a program or the user can change these values at
168 any time. */
169 inline bool
170 dev_console::con_to_str (char *d, const char *s, DWORD sz)
171 {
172 return cp_convert (get_cp (), d, GetConsoleCP (), s, sz);
173 }
174
175 inline bool
176 dev_console::str_to_con (char *d, const char *s, DWORD sz)
177 {
178 if (alternate_charset_active)
179 {
180 /* no translation when alternate charset is active */
181 memcpy(d, s, sz);
182 return true;
183 }
184 return cp_convert (GetConsoleOutputCP (), d, get_cp (), s, sz);
185 }
186
187 bool
188 fhandler_console::set_raw_win32_keyboard_mode (bool new_mode)
189 {
190 bool old_mode = dev_state->raw_win32_keyboard_mode;
191 dev_state->raw_win32_keyboard_mode = new_mode;
192 syscall_printf ("raw keyboard mode %sabled", dev_state->raw_win32_keyboard_mode ? "en" : "dis");
193 return old_mode;
194 };
195
196 void
197 fhandler_console::set_cursor_maybe ()
198 {
199 CONSOLE_SCREEN_BUFFER_INFO now;
200
201 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now))
202 return;
203
204 if (dev_state->dwLastCursorPosition.X != now.dwCursorPosition.X ||
205 dev_state->dwLastCursorPosition.Y != now.dwCursorPosition.Y)
206 {
207 SetConsoleCursorPosition (get_output_handle (), now.dwCursorPosition);
208 dev_state->dwLastCursorPosition = now.dwCursorPosition;
209 }
210 }
211
212 void
213 fhandler_console::send_winch_maybe ()
214 {
215 SHORT y = dev_state->info.dwWinSize.Y;
216 SHORT x = dev_state->info.dwWinSize.X;
217 fillin_info ();
218
219 if (y != dev_state->info.dwWinSize.Y || x != dev_state->info.dwWinSize.X)
220 {
221 extern fhandler_tty_master *tty_master;
222 dev_state->scroll_region.Top = 0;
223 dev_state->scroll_region.Bottom = -1;
224 if (tty_master)
225 tty_master->set_winsize (true);
226 else
227 tc->kill_pgrp (SIGWINCH);
228 }
229 }
230
231 void __stdcall
232 fhandler_console::read (void *pv, size_t& buflen)
233 {
234 HANDLE h = get_io_handle ();
235
236 #define buf ((char *) pv)
237
238 int ch;
239 set_input_state ();
240
241 int copied_chars = get_readahead_into_buffer (buf, buflen);
242
243 if (copied_chars)
244 {
245 buflen = copied_chars;
246 return;
247 }
248
249 HANDLE w4[2];
250 DWORD nwait;
251 char tmp[60];
252
253 w4[0] = h;
254 if (&_my_tls != _main_tls)
255 nwait = 1;
256 else
257 {
258 w4[1] = signal_arrived;
259 nwait = 2;
260 }
261
262 termios ti = tc->ti;
263 for (;;)
264 {
265 int bgres;
266 if ((bgres = bg_check (SIGTTIN)) <= bg_eof)
267 {
268 buflen = bgres;
269 return;
270 }
271
272 set_cursor_maybe (); /* to make cursor appear on the screen immediately */
273 switch (WaitForMultipleObjects (nwait, w4, FALSE, INFINITE))
274 {
275 case WAIT_OBJECT_0:
276 break;
277 case WAIT_OBJECT_0 + 1:
278 goto sig_exit;
279 default:
280 goto err;
281 }
282
283 DWORD nread;
284 INPUT_RECORD input_rec;
285 const char *toadd = NULL;
286
287 if (!ReadConsoleInput (h, &input_rec, 1, &nread))
288 {
289 syscall_printf ("ReadConsoleInput failed, %E");
290 goto err; /* seems to be failure */
291 }
292
293 /* check the event that occurred */
294 switch (input_rec.EventType)
295 {
296 case KEY_EVENT:
297 #define virtual_key_code (input_rec.Event.KeyEvent.wVirtualKeyCode)
298 #define control_key_state (input_rec.Event.KeyEvent.dwControlKeyState)
299
300 dev_state->nModifiers = 0;
301
302 #ifdef DEBUGGING
303 /* allow manual switching to/from raw mode via ctrl-alt-scrolllock */
304 if (input_rec.Event.KeyEvent.bKeyDown &&
305 virtual_key_code == VK_SCROLL &&
306 control_key_state & (LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED) == LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED
307 )
308 {
309 set_raw_win32_keyboard_mode (!dev_state->raw_win32_keyboard_mode);
310 continue;
311 }
312 #endif
313
314 if (dev_state->raw_win32_keyboard_mode)
315 {
316 __small_sprintf (tmp, "\033{%u;%u;%u;%u;%u;%luK",
317 input_rec.Event.KeyEvent.bKeyDown,
318 input_rec.Event.KeyEvent.wRepeatCount,
319 input_rec.Event.KeyEvent.wVirtualKeyCode,
320 input_rec.Event.KeyEvent.wVirtualScanCode,
321 input_rec.Event.KeyEvent.uChar.UnicodeChar,
322 input_rec.Event.KeyEvent.dwControlKeyState);
323 toadd = tmp;
324 nread = strlen (toadd);
325 break;
326 }
327
328 #define ich (input_rec.Event.KeyEvent.uChar.AsciiChar)
329 #define wch (input_rec.Event.KeyEvent.uChar.UnicodeChar)
330 #define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
331 #define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
332
333 /* Ignore key up events, except for left alt events with non-zero character
334 */
335 if (!input_rec.Event.KeyEvent.bKeyDown &&
336 /*
337 Event for left alt, with a non-zero character, comes from
338 "alt + numerics" key sequence.
339 e.g. <left-alt> 0233 => &eacute;
340 */
341 !(wch != 0
342 // ?? experimentally determined on an XP system
343 && virtual_key_code == VK_MENU
344 // left alt -- see http://www.microsoft.com/hwdev/tech/input/Scancode.asp
345 && input_rec.Event.KeyEvent.wVirtualScanCode == 0x38))
346 continue;
347
348 if (control_key_state & SHIFT_PRESSED)
349 dev_state->nModifiers |= 1;
350 if (control_key_state & RIGHT_ALT_PRESSED)
351 dev_state->nModifiers |= 2;
352 if (control_key_state & CTRL_PRESSED)
353 dev_state->nModifiers |= 4;
354 if (control_key_state & LEFT_ALT_PRESSED)
355 dev_state->nModifiers |= 8;
356
357 if (wch == 0 ||
358 /* arrow/function keys */
359 (input_rec.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
360 {
361 toadd = get_nonascii_key (input_rec, tmp);
362 if (!toadd)
363 {
364 dev_state->nModifiers = 0;
365 continue;
366 }
367 nread = strlen (toadd);
368 }
369 else
370 {
371 tmp[1] = ich;
372 /* Need this check since US code page seems to have a bug when
373 converting a CTRL-U. */
374 if ((unsigned char) ich > 0x7f)
375 dev_state->con_to_str (tmp + 1, tmp + 1, 1);
376 /* Determine if the keystroke is modified by META. The tricky
377 part is to distinguish whether the right Alt key should be
378 recognized as Alt, or as AltGr. */
379 bool meta;
380 if (wincap.altgr_is_ctrl_alt ())
381 /* WinNT: AltGr is reported as Ctrl+Alt, and Ctrl+Alt is
382 treated just like AltGr. However, if Ctrl+Alt+key generates
383 an ASCII control character, interpret is as META. */
384 meta = (control_key_state & ALT_PRESSED) != 0
385 && ((control_key_state & CTRL_PRESSED) == 0
386 || (ich >= 0 && ich <= 0x1f || ich == 0x7f));
387 else
388 /* Win9x: there's no way to distinguish Alt from AltGr, so rely
389 on dev_state->meta_mask heuristic (see fhandler_console constructor). */
390 meta = (control_key_state & dev_state->meta_mask) != 0;
391 if (!meta)
392 toadd = tmp + 1;
393 else
394 {
395 tmp[0] = '\033';
396 tmp[1] = cyg_tolower (tmp[1]);
397 toadd = tmp;
398 nread++;
399 dev_state->nModifiers &= ~4;
400 }
401 }
402 #undef ich
403 #undef wch
404 #undef ALT_PRESSED
405 #undef CTRL_PRESSED
406 break;
407
408 case MOUSE_EVENT:
409 send_winch_maybe ();
410 if (dev_state->use_mouse)
411 {
412 MOUSE_EVENT_RECORD& mouse_event = input_rec.Event.MouseEvent;
413
414 /* Treat the double-click event like a regular button press */
415 if (mouse_event.dwEventFlags == DOUBLE_CLICK)
416 {
417 syscall_printf ("mouse: double-click -> click");
418 mouse_event.dwEventFlags = 0;
419 }
420
421 /* Did something other than a click occur? */
422 if (mouse_event.dwEventFlags)
423 continue;
424
425 /* If the mouse event occurred out of the area we can handle,
426 ignore it. */
427 int x = mouse_event.dwMousePosition.X;
428 int y = mouse_event.dwMousePosition.Y;
429 if ((x + ' ' + 1 > 0xFF) || (y + ' ' + 1 > 0xFF))
430 {
431 syscall_printf ("mouse: position out of range");
432 continue;
433 }
434
435 /* Ignore unimportant mouse buttons */
436 mouse_event.dwButtonState &= 0x7;
437
438 /* This code assumes Windows never reports multiple button
439 events at the same time. */
440 int b = 0;
441 char sz[32];
442 if (mouse_event.dwButtonState == dev_state->dwLastButtonState)
443 {
444 syscall_printf ("mouse: button state unchanged");
445 continue;
446 }
447 else if (mouse_event.dwButtonState < dev_state->dwLastButtonState)
448 {
449 b = 3;
450 strcpy (sz, "btn up");
451 }
452 else if ((mouse_event.dwButtonState & 1) != (dev_state->dwLastButtonState & 1))
453 {
454 b = 0;
455 strcpy (sz, "btn1 down");
456 }
457 else if ((mouse_event.dwButtonState & 2) != (dev_state->dwLastButtonState & 2))
458 {
459 b = 2;
460 strcpy (sz, "btn2 down");
461 }
462 else if ((mouse_event.dwButtonState & 4) != (dev_state->dwLastButtonState & 4))
463 {
464 b = 1;
465 strcpy (sz, "btn3 down");
466 }
467
468 /* Remember the current button state */
469 dev_state->dwLastButtonState = mouse_event.dwButtonState;
470
471 /* If a button was pressed, remember the modifiers */
472 if (b != 3)
473 {
474 dev_state->nModifiers = 0;
475 if (mouse_event.dwControlKeyState & SHIFT_PRESSED)
476 dev_state->nModifiers |= 0x4;
477 if (mouse_event.dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED))
478 dev_state->nModifiers |= 0x8;
479 if (mouse_event.dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED))
480 dev_state->nModifiers |= 0x10;
481 }
482
483 b |= dev_state->nModifiers;
484
485 /* We can now create the code. */
486 sprintf (tmp, "\033[M%c%c%c", b + ' ', x + ' ' + 1, y + ' ' + 1);
487 syscall_printf ("mouse: %s at (%d,%d)", sz, x, y);
488
489 toadd = tmp;
490 nread = 6;
491 }
492 break;
493
494 case FOCUS_EVENT:
495 case WINDOW_BUFFER_SIZE_EVENT:
496 send_winch_maybe ();
497 /* fall through */
498 default:
499 continue;
500 }
501
502 if (toadd)
503 {
504 line_edit_status res = line_edit (toadd, nread, ti);
505 if (res == line_edit_signalled)
506 goto sig_exit;
507 else if (res == line_edit_input_done)
508 break;
509 }
510 #undef ich
511 }
512
513 while (buflen)
514 if ((ch = get_readahead ()) < 0)
515 break;
516 else
517 {
518 buf[copied_chars++] = (unsigned char)(ch & 0xff);
519 buflen--;
520 }
521 #undef buf
522
523 buflen = copied_chars;
524 return;
525
526 err:
527 __seterrno ();
528 buflen = (size_t) -1;
529 return;
530
531 sig_exit:
532 set_sig_errno (EINTR);
533 buflen = (size_t) -1;
534 return;
535 }
536
537 void
538 fhandler_console::set_input_state ()
539 {
540 if (tc->rstcons ())
541 input_tcsetattr (0, &tc->ti);
542 }
543
544 bool
545 fhandler_console::fillin_info (void)
546 {
547 bool ret;
548 CONSOLE_SCREEN_BUFFER_INFO linfo;
549
550 if ((ret = GetConsoleScreenBufferInfo (get_output_handle (), &linfo)))
551 {
552 dev_state->info.winTop = linfo.srWindow.Top;
553 dev_state->info.winBottom = linfo.srWindow.Bottom;
554 dev_state->info.dwWinSize.Y = 1 + linfo.srWindow.Bottom - linfo.srWindow.Top;
555 dev_state->info.dwWinSize.X = 1 + linfo.srWindow.Right - linfo.srWindow.Left;
556 dev_state->info.dwBufferSize = linfo.dwSize;
557 dev_state->info.dwCursorPosition = linfo.dwCursorPosition;
558 dev_state->info.wAttributes = linfo.wAttributes;
559 }
560 else
561 {
562 memset (&dev_state->info, 0, sizeof dev_state->info);
563 dev_state->info.dwWinSize.Y = 25;
564 dev_state->info.dwWinSize.X = 80;
565 dev_state->info.winBottom = 24;
566 }
567
568 return ret;
569 }
570
571 void
572 fhandler_console::scroll_screen (int x1, int y1, int x2, int y2, int xn, int yn)
573 {
574 SMALL_RECT sr1, sr2;
575 CHAR_INFO fill;
576 COORD dest;
577
578 (void) fillin_info ();
579 sr1.Left = x1 >= 0 ? x1 : dev_state->info.dwWinSize.X - 1;
580 if (y1 == 0)
581 sr1.Top = dev_state->info.winTop;
582 else
583 sr1.Top = y1 > 0 ? y1 : dev_state->info.winBottom;
584 sr1.Right = x2 >= 0 ? x2 : dev_state->info.dwWinSize.X - 1;
585 if (y2 == 0)
586 sr1.Bottom = dev_state->info.winTop;
587 else
588 sr1.Bottom = y2 > 0 ? y2 : dev_state->info.winBottom;
589 sr2.Top = srTop;
590 sr2.Left = 0;
591 sr2.Bottom = srBottom;
592 sr2.Right = dev_state->info.dwWinSize.X - 1;
593 if (sr1.Bottom > sr2.Bottom && sr1.Top <= sr2.Bottom)
594 sr1.Bottom = sr2.Bottom;
595 dest.X = xn >= 0 ? xn : dev_state->info.dwWinSize.X - 1;
596 if (yn == 0)
597 dest.Y = dev_state->info.winTop;
598 else
599 dest.Y = yn > 0 ? yn : dev_state->info.winBottom;
600 fill.Char.AsciiChar = ' ';
601 fill.Attributes = dev_state->current_win32_attr;
602 ScrollConsoleScreenBuffer (get_output_handle (), &sr1, &sr2, dest, &fill);
603
604 /* ScrollConsoleScreenBuffer on Windows 95 is buggy - when scroll distance
605 * is more than half of screen, filling doesn't work as expected */
606
607 if (sr1.Top != sr1.Bottom)
608 if (dest.Y <= sr1.Top) /* forward scroll */
609 clear_screen (0, 1 + dest.Y + sr1.Bottom - sr1.Top, sr2.Right, sr2.Bottom);
610 else /* reverse scroll */
611 clear_screen (0, sr1.Top, sr2.Right, dest.Y - 1);
612 }
613
614 int
615 fhandler_console::open (int flags, mode_t)
616 {
617 HANDLE h;
618
619 tcinit (get_tty_stuff (flags));
620
621 set_io_handle (NULL);
622 set_output_handle (NULL);
623
624 set_flags ((flags & ~O_TEXT) | O_BINARY);
625
626 /* Open the input handle as handle_ */
627 h = CreateFile ("CONIN$", GENERIC_READ | GENERIC_WRITE,
628 FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none,
629 OPEN_EXISTING, 0, 0);
630
631 if (h == INVALID_HANDLE_VALUE)
632 {
633 __seterrno ();
634 return 0;
635 }
636 set_io_handle (h);
637 uninterruptible_io (true); // Handled explicitly in read code
638
639 h = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE,
640 FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none,
641 OPEN_EXISTING, 0, 0);
642
643 if (h == INVALID_HANDLE_VALUE)
644 {
645 __seterrno ();
646 return 0;
647 }
648 set_output_handle (h);
649
650 if (fillin_info ())
651 dev_state->default_color = dev_state->info.wAttributes;
652
653 set_default_attr ();
654
655 DWORD cflags;
656 if (GetConsoleMode (get_io_handle (), &cflags))
657 {
658 cflags |= ENABLE_PROCESSED_INPUT;
659 SetConsoleMode (get_io_handle (), ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT | cflags);
660 }
661
662 tc->rstcons (false);
663 set_open_status ();
664 cygheap->open_fhs++;
665 debug_printf ("incremented open_fhs, now %d", cygheap->open_fhs);
666 debug_printf ("opened conin$ %p, conout$ %p", get_io_handle (),
667 get_output_handle ());
668
669 return 1;
670 }
671
672 int
673 fhandler_console::close (void)
674 {
675 CloseHandle (get_io_handle ());
676 CloseHandle (get_output_handle ());
677 set_io_handle (NULL);
678 set_output_handle (NULL);
679 if (--(cygheap->open_fhs) <= 0 && myself->ctty != TTY_CONSOLE)
680 {
681 syscall_printf ("open_fhs %d", cygheap->open_fhs);
682 FreeConsole ();
683 }
684 debug_printf ("decremented open_fhs, now %d", cygheap->open_fhs);
685 return 0;
686 }
687
688 /*
689 * Special console dup to duplicate input and output
690 * handles.
691 */
692
693 int
694 fhandler_console::dup (fhandler_base *child)
695 {
696 fhandler_console *fhc = (fhandler_console *) child;
697
698 if (!fhc->open (get_flags () & ~O_NOCTTY, 0))
699 system_printf ("error opening console, %E");
700
701 return 0;
702 }
703
704 int
705 fhandler_console::ioctl (unsigned int cmd, void *buf)
706 {
707 switch (cmd)
708 {
709 case TIOCGWINSZ:
710 int st;
711
712 st = fillin_info ();
713 if (st)
714 {
715 /* *not* the buffer size, the actual screen size... */
716 /* based on Left Top Right Bottom of srWindow */
717 ((struct winsize *) buf)->ws_row = dev_state->info.dwWinSize.Y;
718 ((struct winsize *) buf)->ws_col = dev_state->info.dwWinSize.X;
719 syscall_printf ("WINSZ: (row=%d,col=%d)",
720 ((struct winsize *) buf)->ws_row,
721 ((struct winsize *) buf)->ws_col);
722 return 0;
723 }
724 else
725 {
726 syscall_printf ("WINSZ failed");
727 __seterrno ();
728 return -1;
729 }
730 return 0;
731 case TIOCSWINSZ:
732 (void) bg_check (SIGTTOU);
733 return 0;
734 case TIOCLINUX:
735 if (* (int *) buf == 6)
736 {
737 * (int *) buf = dev_state->nModifiers;
738 return 0;
739 }
740 else
741 {
742 set_errno (EINVAL);
743 return -1;
744 }
745 }
746
747 return fhandler_base::ioctl (cmd, buf);
748 }
749
750 int
751 fhandler_console::tcflush (int queue)
752 {
753 int res = 0;
754 if (queue == TCIFLUSH
755 || queue == TCIOFLUSH)
756 {
757 if (!FlushConsoleInputBuffer (get_io_handle ()))
758 {
759 __seterrno ();
760 res = -1;
761 }
762 }
763 return res;
764 }
765
766 int
767 fhandler_console::output_tcsetattr (int, struct termios const *t)
768 {
769 /* All the output bits we can ignore */
770
771 DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
772
773 int res = SetConsoleMode (get_output_handle (), flags) ? 0 : -1;
774 syscall_printf ("%d = tcsetattr (,%x) (ENABLE FLAGS %x) (lflag %x oflag %x)",
775 res, t, flags, t->c_lflag, t->c_oflag);
776 return res;
777 }
778
779 int
780 fhandler_console::input_tcsetattr (int, struct termios const *t)
781 {
782 /* Ignore the optional_actions stuff, since all output is emitted
783 instantly */
784
785 DWORD oflags;
786
787 if (!GetConsoleMode (get_io_handle (), &oflags))
788 oflags = 0;
789 DWORD flags = 0;
790
791 #if 0
792 /* Enable/disable LF -> CRLF conversions */
793 rbinary ((t->c_iflag & INLCR) ? false : true);
794 #endif
795
796 /* There's some disparity between what we need and what's
797 available. We've got ECHO and ICANON, they've
798 got ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT. */
799
800 tc->ti = *t;
801
802 if (t->c_lflag & ECHO)
803 {
804 flags |= ENABLE_ECHO_INPUT;
805 }
806 if (t->c_lflag & ICANON)
807 {
808 flags |= ENABLE_LINE_INPUT;
809 }
810
811 if (flags & ENABLE_ECHO_INPUT
812 && !(flags & ENABLE_LINE_INPUT))
813 {
814 /* This is illegal, so turn off the echo here, and fake it
815 when we read the characters */
816
817 flags &= ~ENABLE_ECHO_INPUT;
818 }
819
820 if (t->c_lflag & ISIG)
821 {
822 flags |= ENABLE_PROCESSED_INPUT;
823 }
824
825 if (use_tty)
826 {
827 flags = 0; // ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
828 tc->ti.c_iflag = 0;
829 tc->ti.c_lflag = 0;
830 }
831
832 flags |= ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT;
833
834 int res;
835 if (flags == oflags)
836 res = 0;
837 else
838 {
839 res = SetConsoleMode (get_io_handle (), flags) ? 0 : -1;
840 if (res < 0)
841 __seterrno ();
842 syscall_printf ("%d = tcsetattr (,%x) enable flags %p, c_lflag %p iflag %p",
843 res, t, flags, t->c_lflag, t->c_iflag);
844 }
845
846 tc->rstcons (false);
847 return res;
848 }
849
850 int
851 fhandler_console::tcsetattr (int a, struct termios const *t)
852 {
853 int res = output_tcsetattr (a, t);
854 if (res != 0)
855 return res;
856 return input_tcsetattr (a, t);
857 }
858
859 int
860 fhandler_console::tcgetattr (struct termios *t)
861 {
862 int res;
863 *t = tc->ti;
864
865 t->c_cflag |= CS8;
866
867 DWORD flags;
868
869 if (!GetConsoleMode (get_io_handle (), &flags))
870 {
871 __seterrno ();
872 res = -1;
873 }
874 else
875 {
876 if (flags & ENABLE_ECHO_INPUT)
877 t->c_lflag |= ECHO;
878
879 if (flags & ENABLE_LINE_INPUT)
880 t->c_lflag |= ICANON;
881
882 if (flags & ENABLE_PROCESSED_INPUT)
883 t->c_lflag |= ISIG;
884
885 /* What about ENABLE_WINDOW_INPUT
886 and ENABLE_MOUSE_INPUT ? */
887
888 /* All the output bits we can ignore */
889 res = 0;
890 }
891 syscall_printf ("%d = tcgetattr (%p) enable flags %p, t->lflag %p, t->iflag %p",
892 res, t, flags, t->c_lflag, t->c_iflag);
893 return res;
894 }
895
896 fhandler_console::fhandler_console () :
897 fhandler_termios ()
898 {
899 }
900
901 #define FOREGROUND_ATTR_MASK (FOREGROUND_RED | FOREGROUND_GREEN | \
902 FOREGROUND_BLUE | FOREGROUND_INTENSITY)
903 #define BACKGROUND_ATTR_MASK (BACKGROUND_RED | BACKGROUND_GREEN | \
904 BACKGROUND_BLUE | BACKGROUND_INTENSITY)
905 void
906 fhandler_console::set_default_attr ()
907 {
908 dev_state->blink = dev_state->underline = dev_state->reverse = false;
909 dev_state->intensity = INTENSITY_NORMAL;
910 dev_state->fg = dev_state->default_color & FOREGROUND_ATTR_MASK;
911 dev_state->bg = dev_state->default_color & BACKGROUND_ATTR_MASK;
912 dev_state->current_win32_attr = get_win32_attr ();
913 SetConsoleTextAttribute (get_output_handle (), dev_state->current_win32_attr);
914 }
915
916 WORD
917 fhandler_console::get_win32_attr ()
918 {
919 WORD win_fg = dev_state->fg;
920 WORD win_bg = dev_state->bg;
921 if (dev_state->reverse)
922 {
923 WORD save_fg = win_fg;
924 win_fg = (win_bg & BACKGROUND_RED ? FOREGROUND_RED : 0) |
925 (win_bg & BACKGROUND_GREEN ? FOREGROUND_GREEN : 0) |
926 (win_bg & BACKGROUND_BLUE ? FOREGROUND_BLUE : 0) |
927 (win_fg & FOREGROUND_INTENSITY);
928 win_bg = (save_fg & FOREGROUND_RED ? BACKGROUND_RED : 0) |
929 (save_fg & FOREGROUND_GREEN ? BACKGROUND_GREEN : 0) |
930 (save_fg & FOREGROUND_BLUE ? BACKGROUND_BLUE : 0) |
931 (win_bg & BACKGROUND_INTENSITY);
932 }
933 if (dev_state->underline)
934 win_fg = dev_state->underline_color;
935 /* emulate blink with bright background */
936 if (dev_state->blink)
937 win_bg |= BACKGROUND_INTENSITY;
938 if (dev_state->intensity == INTENSITY_INVISIBLE)
939 win_fg = win_bg;
940 else if (dev_state->intensity == INTENSITY_BOLD)
941 win_fg |= FOREGROUND_INTENSITY;
942 return (win_fg | win_bg);
943 }
944
945 /*
946 * Clear the screen context from x1/y1 to x2/y2 cell.
947 * Negative values represents current screen dimensions
948 */
949 void
950 fhandler_console::clear_screen (int x1, int y1, int x2, int y2)
951 {
952 COORD tlc;
953 DWORD done;
954 int num;
955
956 (void)fillin_info ();
957
958 if (x1 < 0)
959 x1 = dev_state->info.dwWinSize.X - 1;
960 if (y1 < 0)
961 y1 = dev_state->info.winBottom;
962 if (x2 < 0)
963 x2 = dev_state->info.dwWinSize.X - 1;
964 if (y2 < 0)
965 y2 = dev_state->info.winBottom;
966
967 num = abs (y1 - y2) * dev_state->info.dwBufferSize.X + abs (x1 - x2) + 1;
968
969 if ((y2 * dev_state->info.dwBufferSize.X + x2) > (y1 * dev_state->info.dwBufferSize.X + x1))
970 {
971 tlc.X = x1;
972 tlc.Y = y1;
973 }
974 else
975 {
976 tlc.X = x2;
977 tlc.Y = y2;
978 }
979 FillConsoleOutputCharacterA (get_output_handle (), ' ',
980 num,
981 tlc,
982 &done);
983 FillConsoleOutputAttribute (get_output_handle (),
984 dev_state->current_win32_attr,
985 num,
986 tlc,
987 &done);
988 }
989
990 void
991 fhandler_console::cursor_set (bool rel_to_top, int x, int y)
992 {
993 COORD pos;
994
995 (void) fillin_info ();
996 if (y > dev_state->info.winBottom)
997 y = dev_state->info.winBottom;
998 else if (y < 0)
999 y = 0;
1000 else if (rel_to_top)
1001 y += dev_state->info.winTop;
1002
1003 if (x > dev_state->info.dwWinSize.X)
1004 x = dev_state->info.dwWinSize.X - 1;
1005 else if (x < 0)
1006 x = 0;
1007
1008 pos.X = x;
1009 pos.Y = y;
1010 SetConsoleCursorPosition (get_output_handle (), pos);
1011 }
1012
1013 void
1014 fhandler_console::cursor_rel (int x, int y)
1015 {
1016 fillin_info ();
1017 x += dev_state->info.dwCursorPosition.X;
1018 y += dev_state->info.dwCursorPosition.Y;
1019 cursor_set (false, x, y);
1020 }
1021
1022 void
1023 fhandler_console::cursor_get (int *x, int *y)
1024 {
1025 fillin_info ();
1026 *y = dev_state->info.dwCursorPosition.Y;
1027 *x = dev_state->info.dwCursorPosition.X;
1028 }
1029
1030 #define BAK 1
1031 #define ESC 2
1032 #define NOR 0
1033 #define IGN 4
1034 #if 0
1035 #define ERR 5
1036 #else
1037 #define ERR NOR
1038 #endif
1039 #define DWN 6
1040 #define BEL 7
1041 #define TAB 8 /* We should't let the console deal with these */
1042 #define CR 13
1043 #define LF 10
1044
1045 static const char base_chars[256] =
1046 {
1047 /*00 01 02 03 04 05 06 07 */ IGN, ERR, ERR, NOR, NOR, NOR, NOR, BEL,
1048 /*08 09 0A 0B 0C 0D 0E 0F */ BAK, TAB, DWN, ERR, ERR, CR, ERR, IGN,
1049 /*10 11 12 13 14 15 16 17 */ NOR, NOR, ERR, ERR, ERR, ERR, ERR, ERR,
1050 /*18 19 1A 1B 1C 1D 1E 1F */ NOR, NOR, ERR, ESC, ERR, ERR, ERR, ERR,
1051 /* ! " # $ % & ' */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1052 /*() * + , - . / */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1053 /*0 1 2 3 4 5 6 7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1054 /*8 9 : ; < = > ? */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1055 /*@ A B C D E F G */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1056 /*H I J K L M N O */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1057 /*P Q R S T U V W */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1058 /*X Y Z [ \ ] ^ _ */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1059 /*` a b c d e f g */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1060 /*h i j k l m n o */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1061 /*p q r s t u v w */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1062 /*x y z { | } ~ 7F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1063 /*80 81 82 83 84 85 86 87 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1064 /*88 89 8A 8B 8C 8D 8E 8F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1065 /*90 91 92 93 94 95 96 97 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1066 /*98 99 9A 9B 9C 9D 9E 9F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1067 /*A0 A1 A2 A3 A4 A5 A6 A7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1068 /*A8 A9 AA AB AC AD AE AF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1069 /*B0 B1 B2 B3 B4 B5 B6 B7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1070 /*B8 B9 BA BB BC BD BE BF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1071 /*C0 C1 C2 C3 C4 C5 C6 C7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1072 /*C8 C9 CA CB CC CD CE CF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1073 /*D0 D1 D2 D3 D4 D5 D6 D7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1074 /*D8 D9 DA DB DC DD DE DF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1075 /*E0 E1 E2 E3 E4 E5 E6 E7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1076 /*E8 E9 EA EB EC ED EE EF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1077 /*F0 F1 F2 F3 F4 F5 F6 F7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
1078 /*F8 F9 FA FB FC FD FE FF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR };
1079
1080 void
1081 fhandler_console::char_command (char c)
1082 {
1083 int x, y;
1084 char buf[40];
1085
1086 switch (c)
1087 {
1088 case 'm': /* Set Graphics Rendition */
1089 int i;
1090
1091 for (i = 0; i <= dev_state->nargs_; i++)
1092 switch (dev_state->args_[i])
1093 {
1094 case 0: /* normal color */
1095 set_default_attr ();
1096 break;
1097 case 1: /* bold */
1098 dev_state->intensity = INTENSITY_BOLD;
1099 break;
1100 case 4:
1101 dev_state->underline = 1;
1102 break;
1103 case 5: /* blink mode */
1104 dev_state->blink = true;
1105 break;
1106 case 7: /* reverse */
1107 dev_state->reverse = true;
1108 break;
1109 case 8: /* invisible */
1110 dev_state->intensity = INTENSITY_INVISIBLE;
1111 break;
1112 case 9: /* dim */
1113 dev_state->intensity = INTENSITY_DIM;
1114 break;
1115 case 10: /* end alternate charset */
1116 dev_state->alternate_charset_active = false;
1117 break;
1118 case 11: /* start alternate charset */
1119 dev_state->alternate_charset_active = true;
1120 break;
1121 case 24:
1122 dev_state->underline = false;
1123 break;
1124 case 27:
1125 dev_state->reverse = false;
1126 break;
1127 case 30: /* BLACK foreground */
1128 dev_state->fg = 0;
1129 break;
1130 case 31: /* RED foreground */
1131 dev_state->fg = FOREGROUND_RED;
1132 break;
1133 case 32: /* GREEN foreground */
1134 dev_state->fg = FOREGROUND_GREEN;
1135 break;
1136 case 33: /* YELLOW foreground */
1137 dev_state->fg = FOREGROUND_RED | FOREGROUND_GREEN;
1138 break;
1139 case 34: /* BLUE foreground */
1140 dev_state->fg = FOREGROUND_BLUE;
1141 break;
1142 case 35: /* MAGENTA foreground */
1143 dev_state->fg = FOREGROUND_RED | FOREGROUND_BLUE;
1144 break;
1145 case 36: /* CYAN foreground */
1146 dev_state->fg = FOREGROUND_BLUE | FOREGROUND_GREEN;
1147 break;
1148 case 37: /* WHITE foreg */
1149 dev_state->fg = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
1150 break;
1151 case 39:
1152 dev_state->fg = dev_state->default_color & FOREGROUND_ATTR_MASK;
1153 break;
1154 case 40: /* BLACK background */
1155 dev_state->bg = 0;
1156 break;
1157 case 41: /* RED background */
1158 dev_state->bg = BACKGROUND_RED;
1159 break;
1160 case 42: /* GREEN background */
1161 dev_state->bg = BACKGROUND_GREEN;
1162 break;
1163 case 43: /* YELLOW background */
1164 dev_state->bg = BACKGROUND_RED | BACKGROUND_GREEN;
1165 break;
1166 case 44: /* BLUE background */
1167 dev_state->bg = BACKGROUND_BLUE;
1168 break;
1169 case 45: /* MAGENTA background */
1170 dev_state->bg = BACKGROUND_RED | BACKGROUND_BLUE;
1171 break;
1172 case 46: /* CYAN background */
1173 dev_state->bg = BACKGROUND_BLUE | BACKGROUND_GREEN;
1174 break;
1175 case 47: /* WHITE background */
1176 dev_state->bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
1177 break;
1178 case 49:
1179 dev_state->bg = dev_state->default_color & BACKGROUND_ATTR_MASK;
1180 break;
1181 }
1182 dev_state->current_win32_attr = get_win32_attr ();
1183 SetConsoleTextAttribute (get_output_handle (), dev_state->current_win32_attr);
1184 break;
1185 case 'h':
1186 case 'l':
1187 if (!dev_state->saw_question_mark)
1188 {
1189 switch (dev_state->args_[0])
1190 {
1191 case 4: /* Insert mode */
1192 dev_state->insert_mode = (c == 'h') ? true : false;
1193 syscall_printf ("insert mode %sabled", dev_state->insert_mode ? "en" : "dis");
1194 break;
1195 }
1196 break;
1197 }
1198 switch (dev_state->args_[0])
1199 {
1200 case 47: /* Save/Restore screen */
1201 if (c == 'h') /* save */
1202 {
1203 CONSOLE_SCREEN_BUFFER_INFO now;
1204 COORD cob = { 0, 0 };
1205
1206 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now))
1207 break;
1208
1209 dev_state->savebufsiz.X = now.srWindow.Right - now.srWindow.Left + 1;
1210 dev_state->savebufsiz.Y = now.srWindow.Bottom - now.srWindow.Top + 1;
1211
1212 if (dev_state->savebuf)
1213 cfree (dev_state->savebuf);
1214 dev_state->savebuf = (PCHAR_INFO) cmalloc (HEAP_1_BUF, sizeof (CHAR_INFO) *
1215 dev_state->savebufsiz.X * dev_state->savebufsiz.Y);
1216
1217 ReadConsoleOutputA (get_output_handle (), dev_state->savebuf,
1218 dev_state->savebufsiz, cob, &now.srWindow);
1219 }
1220 else /* restore */
1221 {
1222 CONSOLE_SCREEN_BUFFER_INFO now;
1223 COORD cob = { 0, 0 };
1224
1225 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now))
1226 break;
1227
1228 if (!dev_state->savebuf)
1229 break;
1230
1231 WriteConsoleOutputA (get_output_handle (), dev_state->savebuf,
1232 dev_state->savebufsiz, cob, &now.srWindow);
1233
1234 cfree (dev_state->savebuf);
1235 dev_state->savebuf = NULL;
1236 dev_state->savebufsiz.X = dev_state->savebufsiz.Y = 0;
1237 }
1238 break;
1239
1240 case 1000: /* Mouse support */
1241 dev_state->use_mouse = (c == 'h') ? true : false;
1242 syscall_printf ("mouse support %sabled", dev_state->use_mouse ? "en" : "dis");
1243 break;
1244
1245 case 2000: /* Raw keyboard mode */
1246 set_raw_win32_keyboard_mode ((c == 'h') ? true : false);
1247 break;
1248
1249 default: /* Ignore */
1250 syscall_printf ("unknown h/l command: %d", dev_state->args_[0]);
1251 break;
1252 }
1253 break;
1254 case 'J':
1255 switch (dev_state->args_[0])
1256 {
1257 case 0: /* Clear to end of screen */
1258 cursor_get (&x, &y);
1259 clear_screen (x, y, -1, -1);
1260 break;
1261 case 1: /* Clear from beginning of screen to cursor */
1262 cursor_get (&x, &y);
1263 clear_screen (0, 0, x, y);
1264 break;
1265 case 2: /* Clear screen */
1266 clear_screen (0, 0, -1, -1);
1267 cursor_set (true, 0,0);
1268 break;
1269 default:
1270 goto bad_escape;
1271 }
1272 break;
1273
1274 case 'A':
1275 cursor_rel (0, -(dev_state->args_[0] ? dev_state->args_[0] : 1));
1276 break;
1277 case 'B':
1278 cursor_rel (0, dev_state->args_[0] ? dev_state->args_[0] : 1);
1279 break;
1280 case 'C':
1281 cursor_rel (dev_state->args_[0] ? dev_state->args_[0] : 1, 0);
1282 break;
1283 case 'D':
1284 cursor_rel (-(dev_state->args_[0] ? dev_state->args_[0] : 1),0);
1285 break;
1286 case 'K':
1287 switch (dev_state->args_[0])
1288 {
1289 case 0: /* Clear to end of line */
1290 cursor_get (&x, &y);
1291 clear_screen (x, y, -1, y);
1292 break;
1293 case 2: /* Clear line */
1294 cursor_get (&x, &y);
1295 clear_screen (0, y, -1, y);
1296 break;
1297 case 1: /* Clear from bol to cursor */
1298 cursor_get (&x, &y);
1299 clear_screen (0, y, x, y);
1300 break;
1301 default:
1302 goto bad_escape;
1303 }
1304 break;
1305 case 'H':
1306 case 'f':
1307 cursor_set (true, (dev_state->args_[1] ? dev_state->args_[1] : 1) - 1,
1308 (dev_state->args_[0] ? dev_state->args_[0] : 1) - 1);
1309 break;
1310 case 'G': /* hpa - position cursor at column n - 1 */
1311 cursor_get (&x, &y);
1312 cursor_set (false, (dev_state->args_[0] ? dev_state->args_[0] - 1 : 0), y);
1313 break;
1314 case 'd': /* vpa - position cursor at line n */
1315 cursor_get (&x, &y);
1316 cursor_set (true, x, (dev_state->args_[0] ? dev_state->args_[0] - 1 : 0));
1317 break;
1318 case 's': /* Save cursor position */
1319 cursor_get (&dev_state->savex, &dev_state->savey);
1320 dev_state->savey -= dev_state->info.winTop;
1321 break;
1322 case 'u': /* Restore cursor position */
1323 cursor_set (true, dev_state->savex, dev_state->savey);
1324 break;
1325 case 'I': /* TAB */
1326 cursor_get (&x, &y);
1327 cursor_set (false, 8 * (x / 8 + 1), y);
1328 break;
1329 case 'L': /* AL - insert blank lines */
1330 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1331 cursor_get (&x, &y);
1332 scroll_screen (0, y, -1, -1, 0, y + dev_state->args_[0]);
1333 break;
1334 case 'M': /* DL - delete lines */
1335 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1336 cursor_get (&x, &y);
1337 scroll_screen (0, y + dev_state->args_[0], -1, -1, 0, y);
1338 break;
1339 case '@': /* IC - insert chars */
1340 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1341 cursor_get (&x, &y);
1342 scroll_screen (x, y, -1, y, x + dev_state->args_[0], y);
1343 break;
1344 case 'P': /* DC - delete chars */
1345 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1346 cursor_get (&x, &y);
1347 scroll_screen (x + dev_state->args_[0], y, -1, y, x, y);
1348 break;
1349 case 'S': /* SF - Scroll forward */
1350 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1351 scroll_screen (0, dev_state->args_[0], -1, -1, 0, 0);
1352 break;
1353 case 'T': /* SR - Scroll down */
1354 fillin_info ();
1355 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1356 scroll_screen (0, 0, -1, -1, 0, dev_state->info.winTop + dev_state->args_[0]);
1357 break;
1358 case 'X': /* ec - erase chars */
1359 dev_state->args_[0] = dev_state->args_[0] ? dev_state->args_[0] : 1;
1360 cursor_get (&x, &y);
1361 scroll_screen (x + dev_state->args_[0], y, -1, y, x, y);
1362 scroll_screen (x, y, -1, y, x + dev_state->args_[0], y);
1363 break;
1364 case 'Z': /* Back tab */
1365 cursor_get (&x, &y);
1366 cursor_set (false, ((8 * (x / 8 + 1)) - 8), y);
1367 break;
1368 case 'b': /* Repeat char #1 #2 times */
1369 if (dev_state->insert_mode)
1370 {
1371 cursor_get (&x, &y);
1372 scroll_screen (x, y, -1, y, x + dev_state->args_[1], y);
1373 }
1374 while (dev_state->args_[1]--)
1375 WriteFile (get_output_handle (), &dev_state->args_[0], 1, (DWORD *) &x, 0);
1376 break;
1377 case 'c': /* u9 - Terminal enquire string */
1378 strcpy (buf, "\033[?6c");
1379 puts_readahead (buf);
1380 break;
1381 case 'n':
1382 switch (dev_state->args_[0])
1383 {
1384 case 6: /* u7 - Cursor position request */
1385 cursor_get (&x, &y);
1386 y -= dev_state->info.winTop;
1387 /* x -= dev_state->info.winLeft; // not available yet */
1388 __small_sprintf (buf, "\033[%d;%dR", y + 1, x + 1);
1389 puts_readahead (buf);
1390 break;
1391 default:
1392 goto bad_escape;
1393 }
1394 break;
1395 case 'r': /* Set Scroll region */
1396 dev_state->scroll_region.Top = dev_state->args_[0] ? dev_state->args_[0] - 1 : 0;
1397 dev_state->scroll_region.Bottom = dev_state->args_[1] ? dev_state->args_[1] - 1 : -1;
1398 cursor_set (true, 0, 0);
1399 break;
1400 case 'g': /* TAB set/clear */
1401 break;
1402 default:
1403 bad_escape:
1404 break;
1405 }
1406 }
1407
1408 const unsigned char *
1409 fhandler_console::write_normal (const unsigned char *src,
1410 const unsigned char *end)
1411 {
1412 /* Scan forward to see what a char which needs special treatment */
1413 DWORD done;
1414 const unsigned char *found = src;
1415
1416 while (found < end)
1417 {
1418 if (base_chars[*found] != NOR)
1419 break;
1420 found++;
1421 }
1422
1423 /* Print all the base ones out */
1424 if (found != src)
1425 {
1426 DWORD len = found - src;
1427 do
1428 {
1429 DWORD buf_len;
1430 char buf[CONVERT_LIMIT];
1431 done = buf_len = min (sizeof (buf), len);
1432 if (!dev_state->str_to_con (buf, (const char *) src, buf_len))
1433 {
1434 debug_printf ("conversion error, handle %p",
1435 get_output_handle ());
1436 __seterrno ();
1437 return 0;
1438 }
1439
1440 if (dev_state->insert_mode)
1441 {
1442 int x, y;
1443 cursor_get (&x, &y);
1444 scroll_screen (x, y, -1, y, x + buf_len, y);
1445 }
1446
1447 if (!WriteFile (get_output_handle (), buf, buf_len, &done, 0))
1448 {
1449 debug_printf ("write failed, handle %p", get_output_handle ());
1450 __seterrno ();
1451 return 0;
1452 }
1453 len -= done;
1454 src += done;
1455 }
1456 while (len > 0);
1457 }
1458
1459 if (src < end)
1460 {
1461 int x, y;
1462 switch (base_chars[*src])
1463 {
1464 case BEL:
1465 MessageBeep (0xFFFFFFFF);
1466 break;
1467 case ESC:
1468 dev_state->state_ = gotesc;
1469 break;
1470 case DWN:
1471 cursor_get (&x, &y);
1472 if (y >= srBottom)
1473 {
1474 if (y >= dev_state->info.winBottom && !dev_state->scroll_region.Top)
1475 WriteFile (get_output_handle (), "\n", 1, &done, 0);
1476 else
1477 {
1478 scroll_screen (0, srTop + 1, -1, srBottom, 0, srTop);
1479 y--;
1480 }
1481 }
1482 cursor_set (false, ((tc->ti.c_oflag & ONLCR) ? 0 : x), y + 1);
1483 break;
1484 case BAK:
1485 cursor_rel (-1, 0);
1486 break;
1487 case IGN:
1488 cursor_rel (1, 0);
1489 break;
1490 case CR:
1491 cursor_get (&x, &y);
1492 cursor_set (false, 0, y);
1493 break;
1494 case ERR:
1495 WriteFile (get_output_handle (), src, 1, &done, 0);
1496 break;
1497 case TAB:
1498 cursor_get (&x, &y);
1499 cursor_set (false, 8 * (x / 8 + 1), y);
1500 break;
1501 }
1502 src ++;
1503 }
1504 return src;
1505 }
1506
1507 int
1508 fhandler_console::write (const void *vsrc, size_t len)
1509 {
1510 /* Run and check for ansi sequences */
1511 unsigned const char *src = (unsigned char *) vsrc;
1512 unsigned const char *end = src + len;
1513
1514 debug_printf ("%x, %d", vsrc, len);
1515
1516 while (src < end)
1517 {
1518 debug_printf ("at %d(%c) state is %d", *src, isprint (*src) ? *src : ' ',
1519 dev_state->state_);
1520 switch (dev_state->state_)
1521 {
1522 case normal:
1523 src = write_normal (src, end);
1524 if (!src) /* write_normal failed */
1525 return -1;
1526 break;
1527 case gotesc:
1528 if (*src == '[')
1529 {
1530 dev_state->state_ = gotsquare;
1531 dev_state->saw_question_mark = false;
1532 for (dev_state->nargs_ = 0; dev_state->nargs_ < MAXARGS; dev_state->nargs_++)
1533 dev_state->args_[dev_state->nargs_] = 0;
1534 dev_state->nargs_ = 0;
1535 }
1536 else if (*src == ']')
1537 {
1538 dev_state->rarg = 0;
1539 dev_state->my_title_buf[0] = '\0';
1540 dev_state->state_ = gotrsquare;
1541 }
1542 else if (*src == 'M') /* Reverse Index */
1543 {
1544 fillin_info ();
1545 scroll_screen (0, 0, -1, -1, 0, dev_state->info.winTop + 1);
1546 dev_state->state_ = normal;
1547 }
1548 else if (*src == 'c') /* Reset Linux terminal */
1549 {
1550 set_default_attr ();
1551 clear_screen (0, 0, -1, -1);
1552 cursor_set (true, 0, 0);
1553 dev_state->state_ = normal;
1554 }
1555 else if (*src == '8') /* Restore cursor position */
1556 {
1557 cursor_set (true, dev_state->savex, dev_state->savey);
1558 dev_state->state_ = normal;
1559 }
1560 else if (*src == '7') /* Save cursor position */
1561 {
1562 cursor_get (&dev_state->savex, &dev_state->savey);
1563 dev_state->savey -= dev_state->info.winTop;
1564 dev_state->state_ = normal;
1565 }
1566 else if (*src == 'R')
1567 dev_state->state_ = normal;
1568 else
1569 {
1570 dev_state->state_ = normal;
1571 }
1572 src++;
1573 break;
1574 case gotarg1:
1575 if (isdigit (*src))
1576 {
1577 dev_state->args_[dev_state->nargs_] = dev_state->args_[dev_state->nargs_] * 10 + *src - '0';
1578 src++;
1579 }
1580 else if (*src == ';')
1581 {
1582 src++;
1583 dev_state->nargs_++;
1584 if (dev_state->nargs_ >= MAXARGS)
1585 dev_state->nargs_--;
1586 }
1587 else
1588 {
1589 dev_state->state_ = gotcommand;
1590 }
1591 break;
1592 case gotcommand:
1593 char_command (*src++);
1594 dev_state->state_ = normal;
1595 break;
1596 case gotrsquare:
1597 if (isdigit (*src))
1598 dev_state->rarg = dev_state->rarg * 10 + (*src - '0');
1599 else if (*src == ';' && (dev_state->rarg == 2 || dev_state->rarg == 0))
1600 dev_state->state_ = gettitle;
1601 else
1602 dev_state->state_ = eattitle;
1603 src++;
1604 break;
1605 case eattitle:
1606 case gettitle:
1607 {
1608 int n = strlen (dev_state->my_title_buf);
1609 if (*src < ' ')
1610 {
1611 if (*src == '\007' && dev_state->state_ == gettitle)
1612 {
1613 if (old_title)
1614 strcpy (old_title, dev_state->my_title_buf);
1615 set_console_title (dev_state->my_title_buf);
1616 }
1617 dev_state->state_ = normal;
1618 }
1619 else if (n < TITLESIZE)
1620 {
1621 dev_state->my_title_buf[n++] = *src;
1622 dev_state->my_title_buf[n] = '\0';
1623 }
1624 src++;
1625 break;
1626 }
1627 case gotsquare:
1628 if (*src == ';')
1629 {
1630 dev_state->state_ = gotarg1;
1631 dev_state->nargs_++;
1632 src++;
1633 }
1634 else if (isalpha (*src))
1635 dev_state->state_ = gotcommand;
1636 else if (*src != '@' && !isalpha (*src) && !isdigit (*src))
1637 {
1638 if (*src == '?')
1639 dev_state->saw_question_mark = true;
1640 /* ignore any extra chars between [ and first arg or command */
1641 src++;
1642 }
1643 else
1644 dev_state->state_ = gotarg1;
1645 break;
1646 }
1647 }
1648
1649 syscall_printf ("%d = write_console (,..%d)", len, len);
1650
1651 return len;
1652 }
1653
1654 static struct {
1655 int vk;
1656 const char *val[4];
1657 } keytable[] NO_COPY = {
1658 /* NORMAL */ /* SHIFT */ /* CTRL */ /* ALT */
1659 {VK_LEFT, {"\033[D", "\033[D", "\033[D", "\033\033[D"}},
1660 {VK_RIGHT, {"\033[C", "\033[C", "\033[C", "\033\033[C"}},
1661 {VK_UP, {"\033[A", "\033[A", "\033[A", "\033\033[A"}},
1662 {VK_DOWN, {"\033[B", "\033[B", "\033[B", "\033\033[B"}},
1663 {VK_PRIOR, {"\033[5~", "\033[5~", "\033[5~", "\033\033[5~"}},
1664 {VK_NEXT, {"\033[6~", "\033[6~", "\033[6~", "\033\033[6~"}},
1665 {VK_HOME, {"\033[1~", "\033[1~", "\033[1~", "\033\033[1~"}},
1666 {VK_END, {"\033[4~", "\033[4~", "\033[4~", "\033\033[4~"}},
1667 {VK_INSERT, {"\033[2~", "\033[2~", "\033[2~", "\033\033[2~"}},
1668 {VK_DELETE, {"\033[3~", "\033[3~", "\033[3~", "\033\033[3~"}},
1669 {VK_F1, {"\033[[A", "\033[23~", NULL, NULL}},
1670 {VK_F2, {"\033[[B", "\033[24~", NULL, NULL}},
1671 {VK_F3, {"\033[[C", "\033[25~", NULL, NULL}},
1672 {VK_F4, {"\033[[D", "\033[26~", NULL, NULL}},
1673 {VK_F5, {"\033[[E", "\033[28~", NULL, NULL}},
1674 {VK_F6, {"\033[17~", "\033[29~", "\036", NULL}},
1675 {VK_F7, {"\033[18~", "\033[31~", NULL, NULL}},
1676 {VK_F8, {"\033[19~", "\033[32~", NULL, NULL}},
1677 {VK_F9, {"\033[20~", "\033[33~", NULL, NULL}},
1678 {VK_F10, {"\033[21~", "\033[34~", NULL, NULL}},
1679 {VK_F11, {"\033[23~", NULL, NULL, NULL}},
1680 {VK_F12, {"\033[24~", NULL, NULL, NULL}},
1681 {VK_NUMPAD5, {"\033[G", NULL, NULL, NULL}},
1682 {VK_CLEAR, {"\033[G", NULL, NULL, NULL}},
1683 {'6', {NULL, NULL, "\036", NULL}},
1684 {0, {"", NULL, NULL, NULL}}
1685 };
1686
1687 const char *
1688 get_nonascii_key (INPUT_RECORD& input_rec, char *tmp)
1689 {
1690 #define NORMAL 0
1691 #define SHIFT 1
1692 #define CONTROL 2
1693 #define ALT 3
1694 int modifier_index = NORMAL;
1695
1696 if (input_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
1697 modifier_index = SHIFT;
1698 else if (input_rec.Event.KeyEvent.dwControlKeyState &
1699 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
1700 modifier_index = CONTROL;
1701 else if (input_rec.Event.KeyEvent.dwControlKeyState &
1702 (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
1703 modifier_index = ALT;
1704
1705 for (int i = 0; keytable[i].vk; i++)
1706 if (input_rec.Event.KeyEvent.wVirtualKeyCode == keytable[i].vk)
1707 return keytable[i].val[modifier_index];
1708
1709 if (input_rec.Event.KeyEvent.uChar.AsciiChar)
1710 {
1711 tmp[0] = input_rec.Event.KeyEvent.uChar.AsciiChar;
1712 tmp[1] = '\0';
1713 return tmp;
1714 }
1715 return NULL;
1716 }
1717
1718 void
1719 fhandler_console::init (HANDLE f, DWORD a, mode_t bin)
1720 {
1721 // this->fhandler_termios::init (f, mode, bin);
1722 /* Ensure both input and output console handles are open */
1723 int flags = 0;
1724
1725 a &= GENERIC_READ | GENERIC_WRITE;
1726 if (a == GENERIC_READ)
1727 flags = O_RDONLY;
1728 if (a == GENERIC_WRITE)
1729 flags = O_WRONLY;
1730 if (a == (GENERIC_READ | GENERIC_WRITE))
1731 flags = O_RDWR;
1732 open (flags | O_BINARY);
1733 if (f != INVALID_HANDLE_VALUE)
1734 CloseHandle (f); /* Reopened by open */
1735
1736 tcsetattr (0, &tc->ti);
1737 }
1738
1739 int
1740 fhandler_console::igncr_enabled (void)
1741 {
1742 return tc->ti.c_iflag & IGNCR;
1743 }
1744
1745 void
1746 fhandler_console::set_close_on_exec (bool val)
1747 {
1748 fhandler_base::set_close_on_exec (val);
1749 set_no_inheritance (output_handle, val);
1750 }
1751
1752 void
1753 fhandler_console::fixup_after_fork (HANDLE)
1754 {
1755 HANDLE h = get_handle ();
1756 HANDLE oh = get_output_handle ();
1757
1758 /* Windows does not allow duplication of console handles between processes
1759 so open the console explicitly. */
1760
1761 cygheap->open_fhs--; /* The downside of storing this in cygheap. */
1762 if (!open (O_NOCTTY | get_flags (), 0))
1763 system_printf ("error opening console after fork, %E");
1764
1765 if (!close_on_exec ())
1766 {
1767 CloseHandle (h);
1768 CloseHandle (oh);
1769 }
1770 }
1771
1772 void __stdcall
1773 set_console_title (char *title)
1774 {
1775 int rc;
1776 char buf[257];
1777 strncpy (buf, title, sizeof (buf) - 1);
1778 buf[sizeof (buf) - 1] = '\0';
1779 if ((rc = WaitForSingleObject (tty_mutex, 15000)) != WAIT_OBJECT_0)
1780 sigproc_printf ("wait for title mutex failed rc %d, %E", rc);
1781 SetConsoleTitle (buf);
1782 ReleaseMutex (tty_mutex);
1783 debug_printf ("title '%s'", buf);
1784 }
1785
1786 void
1787 fhandler_console::fixup_after_exec ()
1788 {
1789 HANDLE h = get_handle ();
1790 HANDLE oh = get_output_handle ();
1791
1792 cygheap->open_fhs--; /* The downside of storing this in cygheap. */
1793 if (!open (O_NOCTTY | get_flags (), 0))
1794 {
1795 bool sawerr = false;
1796 if (!get_io_handle ())
1797 {
1798 system_printf ("error opening input console handle after exec, errno %d, %E", get_errno ());
1799 sawerr = true;
1800 }
1801 if (!get_output_handle ())
1802 {
1803 system_printf ("error opening output console handle after exec, errno %d, %E", get_errno ());
1804 sawerr = true;
1805 }
1806
1807 if (!sawerr)
1808 system_printf ("error opening console after exec, errno %d, %E", get_errno ());
1809 }
1810
1811 CloseHandle (h);
1812 CloseHandle (oh);
1813 return;
1814 }
This page took 0.119244 seconds and 5 git commands to generate.