3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2008, 2009, 2010 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"
21 #include <sys/cygwin.h>
22 #include <cygwin/kd.h>
31 #include "shared_info.h"
36 /* Don't make this bigger than NT_MAX_PATH as long as the temporary buffer
37 is allocated using tmp_pathbuf!!! */
38 #define CONVERT_LIMIT NT_MAX_PATH
41 * Scroll the screen context.
44 * xn, yn - new ul corner
45 * Negative values represents current screen dimensions
48 #define srTop (dev_state->info.winTop + dev_state->scroll_region.Top)
49 #define srBottom ((dev_state->scroll_region.Bottom < 0) ? dev_state->info.winBottom : dev_state->info.winTop + dev_state->scroll_region.Bottom)
51 #define use_tty ISSTATE (myself, PID_USETTY)
53 const char *get_nonascii_key (INPUT_RECORD
&, char *);
55 const unsigned fhandler_console::MAX_WRITE_CHARS
= 16384;
57 static console_state NO_COPY
*shared_console_info
;
59 dev_console NO_COPY
*fhandler_console::dev_state
;
64 reg_key
r (HKEY_CURRENT_USER
, KEY_ALL_ACCESS
, "AppEvents", "Schemes", "Apps",
65 ".Default", ".Default", ".Current", NULL
);
69 UINT len
= GetWindowsDirectory (buf
, 0);
70 buf
= (char *) alloca (len
+= sizeof ("\\media\\ding.wav"));
71 UINT res
= GetWindowsDirectory (buf
, len
);
72 if (res
&& res
<= len
)
73 r
.set_string ("", strcat (buf
, "\\media\\ding.wav"));
78 /* Allocate and initialize the shared record for the current console.
79 Returns a pointer to shared_console_info. */
81 fhandler_console::get_tty_stuff (int flags
= 0)
84 return &shared_console_info
->tty_min_state
;
86 shared_locations sh_shared_console
= SH_SHARED_CONSOLE
;
88 (console_state
*) open_shared (NULL
, 0, cygheap
->console_h
,
89 sizeof (*shared_console_info
),
91 dev_state
= &shared_console_info
->dev_state
;
93 ProtectHandleINH (cygheap
->console_h
);
94 if (!shared_console_info
->tty_min_state
.ntty
)
96 shared_console_info
->tty_min_state
.setntty (TTY_CONSOLE
);
97 shared_console_info
->tty_min_state
.setsid (myself
->sid
);
98 myself
->set_ctty (&shared_console_info
->tty_min_state
, flags
, NULL
);
100 dev_state
->scroll_region
.Bottom
= -1;
101 dev_state
->dwLastCursorPosition
.X
= -1;
102 dev_state
->dwLastCursorPosition
.Y
= -1;
103 dev_state
->dwLastMousePosition
.X
= -1;
104 dev_state
->dwLastMousePosition
.Y
= -1;
105 dev_state
->dwLastButtonState
= 0; /* none pressed */
106 dev_state
->last_button_code
= 3; /* released */
107 dev_state
->underline_color
= FOREGROUND_GREEN
| FOREGROUND_BLUE
;
108 dev_state
->dim_color
= FOREGROUND_RED
| FOREGROUND_GREEN
| FOREGROUND_BLUE
;
109 dev_state
->meta_mask
= LEFT_ALT_PRESSED
;
110 /* Set the mask that determines if an input keystroke is modified by
111 META. We set this based on the keyboard layout language loaded
112 for the current thread. The left <ALT> key always generates
113 META, but the right <ALT> key only generates META if we are using
114 an English keyboard because many "international" keyboards
115 replace common shell symbols ('[', '{', etc.) with accented
116 language-specific characters (umlaut, accent grave, etc.). On
117 these keyboards right <ALT> (called AltGr) is used to produce the
118 shell symbols and should not be interpreted as META. */
119 if (PRIMARYLANGID (LOWORD (GetKeyboardLayout (0))) == LANG_ENGLISH
)
120 dev_state
->meta_mask
|= RIGHT_ALT_PRESSED
;
121 dev_state
->set_default_attr ();
122 shared_console_info
->tty_min_state
.sethwnd ((HWND
) INVALID_HANDLE_VALUE
);
125 return &shared_console_info
->tty_min_state
;
131 fhandler_console::get_tty_stuff ();
134 /* Return the tty structure associated with a given tty number. If the
135 tty number is < 0, just return a dummy record. */
137 tty_list::get_tty (int n
)
140 if (n
== TTY_CONSOLE
)
141 return fhandler_console::get_tty_stuff ();
143 return &cygwin_shared
->tty
.ttys
[n
];
149 dev_console::con_to_str (char *d
, int dlen
, WCHAR w
)
151 return sys_cp_wcstombs (cygheap
->locale
.wctomb
, cygheap
->locale
.charset
,
156 dev_console::get_console_cp ()
158 /* The alternate charset is always 437, just as in the Linux console. */
159 return alternate_charset_active
? 437 : 0;
163 dev_console::str_to_con (mbtowc_p f_mbtowc
, const char *charset
,
164 PWCHAR d
, const char *s
, DWORD sz
)
166 return sys_cp_mbstowcs (f_mbtowc
, charset
, d
, CONVERT_LIMIT
, s
, sz
);
170 fhandler_console::set_raw_win32_keyboard_mode (bool new_mode
)
172 bool old_mode
= dev_state
->raw_win32_keyboard_mode
;
173 dev_state
->raw_win32_keyboard_mode
= new_mode
;
174 syscall_printf ("raw keyboard mode %sabled", dev_state
->raw_win32_keyboard_mode
? "en" : "dis");
179 fhandler_console::set_cursor_maybe ()
181 CONSOLE_SCREEN_BUFFER_INFO now
;
183 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now
))
186 if (dev_state
->dwLastCursorPosition
.X
!= now
.dwCursorPosition
.X
||
187 dev_state
->dwLastCursorPosition
.Y
!= now
.dwCursorPosition
.Y
)
189 SetConsoleCursorPosition (get_output_handle (), now
.dwCursorPosition
);
190 dev_state
->dwLastCursorPosition
= now
.dwCursorPosition
;
195 fhandler_console::send_winch_maybe ()
197 SHORT y
= dev_state
->info
.dwWinSize
.Y
;
198 SHORT x
= dev_state
->info
.dwWinSize
.X
;
199 dev_state
->fillin_info (get_output_handle ());
201 if (y
!= dev_state
->info
.dwWinSize
.Y
|| x
!= dev_state
->info
.dwWinSize
.X
)
203 extern fhandler_tty_master
*tty_master
;
204 dev_state
->scroll_region
.Top
= 0;
205 dev_state
->scroll_region
.Bottom
= -1;
207 tty_master
->set_winsize (true);
209 tc
->kill_pgrp (SIGWINCH
);
213 /* Check whether a mouse event is to be reported as an escape sequence */
215 fhandler_console::mouse_aware (MOUSE_EVENT_RECORD
& mouse_event
)
217 if (! dev_state
->use_mouse
)
220 /* Adjust mouse position by window scroll buffer offset
221 and remember adjusted position in state for use by read() */
222 CONSOLE_SCREEN_BUFFER_INFO now
;
223 if (GetConsoleScreenBufferInfo (get_output_handle (), &now
))
225 dev_state
->dwMousePosition
.X
= mouse_event
.dwMousePosition
.X
- now
.srWindow
.Left
;
226 dev_state
->dwMousePosition
.Y
= mouse_event
.dwMousePosition
.Y
- now
.srWindow
.Top
;
230 /* Cannot adjust position by window scroll buffer offset */
234 /* Check whether adjusted mouse position can be reported */
235 if (dev_state
->dwMousePosition
.X
> 0xFF - ' ' - 1
236 || dev_state
->dwMousePosition
.Y
> 0xFF - ' ' - 1)
238 /* Mouse position out of reporting range */
242 return ((mouse_event
.dwEventFlags
== 0 || mouse_event
.dwEventFlags
== DOUBLE_CLICK
)
243 && mouse_event
.dwButtonState
!= dev_state
->dwLastButtonState
)
244 || mouse_event
.dwEventFlags
== MOUSE_WHEELED
245 || (mouse_event
.dwEventFlags
== MOUSE_MOVED
246 && (dev_state
->dwMousePosition
.X
!= dev_state
->dwLastMousePosition
.X
247 || dev_state
->dwMousePosition
.Y
!= dev_state
->dwLastMousePosition
.Y
)
248 && ((dev_state
->use_mouse
>= 2 && mouse_event
.dwButtonState
)
249 || dev_state
->use_mouse
>= 3));
253 fhandler_console::read (void *pv
, size_t& buflen
)
255 HANDLE h
= get_io_handle ();
257 #define buf ((char *) pv)
262 int copied_chars
= get_readahead_into_buffer (buf
, buflen
);
266 buflen
= copied_chars
;
275 if (&_my_tls
!= _main_tls
)
279 w4
[1] = signal_arrived
;
287 if ((bgres
= bg_check (SIGTTIN
)) <= bg_eof
)
293 set_cursor_maybe (); /* to make cursor appear on the screen immediately */
294 switch (WaitForMultipleObjects (nwait
, w4
, FALSE
, INFINITE
))
298 case WAIT_OBJECT_0
+ 1:
305 INPUT_RECORD input_rec
;
306 const char *toadd
= NULL
;
308 if (!ReadConsoleInputW (h
, &input_rec
, 1, &nread
))
310 syscall_printf ("ReadConsoleInput failed, %E");
311 goto err
; /* seems to be failure */
314 /* check the event that occurred */
315 switch (input_rec
.EventType
)
318 #define virtual_key_code (input_rec.Event.KeyEvent.wVirtualKeyCode)
319 #define control_key_state (input_rec.Event.KeyEvent.dwControlKeyState)
321 dev_state
->nModifiers
= 0;
324 /* allow manual switching to/from raw mode via ctrl-alt-scrolllock */
325 if (input_rec
.Event
.KeyEvent
.bKeyDown
&&
326 virtual_key_code
== VK_SCROLL
&&
327 ((control_key_state
& (LEFT_ALT_PRESSED
| LEFT_CTRL_PRESSED
)) == (LEFT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
330 set_raw_win32_keyboard_mode (!dev_state
->raw_win32_keyboard_mode
);
335 if (dev_state
->raw_win32_keyboard_mode
)
337 __small_sprintf (tmp
, "\033{%u;%u;%u;%u;%u;%luK",
338 input_rec
.Event
.KeyEvent
.bKeyDown
,
339 input_rec
.Event
.KeyEvent
.wRepeatCount
,
340 input_rec
.Event
.KeyEvent
.wVirtualKeyCode
,
341 input_rec
.Event
.KeyEvent
.wVirtualScanCode
,
342 input_rec
.Event
.KeyEvent
.uChar
.UnicodeChar
,
343 input_rec
.Event
.KeyEvent
.dwControlKeyState
);
345 nread
= strlen (toadd
);
349 #define ich (input_rec.Event.KeyEvent.uChar.AsciiChar)
350 #define wch (input_rec.Event.KeyEvent.uChar.UnicodeChar)
351 #define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
352 #define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
354 /* Ignore key up events, except for left alt events with non-zero character
356 if (!input_rec
.Event
.KeyEvent
.bKeyDown
&&
358 Event for left alt, with a non-zero character, comes from
359 "alt + numerics" key sequence.
360 e.g. <left-alt> 0233 => é
363 // ?? experimentally determined on an XP system
364 && virtual_key_code
== VK_MENU
365 // left alt -- see http://www.microsoft.com/hwdev/tech/input/Scancode.asp
366 && input_rec
.Event
.KeyEvent
.wVirtualScanCode
== 0x38))
369 if (control_key_state
& SHIFT_PRESSED
)
370 dev_state
->nModifiers
|= 1;
371 if (control_key_state
& RIGHT_ALT_PRESSED
)
372 dev_state
->nModifiers
|= 2;
373 if (control_key_state
& CTRL_PRESSED
)
374 dev_state
->nModifiers
|= 4;
375 if (control_key_state
& LEFT_ALT_PRESSED
)
376 dev_state
->nModifiers
|= 8;
378 /* Send the VERASE character from the terminal settings as backspace keycode. */
379 if (input_rec
.Event
.KeyEvent
.wVirtualScanCode
== 14)
381 char c
= ti
.c_cc
[VERASE
];
383 if (control_key_state
& ALT_PRESSED
) {
384 if (dev_state
->metabit
)
393 /* Allow Ctrl-Space to emit ^@ */
394 else if (input_rec
.Event
.KeyEvent
.wVirtualKeyCode
== VK_SPACE
395 && (control_key_state
& CTRL_PRESSED
))
398 /* arrow/function keys */
399 || (input_rec
.Event
.KeyEvent
.dwControlKeyState
& ENHANCED_KEY
))
401 toadd
= get_nonascii_key (input_rec
, tmp
);
404 dev_state
->nModifiers
= 0;
407 nread
= strlen (toadd
);
411 nread
= dev_state
->con_to_str (tmp
+ 1, 59, wch
);
412 /* Determine if the keystroke is modified by META. The tricky
413 part is to distinguish whether the right Alt key should be
414 recognized as Alt, or as AltGr. */
416 /* Alt but not AltGr (= left ctrl + right alt)? */
417 (control_key_state
& ALT_PRESSED
) != 0
418 && ((control_key_state
& CTRL_PRESSED
) == 0
419 /* but also allow Alt-AltGr: */
420 || (control_key_state
& ALT_PRESSED
) == ALT_PRESSED
421 || (wch
<= 0x1f || wch
== 0x7f));
424 /* Determine if the character is in the current multibyte
425 charset. The test is easy. If the multibyte sequence
426 is > 1 and the first byte is ASCII CAN, the character
427 has been translated into the ASCII CAN + UTF-8 replacement
428 sequence. If so, just ignore the keypress.
429 FIXME: Is there a better solution? */
430 if (nread
> 1 && tmp
[1] == 0x18)
435 else if (dev_state
->metabit
)
443 tmp
[1] = cyg_tolower (tmp
[1]);
446 dev_state
->nModifiers
&= ~4;
458 MOUSE_EVENT_RECORD
& mouse_event
= input_rec
.Event
.MouseEvent
;
459 /* As a unique guard for mouse report generation,
460 call mouse_aware() which is common with select(), so the result
461 of select() and the actual read() will be consistent on the
462 issue of whether input (i.e. a mouse escape sequence) will
463 be available or not */
464 if (mouse_aware (mouse_event
))
466 /* Note: Reported mouse position was already retrieved by
467 mouse_aware() and adjusted by window scroll buffer offset */
469 /* Treat the double-click event like a regular button press */
470 if (mouse_event
.dwEventFlags
== DOUBLE_CLICK
)
472 syscall_printf ("mouse: double-click -> click");
473 mouse_event
.dwEventFlags
= 0;
476 /* This code assumes Windows never reports multiple button
477 events at the same time. */
481 if (mouse_event
.dwEventFlags
== MOUSE_WHEELED
)
483 if (mouse_event
.dwButtonState
& 0xFF800000)
486 strcpy (sz
, "wheel down");
491 strcpy (sz
, "wheel up");
496 /* Ignore unimportant mouse buttons */
497 mouse_event
.dwButtonState
&= 0x7;
499 if (mouse_event
.dwEventFlags
== MOUSE_MOVED
)
501 b
= dev_state
->last_button_code
;
503 else if (mouse_event
.dwButtonState
< dev_state
->dwLastButtonState
)
506 strcpy (sz
, "btn up");
508 else if ((mouse_event
.dwButtonState
& 1) != (dev_state
->dwLastButtonState
& 1))
511 strcpy (sz
, "btn1 down");
513 else if ((mouse_event
.dwButtonState
& 2) != (dev_state
->dwLastButtonState
& 2))
516 strcpy (sz
, "btn2 down");
518 else if ((mouse_event
.dwButtonState
& 4) != (dev_state
->dwLastButtonState
& 4))
521 strcpy (sz
, "btn3 down");
524 dev_state
->last_button_code
= b
;
526 if (mouse_event
.dwEventFlags
== MOUSE_MOVED
)
533 /* Remember the modified button state */
534 dev_state
->dwLastButtonState
= mouse_event
.dwButtonState
;
538 /* Remember mouse position */
539 dev_state
->dwLastMousePosition
.X
= dev_state
->dwMousePosition
.X
;
540 dev_state
->dwLastMousePosition
.Y
= dev_state
->dwMousePosition
.Y
;
542 /* Remember the modifiers */
543 dev_state
->nModifiers
= 0;
544 if (mouse_event
.dwControlKeyState
& SHIFT_PRESSED
)
545 dev_state
->nModifiers
|= 0x4;
546 if (mouse_event
.dwControlKeyState
& (RIGHT_ALT_PRESSED
|LEFT_ALT_PRESSED
))
547 dev_state
->nModifiers
|= 0x8;
548 if (mouse_event
.dwControlKeyState
& (RIGHT_CTRL_PRESSED
|LEFT_CTRL_PRESSED
))
549 dev_state
->nModifiers
|= 0x10;
551 /* Indicate the modifiers */
552 b
|= dev_state
->nModifiers
;
554 /* We can now create the code. */
555 sprintf (tmp
, "\033[M%c%c%c", b
+ ' ', dev_state
->dwMousePosition
.X
+ ' ' + 1, dev_state
->dwMousePosition
.Y
+ ' ' + 1);
556 syscall_printf ("mouse: %s at (%d,%d)", sz
, dev_state
->dwMousePosition
.X
, dev_state
->dwMousePosition
.Y
);
565 if (dev_state
->use_focus
) {
566 if (input_rec
.Event
.FocusEvent
.bSetFocus
)
567 sprintf (tmp
, "\033[I");
569 sprintf (tmp
, "\033[O");
576 case WINDOW_BUFFER_SIZE_EVENT
:
585 line_edit_status res
= line_edit (toadd
, nread
, ti
);
586 if (res
== line_edit_signalled
)
588 else if (res
== line_edit_input_done
)
594 if ((ch
= get_readahead ()) < 0)
598 buf
[copied_chars
++] = (unsigned char)(ch
& 0xff);
603 buflen
= copied_chars
;
608 buflen
= (size_t) -1;
612 set_sig_errno (EINTR
);
613 buflen
= (size_t) -1;
617 fhandler_console::set_input_state ()
620 input_tcsetattr (0, &tc
->ti
);
624 dev_console::fillin_info (HANDLE h
)
627 CONSOLE_SCREEN_BUFFER_INFO linfo
;
629 if ((ret
= GetConsoleScreenBufferInfo (h
, &linfo
)))
631 info
.winTop
= linfo
.srWindow
.Top
;
632 info
.winBottom
= linfo
.srWindow
.Bottom
;
633 info
.dwWinSize
.Y
= 1 + linfo
.srWindow
.Bottom
- linfo
.srWindow
.Top
;
634 info
.dwWinSize
.X
= 1 + linfo
.srWindow
.Right
- linfo
.srWindow
.Left
;
635 info
.dwBufferSize
= linfo
.dwSize
;
636 info
.dwCursorPosition
= linfo
.dwCursorPosition
;
637 info
.wAttributes
= linfo
.wAttributes
;
641 memset (&info
, 0, sizeof info
);
642 info
.dwWinSize
.Y
= 25;
643 info
.dwWinSize
.X
= 80;
651 fhandler_console::scroll_screen (int x1
, int y1
, int x2
, int y2
, int xn
, int yn
)
657 dev_state
->fillin_info (get_output_handle ());
658 sr1
.Left
= x1
>= 0 ? x1
: dev_state
->info
.dwWinSize
.X
- 1;
660 sr1
.Top
= dev_state
->info
.winTop
;
662 sr1
.Top
= y1
> 0 ? y1
: dev_state
->info
.winBottom
;
663 sr1
.Right
= x2
>= 0 ? x2
: dev_state
->info
.dwWinSize
.X
- 1;
665 sr1
.Bottom
= dev_state
->info
.winTop
;
667 sr1
.Bottom
= y2
> 0 ? y2
: dev_state
->info
.winBottom
;
670 sr2
.Bottom
= srBottom
;
671 sr2
.Right
= dev_state
->info
.dwWinSize
.X
- 1;
672 if (sr1
.Bottom
> sr2
.Bottom
&& sr1
.Top
<= sr2
.Bottom
)
673 sr1
.Bottom
= sr2
.Bottom
;
674 dest
.X
= xn
>= 0 ? xn
: dev_state
->info
.dwWinSize
.X
- 1;
676 dest
.Y
= dev_state
->info
.winTop
;
678 dest
.Y
= yn
> 0 ? yn
: dev_state
->info
.winBottom
;
679 fill
.Char
.AsciiChar
= ' ';
680 fill
.Attributes
= dev_state
->current_win32_attr
;
681 ScrollConsoleScreenBuffer (get_output_handle (), &sr1
, &sr2
, dest
, &fill
);
683 /* ScrollConsoleScreenBuffer on Windows 95 is buggy - when scroll distance
684 * is more than half of screen, filling doesn't work as expected */
686 if (sr1
.Top
== sr1
.Bottom
)
688 else if (dest
.Y
<= sr1
.Top
) /* forward scroll */
689 clear_screen (0, 1 + dest
.Y
+ sr1
.Bottom
- sr1
.Top
, sr2
.Right
, sr2
.Bottom
);
690 else /* reverse scroll */
691 clear_screen (0, sr1
.Top
, sr2
.Right
, dest
.Y
- 1);
695 fhandler_console::open (int flags
, mode_t
)
699 tcinit (get_tty_stuff (flags
));
701 set_io_handle (NULL
);
702 set_output_handle (NULL
);
704 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
706 /* Open the input handle as handle_ */
707 h
= CreateFile ("CONIN$", GENERIC_READ
| GENERIC_WRITE
,
708 FILE_SHARE_READ
| FILE_SHARE_WRITE
, sec_none_cloexec (flags
),
709 OPEN_EXISTING
, 0, 0);
711 if (h
== INVALID_HANDLE_VALUE
)
717 uninterruptible_io (true); // Handled explicitly in read code
719 h
= CreateFile ("CONOUT$", GENERIC_READ
| GENERIC_WRITE
,
720 FILE_SHARE_READ
| FILE_SHARE_WRITE
, sec_none_cloexec (flags
),
721 OPEN_EXISTING
, 0, 0);
723 if (h
== INVALID_HANDLE_VALUE
)
728 set_output_handle (h
);
730 if (dev_state
->fillin_info (get_output_handle ()))
732 dev_state
->current_win32_attr
= dev_state
->info
.wAttributes
;
733 if (!dev_state
->default_color
)
734 dev_state
->default_color
= dev_state
->info
.wAttributes
;
735 dev_state
->set_default_attr ();
740 cygheap
->manage_console_count ("fhandler_console::open", 1);
743 if (GetConsoleMode (get_io_handle (), &cflags
))
744 SetConsoleMode (get_io_handle (),
745 ENABLE_WINDOW_INPUT
| ENABLE_MOUSE_INPUT
| cflags
);
747 debug_printf ("opened conin$ %p, conout$ %p", get_io_handle (),
748 get_output_handle ());
754 fhandler_console::close ()
756 CloseHandle (get_io_handle ());
757 CloseHandle (get_output_handle ());
759 cygheap
->manage_console_count ("fhandler_console::close", -1);
763 /* Special console dup to duplicate input and output handles. */
766 fhandler_console::dup (fhandler_base
*child
)
768 fhandler_console
*fhc
= (fhandler_console
*) child
;
770 if (!fhc
->open (get_flags () & ~O_NOCTTY
, 0))
771 system_printf ("error opening console, %E");
777 fhandler_console::ioctl (unsigned int cmd
, void *buf
)
784 st
= dev_state
->fillin_info (get_output_handle ());
787 /* *not* the buffer size, the actual screen size... */
788 /* based on Left Top Right Bottom of srWindow */
789 ((struct winsize
*) buf
)->ws_row
= dev_state
->info
.dwWinSize
.Y
;
790 ((struct winsize
*) buf
)->ws_col
= dev_state
->info
.dwWinSize
.X
;
791 syscall_printf ("WINSZ: (row=%d,col=%d)",
792 ((struct winsize
*) buf
)->ws_row
,
793 ((struct winsize
*) buf
)->ws_col
);
798 syscall_printf ("WINSZ failed");
807 *(int *) buf
= (dev_state
->metabit
) ? K_METABIT
: K_ESCPREFIX
;
810 if ((int) buf
== K_METABIT
)
811 dev_state
->metabit
= TRUE
;
812 else if ((int) buf
== K_ESCPREFIX
)
813 dev_state
->metabit
= FALSE
;
821 if (*(unsigned char *) buf
== 6)
823 *(unsigned char *) buf
= (unsigned char) dev_state
->nModifiers
;
833 return fhandler_base::ioctl (cmd
, buf
);
837 fhandler_console::tcflush (int queue
)
840 if (queue
== TCIFLUSH
841 || queue
== TCIOFLUSH
)
843 if (!FlushConsoleInputBuffer (get_io_handle ()))
853 fhandler_console::output_tcsetattr (int, struct termios
const *t
)
855 /* All the output bits we can ignore */
857 DWORD flags
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
859 int res
= SetConsoleMode (get_output_handle (), flags
) ? 0 : -1;
860 syscall_printf ("%d = tcsetattr (,%x) (ENABLE FLAGS %x) (lflag %x oflag %x)",
861 res
, t
, flags
, t
->c_lflag
, t
->c_oflag
);
866 fhandler_console::input_tcsetattr (int, struct termios
const *t
)
868 /* Ignore the optional_actions stuff, since all output is emitted
873 if (!GetConsoleMode (get_io_handle (), &oflags
))
878 /* Enable/disable LF -> CRLF conversions */
879 rbinary ((t
->c_iflag
& INLCR
) ? false : true);
882 /* There's some disparity between what we need and what's
883 available. We've got ECHO and ICANON, they've
884 got ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT. */
888 if (t
->c_lflag
& ECHO
)
890 flags
|= ENABLE_ECHO_INPUT
;
892 if (t
->c_lflag
& ICANON
)
894 flags
|= ENABLE_LINE_INPUT
;
897 if (flags
& ENABLE_ECHO_INPUT
898 && !(flags
& ENABLE_LINE_INPUT
))
900 /* This is illegal, so turn off the echo here, and fake it
901 when we read the characters */
903 flags
&= ~ENABLE_ECHO_INPUT
;
906 if (t
->c_lflag
& ISIG
)
908 flags
|= ENABLE_PROCESSED_INPUT
;
913 flags
= 0; // ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
918 flags
|= ENABLE_WINDOW_INPUT
| ENABLE_MOUSE_INPUT
;
925 res
= SetConsoleMode (get_io_handle (), flags
) ? 0 : -1;
928 syscall_printf ("%d = tcsetattr (,%x) enable flags %p, c_lflag %p iflag %p",
929 res
, t
, flags
, t
->c_lflag
, t
->c_iflag
);
937 fhandler_console::tcsetattr (int a
, struct termios
const *t
)
939 int res
= output_tcsetattr (a
, t
);
942 return input_tcsetattr (a
, t
);
946 fhandler_console::tcgetattr (struct termios
*t
)
955 if (!GetConsoleMode (get_io_handle (), &flags
))
962 if (flags
& ENABLE_ECHO_INPUT
)
965 if (flags
& ENABLE_LINE_INPUT
)
966 t
->c_lflag
|= ICANON
;
968 if (flags
& ENABLE_PROCESSED_INPUT
)
971 /* What about ENABLE_WINDOW_INPUT
972 and ENABLE_MOUSE_INPUT ? */
974 /* All the output bits we can ignore */
977 syscall_printf ("%d = tcgetattr (%p) enable flags %p, t->lflag %p, t->iflag %p",
978 res
, t
, flags
, t
->c_lflag
, t
->c_iflag
);
982 fhandler_console::fhandler_console () :
989 dev_console::set_color (HANDLE h
)
995 WORD save_fg
= win_fg
;
996 win_fg
= (win_bg
& BACKGROUND_RED
? FOREGROUND_RED
: 0) |
997 (win_bg
& BACKGROUND_GREEN
? FOREGROUND_GREEN
: 0) |
998 (win_bg
& BACKGROUND_BLUE
? FOREGROUND_BLUE
: 0) |
999 (win_bg
& BACKGROUND_INTENSITY
? FOREGROUND_INTENSITY
: 0);
1000 win_bg
= (save_fg
& FOREGROUND_RED
? BACKGROUND_RED
: 0) |
1001 (save_fg
& FOREGROUND_GREEN
? BACKGROUND_GREEN
: 0) |
1002 (save_fg
& FOREGROUND_BLUE
? BACKGROUND_BLUE
: 0) |
1003 (save_fg
& FOREGROUND_INTENSITY
? BACKGROUND_INTENSITY
: 0);
1006 /* apply attributes */
1008 win_fg
= underline_color
;
1009 /* emulate blink with bright background */
1011 win_bg
|= BACKGROUND_INTENSITY
;
1012 if (intensity
== INTENSITY_INVISIBLE
)
1014 else if (intensity
!= INTENSITY_BOLD
)
1015 /* nothing to do */;
1016 /* apply foreground intensity only in non-reverse mode! */
1018 win_bg
|= BACKGROUND_INTENSITY
;
1020 win_fg
|= FOREGROUND_INTENSITY
;
1022 current_win32_attr
= win_fg
| win_bg
;
1024 SetConsoleTextAttribute (h
, current_win32_attr
);
1027 #define FOREGROUND_ATTR_MASK (FOREGROUND_RED | FOREGROUND_GREEN | \
1028 FOREGROUND_BLUE | FOREGROUND_INTENSITY)
1029 #define BACKGROUND_ATTR_MASK (BACKGROUND_RED | BACKGROUND_GREEN | \
1030 BACKGROUND_BLUE | BACKGROUND_INTENSITY)
1032 dev_console::set_default_attr ()
1034 blink
= underline
= reverse
= false;
1035 intensity
= INTENSITY_NORMAL
;
1036 fg
= default_color
& FOREGROUND_ATTR_MASK
;
1037 bg
= default_color
& BACKGROUND_ATTR_MASK
;
1042 * Clear the screen context from x1/y1 to x2/y2 cell.
1043 * Negative values represents current screen dimensions
1046 fhandler_console::clear_screen (int x1
, int y1
, int x2
, int y2
)
1052 dev_state
->fillin_info (get_output_handle ());
1055 x1
= dev_state
->info
.dwWinSize
.X
- 1;
1057 y1
= dev_state
->info
.winBottom
;
1059 x2
= dev_state
->info
.dwWinSize
.X
- 1;
1061 y2
= dev_state
->info
.winBottom
;
1063 num
= abs (y1
- y2
) * dev_state
->info
.dwBufferSize
.X
+ abs (x1
- x2
) + 1;
1065 if ((y2
* dev_state
->info
.dwBufferSize
.X
+ x2
) > (y1
* dev_state
->info
.dwBufferSize
.X
+ x1
))
1075 FillConsoleOutputCharacterA (get_output_handle (), ' ',
1079 FillConsoleOutputAttribute (get_output_handle (),
1080 dev_state
->current_win32_attr
,
1087 fhandler_console::cursor_set (bool rel_to_top
, int x
, int y
)
1091 dev_state
->fillin_info (get_output_handle ());
1092 if (y
> dev_state
->info
.winBottom
)
1093 y
= dev_state
->info
.winBottom
;
1096 else if (rel_to_top
)
1097 y
+= dev_state
->info
.winTop
;
1099 if (x
> dev_state
->info
.dwWinSize
.X
)
1100 x
= dev_state
->info
.dwWinSize
.X
- 1;
1106 SetConsoleCursorPosition (get_output_handle (), pos
);
1110 fhandler_console::cursor_rel (int x
, int y
)
1112 dev_state
->fillin_info (get_output_handle ());
1113 x
+= dev_state
->info
.dwCursorPosition
.X
;
1114 y
+= dev_state
->info
.dwCursorPosition
.Y
;
1115 cursor_set (false, x
, y
);
1119 fhandler_console::cursor_get (int *x
, int *y
)
1121 dev_state
->fillin_info (get_output_handle ());
1122 *y
= dev_state
->info
.dwCursorPosition
.Y
;
1123 *x
= dev_state
->info
.dwCursorPosition
.X
;
1126 /* VT100 line drawing graphics mode maps `abcdefghijklmnopqrstuvwxyz{|}~ to
1127 graphical characters */
1128 static wchar_t __vt100_conv
[31] = {
1129 0x25C6, /* Black Diamond */
1130 0x2592, /* Medium Shade */
1131 0x2409, /* Symbol for Horizontal Tabulation */
1132 0x240C, /* Symbol for Form Feed */
1133 0x240D, /* Symbol for Carriage Return */
1134 0x240A, /* Symbol for Line Feed */
1135 0x00B0, /* Degree Sign */
1136 0x00B1, /* Plus-Minus Sign */
1137 0x2424, /* Symbol for Newline */
1138 0x240B, /* Symbol for Vertical Tabulation */
1139 0x2518, /* Box Drawings Light Up And Left */
1140 0x2510, /* Box Drawings Light Down And Left */
1141 0x250C, /* Box Drawings Light Down And Right */
1142 0x2514, /* Box Drawings Light Up And Right */
1143 0x253C, /* Box Drawings Light Vertical And Horizontal */
1144 0x23BA, /* Horizontal Scan Line-1 */
1145 0x23BB, /* Horizontal Scan Line-3 */
1146 0x2500, /* Box Drawings Light Horizontal */
1147 0x23BC, /* Horizontal Scan Line-7 */
1148 0x23BD, /* Horizontal Scan Line-9 */
1149 0x251C, /* Box Drawings Light Vertical And Right */
1150 0x2524, /* Box Drawings Light Vertical And Left */
1151 0x2534, /* Box Drawings Light Up And Horizontal */
1152 0x252C, /* Box Drawings Light Down And Horizontal */
1153 0x2502, /* Box Drawings Light Vertical */
1154 0x2264, /* Less-Than Or Equal To */
1155 0x2265, /* Greater-Than Or Equal To */
1156 0x03C0, /* Greek Small Letter Pi */
1157 0x2260, /* Not Equal To */
1158 0x00A3, /* Pound Sign */
1159 0x00B7, /* Middle Dot */
1163 bool fhandler_console::write_console (PWCHAR buf
, DWORD len
, DWORD
& done
)
1165 if (dev_state
->vt100_graphics_mode_active
)
1166 for (DWORD i
= 0; i
< len
; i
++)
1167 if (buf
[i
] >= (unsigned char) '`' && buf
[i
] <= (unsigned char) '~')
1168 buf
[i
] = __vt100_conv
[buf
[i
] - (unsigned char) '`'];
1172 DWORD nbytes
= len
> MAX_WRITE_CHARS
? MAX_WRITE_CHARS
: len
;
1173 if (!WriteConsoleW (get_output_handle (), buf
, nbytes
, &done
, 0))
1195 #define TAB 8 /* We should't let the console deal with these */
1201 static const char base_chars
[256] =
1203 /*00 01 02 03 04 05 06 07 */ IGN
, ERR
, ERR
, NOR
, NOR
, NOR
, NOR
, BEL
,
1204 /*08 09 0A 0B 0C 0D 0E 0F */ BAK
, TAB
, DWN
, ERR
, ERR
, CR
, SO
, SI
,
1205 /*10 11 12 13 14 15 16 17 */ NOR
, NOR
, ERR
, ERR
, ERR
, ERR
, ERR
, ERR
,
1206 /*18 19 1A 1B 1C 1D 1E 1F */ NOR
, NOR
, ERR
, ESC
, ERR
, ERR
, ERR
, ERR
,
1207 /* ! " # $ % & ' */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1208 /*( ) * + , - . / */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1209 /*0 1 2 3 4 5 6 7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1210 /*8 9 : ; < = > ? */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1211 /*@ A B C D E F G */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1212 /*H I J K L M N O */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1213 /*P Q R S T U V W */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1214 /*X Y Z [ \ ] ^ _ */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1215 /*` a b c d e f g */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1216 /*h i j k l m n o */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1217 /*p q r s t u v w */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1218 /*x y z { | } ~ 7F */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1219 /*80 81 82 83 84 85 86 87 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1220 /*88 89 8A 8B 8C 8D 8E 8F */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1221 /*90 91 92 93 94 95 96 97 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1222 /*98 99 9A 9B 9C 9D 9E 9F */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1223 /*A0 A1 A2 A3 A4 A5 A6 A7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1224 /*A8 A9 AA AB AC AD AE AF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1225 /*B0 B1 B2 B3 B4 B5 B6 B7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1226 /*B8 B9 BA BB BC BD BE BF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1227 /*C0 C1 C2 C3 C4 C5 C6 C7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1228 /*C8 C9 CA CB CC CD CE CF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1229 /*D0 D1 D2 D3 D4 D5 D6 D7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1230 /*D8 D9 DA DB DC DD DE DF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1231 /*E0 E1 E2 E3 E4 E5 E6 E7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1232 /*E8 E9 EA EB EC ED EE EF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1233 /*F0 F1 F2 F3 F4 F5 F6 F7 */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
,
1234 /*F8 F9 FA FB FC FD FE FF */ NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
, NOR
};
1237 fhandler_console::char_command (char c
)
1244 case 'm': /* Set Graphics Rendition */
1245 for (int i
= 0; i
<= dev_state
->nargs_
; i
++)
1246 switch (dev_state
->args_
[i
])
1248 case 0: /* normal color */
1249 dev_state
->set_default_attr ();
1252 dev_state
->intensity
= INTENSITY_BOLD
;
1255 dev_state
->intensity
= INTENSITY_DIM
;
1257 case 4: /* underlined */
1258 dev_state
->underline
= 1;
1260 case 5: /* blink mode */
1261 dev_state
->blink
= true;
1263 case 7: /* reverse */
1264 dev_state
->reverse
= true;
1266 case 8: /* invisible */
1267 dev_state
->intensity
= INTENSITY_INVISIBLE
;
1269 case 10: /* end alternate charset */
1270 dev_state
->alternate_charset_active
= false;
1272 case 11: /* start alternate charset */
1273 dev_state
->alternate_charset_active
= true;
1277 dev_state
->intensity
= INTENSITY_NORMAL
;
1280 dev_state
->underline
= false;
1283 dev_state
->blink
= false;
1286 dev_state
->reverse
= false;
1288 case 30: /* BLACK foreground */
1291 case 31: /* RED foreground */
1292 dev_state
->fg
= FOREGROUND_RED
;
1294 case 32: /* GREEN foreground */
1295 dev_state
->fg
= FOREGROUND_GREEN
;
1297 case 33: /* YELLOW foreground */
1298 dev_state
->fg
= FOREGROUND_RED
| FOREGROUND_GREEN
;
1300 case 34: /* BLUE foreground */
1301 dev_state
->fg
= FOREGROUND_BLUE
;
1303 case 35: /* MAGENTA foreground */
1304 dev_state
->fg
= FOREGROUND_RED
| FOREGROUND_BLUE
;
1306 case 36: /* CYAN foreground */
1307 dev_state
->fg
= FOREGROUND_BLUE
| FOREGROUND_GREEN
;
1309 case 37: /* WHITE foreg */
1310 dev_state
->fg
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
1313 dev_state
->fg
= dev_state
->default_color
& FOREGROUND_ATTR_MASK
;
1315 case 40: /* BLACK background */
1318 case 41: /* RED background */
1319 dev_state
->bg
= BACKGROUND_RED
;
1321 case 42: /* GREEN background */
1322 dev_state
->bg
= BACKGROUND_GREEN
;
1324 case 43: /* YELLOW background */
1325 dev_state
->bg
= BACKGROUND_RED
| BACKGROUND_GREEN
;
1327 case 44: /* BLUE background */
1328 dev_state
->bg
= BACKGROUND_BLUE
;
1330 case 45: /* MAGENTA background */
1331 dev_state
->bg
= BACKGROUND_RED
| BACKGROUND_BLUE
;
1333 case 46: /* CYAN background */
1334 dev_state
->bg
= BACKGROUND_BLUE
| BACKGROUND_GREEN
;
1336 case 47: /* WHITE background */
1337 dev_state
->bg
= BACKGROUND_BLUE
| BACKGROUND_GREEN
| BACKGROUND_RED
;
1340 dev_state
->bg
= dev_state
->default_color
& BACKGROUND_ATTR_MASK
;
1343 dev_state
->set_color (get_output_handle ());
1347 if (!dev_state
->saw_question_mark
)
1349 switch (dev_state
->args_
[0])
1351 case 4: /* Insert mode */
1352 dev_state
->insert_mode
= (c
== 'h') ? true : false;
1353 syscall_printf ("insert mode %sabled", dev_state
->insert_mode
? "en" : "dis");
1358 switch (dev_state
->args_
[0])
1360 case 47: /* Save/Restore screen */
1361 if (c
== 'h') /* save */
1363 CONSOLE_SCREEN_BUFFER_INFO now
;
1364 COORD cob
= { 0, 0 };
1366 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now
))
1369 dev_state
->savebufsiz
.X
= now
.srWindow
.Right
- now
.srWindow
.Left
+ 1;
1370 dev_state
->savebufsiz
.Y
= now
.srWindow
.Bottom
- now
.srWindow
.Top
+ 1;
1372 if (dev_state
->savebuf
)
1373 cfree (dev_state
->savebuf
);
1374 dev_state
->savebuf
= (PCHAR_INFO
) cmalloc_abort (HEAP_1_BUF
, sizeof (CHAR_INFO
) *
1375 dev_state
->savebufsiz
.X
* dev_state
->savebufsiz
.Y
);
1377 ReadConsoleOutputW (get_output_handle (), dev_state
->savebuf
,
1378 dev_state
->savebufsiz
, cob
, &now
.srWindow
);
1382 CONSOLE_SCREEN_BUFFER_INFO now
;
1383 COORD cob
= { 0, 0 };
1385 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now
))
1388 if (!dev_state
->savebuf
)
1391 WriteConsoleOutputW (get_output_handle (), dev_state
->savebuf
,
1392 dev_state
->savebufsiz
, cob
, &now
.srWindow
);
1394 cfree (dev_state
->savebuf
);
1395 dev_state
->savebuf
= NULL
;
1396 dev_state
->savebufsiz
.X
= dev_state
->savebufsiz
.Y
= 0;
1400 case 1000: /* Mouse tracking */
1401 dev_state
->use_mouse
= (c
== 'h') ? 1 : 0;
1402 syscall_printf ("mouse support set to mode %d", dev_state
->use_mouse
);
1405 case 1002: /* Mouse button event tracking */
1406 dev_state
->use_mouse
= (c
== 'h') ? 2 : 0;
1407 syscall_printf ("mouse support set to mode %d", dev_state
->use_mouse
);
1410 case 1003: /* Mouse any event tracking */
1411 dev_state
->use_mouse
= (c
== 'h') ? 3 : 0;
1412 syscall_printf ("mouse support set to mode %d", dev_state
->use_mouse
);
1415 case 1004: /* Focus in/out event reporting */
1416 dev_state
->use_focus
= (c
== 'h') ? true : false;
1417 syscall_printf ("focus reporting set to %d", dev_state
->use_focus
);
1420 case 2000: /* Raw keyboard mode */
1421 set_raw_win32_keyboard_mode ((c
== 'h') ? true : false);
1424 default: /* Ignore */
1425 syscall_printf ("unknown h/l command: %d", dev_state
->args_
[0]);
1430 switch (dev_state
->args_
[0])
1432 case 0: /* Clear to end of screen */
1433 cursor_get (&x
, &y
);
1434 clear_screen (x
, y
, -1, -1);
1436 case 1: /* Clear from beginning of screen to cursor */
1437 cursor_get (&x
, &y
);
1438 clear_screen (0, 0, x
, y
);
1440 case 2: /* Clear screen */
1441 clear_screen (0, 0, -1, -1);
1442 cursor_set (true, 0,0);
1450 cursor_rel (0, -(dev_state
->args_
[0] ? dev_state
->args_
[0] : 1));
1453 cursor_rel (0, dev_state
->args_
[0] ? dev_state
->args_
[0] : 1);
1456 cursor_rel (dev_state
->args_
[0] ? dev_state
->args_
[0] : 1, 0);
1459 cursor_rel (-(dev_state
->args_
[0] ? dev_state
->args_
[0] : 1),0);
1462 switch (dev_state
->args_
[0])
1464 case 0: /* Clear to end of line */
1465 cursor_get (&x
, &y
);
1466 clear_screen (x
, y
, -1, y
);
1468 case 2: /* Clear line */
1469 cursor_get (&x
, &y
);
1470 clear_screen (0, y
, -1, y
);
1472 case 1: /* Clear from bol to cursor */
1473 cursor_get (&x
, &y
);
1474 clear_screen (0, y
, x
, y
);
1482 cursor_set (true, (dev_state
->args_
[1] ? dev_state
->args_
[1] : 1) - 1,
1483 (dev_state
->args_
[0] ? dev_state
->args_
[0] : 1) - 1);
1485 case 'G': /* hpa - position cursor at column n - 1 */
1486 cursor_get (&x
, &y
);
1487 cursor_set (false, (dev_state
->args_
[0] ? dev_state
->args_
[0] - 1 : 0), y
);
1489 case 'd': /* vpa - position cursor at line n */
1490 cursor_get (&x
, &y
);
1491 cursor_set (true, x
, (dev_state
->args_
[0] ? dev_state
->args_
[0] - 1 : 0));
1493 case 's': /* Save cursor position */
1494 cursor_get (&dev_state
->savex
, &dev_state
->savey
);
1495 dev_state
->savey
-= dev_state
->info
.winTop
;
1497 case 'u': /* Restore cursor position */
1498 cursor_set (true, dev_state
->savex
, dev_state
->savey
);
1501 cursor_get (&x
, &y
);
1502 cursor_set (false, 8 * (x
/ 8 + 1), y
);
1504 case 'L': /* AL - insert blank lines */
1505 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1506 cursor_get (&x
, &y
);
1507 scroll_screen (0, y
, -1, -1, 0, y
+ dev_state
->args_
[0]);
1509 case 'M': /* DL - delete lines */
1510 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1511 cursor_get (&x
, &y
);
1512 scroll_screen (0, y
+ dev_state
->args_
[0], -1, -1, 0, y
);
1514 case '@': /* IC - insert chars */
1515 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1516 cursor_get (&x
, &y
);
1517 scroll_screen (x
, y
, -1, y
, x
+ dev_state
->args_
[0], y
);
1519 case 'P': /* DC - delete chars */
1520 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1521 cursor_get (&x
, &y
);
1522 scroll_screen (x
+ dev_state
->args_
[0], y
, -1, y
, x
, y
);
1524 case 'S': /* SF - Scroll forward */
1525 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1526 scroll_screen (0, dev_state
->args_
[0], -1, -1, 0, 0);
1528 case 'T': /* SR - Scroll down */
1529 dev_state
->fillin_info (get_output_handle ());
1530 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1531 scroll_screen (0, 0, -1, -1, 0, dev_state
->info
.winTop
+ dev_state
->args_
[0]);
1533 case 'X': /* ec - erase chars */
1534 dev_state
->args_
[0] = dev_state
->args_
[0] ? dev_state
->args_
[0] : 1;
1535 cursor_get (&x
, &y
);
1536 scroll_screen (x
+ dev_state
->args_
[0], y
, -1, y
, x
, y
);
1537 scroll_screen (x
, y
, -1, y
, x
+ dev_state
->args_
[0], y
);
1539 case 'Z': /* Back tab */
1540 cursor_get (&x
, &y
);
1541 cursor_set (false, ((8 * (x
/ 8 + 1)) - 8), y
);
1543 case 'b': /* Repeat char #1 #2 times */
1544 if (dev_state
->insert_mode
)
1546 cursor_get (&x
, &y
);
1547 scroll_screen (x
, y
, -1, y
, x
+ dev_state
->args_
[1], y
);
1549 while (dev_state
->args_
[1]--)
1550 WriteFile (get_output_handle (), &dev_state
->args_
[0], 1, (DWORD
*) &x
, 0);
1552 case 'c': /* u9 - Terminal enquire string */
1553 if (dev_state
->saw_greater_than_sign
)
1554 /* Generate Secondary Device Attribute report, using 67 = ASCII 'C'
1555 to indicate Cygwin (convention used by Rxvt, Urxvt, Screen, Mintty),
1556 and cygwin version for terminal version. */
1557 __small_sprintf (buf
, "\033[>67;%d%02d;0c", CYGWIN_VERSION_DLL_MAJOR
, CYGWIN_VERSION_DLL_MINOR
);
1559 strcpy (buf
, "\033[?6c");
1560 /* The generated report needs to be injected for read-ahead into the
1561 fhandler_console object associated with standard input.
1562 The current call does not work. */
1563 puts_readahead (buf
);
1566 switch (dev_state
->args_
[0])
1568 case 6: /* u7 - Cursor position request */
1569 cursor_get (&x
, &y
);
1570 y
-= dev_state
->info
.winTop
;
1571 /* x -= dev_state->info.winLeft; // not available yet */
1572 __small_sprintf (buf
, "\033[%d;%dR", y
+ 1, x
+ 1);
1573 puts_readahead (buf
);
1579 case 'r': /* Set Scroll region */
1580 dev_state
->scroll_region
.Top
= dev_state
->args_
[0] ? dev_state
->args_
[0] - 1 : 0;
1581 dev_state
->scroll_region
.Bottom
= dev_state
->args_
[1] ? dev_state
->args_
[1] - 1 : -1;
1582 cursor_set (true, 0, 0);
1584 case 'g': /* TAB set/clear */
1592 /* This gets called when we found an invalid input character. We just
1593 print a half filled square (UTF 0x2592). We have no chance to figure
1594 out the "meaning" of the input char anyway. */
1596 fhandler_console::write_replacement_char ()
1598 static const wchar_t replacement_char
= 0x2592; /* Half filled square */
1600 WriteConsoleW (get_output_handle (), &replacement_char
, 1, &done
, 0);
1603 const unsigned char *
1604 fhandler_console::write_normal (const unsigned char *src
,
1605 const unsigned char *end
)
1607 /* Scan forward to see what a char which needs special treatment */
1610 const unsigned char *found
= src
;
1613 UINT cp
= dev_state
->get_console_cp ();
1614 const char *charset
;
1619 /* The alternate charset is always 437, just as in the Linux console. */
1620 f_mbtowc
= __cp_mbtowc
;
1625 f_mbtowc
= cygheap
->locale
.mbtowc
;
1626 charset
= cygheap
->locale
.charset
;
1629 /* First check if we have cached lead bytes of a former try to write
1630 a truncated multibyte sequence. If so, process it. */
1633 const unsigned char *nfound
;
1634 int cp_len
= min (end
- src
, 4 - trunc_buf
.len
);
1635 memcpy (trunc_buf
.buf
+ trunc_buf
.len
, src
, cp_len
);
1636 memset (&ps
, 0, sizeof ps
);
1637 switch (ret
= f_mbtowc (_REENT
, NULL
, (const char *) trunc_buf
.buf
,
1638 trunc_buf
.len
+ cp_len
, charset
, &ps
))
1641 /* Still truncated multibyte sequence? Keep in trunc_buf. */
1642 trunc_buf
.len
+= cp_len
;
1645 /* Give up, print replacement chars for trunc_buf... */
1646 for (int i
= 0; i
< trunc_buf
.len
; ++i
)
1647 write_replacement_char ();
1648 /* ... mark trunc_buf as unused... */
1650 /* ... and proceed. */
1654 nfound
= trunc_buf
.buf
+ 1;
1657 nfound
= trunc_buf
.buf
+ ret
;
1660 /* Valid multibyte sequence? Process. */
1663 buf_len
= dev_state
->str_to_con (f_mbtowc
, charset
, write_buf
,
1664 (const char *) trunc_buf
.buf
,
1665 nfound
- trunc_buf
.buf
);
1666 if (!write_console (write_buf
, buf_len
, done
))
1668 debug_printf ("multibyte sequence write failed, handle %p", get_output_handle ());
1671 found
= src
+ (nfound
- trunc_buf
.buf
- trunc_buf
.len
);
1677 memset (&ps
, 0, sizeof ps
);
1679 && found
- src
< CONVERT_LIMIT
1680 && base_chars
[*found
] == NOR
)
1682 switch (ret
= f_mbtowc (_REENT
, NULL
, (const char *) found
,
1683 end
- found
, charset
, &ps
))
1686 /* Truncated multibyte sequence. Stick to it until the next write. */
1687 trunc_buf
.len
= end
- found
;
1688 memcpy (trunc_buf
.buf
, found
, trunc_buf
.len
);
1699 if (ret
== (size_t) -1) /* Invalid multibyte sequence. */
1703 /* Print all the base ones out */
1706 DWORD len
= found
- src
;
1707 buf_len
= dev_state
->str_to_con (f_mbtowc
, charset
, write_buf
,
1708 (const char *) src
, len
);
1711 debug_printf ("conversion error, handle %p",
1712 get_output_handle ());
1717 if (dev_state
->insert_mode
)
1720 cursor_get (&x
, &y
);
1721 scroll_screen (x
, y
, -1, y
, x
+ buf_len
, y
);
1724 if (!write_console (write_buf
, buf_len
, done
))
1726 debug_printf ("write failed, handle %p", get_output_handle ());
1729 if (len
>= CONVERT_LIMIT
)
1736 switch (base_chars
[*found
])
1739 dev_state
->vt100_graphics_mode_active
= true;
1742 dev_state
->vt100_graphics_mode_active
= false;
1748 dev_state
->state_
= gotesc
;
1751 cursor_get (&x
, &y
);
1754 if (y
>= dev_state
->info
.winBottom
&& !dev_state
->scroll_region
.Top
)
1755 WriteConsoleW (get_output_handle (), L
"\n", 1, &done
, 0);
1758 scroll_screen (0, srTop
+ 1, -1, srBottom
, 0, srTop
);
1762 cursor_set (false, ((tc
->ti
.c_oflag
& ONLCR
) ? 0 : x
), y
+ 1);
1771 cursor_get (&x
, &y
);
1772 cursor_set (false, 0, y
);
1775 /* Don't print chars marked as ERR chars, except for a ASCII CAN
1776 sequence which is printed as singlebyte chars from the UTF
1777 Basic Latin and Latin 1 Supplement plains. */
1780 write_replacement_char ();
1781 if (found
+ 1 < end
)
1783 ret
= __utf8_mbtowc (_REENT
, NULL
, (const char *) found
+ 1,
1784 end
- found
- 1, NULL
, &ps
);
1785 if (ret
!= (size_t) -1)
1788 WCHAR w
= *(found
+ 1);
1789 WriteConsoleW (get_output_handle (), &w
, 1, &done
, 0);
1796 cursor_get (&x
, &y
);
1797 cursor_set (false, 8 * (x
/ 8 + 1), y
);
1800 write_replacement_char ();
1809 fhandler_console::write (const void *vsrc
, size_t len
)
1811 /* Run and check for ansi sequences */
1812 unsigned const char *src
= (unsigned char *) vsrc
;
1813 unsigned const char *end
= src
+ len
;
1814 /* This might look a bit far fetched, but using the TLS path buffer allows
1815 to allocate a big buffer without using the stack too much. Doing it here
1816 in write instead of in write_normal should be faster, too. */
1818 write_buf
= tp
.w_get ();
1820 debug_printf ("%x, %d", vsrc
, len
);
1824 debug_printf ("at %d(%c) state is %d", *src
, isprint (*src
) ? *src
: ' ',
1826 switch (dev_state
->state_
)
1829 src
= write_normal (src
, end
);
1830 if (!src
) /* write_normal failed */
1834 if (*src
== '[') /* CSI Control Sequence Introducer */
1836 dev_state
->state_
= gotsquare
;
1837 dev_state
->saw_question_mark
= false;
1838 dev_state
->saw_greater_than_sign
= false;
1839 for (dev_state
->nargs_
= 0; dev_state
->nargs_
< MAXARGS
; dev_state
->nargs_
++)
1840 dev_state
->args_
[dev_state
->nargs_
] = 0;
1841 dev_state
->nargs_
= 0;
1843 else if (*src
== ']') /* OSC Operating System Command */
1845 dev_state
->rarg
= 0;
1846 dev_state
->my_title_buf
[0] = '\0';
1847 dev_state
->state_
= gotrsquare
;
1849 else if (*src
== '(') /* Designate G0 character set */
1851 dev_state
->state_
= gotparen
;
1853 else if (*src
== ')') /* Designate G1 character set */
1855 dev_state
->state_
= gotrparen
;
1857 else if (*src
== 'M') /* Reverse Index (scroll down) */
1859 dev_state
->fillin_info (get_output_handle ());
1860 scroll_screen (0, 0, -1, -1, 0, dev_state
->info
.winTop
+ 1);
1861 dev_state
->state_
= normal
;
1863 else if (*src
== 'c') /* RIS Full Reset */
1865 dev_state
->set_default_attr ();
1866 clear_screen (0, 0, -1, -1);
1867 cursor_set (true, 0, 0);
1868 dev_state
->state_
= normal
;
1870 else if (*src
== '8') /* DECRC Restore cursor position */
1872 cursor_set (true, dev_state
->savex
, dev_state
->savey
);
1873 dev_state
->state_
= normal
;
1875 else if (*src
== '7') /* DECSC Save cursor position */
1877 cursor_get (&dev_state
->savex
, &dev_state
->savey
);
1878 dev_state
->savey
-= dev_state
->info
.winTop
;
1879 dev_state
->state_
= normal
;
1881 else if (*src
== 'R') /* ? */
1882 dev_state
->state_
= normal
;
1885 dev_state
->state_
= normal
;
1892 dev_state
->args_
[dev_state
->nargs_
] = dev_state
->args_
[dev_state
->nargs_
] * 10 + *src
- '0';
1895 else if (*src
== ';')
1898 dev_state
->nargs_
++;
1899 if (dev_state
->nargs_
>= MAXARGS
)
1900 dev_state
->nargs_
--;
1904 dev_state
->state_
= gotcommand
;
1908 char_command (*src
++);
1909 dev_state
->state_
= normal
;
1913 dev_state
->rarg
= dev_state
->rarg
* 10 + (*src
- '0');
1914 else if (*src
== ';' && (dev_state
->rarg
== 2 || dev_state
->rarg
== 0))
1915 dev_state
->state_
= gettitle
;
1917 dev_state
->state_
= eattitle
;
1923 int n
= strlen (dev_state
->my_title_buf
);
1926 if (*src
== '\007' && dev_state
->state_
== gettitle
)
1929 strcpy (old_title
, dev_state
->my_title_buf
);
1930 set_console_title (dev_state
->my_title_buf
);
1932 dev_state
->state_
= normal
;
1934 else if (n
< TITLESIZE
)
1936 dev_state
->my_title_buf
[n
++] = *src
;
1937 dev_state
->my_title_buf
[n
] = '\0';
1945 dev_state
->state_
= gotarg1
;
1946 dev_state
->nargs_
++;
1949 else if (isalpha (*src
))
1950 dev_state
->state_
= gotcommand
;
1951 else if (*src
!= '@' && !isalpha (*src
) && !isdigit (*src
))
1954 dev_state
->saw_question_mark
= true;
1955 else if (*src
== '>')
1956 dev_state
->saw_greater_than_sign
= true;
1957 /* ignore any extra chars between [ and first arg or command */
1961 dev_state
->state_
= gotarg1
;
1965 dev_state
->vt100_graphics_mode_active
= true;
1967 dev_state
->vt100_graphics_mode_active
= false;
1968 dev_state
->state_
= normal
;
1972 /* This is not strictly needed, ^N/^O can just always be enabled */
1974 /*dev_state->vt100_graphics_mode_SOSI_enabled = true*/;
1976 /*dev_state->vt100_graphics_mode_SOSI_enabled = false*/;
1977 dev_state
->state_
= normal
;
1983 syscall_printf ("%d = fhandler_console::write (,..%d)", len
, len
);
1991 } keytable
[] NO_COPY
= {
1992 /* NORMAL */ /* SHIFT */ /* CTRL */ /* CTRL-SHIFT */
1993 /* Unmodified and Alt-modified keypad keys comply with linux console
1994 SHIFT, CTRL, CTRL-SHIFT modifiers comply with xterm modifier usage */
1995 {VK_NUMPAD5
, {"\033[G", "\033[1;2G", "\033[1;5G", "\033[1;6G"}},
1996 {VK_CLEAR
, {"\033[G", "\033[1;2G", "\033[1;5G", "\033[1;6G"}},
1997 {VK_LEFT
, {"\033[D", "\033[1;2D", "\033[1;5D", "\033[1;6D"}},
1998 {VK_RIGHT
, {"\033[C", "\033[1;2C", "\033[1;5C", "\033[1;6C"}},
1999 {VK_UP
, {"\033[A", "\033[1;2A", "\033[1;5A", "\033[1;6A"}},
2000 {VK_DOWN
, {"\033[B", "\033[1;2B", "\033[1;5B", "\033[1;6B"}},
2001 {VK_PRIOR
, {"\033[5~", "\033[5;2~", "\033[5;5~", "\033[5;6~"}},
2002 {VK_NEXT
, {"\033[6~", "\033[6;2~", "\033[6;5~", "\033[6;6~"}},
2003 {VK_HOME
, {"\033[1~", "\033[1;2~", "\033[1;5~", "\033[1;6~"}},
2004 {VK_END
, {"\033[4~", "\033[4;2~", "\033[4;5~", "\033[4;6~"}},
2005 {VK_INSERT
, {"\033[2~", "\033[2;2~", "\033[2;5~", "\033[2;6~"}},
2006 {VK_DELETE
, {"\033[3~", "\033[3;2~", "\033[3;5~", "\033[3;6~"}},
2007 /* F1...F12, SHIFT-F1...SHIFT-F10 comply with linux console
2008 F6...F12, and all modified F-keys comply with rxvt (compatible extension) */
2009 {VK_F1
, {"\033[[A", "\033[23~", "\033[11^", "\033[23^"}},
2010 {VK_F2
, {"\033[[B", "\033[24~", "\033[12^", "\033[24^"}},
2011 {VK_F3
, {"\033[[C", "\033[25~", "\033[13^", "\033[25^"}},
2012 {VK_F4
, {"\033[[D", "\033[26~", "\033[14^", "\033[26^"}},
2013 {VK_F5
, {"\033[[E", "\033[28~", "\033[15^", "\033[28^"}},
2014 {VK_F6
, {"\033[17~", "\033[29~", "\033[17^", "\033[29^"}},
2015 {VK_F7
, {"\033[18~", "\033[31~", "\033[18^", "\033[31^"}},
2016 {VK_F8
, {"\033[19~", "\033[32~", "\033[19^", "\033[32^"}},
2017 {VK_F9
, {"\033[20~", "\033[33~", "\033[20^", "\033[33^"}},
2018 {VK_F10
, {"\033[21~", "\033[34~", "\033[21^", "\033[34^"}},
2019 {VK_F11
, {"\033[23~", "\033[23$", "\033[23^", "\033[23@"}},
2020 {VK_F12
, {"\033[24~", "\033[24$", "\033[24^", "\033[24@"}},
2021 /* CTRL-6 complies with Windows cmd console but should be fixed */
2022 {'6', {NULL
, NULL
, "\036", NULL
}},
2023 /* Table end marker */
2028 get_nonascii_key (INPUT_RECORD
& input_rec
, char *tmp
)
2033 /*#define CONTROLSHIFT 3*/
2035 int modifier_index
= NORMAL
;
2036 if (input_rec
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
)
2037 modifier_index
= SHIFT
;
2038 if (input_rec
.Event
.KeyEvent
.dwControlKeyState
&
2039 (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
2040 modifier_index
+= CONTROL
;
2042 for (int i
= 0; keytable
[i
].vk
; i
++)
2043 if (input_rec
.Event
.KeyEvent
.wVirtualKeyCode
== keytable
[i
].vk
)
2045 if ((input_rec
.Event
.KeyEvent
.dwControlKeyState
&
2046 (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
))
2047 && keytable
[i
].val
[modifier_index
] != NULL
)
2048 { /* Generic ESC prefixing if Alt is pressed */
2050 strcpy (tmp
+ 1, keytable
[i
].val
[modifier_index
]);
2054 return keytable
[i
].val
[modifier_index
];
2057 if (input_rec
.Event
.KeyEvent
.uChar
.AsciiChar
)
2059 tmp
[0] = input_rec
.Event
.KeyEvent
.uChar
.AsciiChar
;
2067 fhandler_console::init (HANDLE f
, DWORD a
, mode_t bin
)
2069 // this->fhandler_termios::init (f, mode, bin);
2070 /* Ensure both input and output console handles are open */
2073 a
&= GENERIC_READ
| GENERIC_WRITE
;
2074 if (a
== GENERIC_READ
)
2076 if (a
== GENERIC_WRITE
)
2078 if (a
== (GENERIC_READ
| GENERIC_WRITE
))
2080 open (flags
| O_BINARY
);
2081 if (f
!= INVALID_HANDLE_VALUE
)
2082 CloseHandle (f
); /* Reopened by open */
2084 return !tcsetattr (0, &tc
->ti
);
2088 fhandler_console::igncr_enabled ()
2090 return tc
->ti
.c_iflag
& IGNCR
;
2094 fhandler_console::set_close_on_exec (bool val
)
2096 fhandler_base::set_close_on_exec (val
);
2097 set_no_inheritance (output_handle
, val
);
2101 set_console_title (char *title
)
2103 wchar_t buf
[TITLESIZE
+ 1];
2104 sys_mbstowcs (buf
, TITLESIZE
+ 1, title
);
2105 lock_ttys
here (15000);
2106 SetConsoleTitleW (buf
);
2107 debug_printf ("title '%W'", buf
);
2111 fhandler_console::fixup_after_fork_exec (bool execing
)
2113 HANDLE h
= get_handle ();
2114 HANDLE oh
= get_output_handle ();
2116 if ((execing
&& close_on_exec ()) || open (O_NOCTTY
| get_flags (), 0))
2117 cygheap
->manage_console_count ("fhandler_console::fixup_after_fork_exec", -1);
2120 bool sawerr
= false;
2121 if (!get_io_handle ())
2123 system_printf ("error opening input console handle for %s after fork/exec, errno %d, %E", get_name (), get_errno ());
2126 if (!get_output_handle ())
2128 system_printf ("error opening output console handle for %s after fork/exec, errno %d, %E", get_name (), get_errno ());
2133 system_printf ("error opening console after fork/exec, errno %d, %E", get_errno ());
2136 if (!close_on_exec ())
2143 bool NO_COPY
fhandler_console::invisible_console
;
2145 // #define WINSTA_ACCESS (WINSTA_READATTRIBUTES | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE | WINSTA_CREATEDESKTOP | WINSTA_EXITWINDOWS)
2146 #define WINSTA_ACCESS WINSTA_ALL_ACCESS
2148 /* Create a console in an invisible window station. This should work
2149 in all versions of Windows NT except Windows 7 (so far). */
2151 fhandler_console::create_invisible_console (HWINSTA horig
)
2153 HWINSTA h
= CreateWindowStationW (NULL
, 0, WINSTA_ACCESS
, NULL
);
2154 termios_printf ("%p = CreateWindowStation(NULL), %E", h
);
2158 b
= SetProcessWindowStation (h
);
2159 termios_printf ("SetProcessWindowStation %d, %E", b
);
2161 b
= AllocConsole (); /* will cause flashing if CreateWindowStation
2164 SetParent (GetConsoleWindow (), HWND_MESSAGE
);
2165 if (horig
&& h
&& h
!= horig
&& SetProcessWindowStation (horig
))
2166 CloseWindowStation (h
);
2167 termios_printf ("%d = AllocConsole (), %E", b
);
2168 invisible_console
= true;
2172 /* Ugly workaround for Windows 7.
2174 First try to just attach to any console which may have started this
2175 app. If that works use this as our "invisible console".
2177 This will fail if not started from the command prompt. In that case, start
2178 a dummy console application in a hidden state so that we can use its console
2179 as our invisible console. This probably works everywhere but process
2180 creation is slow and to be avoided if possible so the window station method
2181 is vastly preferred.
2183 FIXME: This is not completely thread-safe since it creates two inheritable
2184 handles which are known only to this function. If another thread starts
2185 a process the new process will inherit these handles. However, since this
2186 function is currently only called at startup and during exec, it shouldn't
2189 fhandler_console::create_invisible_console_workaround ()
2191 if (!AttachConsole (-1))
2194 DWORD err
= GetLastError ();
2195 path_conv
helper ("/bin/cygwin-console-helper.exe");
2196 HANDLE hello
= NULL
;
2197 HANDLE goodbye
= NULL
;
2198 /* If err == ERROR_PROC_FOUND then this method won't work. But that's
2199 ok. The window station method should work ok when AttachConsole doesn't
2202 If the helper doesn't exist or we can't create event handles then we
2203 can't use this method. */
2204 if (err
== ERROR_PROC_NOT_FOUND
|| !helper
.exists ()
2205 || !(hello
= CreateEvent (&sec_none
, true, false, NULL
))
2206 || !(goodbye
= CreateEvent (&sec_none
, true, false, NULL
)))
2208 AllocConsole (); /* This is just sanity check code. We should
2209 never actually hit here unless we're running
2210 in an environment which lacks the helper
2216 STARTUPINFOW si
= {};
2217 PROCESS_INFORMATION pi
;
2218 size_t len
= helper
.get_wide_win32_path_len ();
2219 WCHAR cmd
[len
+ (2 * strlen (" 0xffffffff")) + 1];
2220 WCHAR title
[] = L
"invisible cygwin console";
2222 helper
.get_wide_win32_path (cmd
);
2223 __small_swprintf (cmd
+ len
, L
" %p %p", hello
, goodbye
);
2225 si
.cb
= sizeof (si
);
2226 si
.dwFlags
= STARTF_USESHOWWINDOW
;
2227 si
.wShowWindow
= SW_HIDE
;
2230 /* Create a new hidden process. Use the two event handles as
2231 argv[1] and argv[2]. */
2232 BOOL x
= CreateProcessW (NULL
, cmd
, &sec_none_nih
, &sec_none_nih
, true,
2233 CREATE_NEW_CONSOLE
, NULL
, NULL
, &si
, &pi
);
2236 CloseHandle (pi
.hProcess
); /* Don't need */
2237 CloseHandle (pi
.hThread
); /* these. */
2240 /* Wait for subprocess to indicate that it is live. This may not
2241 actually be needed but it's hard to say since it is possible that
2242 there will be no console for a brief time after the process
2243 returns and there is no easy way to determine if/when this happens
2244 in Windows. So play it safe. */
2245 if (!x
|| (WaitForSingleObject (hello
, 10000) != WAIT_OBJECT_0
)
2246 || !AttachConsole (pi
.dwProcessId
))
2247 AllocConsole (); /* Oh well. Watch the flash. */
2251 /* Setting the owner of the console window to HWND_MESSAGE seems to
2252 hide it from the taskbar. Don't know if this method is faster than
2253 calling ShowWindowAsync but it should guarantee no taskbar presence
2254 for the hidden console. */
2255 SetParent (GetConsoleWindow (), HWND_MESSAGE
);
2257 CloseHandle (hello
);
2260 SetEvent (goodbye
); /* Tell helper process it's ok to exit. */
2261 CloseHandle (goodbye
);
2264 return invisible_console
= true;
2268 fhandler_console::need_invisible ()
2271 if (GetConsoleCP ())
2272 invisible_console
= false;
2276 /* The intent here is to allocate an "invisible" console if we have no
2277 controlling tty or to reuse the existing console if we already have
2278 a tty. So, first get the old window station. If there is no controlling
2279 terminal, create a new window station and then set it as the current
2280 window station. The subsequent AllocConsole will then be allocated
2281 invisibly. But, after doing that we have to restore any existing windows
2282 station or, strangely, characters will not be displayed in any windows
2283 drawn on the current screen. We only do this if we have changed to
2284 a new window station and if we had an existing windows station previously.
2285 We also close the previously opened window station even though AllocConsole
2286 is now "using" it. This doesn't seem to cause any problems.
2288 Things to watch out for if you make changes in this code:
2290 - Flashing, black consoles showing up when you start, e.g., ssh in
2292 - Non-displaying of characters in rxvt or xemacs if you start a
2293 process using setsid: bash -lc "setsid rxvt". */
2295 h
= GetProcessWindowStation ();
2300 || !GetUserObjectInformationW (h
, UOI_FLAGS
, &oi
, sizeof (oi
), &len
)
2301 || !(oi
.dwFlags
& WSF_VISIBLE
))
2304 debug_printf ("window station is not visible");
2306 invisible_console
= true;
2308 else if (wincap
.has_broken_alloc_console ())
2309 b
= create_invisible_console_workaround ();
2311 b
= create_invisible_console (h
);
2314 debug_printf ("invisible_console %d", invisible_console
);