3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 #include <sys/termios.h>
21 #include <sys/cygwin.h>
30 #include "shared_info.h"
31 #include "cygthread.h"
34 #define CONVERT_LIMIT 16384
37 cp_convert (UINT destcp
, char *dest
, UINT srccp
, const char *src
, DWORD size
)
41 else if (destcp
== srccp
)
44 memcpy (dest
, src
, size
);
48 WCHAR wbuffer
[CONVERT_LIMIT
]; /* same size as the maximum input, s.b. */
49 if (!MultiByteToWideChar (srccp
, 0, src
, size
, wbuffer
, sizeof (wbuffer
)))
51 if (!WideCharToMultiByte (destcp
, 0, wbuffer
, size
, dest
, size
,
59 * Scroll the screen context.
62 * xn, yn - new ul corner
63 * Negative values represents current screen dimensions
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)
69 #define use_tty ISSTATE (myself, PID_USETTY)
71 const char * get_nonascii_key (INPUT_RECORD
&, char *);
73 static console_state NO_COPY
*shared_console_info
;
75 dev_console NO_COPY
*fhandler_console::dev_state
;
77 /* Allocate and initialize the shared record for the current console.
78 Returns a pointer to shared_console_info. */
80 fhandler_console::get_tty_stuff (int flags
= 0)
83 return &shared_console_info
->tty_min_state
;
86 (console_state
*) open_shared (NULL
, 0, cygheap
->console_h
,
87 sizeof (*shared_console_info
),
89 dev_state
= &shared_console_info
->dev_state
;
91 ProtectHandleINH (cygheap
->console_h
);
92 if (!shared_console_info
->tty_min_state
.ntty
)
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
);
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
;
118 return &shared_console_info
->tty_min_state
;
124 (void) fhandler_console::get_tty_stuff ();
127 /* Return the tty structure associated with a given tty number. If the
128 tty number is < 0, just return a dummy record. */
130 tty_list::get_tty (int n
)
133 if (n
== TTY_CONSOLE
)
134 return fhandler_console::get_tty_stuff ();
136 return &cygwin_shared
->tty
.ttys
[n
];
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. */
146 set_console_state_for_spawn ()
148 HANDLE h
= CreateFile ("CONIN$", GENERIC_READ
, FILE_SHARE_WRITE
,
149 &sec_none_nih
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
,
152 if (h
== INVALID_HANDLE_VALUE
)
155 if (shared_console_info
!= NULL
)
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);
166 /* The results of GetConsoleCP() and GetConsoleOutputCP() cannot be
167 cached, because a program or the user can change these values at
170 dev_console::con_to_str (char *d
, const char *s
, DWORD sz
)
172 return cp_convert (get_cp (), d
, GetConsoleCP (), s
, sz
);
176 dev_console::str_to_con (char *d
, const char *s
, DWORD sz
)
178 if (alternate_charset_active
)
180 /* no translation when alternate charset is active */
184 return cp_convert (GetConsoleOutputCP (), d
, get_cp (), s
, sz
);
188 fhandler_console::set_raw_win32_keyboard_mode (bool new_mode
)
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");
197 fhandler_console::set_cursor_maybe ()
199 CONSOLE_SCREEN_BUFFER_INFO now
;
201 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now
))
204 if (dev_state
->dwLastCursorPosition
.X
!= now
.dwCursorPosition
.X
||
205 dev_state
->dwLastCursorPosition
.Y
!= now
.dwCursorPosition
.Y
)
207 SetConsoleCursorPosition (get_output_handle (), now
.dwCursorPosition
);
208 dev_state
->dwLastCursorPosition
= now
.dwCursorPosition
;
213 fhandler_console::send_winch_maybe ()
215 SHORT y
= dev_state
->info
.dwWinSize
.Y
;
216 SHORT x
= dev_state
->info
.dwWinSize
.X
;
219 if (y
!= dev_state
->info
.dwWinSize
.Y
|| x
!= dev_state
->info
.dwWinSize
.X
)
221 extern fhandler_tty_master
*tty_master
;
222 dev_state
->scroll_region
.Top
= 0;
223 dev_state
->scroll_region
.Bottom
= -1;
225 tty_master
->set_winsize (true);
227 tc
->kill_pgrp (SIGWINCH
);
232 fhandler_console::read (void *pv
, size_t& buflen
)
234 HANDLE h
= get_io_handle ();
236 #define buf ((char *) pv)
241 int copied_chars
= get_readahead_into_buffer (buf
, buflen
);
245 buflen
= copied_chars
;
254 if (&_my_tls
!= _main_tls
)
258 w4
[1] = signal_arrived
;
266 if ((bgres
= bg_check (SIGTTIN
)) <= bg_eof
)
272 set_cursor_maybe (); /* to make cursor appear on the screen immediately */
273 switch (WaitForMultipleObjects (nwait
, w4
, FALSE
, INFINITE
))
277 case WAIT_OBJECT_0
+ 1:
284 INPUT_RECORD input_rec
;
285 const char *toadd
= NULL
;
287 if (!ReadConsoleInput (h
, &input_rec
, 1, &nread
))
289 syscall_printf ("ReadConsoleInput failed, %E");
290 goto err
; /* seems to be failure */
293 /* check the event that occurred */
294 switch (input_rec
.EventType
)
297 #define virtual_key_code (input_rec.Event.KeyEvent.wVirtualKeyCode)
298 #define control_key_state (input_rec.Event.KeyEvent.dwControlKeyState)
300 dev_state
->nModifiers
= 0;
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
309 set_raw_win32_keyboard_mode (!dev_state
->raw_win32_keyboard_mode
);
314 if (dev_state
->raw_win32_keyboard_mode
)
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
);
324 nread
= strlen (toadd
);
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)
333 /* Ignore key up events, except for left alt events with non-zero character
335 if (!input_rec
.Event
.KeyEvent
.bKeyDown
&&
337 Event for left alt, with a non-zero character, comes from
338 "alt + numerics" key sequence.
339 e.g. <left-alt> 0233 => é
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))
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;
358 /* arrow/function keys */
359 (input_rec
.Event
.KeyEvent
.dwControlKeyState
& ENHANCED_KEY
))
361 toadd
= get_nonascii_key (input_rec
, tmp
);
364 dev_state
->nModifiers
= 0;
367 nread
= strlen (toadd
);
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. */
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));
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;
396 tmp
[1] = cyg_tolower (tmp
[1]);
399 dev_state
->nModifiers
&= ~4;
410 if (dev_state
->use_mouse
)
412 MOUSE_EVENT_RECORD
& mouse_event
= input_rec
.Event
.MouseEvent
;
414 /* Treat the double-click event like a regular button press */
415 if (mouse_event
.dwEventFlags
== DOUBLE_CLICK
)
417 syscall_printf ("mouse: double-click -> click");
418 mouse_event
.dwEventFlags
= 0;
421 /* Did something other than a click occur? */
422 if (mouse_event
.dwEventFlags
)
425 /* If the mouse event occurred out of the area we can handle,
427 int x
= mouse_event
.dwMousePosition
.X
;
428 int y
= mouse_event
.dwMousePosition
.Y
;
429 if ((x
+ ' ' + 1 > 0xFF) || (y
+ ' ' + 1 > 0xFF))
431 syscall_printf ("mouse: position out of range");
435 /* Ignore unimportant mouse buttons */
436 mouse_event
.dwButtonState
&= 0x7;
438 /* This code assumes Windows never reports multiple button
439 events at the same time. */
442 if (mouse_event
.dwButtonState
== dev_state
->dwLastButtonState
)
444 syscall_printf ("mouse: button state unchanged");
447 else if (mouse_event
.dwButtonState
< dev_state
->dwLastButtonState
)
450 strcpy (sz
, "btn up");
452 else if ((mouse_event
.dwButtonState
& 1) != (dev_state
->dwLastButtonState
& 1))
455 strcpy (sz
, "btn1 down");
457 else if ((mouse_event
.dwButtonState
& 2) != (dev_state
->dwLastButtonState
& 2))
460 strcpy (sz
, "btn2 down");
462 else if ((mouse_event
.dwButtonState
& 4) != (dev_state
->dwLastButtonState
& 4))
465 strcpy (sz
, "btn3 down");
468 /* Remember the current button state */
469 dev_state
->dwLastButtonState
= mouse_event
.dwButtonState
;
471 /* If a button was pressed, remember the modifiers */
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;
483 b
|= dev_state
->nModifiers
;
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
);
495 case WINDOW_BUFFER_SIZE_EVENT
:
504 line_edit_status res
= line_edit (toadd
, nread
, ti
);
505 if (res
== line_edit_signalled
)
507 else if (res
== line_edit_input_done
)
514 if ((ch
= get_readahead ()) < 0)
518 buf
[copied_chars
++] = (unsigned char)(ch
& 0xff);
523 buflen
= copied_chars
;
528 buflen
= (size_t) -1;
532 set_sig_errno (EINTR
);
533 buflen
= (size_t) -1;
538 fhandler_console::set_input_state ()
541 input_tcsetattr (0, &tc
->ti
);
545 fhandler_console::fillin_info (void)
548 CONSOLE_SCREEN_BUFFER_INFO linfo
;
550 if ((ret
= GetConsoleScreenBufferInfo (get_output_handle (), &linfo
)))
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
;
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;
572 fhandler_console::scroll_screen (int x1
, int y1
, int x2
, int y2
, int xn
, int yn
)
578 (void) fillin_info ();
579 sr1
.Left
= x1
>= 0 ? x1
: dev_state
->info
.dwWinSize
.X
- 1;
581 sr1
.Top
= dev_state
->info
.winTop
;
583 sr1
.Top
= y1
> 0 ? y1
: dev_state
->info
.winBottom
;
584 sr1
.Right
= x2
>= 0 ? x2
: dev_state
->info
.dwWinSize
.X
- 1;
586 sr1
.Bottom
= dev_state
->info
.winTop
;
588 sr1
.Bottom
= y2
> 0 ? y2
: dev_state
->info
.winBottom
;
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;
597 dest
.Y
= dev_state
->info
.winTop
;
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
);
604 /* ScrollConsoleScreenBuffer on Windows 95 is buggy - when scroll distance
605 * is more than half of screen, filling doesn't work as expected */
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);
615 fhandler_console::open (int flags
, mode_t
)
619 tcinit (get_tty_stuff (flags
));
621 set_io_handle (NULL
);
622 set_output_handle (NULL
);
624 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
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);
631 if (h
== INVALID_HANDLE_VALUE
)
637 uninterruptible_io (true); // Handled explicitly in read code
639 h
= CreateFile ("CONOUT$", GENERIC_READ
| GENERIC_WRITE
,
640 FILE_SHARE_READ
| FILE_SHARE_WRITE
, &sec_none
,
641 OPEN_EXISTING
, 0, 0);
643 if (h
== INVALID_HANDLE_VALUE
)
648 set_output_handle (h
);
651 dev_state
->default_color
= dev_state
->info
.wAttributes
;
656 if (GetConsoleMode (get_io_handle (), &cflags
))
658 cflags
|= ENABLE_PROCESSED_INPUT
;
659 SetConsoleMode (get_io_handle (), ENABLE_WINDOW_INPUT
| ENABLE_MOUSE_INPUT
| cflags
);
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 ());
673 fhandler_console::close (void)
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
)
681 syscall_printf ("open_fhs %d", cygheap
->open_fhs
);
684 debug_printf ("decremented open_fhs, now %d", cygheap
->open_fhs
);
689 * Special console dup to duplicate input and output
694 fhandler_console::dup (fhandler_base
*child
)
696 fhandler_console
*fhc
= (fhandler_console
*) child
;
698 if (!fhc
->open (get_flags () & ~O_NOCTTY
, 0))
699 system_printf ("error opening console, %E");
705 fhandler_console::ioctl (unsigned int cmd
, void *buf
)
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
);
726 syscall_printf ("WINSZ failed");
732 (void) bg_check (SIGTTOU
);
735 if (* (int *) buf
== 6)
737 * (int *) buf
= dev_state
->nModifiers
;
747 return fhandler_base::ioctl (cmd
, buf
);
751 fhandler_console::tcflush (int queue
)
754 if (queue
== TCIFLUSH
755 || queue
== TCIOFLUSH
)
757 if (!FlushConsoleInputBuffer (get_io_handle ()))
767 fhandler_console::output_tcsetattr (int, struct termios
const *t
)
769 /* All the output bits we can ignore */
771 DWORD flags
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
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
);
780 fhandler_console::input_tcsetattr (int, struct termios
const *t
)
782 /* Ignore the optional_actions stuff, since all output is emitted
787 if (!GetConsoleMode (get_io_handle (), &oflags
))
792 /* Enable/disable LF -> CRLF conversions */
793 rbinary ((t
->c_iflag
& INLCR
) ? false : true);
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. */
802 if (t
->c_lflag
& ECHO
)
804 flags
|= ENABLE_ECHO_INPUT
;
806 if (t
->c_lflag
& ICANON
)
808 flags
|= ENABLE_LINE_INPUT
;
811 if (flags
& ENABLE_ECHO_INPUT
812 && !(flags
& ENABLE_LINE_INPUT
))
814 /* This is illegal, so turn off the echo here, and fake it
815 when we read the characters */
817 flags
&= ~ENABLE_ECHO_INPUT
;
820 if (t
->c_lflag
& ISIG
)
822 flags
|= ENABLE_PROCESSED_INPUT
;
827 flags
= 0; // ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
832 flags
|= ENABLE_WINDOW_INPUT
| ENABLE_MOUSE_INPUT
;
839 res
= SetConsoleMode (get_io_handle (), flags
) ? 0 : -1;
842 syscall_printf ("%d = tcsetattr (,%x) enable flags %p, c_lflag %p iflag %p",
843 res
, t
, flags
, t
->c_lflag
, t
->c_iflag
);
851 fhandler_console::tcsetattr (int a
, struct termios
const *t
)
853 int res
= output_tcsetattr (a
, t
);
856 return input_tcsetattr (a
, t
);
860 fhandler_console::tcgetattr (struct termios
*t
)
869 if (!GetConsoleMode (get_io_handle (), &flags
))
876 if (flags
& ENABLE_ECHO_INPUT
)
879 if (flags
& ENABLE_LINE_INPUT
)
880 t
->c_lflag
|= ICANON
;
882 if (flags
& ENABLE_PROCESSED_INPUT
)
885 /* What about ENABLE_WINDOW_INPUT
886 and ENABLE_MOUSE_INPUT ? */
888 /* All the output bits we can ignore */
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
);
896 fhandler_console::fhandler_console () :
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)
906 fhandler_console::set_default_attr ()
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
);
917 fhandler_console::get_win32_attr ()
919 WORD win_fg
= dev_state
->fg
;
920 WORD win_bg
= dev_state
->bg
;
921 if (dev_state
->reverse
)
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
);
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
)
940 else if (dev_state
->intensity
== INTENSITY_BOLD
)
941 win_fg
|= FOREGROUND_INTENSITY
;
942 return (win_fg
| win_bg
);
946 * Clear the screen context from x1/y1 to x2/y2 cell.
947 * Negative values represents current screen dimensions
950 fhandler_console::clear_screen (int x1
, int y1
, int x2
, int y2
)
956 (void)fillin_info ();
959 x1
= dev_state
->info
.dwWinSize
.X
- 1;
961 y1
= dev_state
->info
.winBottom
;
963 x2
= dev_state
->info
.dwWinSize
.X
- 1;
965 y2
= dev_state
->info
.winBottom
;
967 num
= abs (y1
- y2
) * dev_state
->info
.dwBufferSize
.X
+ abs (x1
- x2
) + 1;
969 if ((y2
* dev_state
->info
.dwBufferSize
.X
+ x2
) > (y1
* dev_state
->info
.dwBufferSize
.X
+ x1
))
979 FillConsoleOutputCharacterA (get_output_handle (), ' ',
983 FillConsoleOutputAttribute (get_output_handle (),
984 dev_state
->current_win32_attr
,
991 fhandler_console::cursor_set (bool rel_to_top
, int x
, int y
)
995 (void) fillin_info ();
996 if (y
> dev_state
->info
.winBottom
)
997 y
= dev_state
->info
.winBottom
;
1000 else if (rel_to_top
)
1001 y
+= dev_state
->info
.winTop
;
1003 if (x
> dev_state
->info
.dwWinSize
.X
)
1004 x
= dev_state
->info
.dwWinSize
.X
- 1;
1010 SetConsoleCursorPosition (get_output_handle (), pos
);
1014 fhandler_console::cursor_rel (int x
, int y
)
1017 x
+= dev_state
->info
.dwCursorPosition
.X
;
1018 y
+= dev_state
->info
.dwCursorPosition
.Y
;
1019 cursor_set (false, x
, y
);
1023 fhandler_console::cursor_get (int *x
, int *y
)
1026 *y
= dev_state
->info
.dwCursorPosition
.Y
;
1027 *x
= dev_state
->info
.dwCursorPosition
.X
;
1041 #define TAB 8 /* We should't let the console deal with these */
1045 static const char base_chars
[256] =
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
};
1081 fhandler_console::char_command (char c
)
1088 case 'm': /* Set Graphics Rendition */
1091 for (i
= 0; i
<= dev_state
->nargs_
; i
++)
1092 switch (dev_state
->args_
[i
])
1094 case 0: /* normal color */
1095 set_default_attr ();
1098 dev_state
->intensity
= INTENSITY_BOLD
;
1101 dev_state
->underline
= 1;
1103 case 5: /* blink mode */
1104 dev_state
->blink
= true;
1106 case 7: /* reverse */
1107 dev_state
->reverse
= true;
1109 case 8: /* invisible */
1110 dev_state
->intensity
= INTENSITY_INVISIBLE
;
1113 dev_state
->intensity
= INTENSITY_DIM
;
1115 case 10: /* end alternate charset */
1116 dev_state
->alternate_charset_active
= false;
1118 case 11: /* start alternate charset */
1119 dev_state
->alternate_charset_active
= true;
1122 dev_state
->underline
= false;
1125 dev_state
->reverse
= false;
1127 case 30: /* BLACK foreground */
1130 case 31: /* RED foreground */
1131 dev_state
->fg
= FOREGROUND_RED
;
1133 case 32: /* GREEN foreground */
1134 dev_state
->fg
= FOREGROUND_GREEN
;
1136 case 33: /* YELLOW foreground */
1137 dev_state
->fg
= FOREGROUND_RED
| FOREGROUND_GREEN
;
1139 case 34: /* BLUE foreground */
1140 dev_state
->fg
= FOREGROUND_BLUE
;
1142 case 35: /* MAGENTA foreground */
1143 dev_state
->fg
= FOREGROUND_RED
| FOREGROUND_BLUE
;
1145 case 36: /* CYAN foreground */
1146 dev_state
->fg
= FOREGROUND_BLUE
| FOREGROUND_GREEN
;
1148 case 37: /* WHITE foreg */
1149 dev_state
->fg
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
1152 dev_state
->fg
= dev_state
->default_color
& FOREGROUND_ATTR_MASK
;
1154 case 40: /* BLACK background */
1157 case 41: /* RED background */
1158 dev_state
->bg
= BACKGROUND_RED
;
1160 case 42: /* GREEN background */
1161 dev_state
->bg
= BACKGROUND_GREEN
;
1163 case 43: /* YELLOW background */
1164 dev_state
->bg
= BACKGROUND_RED
| BACKGROUND_GREEN
;
1166 case 44: /* BLUE background */
1167 dev_state
->bg
= BACKGROUND_BLUE
;
1169 case 45: /* MAGENTA background */
1170 dev_state
->bg
= BACKGROUND_RED
| BACKGROUND_BLUE
;
1172 case 46: /* CYAN background */
1173 dev_state
->bg
= BACKGROUND_BLUE
| BACKGROUND_GREEN
;
1175 case 47: /* WHITE background */
1176 dev_state
->bg
= BACKGROUND_BLUE
| BACKGROUND_GREEN
| BACKGROUND_RED
;
1179 dev_state
->bg
= dev_state
->default_color
& BACKGROUND_ATTR_MASK
;
1182 dev_state
->current_win32_attr
= get_win32_attr ();
1183 SetConsoleTextAttribute (get_output_handle (), dev_state
->current_win32_attr
);
1187 if (!dev_state
->saw_question_mark
)
1189 switch (dev_state
->args_
[0])
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");
1198 switch (dev_state
->args_
[0])
1200 case 47: /* Save/Restore screen */
1201 if (c
== 'h') /* save */
1203 CONSOLE_SCREEN_BUFFER_INFO now
;
1204 COORD cob
= { 0, 0 };
1206 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now
))
1209 dev_state
->savebufsiz
.X
= now
.srWindow
.Right
- now
.srWindow
.Left
+ 1;
1210 dev_state
->savebufsiz
.Y
= now
.srWindow
.Bottom
- now
.srWindow
.Top
+ 1;
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
);
1217 ReadConsoleOutputA (get_output_handle (), dev_state
->savebuf
,
1218 dev_state
->savebufsiz
, cob
, &now
.srWindow
);
1222 CONSOLE_SCREEN_BUFFER_INFO now
;
1223 COORD cob
= { 0, 0 };
1225 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now
))
1228 if (!dev_state
->savebuf
)
1231 WriteConsoleOutputA (get_output_handle (), dev_state
->savebuf
,
1232 dev_state
->savebufsiz
, cob
, &now
.srWindow
);
1234 cfree (dev_state
->savebuf
);
1235 dev_state
->savebuf
= NULL
;
1236 dev_state
->savebufsiz
.X
= dev_state
->savebufsiz
.Y
= 0;
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");
1245 case 2000: /* Raw keyboard mode */
1246 set_raw_win32_keyboard_mode ((c
== 'h') ? true : false);
1249 default: /* Ignore */
1250 syscall_printf ("unknown h/l command: %d", dev_state
->args_
[0]);
1255 switch (dev_state
->args_
[0])
1257 case 0: /* Clear to end of screen */
1258 cursor_get (&x
, &y
);
1259 clear_screen (x
, y
, -1, -1);
1261 case 1: /* Clear from beginning of screen to cursor */
1262 cursor_get (&x
, &y
);
1263 clear_screen (0, 0, x
, y
);
1265 case 2: /* Clear screen */
1266 clear_screen (0, 0, -1, -1);
1267 cursor_set (true, 0,0);
1275 cursor_rel (0, -(dev_state
->args_
[0] ? dev_state
->args_
[0] : 1));
1278 cursor_rel (0, dev_state
->args_
[0] ? dev_state
->args_
[0] : 1);
1281 cursor_rel (dev_state
->args_
[0] ? dev_state
->args_
[0] : 1, 0);
1284 cursor_rel (-(dev_state
->args_
[0] ? dev_state
->args_
[0] : 1),0);
1287 switch (dev_state
->args_
[0])
1289 case 0: /* Clear to end of line */
1290 cursor_get (&x
, &y
);
1291 clear_screen (x
, y
, -1, y
);
1293 case 2: /* Clear line */
1294 cursor_get (&x
, &y
);
1295 clear_screen (0, y
, -1, y
);
1297 case 1: /* Clear from bol to cursor */
1298 cursor_get (&x
, &y
);
1299 clear_screen (0, y
, x
, y
);
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);
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
);
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));
1318 case 's': /* Save cursor position */
1319 cursor_get (&dev_state
->savex
, &dev_state
->savey
);
1320 dev_state
->savey
-= dev_state
->info
.winTop
;
1322 case 'u': /* Restore cursor position */
1323 cursor_set (true, dev_state
->savex
, dev_state
->savey
);
1326 cursor_get (&x
, &y
);
1327 cursor_set (false, 8 * (x
/ 8 + 1), y
);
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]);
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
);
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
);
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
);
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);
1353 case 'T': /* SR - Scroll down */
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]);
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
);
1364 case 'Z': /* Back tab */
1365 cursor_get (&x
, &y
);
1366 cursor_set (false, ((8 * (x
/ 8 + 1)) - 8), y
);
1368 case 'b': /* Repeat char #1 #2 times */
1369 if (dev_state
->insert_mode
)
1371 cursor_get (&x
, &y
);
1372 scroll_screen (x
, y
, -1, y
, x
+ dev_state
->args_
[1], y
);
1374 while (dev_state
->args_
[1]--)
1375 WriteFile (get_output_handle (), &dev_state
->args_
[0], 1, (DWORD
*) &x
, 0);
1377 case 'c': /* u9 - Terminal enquire string */
1378 strcpy (buf
, "\033[?6c");
1379 puts_readahead (buf
);
1382 switch (dev_state
->args_
[0])
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
);
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);
1400 case 'g': /* TAB set/clear */
1408 const unsigned char *
1409 fhandler_console::write_normal (const unsigned char *src
,
1410 const unsigned char *end
)
1412 /* Scan forward to see what a char which needs special treatment */
1414 const unsigned char *found
= src
;
1418 if (base_chars
[*found
] != NOR
)
1423 /* Print all the base ones out */
1426 DWORD len
= found
- src
;
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
))
1434 debug_printf ("conversion error, handle %p",
1435 get_output_handle ());
1440 if (dev_state
->insert_mode
)
1443 cursor_get (&x
, &y
);
1444 scroll_screen (x
, y
, -1, y
, x
+ buf_len
, y
);
1447 if (!WriteFile (get_output_handle (), buf
, buf_len
, &done
, 0))
1449 debug_printf ("write failed, handle %p", get_output_handle ());
1462 switch (base_chars
[*src
])
1465 MessageBeep (0xFFFFFFFF);
1468 dev_state
->state_
= gotesc
;
1471 cursor_get (&x
, &y
);
1474 if (y
>= dev_state
->info
.winBottom
&& !dev_state
->scroll_region
.Top
)
1475 WriteFile (get_output_handle (), "\n", 1, &done
, 0);
1478 scroll_screen (0, srTop
+ 1, -1, srBottom
, 0, srTop
);
1482 cursor_set (false, ((tc
->ti
.c_oflag
& ONLCR
) ? 0 : x
), y
+ 1);
1491 cursor_get (&x
, &y
);
1492 cursor_set (false, 0, y
);
1495 WriteFile (get_output_handle (), src
, 1, &done
, 0);
1498 cursor_get (&x
, &y
);
1499 cursor_set (false, 8 * (x
/ 8 + 1), y
);
1508 fhandler_console::write (const void *vsrc
, size_t len
)
1510 /* Run and check for ansi sequences */
1511 unsigned const char *src
= (unsigned char *) vsrc
;
1512 unsigned const char *end
= src
+ len
;
1514 debug_printf ("%x, %d", vsrc
, len
);
1518 debug_printf ("at %d(%c) state is %d", *src
, isprint (*src
) ? *src
: ' ',
1520 switch (dev_state
->state_
)
1523 src
= write_normal (src
, end
);
1524 if (!src
) /* write_normal failed */
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;
1536 else if (*src
== ']')
1538 dev_state
->rarg
= 0;
1539 dev_state
->my_title_buf
[0] = '\0';
1540 dev_state
->state_
= gotrsquare
;
1542 else if (*src
== 'M') /* Reverse Index */
1545 scroll_screen (0, 0, -1, -1, 0, dev_state
->info
.winTop
+ 1);
1546 dev_state
->state_
= normal
;
1548 else if (*src
== 'c') /* Reset Linux terminal */
1550 set_default_attr ();
1551 clear_screen (0, 0, -1, -1);
1552 cursor_set (true, 0, 0);
1553 dev_state
->state_
= normal
;
1555 else if (*src
== '8') /* Restore cursor position */
1557 cursor_set (true, dev_state
->savex
, dev_state
->savey
);
1558 dev_state
->state_
= normal
;
1560 else if (*src
== '7') /* Save cursor position */
1562 cursor_get (&dev_state
->savex
, &dev_state
->savey
);
1563 dev_state
->savey
-= dev_state
->info
.winTop
;
1564 dev_state
->state_
= normal
;
1566 else if (*src
== 'R')
1567 dev_state
->state_
= normal
;
1570 dev_state
->state_
= normal
;
1577 dev_state
->args_
[dev_state
->nargs_
] = dev_state
->args_
[dev_state
->nargs_
] * 10 + *src
- '0';
1580 else if (*src
== ';')
1583 dev_state
->nargs_
++;
1584 if (dev_state
->nargs_
>= MAXARGS
)
1585 dev_state
->nargs_
--;
1589 dev_state
->state_
= gotcommand
;
1593 char_command (*src
++);
1594 dev_state
->state_
= normal
;
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
;
1602 dev_state
->state_
= eattitle
;
1608 int n
= strlen (dev_state
->my_title_buf
);
1611 if (*src
== '\007' && dev_state
->state_
== gettitle
)
1614 strcpy (old_title
, dev_state
->my_title_buf
);
1615 set_console_title (dev_state
->my_title_buf
);
1617 dev_state
->state_
= normal
;
1619 else if (n
< TITLESIZE
)
1621 dev_state
->my_title_buf
[n
++] = *src
;
1622 dev_state
->my_title_buf
[n
] = '\0';
1630 dev_state
->state_
= gotarg1
;
1631 dev_state
->nargs_
++;
1634 else if (isalpha (*src
))
1635 dev_state
->state_
= gotcommand
;
1636 else if (*src
!= '@' && !isalpha (*src
) && !isdigit (*src
))
1639 dev_state
->saw_question_mark
= true;
1640 /* ignore any extra chars between [ and first arg or command */
1644 dev_state
->state_
= gotarg1
;
1649 syscall_printf ("%d = write_console (,..%d)", len
, len
);
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
}}
1688 get_nonascii_key (INPUT_RECORD
& input_rec
, char *tmp
)
1694 int modifier_index
= NORMAL
;
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
;
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
];
1709 if (input_rec
.Event
.KeyEvent
.uChar
.AsciiChar
)
1711 tmp
[0] = input_rec
.Event
.KeyEvent
.uChar
.AsciiChar
;
1719 fhandler_console::init (HANDLE f
, DWORD a
, mode_t bin
)
1721 // this->fhandler_termios::init (f, mode, bin);
1722 /* Ensure both input and output console handles are open */
1725 a
&= GENERIC_READ
| GENERIC_WRITE
;
1726 if (a
== GENERIC_READ
)
1728 if (a
== GENERIC_WRITE
)
1730 if (a
== (GENERIC_READ
| GENERIC_WRITE
))
1732 open (flags
| O_BINARY
);
1733 if (f
!= INVALID_HANDLE_VALUE
)
1734 CloseHandle (f
); /* Reopened by open */
1736 tcsetattr (0, &tc
->ti
);
1740 fhandler_console::igncr_enabled (void)
1742 return tc
->ti
.c_iflag
& IGNCR
;
1746 fhandler_console::set_close_on_exec (bool val
)
1748 fhandler_base::set_close_on_exec (val
);
1749 set_no_inheritance (output_handle
, val
);
1753 fhandler_console::fixup_after_fork (HANDLE
)
1755 HANDLE h
= get_handle ();
1756 HANDLE oh
= get_output_handle ();
1758 /* Windows does not allow duplication of console handles between processes
1759 so open the console explicitly. */
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");
1765 if (!close_on_exec ())
1773 set_console_title (char *title
)
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
);
1787 fhandler_console::fixup_after_exec ()
1789 HANDLE h
= get_handle ();
1790 HANDLE oh
= get_output_handle ();
1792 cygheap
->open_fhs
--; /* The downside of storing this in cygheap. */
1793 if (!open (O_NOCTTY
| get_flags (), 0))
1795 bool sawerr
= false;
1796 if (!get_io_handle ())
1798 system_printf ("error opening input console handle after exec, errno %d, %E", get_errno ());
1801 if (!get_output_handle ())
1803 system_printf ("error opening output console handle after exec, errno %d, %E", get_errno ());
1808 system_printf ("error opening console after exec, errno %d, %E", get_errno ());