3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2008 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
13 #include "miscfuncs.h"
20 #include <sys/cygwin.h>
21 #include <cygwin/kd.h>
30 #include "shared_info.h"
35 /* Don't make this bigger than NT_MAX_PATH as long as the temporary buffer
36 is allocated using tmp_pathbuf!!! */
37 #define CONVERT_LIMIT NT_MAX_PATH
40 * Scroll the screen context.
43 * xn, yn - new ul corner
44 * Negative values represents current screen dimensions
47 #define srTop (dev_state->info.winTop + dev_state->scroll_region.Top)
48 #define srBottom ((dev_state->scroll_region.Bottom < 0) ? dev_state->info.winBottom : dev_state->info.winTop + dev_state->scroll_region.Bottom)
50 #define use_tty ISSTATE (myself, PID_USETTY)
52 const char * get_nonascii_key (INPUT_RECORD
&, char *);
54 static console_state NO_COPY
*shared_console_info
;
56 dev_console NO_COPY
*fhandler_console::dev_state
;
58 /* Allocate and initialize the shared record for the current console.
59 Returns a pointer to shared_console_info. */
61 fhandler_console::get_tty_stuff (int flags
= 0)
64 return &shared_console_info
->tty_min_state
;
66 shared_locations sh_shared_console
= SH_SHARED_CONSOLE
;
68 (console_state
*) open_shared (NULL
, 0, cygheap
->console_h
,
69 sizeof (*shared_console_info
),
71 dev_state
= &shared_console_info
->dev_state
;
73 ProtectHandleINH (cygheap
->console_h
);
74 if (!shared_console_info
->tty_min_state
.ntty
)
76 shared_console_info
->tty_min_state
.setntty (TTY_CONSOLE
);
77 shared_console_info
->tty_min_state
.setsid (myself
->sid
);
78 myself
->set_ctty (&shared_console_info
->tty_min_state
, flags
, NULL
);
80 dev_state
->scroll_region
.Bottom
= -1;
81 dev_state
->dwLastCursorPosition
.X
= -1;
82 dev_state
->dwLastCursorPosition
.Y
= -1;
83 dev_state
->underline_color
= FOREGROUND_GREEN
| FOREGROUND_BLUE
;
84 dev_state
->dim_color
= FOREGROUND_RED
| FOREGROUND_GREEN
| FOREGROUND_BLUE
;
85 dev_state
->meta_mask
= LEFT_ALT_PRESSED
;
86 /* Set the mask that determines if an input keystroke is modified by
87 META. We set this based on the keyboard layout language loaded
88 for the current thread. The left <ALT> key always generates
89 META, but the right <ALT> key only generates META if we are using
90 an English keyboard because many "international" keyboards
91 replace common shell symbols ('[', '{', etc.) with accented
92 language-specific characters (umlaut, accent grave, etc.). On
93 these keyboards right <ALT> (called AltGr) is used to produce the
94 shell symbols and should not be interpreted as META. */
95 if (PRIMARYLANGID (LOWORD (GetKeyboardLayout (0))) == LANG_ENGLISH
)
96 dev_state
->meta_mask
|= RIGHT_ALT_PRESSED
;
97 dev_state
->set_default_attr ();
98 shared_console_info
->tty_min_state
.sethwnd ((HWND
) INVALID_HANDLE_VALUE
);
101 return &shared_console_info
->tty_min_state
;
107 fhandler_console::get_tty_stuff ();
110 /* Return the tty structure associated with a given tty number. If the
111 tty number is < 0, just return a dummy record. */
113 tty_list::get_tty (int n
)
116 if (n
== TTY_CONSOLE
)
117 return fhandler_console::get_tty_stuff ();
119 return &cygwin_shared
->tty
.ttys
[n
];
124 /* Determine if a console is associated with this process prior to a spawn.
125 If it is, then just return. If the console has been initialized, then
126 set it into a more friendly state for non-cygwin apps. */
128 set_console_state_for_spawn (bool iscyg
)
130 if (fhandler_console::need_invisible () || iscyg
131 || (myself
->ctty
>= 0 && myself
->ctty
!= TTY_CONSOLE
))
134 HANDLE h
= CreateFile ("CONIN$", GENERIC_READ
, FILE_SHARE_WRITE
,
135 &sec_none_nih
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
,
138 if (h
== INVALID_HANDLE_VALUE
)
141 if (shared_console_info
!= NULL
)
143 /* ACK. Temporarily define for use in TTYSETF macro */
144 SetConsoleMode (h
, ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
| ENABLE_PROCESSED_INPUT
);
145 shared_console_info
->tty_min_state
.rstcons (true);
153 /* The results of GetConsoleCP() and GetConsoleOutputCP() cannot be
154 cached, because a program or the user can change these values at
157 dev_console::con_to_str (char *d
, int dlen
, WCHAR w
)
159 return sys_wcstombs (d
, dlen
, &w
, 1);
163 dev_console::get_console_cp ()
165 return alternate_charset_active
? GetConsoleOutputCP () : get_cp ();
169 dev_console::str_to_con (PWCHAR d
, const char *s
, DWORD sz
)
171 return MultiByteToWideChar (get_console_cp (), 0, s
, sz
, d
, CONVERT_LIMIT
);
175 fhandler_console::set_raw_win32_keyboard_mode (bool new_mode
)
177 bool old_mode
= dev_state
->raw_win32_keyboard_mode
;
178 dev_state
->raw_win32_keyboard_mode
= new_mode
;
179 syscall_printf ("raw keyboard mode %sabled", dev_state
->raw_win32_keyboard_mode
? "en" : "dis");
184 fhandler_console::set_cursor_maybe ()
186 CONSOLE_SCREEN_BUFFER_INFO now
;
188 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now
))
191 if (dev_state
->dwLastCursorPosition
.X
!= now
.dwCursorPosition
.X
||
192 dev_state
->dwLastCursorPosition
.Y
!= now
.dwCursorPosition
.Y
)
194 SetConsoleCursorPosition (get_output_handle (), now
.dwCursorPosition
);
195 dev_state
->dwLastCursorPosition
= now
.dwCursorPosition
;
200 fhandler_console::send_winch_maybe ()
202 SHORT y
= dev_state
->info
.dwWinSize
.Y
;
203 SHORT x
= dev_state
->info
.dwWinSize
.X
;
204 dev_state
->fillin_info (get_output_handle ());
206 if (y
!= dev_state
->info
.dwWinSize
.Y
|| x
!= dev_state
->info
.dwWinSize
.X
)
208 extern fhandler_tty_master
*tty_master
;
209 dev_state
->scroll_region
.Top
= 0;
210 dev_state
->scroll_region
.Bottom
= -1;
212 tty_master
->set_winsize (true);
214 tc
->kill_pgrp (SIGWINCH
);
219 fhandler_console::read (void *pv
, size_t& buflen
)
221 HANDLE h
= get_io_handle ();
223 #define buf ((char *) pv)
228 int copied_chars
= get_readahead_into_buffer (buf
, buflen
);
232 buflen
= copied_chars
;
241 if (&_my_tls
!= _main_tls
)
245 w4
[1] = signal_arrived
;
253 if ((bgres
= bg_check (SIGTTIN
)) <= bg_eof
)
259 set_cursor_maybe (); /* to make cursor appear on the screen immediately */
260 switch (WaitForMultipleObjects (nwait
, w4
, FALSE
, INFINITE
))
264 case WAIT_OBJECT_0
+ 1:
271 INPUT_RECORD input_rec
;
272 const char *toadd
= NULL
;
274 if (!ReadConsoleInputW (h
, &input_rec
, 1, &nread
))
276 syscall_printf ("ReadConsoleInput failed, %E");
277 goto err
; /* seems to be failure */
280 /* check the event that occurred */
281 switch (input_rec
.EventType
)
284 #define virtual_key_code (input_rec.Event.KeyEvent.wVirtualKeyCode)
285 #define control_key_state (input_rec.Event.KeyEvent.dwControlKeyState)
287 dev_state
->nModifiers
= 0;
290 /* allow manual switching to/from raw mode via ctrl-alt-scrolllock */
291 if (input_rec
.Event
.KeyEvent
.bKeyDown
&&
292 virtual_key_code
== VK_SCROLL
&&
293 control_key_state
& (LEFT_ALT_PRESSED
| LEFT_CTRL_PRESSED
) == LEFT_ALT_PRESSED
| LEFT_CTRL_PRESSED
296 set_raw_win32_keyboard_mode (!dev_state
->raw_win32_keyboard_mode
);
301 if (dev_state
->raw_win32_keyboard_mode
)
303 __small_sprintf (tmp
, "\033{%u;%u;%u;%u;%u;%luK",
304 input_rec
.Event
.KeyEvent
.bKeyDown
,
305 input_rec
.Event
.KeyEvent
.wRepeatCount
,
306 input_rec
.Event
.KeyEvent
.wVirtualKeyCode
,
307 input_rec
.Event
.KeyEvent
.wVirtualScanCode
,
308 input_rec
.Event
.KeyEvent
.uChar
.UnicodeChar
,
309 input_rec
.Event
.KeyEvent
.dwControlKeyState
);
311 nread
= strlen (toadd
);
315 #define ich (input_rec.Event.KeyEvent.uChar.AsciiChar)
316 #define wch (input_rec.Event.KeyEvent.uChar.UnicodeChar)
317 #define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
318 #define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
320 /* Ignore key up events, except for left alt events with non-zero character
322 if (!input_rec
.Event
.KeyEvent
.bKeyDown
&&
324 Event for left alt, with a non-zero character, comes from
325 "alt + numerics" key sequence.
326 e.g. <left-alt> 0233 => é
329 // ?? experimentally determined on an XP system
330 && virtual_key_code
== VK_MENU
331 // left alt -- see http://www.microsoft.com/hwdev/tech/input/Scancode.asp
332 && input_rec
.Event
.KeyEvent
.wVirtualScanCode
== 0x38))
335 if (control_key_state
& SHIFT_PRESSED
)
336 dev_state
->nModifiers
|= 1;
337 if (control_key_state
& RIGHT_ALT_PRESSED
)
338 dev_state
->nModifiers
|= 2;
339 if (control_key_state
& CTRL_PRESSED
)
340 dev_state
->nModifiers
|= 4;
341 if (control_key_state
& LEFT_ALT_PRESSED
)
342 dev_state
->nModifiers
|= 8;
345 /* arrow/function keys */
346 (input_rec
.Event
.KeyEvent
.dwControlKeyState
& ENHANCED_KEY
))
348 toadd
= get_nonascii_key (input_rec
, tmp
);
351 dev_state
->nModifiers
= 0;
354 nread
= strlen (toadd
);
358 nread
= dev_state
->con_to_str (tmp
+ 1, 59, wch
);
359 /* Determine if the keystroke is modified by META. The tricky
360 part is to distinguish whether the right Alt key should be
361 recognized as Alt, or as AltGr. */
363 meta
= (control_key_state
& ALT_PRESSED
) != 0
364 && ((control_key_state
& CTRL_PRESSED
) == 0
365 || (wch
<= 0x1f || wch
== 0x7f));
368 else if (dev_state
->metabit
)
376 tmp
[1] = cyg_tolower (tmp
[1]);
379 dev_state
->nModifiers
&= ~4;
390 if (dev_state
->use_mouse
)
392 MOUSE_EVENT_RECORD
& mouse_event
= input_rec
.Event
.MouseEvent
;
394 /* Treat the double-click event like a regular button press */
395 if (mouse_event
.dwEventFlags
== DOUBLE_CLICK
)
397 syscall_printf ("mouse: double-click -> click");
398 mouse_event
.dwEventFlags
= 0;
401 /* Did something other than a click occur? */
402 if (mouse_event
.dwEventFlags
)
405 /* Retrieve reported mouse position */
406 int x
= mouse_event
.dwMousePosition
.X
;
407 int y
= mouse_event
.dwMousePosition
.Y
;
409 /* Adjust mouse position by scroll buffer offset */
410 CONSOLE_SCREEN_BUFFER_INFO now
;
411 if (GetConsoleScreenBufferInfo (get_output_handle (), &now
))
413 y
-= now
.srWindow
.Top
;
414 x
-= now
.srWindow
.Left
;
418 syscall_printf ("mouse: cannot adjust position by scroll buffer offset");
422 /* If the mouse event occurred out of the area we can handle,
424 if ((x
+ ' ' + 1 > 0xFF) || (y
+ ' ' + 1 > 0xFF))
426 syscall_printf ("mouse: position out of range");
430 /* Ignore unimportant mouse buttons */
431 mouse_event
.dwButtonState
&= 0x7;
433 /* This code assumes Windows never reports multiple button
434 events at the same time. */
437 if (mouse_event
.dwButtonState
== dev_state
->dwLastButtonState
)
439 syscall_printf ("mouse: button state unchanged");
442 else if (mouse_event
.dwButtonState
< dev_state
->dwLastButtonState
)
445 strcpy (sz
, "btn up");
447 else if ((mouse_event
.dwButtonState
& 1) != (dev_state
->dwLastButtonState
& 1))
450 strcpy (sz
, "btn1 down");
452 else if ((mouse_event
.dwButtonState
& 2) != (dev_state
->dwLastButtonState
& 2))
455 strcpy (sz
, "btn2 down");
457 else if ((mouse_event
.dwButtonState
& 4) != (dev_state
->dwLastButtonState
& 4))
460 strcpy (sz
, "btn3 down");
463 /* Remember the current button state */
464 dev_state
->dwLastButtonState
= mouse_event
.dwButtonState
;
466 /* If a button was pressed, remember the modifiers */
469 dev_state
->nModifiers
= 0;
470 if (mouse_event
.dwControlKeyState
& SHIFT_PRESSED
)
471 dev_state
->nModifiers
|= 0x4;
472 if (mouse_event
.dwControlKeyState
& (RIGHT_ALT_PRESSED
|LEFT_ALT_PRESSED
))
473 dev_state
->nModifiers
|= 0x8;
474 if (mouse_event
.dwControlKeyState
& (RIGHT_CTRL_PRESSED
|LEFT_CTRL_PRESSED
))
475 dev_state
->nModifiers
|= 0x10;
478 b
|= dev_state
->nModifiers
;
480 /* We can now create the code. */
481 sprintf (tmp
, "\033[M%c%c%c", b
+ ' ', x
+ ' ' + 1, y
+ ' ' + 1);
482 syscall_printf ("mouse: %s at (%d,%d)", sz
, x
, y
);
490 case WINDOW_BUFFER_SIZE_EVENT
:
499 line_edit_status res
= line_edit (toadd
, nread
, ti
);
500 if (res
== line_edit_signalled
)
502 else if (res
== line_edit_input_done
)
508 if ((ch
= get_readahead ()) < 0)
512 buf
[copied_chars
++] = (unsigned char)(ch
& 0xff);
517 buflen
= copied_chars
;
522 buflen
= (size_t) -1;
526 set_sig_errno (EINTR
);
527 buflen
= (size_t) -1;
531 fhandler_console::set_input_state ()
534 input_tcsetattr (0, &tc
->ti
);
538 dev_console::fillin_info (HANDLE h
)
541 CONSOLE_SCREEN_BUFFER_INFO linfo
;
543 if ((ret
= GetConsoleScreenBufferInfo (h
, &linfo
)))
545 info
.winTop
= linfo
.srWindow
.Top
;
546 info
.winBottom
= linfo
.srWindow
.Bottom
;
547 info
.dwWinSize
.Y
= 1 + linfo
.srWindow
.Bottom
- linfo
.srWindow
.Top
;
548 info
.dwWinSize
.X
= 1 + linfo
.srWindow
.Right
- linfo
.srWindow
.Left
;
549 info
.dwBufferSize
= linfo
.dwSize
;
550 info
.dwCursorPosition
= linfo
.dwCursorPosition
;
551 info
.wAttributes
= linfo
.wAttributes
;
555 memset (&info
, 0, sizeof info
);
556 info
.dwWinSize
.Y
= 25;
557 info
.dwWinSize
.X
= 80;
565 fhandler_console::scroll_screen (int x1
, int y1
, int x2
, int y2
, int xn
, int yn
)
571 dev_state
->fillin_info (get_output_handle ());
572 sr1
.Left
= x1
>= 0 ? x1
: dev_state
->info
.dwWinSize
.X
- 1;
574 sr1
.Top
= dev_state
->info
.winTop
;
576 sr1
.Top
= y1
> 0 ? y1
: dev_state
->info
.winBottom
;
577 sr1
.Right
= x2
>= 0 ? x2
: dev_state
->info
.dwWinSize
.X
- 1;
579 sr1
.Bottom
= dev_state
->info
.winTop
;
581 sr1
.Bottom
= y2
> 0 ? y2
: dev_state
->info
.winBottom
;
584 sr2
.Bottom
= srBottom
;
585 sr2
.Right
= dev_state
->info
.dwWinSize
.X
- 1;
586 if (sr1
.Bottom
> sr2
.Bottom
&& sr1
.Top
<= sr2
.Bottom
)
587 sr1
.Bottom
= sr2
.Bottom
;
588 dest
.X
= xn
>= 0 ? xn
: dev_state
->info
.dwWinSize
.X
- 1;
590 dest
.Y
= dev_state
->info
.winTop
;
592 dest
.Y
= yn
> 0 ? yn
: dev_state
->info
.winBottom
;
593 fill
.Char
.AsciiChar
= ' ';
594 fill
.Attributes
= dev_state
->current_win32_attr
;
595 ScrollConsoleScreenBuffer (get_output_handle (), &sr1
, &sr2
, dest
, &fill
);
597 /* ScrollConsoleScreenBuffer on Windows 95 is buggy - when scroll distance
598 * is more than half of screen, filling doesn't work as expected */
600 if (sr1
.Top
!= sr1
.Bottom
)
601 if (dest
.Y
<= sr1
.Top
) /* forward scroll */
602 clear_screen (0, 1 + dest
.Y
+ sr1
.Bottom
- sr1
.Top
, sr2
.Right
, sr2
.Bottom
);
603 else /* reverse scroll */
604 clear_screen (0, sr1
.Top
, sr2
.Right
, dest
.Y
- 1);
608 fhandler_console::open (int flags
, mode_t
)
612 tcinit (get_tty_stuff (flags
));
614 set_io_handle (NULL
);
615 set_output_handle (NULL
);
617 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
619 /* Open the input handle as handle_ */
620 h
= CreateFile ("CONIN$", GENERIC_READ
| GENERIC_WRITE
,
621 FILE_SHARE_READ
| FILE_SHARE_WRITE
, &sec_none
,
622 OPEN_EXISTING
, 0, 0);
624 if (h
== INVALID_HANDLE_VALUE
)
630 uninterruptible_io (true); // Handled explicitly in read code
632 h
= CreateFile ("CONOUT$", GENERIC_READ
| GENERIC_WRITE
,
633 FILE_SHARE_READ
| FILE_SHARE_WRITE
, &sec_none
,
634 OPEN_EXISTING
, 0, 0);
636 if (h
== INVALID_HANDLE_VALUE
)
641 set_output_handle (h
);
643 if (dev_state
->fillin_info (get_output_handle ()))
645 dev_state
->current_win32_attr
= dev_state
->info
.wAttributes
;
646 if (!dev_state
->default_color
)
647 dev_state
->default_color
= dev_state
->info
.wAttributes
;
648 dev_state
->set_default_attr ();
652 if (GetConsoleMode (get_io_handle (), &cflags
))
654 cflags
|= ENABLE_PROCESSED_INPUT
;
655 SetConsoleMode (get_io_handle (), ENABLE_WINDOW_INPUT
| ENABLE_MOUSE_INPUT
| cflags
);
660 cygheap
->manage_console_count ("fhandler_console::open", 1);
661 debug_printf ("opened conin$ %p, conout$ %p", get_io_handle (),
662 get_output_handle ());
668 fhandler_console::close ()
670 CloseHandle (get_io_handle ());
671 CloseHandle (get_output_handle ());
673 cygheap
->manage_console_count ("fhandler_console::close", -1);
677 /* Special console dup to duplicate input and output handles. */
680 fhandler_console::dup (fhandler_base
*child
)
682 fhandler_console
*fhc
= (fhandler_console
*) child
;
684 if (!fhc
->open (get_flags () & ~O_NOCTTY
, 0))
685 system_printf ("error opening console, %E");
691 fhandler_console::ioctl (unsigned int cmd
, void *buf
)
698 st
= dev_state
->fillin_info (get_output_handle ());
701 /* *not* the buffer size, the actual screen size... */
702 /* based on Left Top Right Bottom of srWindow */
703 ((struct winsize
*) buf
)->ws_row
= dev_state
->info
.dwWinSize
.Y
;
704 ((struct winsize
*) buf
)->ws_col
= dev_state
->info
.dwWinSize
.X
;
705 syscall_printf ("WINSZ: (row=%d,col=%d)",
706 ((struct winsize
*) buf
)->ws_row
,
707 ((struct winsize
*) buf
)->ws_col
);
712 syscall_printf ("WINSZ failed");
721 *(int *) buf
= (dev_state
->metabit
) ? K_METABIT
: K_ESCPREFIX
;
724 if ((int) buf
== K_METABIT
)
725 dev_state
->metabit
= TRUE
;
726 else if ((int) buf
== K_ESCPREFIX
)
727 dev_state
->metabit
= FALSE
;
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 () :
903 dev_console::set_color (HANDLE h
)
909 WORD save_fg
= win_fg
;
910 win_fg
= (win_bg
& BACKGROUND_RED
? FOREGROUND_RED
: 0) |
911 (win_bg
& BACKGROUND_GREEN
? FOREGROUND_GREEN
: 0) |
912 (win_bg
& BACKGROUND_BLUE
? FOREGROUND_BLUE
: 0) |
913 (win_bg
& BACKGROUND_INTENSITY
? FOREGROUND_INTENSITY
: 0);
914 win_bg
= (save_fg
& FOREGROUND_RED
? BACKGROUND_RED
: 0) |
915 (save_fg
& FOREGROUND_GREEN
? BACKGROUND_GREEN
: 0) |
916 (save_fg
& FOREGROUND_BLUE
? BACKGROUND_BLUE
: 0) |
917 (save_fg
& FOREGROUND_INTENSITY
? BACKGROUND_INTENSITY
: 0);
920 /* apply attributes */
922 win_fg
= underline_color
;
923 /* emulate blink with bright background */
925 win_bg
|= BACKGROUND_INTENSITY
;
926 if (intensity
== INTENSITY_INVISIBLE
)
928 else if (intensity
== INTENSITY_BOLD
)
929 /* apply foreground intensity only in non-reverse mode! */
931 win_bg
|= BACKGROUND_INTENSITY
;
933 win_fg
|= FOREGROUND_INTENSITY
;
935 current_win32_attr
= win_fg
| win_bg
;
937 SetConsoleTextAttribute (h
, current_win32_attr
);
940 #define FOREGROUND_ATTR_MASK (FOREGROUND_RED | FOREGROUND_GREEN | \
941 FOREGROUND_BLUE | FOREGROUND_INTENSITY)
942 #define BACKGROUND_ATTR_MASK (BACKGROUND_RED | BACKGROUND_GREEN | \
943 BACKGROUND_BLUE | BACKGROUND_INTENSITY)
945 dev_console::set_default_attr ()
947 blink
= underline
= reverse
= false;
948 intensity
= INTENSITY_NORMAL
;
949 fg
= default_color
& FOREGROUND_ATTR_MASK
;
950 bg
= default_color
& BACKGROUND_ATTR_MASK
;
955 * Clear the screen context from x1/y1 to x2/y2 cell.
956 * Negative values represents current screen dimensions
959 fhandler_console::clear_screen (int x1
, int y1
, int x2
, int y2
)
965 dev_state
->fillin_info (get_output_handle ());
968 x1
= dev_state
->info
.dwWinSize
.X
- 1;
970 y1
= dev_state
->info
.winBottom
;
972 x2
= dev_state
->info
.dwWinSize
.X
- 1;
974 y2
= dev_state
->info
.winBottom
;
976 num
= abs (y1
- y2
) * dev_state
->info
.dwBufferSize
.X
+ abs (x1
- x2
) + 1;
978 if ((y2
* dev_state
->info
.dwBufferSize
.X
+ x2
) > (y1
* dev_state
->info
.dwBufferSize
.X
+ x1
))
988 FillConsoleOutputCharacterA (get_output_handle (), ' ',
992 FillConsoleOutputAttribute (get_output_handle (),
993 dev_state
->current_win32_attr
,
1000 fhandler_console::cursor_set (bool rel_to_top
, int x
, int y
)
1004 dev_state
->fillin_info (get_output_handle ());
1005 if (y
> dev_state
->info
.winBottom
)
1006 y
= dev_state
->info
.winBottom
;
1009 else if (rel_to_top
)
1010 y
+= dev_state
->info
.winTop
;
1012 if (x
> dev_state
->info
.dwWinSize
.X
)
1013 x
= dev_state
->info
.dwWinSize
.X
- 1;
1019 SetConsoleCursorPosition (get_output_handle (), pos
);
1023 fhandler_console::cursor_rel (int x
, int y
)
1025 dev_state
->fillin_info (get_output_handle ());
1026 x
+= dev_state
->info
.dwCursorPosition
.X
;
1027 y
+= dev_state
->info
.dwCursorPosition
.Y
;
1028 cursor_set (false, x
, y
);
1032 fhandler_console::cursor_get (int *x
, int *y
)
1034 dev_state
->fillin_info (get_output_handle ());
1035 *y
= dev_state
->info
.dwCursorPosition
.Y
;
1036 *x
= dev_state
->info
.dwCursorPosition
.X
;
1050 #define TAB 8 /* We should't let the console deal with these */
1054 static const char base_chars
[256] =
1056 /*00 01 02 03 04 05 06 07 */ IGN
, ERR
, ERR
, NOR
, NOR
, NOR
, NOR
, BEL
,
1057 /*08 09 0A 0B 0C 0D 0E 0F */ BAK
, TAB
, DWN
, ERR
, ERR
, CR
, ERR
, IGN
,
1058 /*10 11 12 13 14 15 16 17 */ NOR
, NOR
, ERR
, ERR
, ERR
, ERR
, ERR
, ERR
,
1059 /*18 19 1A 1B 1C 1D 1E 1F */ NOR
, NOR
, ERR
, ESC
, ERR
, ERR
, ERR
, ERR
,
1060 /* ! " # $ % & ' */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1061 /*( ) * + , - . / */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1062 /*0 1 2 3 4 5 6 7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1063 /*8 9 : ; < = > ? */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1064 /*@ A B C D E F G */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1065 /*H I J K L M N O */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1066 /*P Q R S T U V W */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1067 /*X Y Z [ \ ] ^ _ */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1068 /*` a b c d e f g */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1069 /*h i j k l m n o */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1070 /*p q r s t u v w */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1071 /*x y z { | } ~ 7F */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1072 /*80 81 82 83 84 85 86 87 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1073 /*88 89 8A 8B 8C 8D 8E 8F */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1074 /*90 91 92 93 94 95 96 97 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1075 /*98 99 9A 9B 9C 9D 9E 9F */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1076 /*A0 A1 A2 A3 A4 A5 A6 A7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1077 /*A8 A9 AA AB AC AD AE AF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1078 /*B0 B1 B2 B3 B4 B5 B6 B7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1079 /*B8 B9 BA BB BC BD BE BF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1080 /*C0 C1 C2 C3 C4 C5 C6 C7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1081 /*C8 C9 CA CB CC CD CE CF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1082 /*D0 D1 D2 D3 D4 D5 D6 D7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1083 /*D8 D9 DA DB DC DD DE DF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1084 /*E0 E1 E2 E3 E4 E5 E6 E7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1085 /*E8 E9 EA EB EC ED EE EF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1086 /*F0 F1 F2 F3 F4 F5 F6 F7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1087 /*F8 F9 FA FB FC FD FE FF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
};
1090 fhandler_console::char_command (char c
)
1097 case 'm': /* Set Graphics Rendition */
1098 for (int i
= 0; i
<= dev_state
->nargs_
; i
++)
1099 switch (dev_state
->args_
[i
])
1101 case 0: /* normal color */
1102 dev_state
->set_default_attr ();
1105 dev_state
->intensity
= INTENSITY_BOLD
;
1108 dev_state
->underline
= 1;
1110 case 5: /* blink mode */
1111 dev_state
->blink
= true;
1113 case 7: /* reverse */
1114 dev_state
->reverse
= true;
1116 case 8: /* invisible */
1117 dev_state
->intensity
= INTENSITY_INVISIBLE
;
1120 dev_state
->intensity
= INTENSITY_DIM
;
1122 case 10: /* end alternate charset */
1123 dev_state
->alternate_charset_active
= false;
1125 case 11: /* start alternate charset */
1126 dev_state
->alternate_charset_active
= true;
1129 dev_state
->underline
= false;
1132 dev_state
->reverse
= false;
1134 case 30: /* BLACK foreground */
1137 case 31: /* RED foreground */
1138 dev_state
->fg
= FOREGROUND_RED
;
1140 case 32: /* GREEN foreground */
1141 dev_state
->fg
= FOREGROUND_GREEN
;
1143 case 33: /* YELLOW foreground */
1144 dev_state
->fg
= FOREGROUND_RED
| FOREGROUND_GREEN
;
1146 case 34: /* BLUE foreground */
1147 dev_state
->fg
= FOREGROUND_BLUE
;
1149 case 35: /* MAGENTA foreground */
1150 dev_state
->fg
= FOREGROUND_RED
| FOREGROUND_BLUE
;
1152 case 36: /* CYAN foreground */
1153 dev_state
->fg
= FOREGROUND_BLUE
| FOREGROUND_GREEN
;
1155 case 37: /* WHITE foreg */
1156 dev_state
->fg
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
1159 dev_state
->fg
= dev_state
->default_color
& FOREGROUND_ATTR_MASK
;
1161 case 40: /* BLACK background */
1164 case 41: /* RED background */
1165 dev_state
->bg
= BACKGROUND_RED
;
1167 case 42: /* GREEN background */
1168 dev_state
->bg
= BACKGROUND_GREEN
;
1170 case 43: /* YELLOW background */
1171 dev_state
->bg
= BACKGROUND_RED
| BACKGROUND_GREEN
;
1173 case 44: /* BLUE background */
1174 dev_state
->bg
= BACKGROUND_BLUE
;
1176 case 45: /* MAGENTA background */
1177 dev_state
->bg
= BACKGROUND_RED
| BACKGROUND_BLUE
;
1179 case 46: /* CYAN background */
1180 dev_state
->bg
= BACKGROUND_BLUE
| BACKGROUND_GREEN
;
1182 case 47: /* WHITE background */
1183 dev_state
->bg
= BACKGROUND_BLUE
| BACKGROUND_GREEN
| BACKGROUND_RED
;
1186 dev_state
->bg
= dev_state
->default_color
& BACKGROUND_ATTR_MASK
;
1189 dev_state
->set_color (get_output_handle ());
1193 if (!dev_state
->saw_question_mark
)
1195 switch (dev_state
->args_
[0])
1197 case 4: /* Insert mode */
1198 dev_state
->insert_mode
= (c
== 'h') ? true : false;
1199 syscall_printf ("insert mode %sabled", dev_state
->insert_mode
? "en" : "dis");
1204 switch (dev_state
->args_
[0])
1206 case 47: /* Save/Restore screen */
1207 if (c
== 'h') /* save */
1209 CONSOLE_SCREEN_BUFFER_INFO now
;
1210 COORD cob
= { 0, 0 };
1212 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now
))
1215 dev_state
->savebufsiz
.X
= now
.srWindow
.Right
- now
.srWindow
.Left
+ 1;
1216 dev_state
->savebufsiz
.Y
= now
.srWindow
.Bottom
- now
.srWindow
.Top
+ 1;
1218 if (dev_state
->savebuf
)
1219 cfree (dev_state
->savebuf
);
1220 dev_state
->savebuf
= (PCHAR_INFO
) cmalloc_abort (HEAP_1_BUF
, sizeof (CHAR_INFO
) *
1221 dev_state
->savebufsiz
.X
* dev_state
->savebufsiz
.Y
);
1223 ReadConsoleOutputW (get_output_handle (), dev_state
->savebuf
,
1224 dev_state
->savebufsiz
, cob
, &now
.srWindow
);
1228 CONSOLE_SCREEN_BUFFER_INFO now
;
1229 COORD cob
= { 0, 0 };
1231 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now
))
1234 if (!dev_state
->savebuf
)
1237 WriteConsoleOutputW (get_output_handle (), dev_state
->savebuf
,
1238 dev_state
->savebufsiz
, cob
, &now
.srWindow
);
1240 cfree (dev_state
->savebuf
);
1241 dev_state
->savebuf
= NULL
;
1242 dev_state
->savebufsiz
.X
= dev_state
->savebufsiz
.Y
= 0;
1246 case 1000: /* Mouse support */
1247 dev_state
->use_mouse
= (c
== 'h') ? true : false;
1248 syscall_printf ("mouse support %sabled", dev_state
->use_mouse
? "en" : "dis");
1251 case 2000: /* Raw keyboard mode */
1252 set_raw_win32_keyboard_mode ((c
== 'h') ? true : false);
1255 default: /* Ignore */
1256 syscall_printf ("unknown h/l command: %d", dev_state
->args_
[0]);
1261 switch (dev_state
->args_
[0])
1263 case 0: /* Clear to end of screen */
1264 cursor_get (&x
, &y
);
1265 clear_screen (x
, y
, -1, -1);
1267 case 1: /* Clear from beginning of screen to cursor */
1268 cursor_get (&x
, &y
);
1269 clear_screen (0, 0, x
, y
);
1271 case 2: /* Clear screen */
1272 clear_screen (0, 0, -1, -1);
1273 cursor_set (true, 0,0);
1281 cursor_rel (0, -(dev_state
->args_
[0] ? dev_state
->args_
[0] : 1));
1284 cursor_rel (0, dev_state
->args_
[0] ? dev_state
->args_
[0] : 1);
1287 cursor_rel (dev_state
->args_
[0] ? dev_state
->args_
[0] : 1, 0);
1290 cursor_rel (-(dev_state
->args_
[0] ? dev_state
->args_
[0] : 1),0);
1293 switch (dev_state
->args_
[0])
1295 case 0: /* Clear to end of line */
1296 cursor_get (&x
, &y
);
1297 clear_screen (x
, y
, -1, y
);
1299 case 2: /* Clear line */
1300 cursor_get (&x
, &y
);
1301 clear_screen (0, y
, -1, y
);
1303 case 1: /* Clear from bol to cursor */
1304 cursor_get (&x
, &y
);
1305 clear_screen (0, y
, x
, y
);
1313 cursor_set (true, (dev_state
->args_
[1] ? dev_state
->args_
[1] : 1) - 1,
1314 (dev_state
->args_
[0] ? dev_state
->args_
[0] : 1) - 1);
1316 case 'G': /* hpa - position cursor at column n - 1 */
1317 cursor_get (&x
, &y
);
1318 cursor_set (false, (dev_state
->args_
[0] ? dev_state
->args_
[0] - 1 : 0), y
);
1320 case 'd': /* vpa - position cursor at line n */
1321 cursor_get (&x
, &y
);
1322 cursor_set (true, x
, (dev_state
->args_
[0] ? dev_state
->args_
[0] - 1 : 0));
1324 case 's': /* Save cursor position */
1325 cursor_get (&dev_state
->savex
, &dev_state
->savey
);
1326 dev_state
->savey
-= dev_state
->info
.winTop
;
1328 case 'u': /* Restore cursor position */
1329 cursor_set (true, dev_state
->savex
, dev_state
->savey
);
1332 cursor_get (&x
, &y
);
1333 cursor_set (false, 8 * (x
/ 8 + 1), y
);
1335 case 'L': /* AL - insert blank lines */
1336 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1337 cursor_get (&x
, &y
);
1338 scroll_screen (0, y
, -1, -1, 0, y
+ dev_state
->args_
[0]);
1340 case 'M': /* DL - delete lines */
1341 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1342 cursor_get (&x
, &y
);
1343 scroll_screen (0, y
+ dev_state
->args_
[0], -1, -1, 0, y
);
1345 case '@': /* IC - insert chars */
1346 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1347 cursor_get (&x
, &y
);
1348 scroll_screen (x
, y
, -1, y
, x
+ dev_state
->args_
[0], y
);
1350 case 'P': /* DC - delete chars */
1351 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1352 cursor_get (&x
, &y
);
1353 scroll_screen (x
+ dev_state
->args_
[0], y
, -1, y
, x
, y
);
1355 case 'S': /* SF - Scroll forward */
1356 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1357 scroll_screen (0, dev_state
->args_
[0], -1, -1, 0, 0);
1359 case 'T': /* SR - Scroll down */
1360 dev_state
->fillin_info (get_output_handle ());
1361 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1362 scroll_screen (0, 0, -1, -1, 0, dev_state
->info
.winTop
+ dev_state
->args_
[0]);
1364 case 'X': /* ec - erase chars */
1365 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1366 cursor_get (&x
, &y
);
1367 scroll_screen (x
+ dev_state
->args_
[0], y
, -1, y
, x
, y
);
1368 scroll_screen (x
, y
, -1, y
, x
+ dev_state
->args_
[0], y
);
1370 case 'Z': /* Back tab */
1371 cursor_get (&x
, &y
);
1372 cursor_set (false, ((8 * (x
/ 8 + 1)) - 8), y
);
1374 case 'b': /* Repeat char #1 #2 times */
1375 if (dev_state
->insert_mode
)
1377 cursor_get (&x
, &y
);
1378 scroll_screen (x
, y
, -1, y
, x
+ dev_state
->args_
[1], y
);
1380 while (dev_state
->args_
[1]--)
1381 WriteFile (get_output_handle (), &dev_state
->args_
[0], 1, (DWORD
*) &x
, 0);
1383 case 'c': /* u9 - Terminal enquire string */
1384 strcpy (buf
, "\033[?6c");
1385 puts_readahead (buf
);
1388 switch (dev_state
->args_
[0])
1390 case 6: /* u7 - Cursor position request */
1391 cursor_get (&x
, &y
);
1392 y
-= dev_state
->info
.winTop
;
1393 /* x -= dev_state->info.winLeft; // not available yet */
1394 __small_sprintf (buf
, "\033[%d;%dR", y
+ 1, x
+ 1);
1395 puts_readahead (buf
);
1401 case 'r': /* Set Scroll region */
1402 dev_state
->scroll_region
.Top
= dev_state
->args_
[0] ? dev_state
->args_
[0] - 1 : 0;
1403 dev_state
->scroll_region
.Bottom
= dev_state
->args_
[1] ? dev_state
->args_
[1] - 1 : -1;
1404 cursor_set (true, 0, 0);
1406 case 'g': /* TAB set/clear */
1417 reg_key
r (HKEY_CURRENT_USER
, KEY_ALL_ACCESS
, "AppEvents", "Schemes", "Apps",
1418 ".Default", ".Default", ".Current", NULL
);
1422 UINT len
= GetWindowsDirectory (buf
, 0);
1423 buf
= (char *) alloca (len
+= sizeof ("\\media\\ding.wav"));
1424 UINT res
= GetWindowsDirectory (buf
, len
);
1425 if (res
&& res
<= len
)
1426 r
.set_string ("", strcat (buf
, "\\media\\ding.wav"));
1428 MessageBeep (MB_OK
);
1431 /* This gets called when we found an invalid UTF-8 character. We try with
1432 the default ANSI codepage. If that fails we just print a question mark.
1433 Looks ugly but is a neat and alomst sane fallback for many languages. */
1435 fhandler_console::write_replacement_char (const unsigned char *char_p
)
1438 WCHAR def_cp_chars
[2];
1441 n
= MultiByteToWideChar (GetACP (), 0, (const CHAR
*) char_p
, 1,
1444 WriteConsoleW (get_output_handle (), def_cp_chars
, n
, &done
, 0);
1446 WriteConsoleW (get_output_handle (), L
"?", 1, &done
, 0);
1449 const unsigned char *
1450 fhandler_console::write_normal (const unsigned char *src
,
1451 const unsigned char *end
)
1453 /* Scan forward to see what a char which needs special treatment */
1456 const unsigned char *found
= src
;
1457 const unsigned char *nfound
;
1458 UINT cp
= dev_state
->get_console_cp ();
1460 /* First check if we have cached lead bytes of a former try to write
1461 a truncated multibyte sequence. If so, process it. */
1464 int cp_len
= min (end
- src
, 4 - trunc_buf
.len
);
1465 memcpy (trunc_buf
.buf
+ trunc_buf
.len
, src
, cp_len
);
1466 nfound
= next_char (cp
, trunc_buf
.buf
,
1467 trunc_buf
.buf
+ trunc_buf
.len
+ cp_len
);
1468 /* Still truncated multibyte sequence? Keep in trunc_buf. */
1469 if (nfound
== trunc_buf
.buf
)
1471 trunc_buf
.len
+= cp_len
;
1474 /* Valid multibyte sequence? Process. */
1477 buf_len
= dev_state
->str_to_con (write_buf
,
1478 (const char *) trunc_buf
.buf
,
1479 nfound
- trunc_buf
.buf
);
1480 WriteConsoleW (get_output_handle (), write_buf
, buf_len
, &done
, 0);
1481 found
= src
+ (nfound
- trunc_buf
.buf
- trunc_buf
.len
);
1485 /* Give up, print replacement chars for trunc_buf... */
1486 for (int i
= 0; i
< trunc_buf
.len
; ++i
)
1487 write_replacement_char (trunc_buf
.buf
+ i
);
1488 /* ... mark trunc_buf as unused... */
1490 /* ... and proceed. */
1494 && found
- src
< CONVERT_LIMIT
1495 && base_chars
[*found
] == NOR
)
1497 nfound
= next_char (cp
, found
, end
);
1498 if (!nfound
) /* Invalid multibyte sequence. */
1500 if (nfound
== found
) /* Truncated multibyte sequence. */
1501 { /* Stick to it until the next write. */
1502 trunc_buf
.len
= end
- found
;
1503 memcpy (trunc_buf
.buf
, found
, trunc_buf
.len
);
1509 /* Print all the base ones out */
1512 DWORD len
= found
- src
;
1513 buf_len
= dev_state
->str_to_con (write_buf
, (const char *) src
, len
);
1516 debug_printf ("conversion error, handle %p",
1517 get_output_handle ());
1522 if (dev_state
->insert_mode
)
1525 cursor_get (&x
, &y
);
1526 scroll_screen (x
, y
, -1, y
, x
+ buf_len
, y
);
1529 register PWCHAR buf
= write_buf
;
1532 if (!WriteConsoleW (get_output_handle (), buf
, buf_len
, &done
, 0))
1534 debug_printf ("write failed, handle %p", get_output_handle ());
1541 while (buf_len
> 0);
1542 if (len
>= CONVERT_LIMIT
)
1549 switch (base_chars
[*found
])
1555 dev_state
->state_
= gotesc
;
1558 cursor_get (&x
, &y
);
1561 if (y
>= dev_state
->info
.winBottom
&& !dev_state
->scroll_region
.Top
)
1562 WriteConsoleW (get_output_handle (), L
"\n", 1, &done
, 0);
1565 scroll_screen (0, srTop
+ 1, -1, srBottom
, 0, srTop
);
1569 cursor_set (false, ((tc
->ti
.c_oflag
& ONLCR
) ? 0 : x
), y
+ 1);
1578 cursor_get (&x
, &y
);
1579 cursor_set (false, 0, y
);
1582 /* Don't print chars marked as ERR chars. */
1585 cursor_get (&x
, &y
);
1586 cursor_set (false, 8 * (x
/ 8 + 1), y
);
1589 write_replacement_char (found
);
1598 fhandler_console::write (const void *vsrc
, size_t len
)
1600 /* Run and check for ansi sequences */
1601 unsigned const char *src
= (unsigned char *) vsrc
;
1602 unsigned const char *end
= src
+ len
;
1603 /* This might look a bit far fetched, but using the TLS path buffer allows
1604 to allocate a big buffer without using the stack too much. Doing it here
1605 in write instead of in write_normal should be faster, too. */
1607 write_buf
= tp
.w_get ();
1609 debug_printf ("%x, %d", vsrc
, len
);
1613 debug_printf ("at %d(%c) state is %d", *src
, isprint (*src
) ? *src
: ' ',
1615 switch (dev_state
->state_
)
1618 src
= write_normal (src
, end
);
1619 if (!src
) /* write_normal failed */
1625 dev_state
->state_
= gotsquare
;
1626 dev_state
->saw_question_mark
= false;
1627 for (dev_state
->nargs_
= 0; dev_state
->nargs_
< MAXARGS
; dev_state
->nargs_
++)
1628 dev_state
->args_
[dev_state
->nargs_
] = 0;
1629 dev_state
->nargs_
= 0;
1631 else if (*src
== ']')
1633 dev_state
->rarg
= 0;
1634 dev_state
->my_title_buf
[0] = '\0';
1635 dev_state
->state_
= gotrsquare
;
1637 else if (*src
== 'M') /* Reverse Index */
1639 dev_state
->fillin_info (get_output_handle ());
1640 scroll_screen (0, 0, -1, -1, 0, dev_state
->info
.winTop
+ 1);
1641 dev_state
->state_
= normal
;
1643 else if (*src
== 'c') /* Reset Linux terminal */
1645 dev_state
->set_default_attr ();
1646 clear_screen (0, 0, -1, -1);
1647 cursor_set (true, 0, 0);
1648 dev_state
->state_
= normal
;
1650 else if (*src
== '8') /* Restore cursor position */
1652 cursor_set (true, dev_state
->savex
, dev_state
->savey
);
1653 dev_state
->state_
= normal
;
1655 else if (*src
== '7') /* Save cursor position */
1657 cursor_get (&dev_state
->savex
, &dev_state
->savey
);
1658 dev_state
->savey
-= dev_state
->info
.winTop
;
1659 dev_state
->state_
= normal
;
1661 else if (*src
== 'R')
1662 dev_state
->state_
= normal
;
1665 dev_state
->state_
= normal
;
1672 dev_state
->args_
[dev_state
->nargs_
] = dev_state
->args_
[dev_state
->nargs_
] * 10 + *src
- '0';
1675 else if (*src
== ';')
1678 dev_state
->nargs_
++;
1679 if (dev_state
->nargs_
>= MAXARGS
)
1680 dev_state
->nargs_
--;
1684 dev_state
->state_
= gotcommand
;
1688 char_command (*src
++);
1689 dev_state
->state_
= normal
;
1693 dev_state
->rarg
= dev_state
->rarg
* 10 + (*src
- '0');
1694 else if (*src
== ';' && (dev_state
->rarg
== 2 || dev_state
->rarg
== 0))
1695 dev_state
->state_
= gettitle
;
1697 dev_state
->state_
= eattitle
;
1703 int n
= strlen (dev_state
->my_title_buf
);
1706 if (*src
== '\007' && dev_state
->state_
== gettitle
)
1709 strcpy (old_title
, dev_state
->my_title_buf
);
1710 set_console_title (dev_state
->my_title_buf
);
1712 dev_state
->state_
= normal
;
1714 else if (n
< TITLESIZE
)
1716 dev_state
->my_title_buf
[n
++] = *src
;
1717 dev_state
->my_title_buf
[n
] = '\0';
1725 dev_state
->state_
= gotarg1
;
1726 dev_state
->nargs_
++;
1729 else if (isalpha (*src
))
1730 dev_state
->state_
= gotcommand
;
1731 else if (*src
!= '@' && !isalpha (*src
) && !isdigit (*src
))
1734 dev_state
->saw_question_mark
= true;
1735 /* ignore any extra chars between [ and first arg or command */
1739 dev_state
->state_
= gotarg1
;
1744 syscall_printf ("%d = write_console (,..%d)", len
, len
);
1752 } keytable
[] NO_COPY
= {
1753 /* NORMAL */ /* SHIFT */ /* CTRL */ /* ALT */
1754 {VK_LEFT
, {"\033[D", "\033[D", "\033[D", "\033\033[D"}},
1755 {VK_RIGHT
, {"\033[C", "\033[C", "\033[C", "\033\033[C"}},
1756 {VK_UP
, {"\033[A", "\033[A", "\033[A", "\033\033[A"}},
1757 {VK_DOWN
, {"\033[B", "\033[B", "\033[B", "\033\033[B"}},
1758 {VK_PRIOR
, {"\033[5~", "\033[5~", "\033[5~", "\033\033[5~"}},
1759 {VK_NEXT
, {"\033[6~", "\033[6~", "\033[6~", "\033\033[6~"}},
1760 {VK_HOME
, {"\033[1~", "\033[1~", "\033[1~", "\033\033[1~"}},
1761 {VK_END
, {"\033[4~", "\033[4~", "\033[4~", "\033\033[4~"}},
1762 {VK_INSERT
, {"\033[2~", "\033[2~", "\033[2~", "\033\033[2~"}},
1763 {VK_DELETE
, {"\033[3~", "\033[3~", "\033[3~", "\033\033[3~"}},
1764 {VK_F1
, {"\033[[A", "\033[23~", NULL
, NULL
}},
1765 {VK_F2
, {"\033[[B", "\033[24~", NULL
, NULL
}},
1766 {VK_F3
, {"\033[[C", "\033[25~", NULL
, NULL
}},
1767 {VK_F4
, {"\033[[D", "\033[26~", NULL
, NULL
}},
1768 {VK_F5
, {"\033[[E", "\033[28~", NULL
, NULL
}},
1769 {VK_F6
, {"\033[17~", "\033[29~", "\036", NULL
}},
1770 {VK_F7
, {"\033[18~", "\033[31~", NULL
, NULL
}},
1771 {VK_F8
, {"\033[19~", "\033[32~", NULL
, NULL
}},
1772 {VK_F9
, {"\033[20~", "\033[33~", NULL
, NULL
}},
1773 {VK_F10
, {"\033[21~", "\033[34~", NULL
, NULL
}},
1774 {VK_F11
, {"\033[23~", NULL
, NULL
, NULL
}},
1775 {VK_F12
, {"\033[24~", NULL
, NULL
, NULL
}},
1776 {VK_NUMPAD5
, {"\033[G", NULL
, NULL
, NULL
}},
1777 {VK_CLEAR
, {"\033[G", NULL
, NULL
, NULL
}},
1778 {'6', {NULL
, NULL
, "\036", NULL
}},
1779 {0, {"", NULL
, NULL
, NULL
}}
1783 get_nonascii_key (INPUT_RECORD
& input_rec
, char *tmp
)
1789 int modifier_index
= NORMAL
;
1791 if (input_rec
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
)
1792 modifier_index
= SHIFT
;
1793 else if (input_rec
.Event
.KeyEvent
.dwControlKeyState
&
1794 (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
1795 modifier_index
= CONTROL
;
1796 else if (input_rec
.Event
.KeyEvent
.dwControlKeyState
&
1797 (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
))
1798 modifier_index
= ALT
;
1800 for (int i
= 0; keytable
[i
].vk
; i
++)
1801 if (input_rec
.Event
.KeyEvent
.wVirtualKeyCode
== keytable
[i
].vk
)
1802 return keytable
[i
].val
[modifier_index
];
1804 if (input_rec
.Event
.KeyEvent
.uChar
.AsciiChar
)
1806 tmp
[0] = input_rec
.Event
.KeyEvent
.uChar
.AsciiChar
;
1814 fhandler_console::init (HANDLE f
, DWORD a
, mode_t bin
)
1816 // this->fhandler_termios::init (f, mode, bin);
1817 /* Ensure both input and output console handles are open */
1820 a
&= GENERIC_READ
| GENERIC_WRITE
;
1821 if (a
== GENERIC_READ
)
1823 if (a
== GENERIC_WRITE
)
1825 if (a
== (GENERIC_READ
| GENERIC_WRITE
))
1827 open (flags
| O_BINARY
);
1828 if (f
!= INVALID_HANDLE_VALUE
)
1829 CloseHandle (f
); /* Reopened by open */
1831 tcsetattr (0, &tc
->ti
);
1835 fhandler_console::igncr_enabled ()
1837 return tc
->ti
.c_iflag
& IGNCR
;
1841 fhandler_console::set_close_on_exec (bool val
)
1843 fhandler_base::set_close_on_exec (val
);
1844 set_no_inheritance (output_handle
, val
);
1848 set_console_title (char *title
)
1851 strncpy (buf
, title
, sizeof (buf
) - 1);
1852 buf
[sizeof (buf
) - 1] = '\0';
1853 lock_ttys
here (15000);
1854 SetConsoleTitle (buf
);
1855 debug_printf ("title '%s'", buf
);
1859 fhandler_console::fixup_after_fork_exec (bool execing
)
1861 HANDLE h
= get_handle ();
1862 HANDLE oh
= get_output_handle ();
1864 if ((execing
&& close_on_exec ()) || open (O_NOCTTY
| get_flags (), 0))
1865 cygheap
->manage_console_count ("fhandler_console::fixup_after_fork_exec", -1);
1868 bool sawerr
= false;
1869 if (!get_io_handle ())
1871 system_printf ("error opening input console handle for %s after fork/exec, errno %d, %E", get_name (), get_errno ());
1874 if (!get_output_handle ())
1876 system_printf ("error opening output console handle for %s after fork/exec, errno %d, %E", get_name (), get_errno ());
1881 system_printf ("error opening console after fork/exec, errno %d, %E", get_errno ());
1884 if (!close_on_exec ())
1891 bool NO_COPY
fhandler_console::invisible_console
;
1893 // #define WINSTA_ACCESS (WINSTA_READATTRIBUTES | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE | WINSTA_CREATEDESKTOP | WINSTA_EXITWINDOWS)
1894 #define WINSTA_ACCESS STANDARD_RIGHTS_READ
1897 fhandler_console::need_invisible ()
1900 if (GetConsoleCP ())
1901 invisible_console
= false;
1905 /* The intent here is to allocate an "invisible" console if we have no
1906 controlling tty or to reuse the existing console if we already have
1907 a tty. So, first get the old windows station. If there is no controlling
1908 terminal, create a new windows station and then set it as the current
1909 windows station. The subsequent AllocConsole will then be allocated
1910 invisibly. But, after doing that we have to restore any existing windows
1911 station or, strangely, characters will not be displayed in any windows
1912 drawn on the current screen. We only do this if we have changed to
1913 a new windows station and if we had an existing windows station previously.
1914 We also close the previously opened workstation even though AllocConsole
1915 is now "using" it. This doesn't seem to cause any problems.
1917 Things to watch out for if you make changes in this code:
1919 - Flashing, black consoles showing up when you start, e.g., ssh in
1921 - Non-displaying of characters in rxvt or xemacs if you start a
1922 process using setsid: bash -lc "setsid rxvt". */
1924 h
= horig
= GetProcessWindowStation ();
1929 || !GetUserObjectInformationW (horig
, UOI_FLAGS
, &oi
, sizeof (oi
), &len
)
1930 || !(oi
.dwFlags
& WSF_VISIBLE
))
1933 debug_printf ("window station is not visible");
1934 invisible_console
= true;
1938 if (myself
->ctty
!= TTY_CONSOLE
)
1940 h
= CreateWindowStationW (NULL
, 0, WINSTA_ACCESS
, NULL
);
1941 termios_printf ("%p = CreateWindowStation(NULL), %E", h
);
1944 b
= SetProcessWindowStation (h
);
1945 termios_printf ("SetProcessWindowStation %d, %E", b
);
1948 b
= AllocConsole (); /* will cause flashing if CreateWindowStation
1950 debug_printf ("h %p, horig %p, flags %p", h
, horig
, oi
.dwFlags
);
1951 if (horig
&& h
&& h
!= horig
&& SetProcessWindowStation (horig
))
1952 CloseWindowStation (h
);
1953 termios_printf ("%d = AllocConsole (), %E", b
);
1954 invisible_console
= true;
1958 debug_printf ("invisible_console %d", invisible_console
);