]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/fhandler_console.cc
Remove unneeded header files from source files throughout.
[newlib-cygwin.git] / winsup / cygwin / fhandler_console.cc
1 /* fhandler_console.cc
2
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2008 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include "miscfuncs.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <wingdi.h>
17 #include <winuser.h>
18 #include <winnls.h>
19 #include <ctype.h>
20 #include <sys/cygwin.h>
21 #include <cygwin/kd.h>
22 #include "cygerrno.h"
23 #include "security.h"
24 #include "path.h"
25 #include "fhandler.h"
26 #include "dtable.h"
27 #include "cygheap.h"
28 #include "sigproc.h"
29 #include "pinfo.h"
30 #include "shared_info.h"
31 #include "cygtls.h"
32 #include "tls_pbuf.h"
33 #include "registry.h"
34
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
38
39 /*
40 * Scroll the screen context.
41 * x1, y1 - ul corner
42 * x2, y2 - dr corner
43 * xn, yn - new ul corner
44 * Negative values represents current screen dimensions
45 */
46
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)
49
50 #define use_tty ISSTATE (myself, PID_USETTY)
51
52 const char * get_nonascii_key (INPUT_RECORD&, char *);
53
54 static console_state NO_COPY *shared_console_info;
55
56 dev_console NO_COPY *fhandler_console::dev_state;
57
58 /* Allocate and initialize the shared record for the current console.
59 Returns a pointer to shared_console_info. */
60 tty_min *
61 fhandler_console::get_tty_stuff (int flags = 0)
62 {
63 if (dev_state)
64 return &shared_console_info->tty_min_state;
65
66 shared_locations sh_shared_console = SH_SHARED_CONSOLE;
67 shared_console_info =
68 (console_state *) open_shared (NULL, 0, cygheap->console_h,
69 sizeof (*shared_console_info),
70 sh_shared_console);
71 dev_state = &shared_console_info->dev_state;
72
73 ProtectHandleINH (cygheap->console_h);
74 if (!shared_console_info->tty_min_state.ntty)
75 {
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);
79
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);
99 }
100
101 return &shared_console_info->tty_min_state;
102 }
103
104 void
105 set_console_ctty ()
106 {
107 fhandler_console::get_tty_stuff ();
108 }
109
110 /* Return the tty structure associated with a given tty number. If the
111 tty number is < 0, just return a dummy record. */
112 tty_min *
113 tty_list::get_tty (int n)
114 {
115 static tty_min nada;
116 if (n == TTY_CONSOLE)
117 return fhandler_console::get_tty_stuff ();
118 else if (n >= 0)
119 return &cygwin_shared->tty.ttys[n];
120 else
121 return &nada;
122 }
123
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. */
127 void __stdcall
128 set_console_state_for_spawn (bool iscyg)
129 {
130 if (fhandler_console::need_invisible () || iscyg
131 || (myself->ctty >= 0 && myself->ctty != TTY_CONSOLE))
132 return;
133
134 HANDLE h = CreateFile ("CONIN$", GENERIC_READ, FILE_SHARE_WRITE,
135 &sec_none_nih, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
136 NULL);
137
138 if (h == INVALID_HANDLE_VALUE)
139 return;
140
141 if (shared_console_info != NULL)
142 {
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);
146 }
147
148 CloseHandle (h);
149
150 return;
151 }
152
153 /* The results of GetConsoleCP() and GetConsoleOutputCP() cannot be
154 cached, because a program or the user can change these values at
155 any time. */
156 inline DWORD
157 dev_console::con_to_str (char *d, int dlen, WCHAR w)
158 {
159 return sys_wcstombs (d, dlen, &w, 1);
160 }
161
162 inline UINT
163 dev_console::get_console_cp ()
164 {
165 return alternate_charset_active ? GetConsoleOutputCP () : get_cp ();
166 }
167
168 inline DWORD
169 dev_console::str_to_con (PWCHAR d, const char *s, DWORD sz)
170 {
171 return MultiByteToWideChar (get_console_cp (), 0, s, sz, d, CONVERT_LIMIT);
172 }
173
174 bool
175 fhandler_console::set_raw_win32_keyboard_mode (bool new_mode)
176 {
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");
180 return old_mode;
181 };
182
183 void
184 fhandler_console::set_cursor_maybe ()
185 {
186 CONSOLE_SCREEN_BUFFER_INFO now;
187
188 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now))
189 return;
190
191 if (dev_state->dwLastCursorPosition.X != now.dwCursorPosition.X ||
192 dev_state->dwLastCursorPosition.Y != now.dwCursorPosition.Y)
193 {
194 SetConsoleCursorPosition (get_output_handle (), now.dwCursorPosition);
195 dev_state->dwLastCursorPosition = now.dwCursorPosition;
196 }
197 }
198
199 void
200 fhandler_console::send_winch_maybe ()
201 {
202 SHORT y = dev_state->info.dwWinSize.Y;
203 SHORT x = dev_state->info.dwWinSize.X;
204 dev_state->fillin_info (get_output_handle ());
205
206 if (y != dev_state->info.dwWinSize.Y || x != dev_state->info.dwWinSize.X)
207 {
208 extern fhandler_tty_master *tty_master;
209 dev_state->scroll_region.Top = 0;
210 dev_state->scroll_region.Bottom = -1;
211 if (tty_master)
212 tty_master->set_winsize (true);
213 else
214 tc->kill_pgrp (SIGWINCH);
215 }
216 }
217
218 void __stdcall
219 fhandler_console::read (void *pv, size_t& buflen)
220 {
221 HANDLE h = get_io_handle ();
222
223 #define buf ((char *) pv)
224
225 int ch;
226 set_input_state ();
227
228 int copied_chars = get_readahead_into_buffer (buf, buflen);
229
230 if (copied_chars)
231 {
232 buflen = copied_chars;
233 return;
234 }
235
236 HANDLE w4[2];
237 DWORD nwait;
238 char tmp[60];
239
240 w4[0] = h;
241 if (&_my_tls != _main_tls)
242 nwait = 1;
243 else
244 {
245 w4[1] = signal_arrived;
246 nwait = 2;
247 }
248
249 termios ti = tc->ti;
250 for (;;)
251 {
252 int bgres;
253 if ((bgres = bg_check (SIGTTIN)) <= bg_eof)
254 {
255 buflen = bgres;
256 return;
257 }
258
259 set_cursor_maybe (); /* to make cursor appear on the screen immediately */
260 switch (WaitForMultipleObjects (nwait, w4, FALSE, INFINITE))
261 {
262 case WAIT_OBJECT_0:
263 break;
264 case WAIT_OBJECT_0 + 1:
265 goto sig_exit;
266 default:
267 goto err;
268 }
269
270 DWORD nread;
271 INPUT_RECORD input_rec;
272 const char *toadd = NULL;
273
274 if (!ReadConsoleInputW (h, &input_rec, 1, &nread))
275 {
276 syscall_printf ("ReadConsoleInput failed, %E");
277 goto err; /* seems to be failure */
278 }
279
280 /* check the event that occurred */
281 switch (input_rec.EventType)
282 {
283 case KEY_EVENT:
284 #define virtual_key_code (input_rec.Event.KeyEvent.wVirtualKeyCode)
285 #define control_key_state (input_rec.Event.KeyEvent.dwControlKeyState)
286
287 dev_state->nModifiers = 0;
288
289 #ifdef DEBUGGING
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
294 )
295 {
296 set_raw_win32_keyboard_mode (!dev_state->raw_win32_keyboard_mode);
297 continue;
298 }
299 #endif
300
301 if (dev_state->raw_win32_keyboard_mode)
302 {
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);
310 toadd = tmp;
311 nread = strlen (toadd);
312 break;
313 }
314
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)
319
320 /* Ignore key up events, except for left alt events with non-zero character
321 */
322 if (!input_rec.Event.KeyEvent.bKeyDown &&
323 /*
324 Event for left alt, with a non-zero character, comes from
325 "alt + numerics" key sequence.
326 e.g. <left-alt> 0233 => &eacute;
327 */
328 !(wch != 0
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))
333 continue;
334
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;
343
344 if (wch == 0 ||
345 /* arrow/function keys */
346 (input_rec.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
347 {
348 toadd = get_nonascii_key (input_rec, tmp);
349 if (!toadd)
350 {
351 dev_state->nModifiers = 0;
352 continue;
353 }
354 nread = strlen (toadd);
355 }
356 else
357 {
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. */
362 bool meta;
363 meta = (control_key_state & ALT_PRESSED) != 0
364 && ((control_key_state & CTRL_PRESSED) == 0
365 || (wch <= 0x1f || wch == 0x7f));
366 if (!meta)
367 toadd = tmp + 1;
368 else if (dev_state->metabit)
369 {
370 tmp[1] |= 0x80;
371 toadd = tmp + 1;
372 }
373 else
374 {
375 tmp[0] = '\033';
376 tmp[1] = cyg_tolower (tmp[1]);
377 toadd = tmp;
378 nread++;
379 dev_state->nModifiers &= ~4;
380 }
381 }
382 #undef ich
383 #undef wch
384 #undef ALT_PRESSED
385 #undef CTRL_PRESSED
386 break;
387
388 case MOUSE_EVENT:
389 send_winch_maybe ();
390 if (dev_state->use_mouse)
391 {
392 MOUSE_EVENT_RECORD& mouse_event = input_rec.Event.MouseEvent;
393
394 /* Treat the double-click event like a regular button press */
395 if (mouse_event.dwEventFlags == DOUBLE_CLICK)
396 {
397 syscall_printf ("mouse: double-click -> click");
398 mouse_event.dwEventFlags = 0;
399 }
400
401 /* Did something other than a click occur? */
402 if (mouse_event.dwEventFlags)
403 continue;
404
405 /* Retrieve reported mouse position */
406 int x = mouse_event.dwMousePosition.X;
407 int y = mouse_event.dwMousePosition.Y;
408
409 /* Adjust mouse position by scroll buffer offset */
410 CONSOLE_SCREEN_BUFFER_INFO now;
411 if (GetConsoleScreenBufferInfo (get_output_handle (), &now))
412 {
413 y -= now.srWindow.Top;
414 x -= now.srWindow.Left;
415 }
416 else
417 {
418 syscall_printf ("mouse: cannot adjust position by scroll buffer offset");
419 continue;
420 }
421
422 /* If the mouse event occurred out of the area we can handle,
423 ignore it. */
424 if ((x + ' ' + 1 > 0xFF) || (y + ' ' + 1 > 0xFF))
425 {
426 syscall_printf ("mouse: position out of range");
427 continue;
428 }
429
430 /* Ignore unimportant mouse buttons */
431 mouse_event.dwButtonState &= 0x7;
432
433 /* This code assumes Windows never reports multiple button
434 events at the same time. */
435 int b = 0;
436 char sz[32];
437 if (mouse_event.dwButtonState == dev_state->dwLastButtonState)
438 {
439 syscall_printf ("mouse: button state unchanged");
440 continue;
441 }
442 else if (mouse_event.dwButtonState < dev_state->dwLastButtonState)
443 {
444 b = 3;
445 strcpy (sz, "btn up");
446 }
447 else if ((mouse_event.dwButtonState & 1) != (dev_state->dwLastButtonState & 1))
448 {
449 b = 0;
450 strcpy (sz, "btn1 down");
451 }
452 else if ((mouse_event.dwButtonState & 2) != (dev_state->dwLastButtonState & 2))
453 {
454 b = 2;
455 strcpy (sz, "btn2 down");
456 }
457 else if ((mouse_event.dwButtonState & 4) != (dev_state->dwLastButtonState & 4))
458 {
459 b = 1;
460 strcpy (sz, "btn3 down");
461 }
462
463 /* Remember the current button state */
464 dev_state->dwLastButtonState = mouse_event.dwButtonState;
465
466 /* If a button was pressed, remember the modifiers */
467 if (b != 3)
468 {
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;
476 }
477
478 b |= dev_state->nModifiers;
479
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);
483
484 toadd = tmp;
485 nread = 6;
486 }
487 break;
488
489 case FOCUS_EVENT:
490 case WINDOW_BUFFER_SIZE_EVENT:
491 send_winch_maybe ();
492 /* fall through */
493 default:
494 continue;
495 }
496
497 if (toadd)
498 {
499 line_edit_status res = line_edit (toadd, nread, ti);
500 if (res == line_edit_signalled)
501 goto sig_exit;
502 else if (res == line_edit_input_done)
503 break;
504 }
505 }
506
507 while (buflen)
508 if ((ch = get_readahead ()) < 0)
509 break;
510 else
511 {
512 buf[copied_chars++] = (unsigned char)(ch & 0xff);
513 buflen--;
514 }
515 #undef buf
516
517 buflen = copied_chars;
518 return;
519
520 err:
521 __seterrno ();
522 buflen = (size_t) -1;
523 return;
524
525 sig_exit:
526 set_sig_errno (EINTR);
527 buflen = (size_t) -1;
528 }
529
530 void
531 fhandler_console::set_input_state ()
532 {
533 if (tc->rstcons ())
534 input_tcsetattr (0, &tc->ti);
535 }
536
537 bool
538 dev_console::fillin_info (HANDLE h)
539 {
540 bool ret;
541 CONSOLE_SCREEN_BUFFER_INFO linfo;
542
543 if ((ret = GetConsoleScreenBufferInfo (h, &linfo)))
544 {
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;
552 }
553 else
554 {
555 memset (&info, 0, sizeof info);
556 info.dwWinSize.Y = 25;
557 info.dwWinSize.X = 80;
558 info.winBottom = 24;
559 }
560
561 return ret;
562 }
563
564 void
565 fhandler_console::scroll_screen (int x1, int y1, int x2, int y2, int xn, int yn)
566 {
567 SMALL_RECT sr1, sr2;
568 CHAR_INFO fill;
569 COORD dest;
570
571 dev_state->fillin_info (get_output_handle ());
572 sr1.Left = x1 >= 0 ? x1 : dev_state->info.dwWinSize.X - 1;
573 if (y1 == 0)
574 sr1.Top = dev_state->info.winTop;
575 else
576 sr1.Top = y1 > 0 ? y1 : dev_state->info.winBottom;
577 sr1.Right = x2 >= 0 ? x2 : dev_state->info.dwWinSize.X - 1;
578 if (y2 == 0)
579 sr1.Bottom = dev_state->info.winTop;
580 else
581 sr1.Bottom = y2 > 0 ? y2 : dev_state->info.winBottom;
582 sr2.Top = srTop;
583 sr2.Left = 0;
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;
589 if (yn == 0)
590 dest.Y = dev_state->info.winTop;
591 else
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);
596
597 /* ScrollConsoleScreenBuffer on Windows 95 is buggy - when scroll distance
598 * is more than half of screen, filling doesn't work as expected */
599
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);
605 }
606
607 int
608 fhandler_console::open (int flags, mode_t)
609 {
610 HANDLE h;
611
612 tcinit (get_tty_stuff (flags));
613
614 set_io_handle (NULL);
615 set_output_handle (NULL);
616
617 set_flags ((flags & ~O_TEXT) | O_BINARY);
618
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);
623
624 if (h == INVALID_HANDLE_VALUE)
625 {
626 __seterrno ();
627 return 0;
628 }
629 set_io_handle (h);
630 uninterruptible_io (true); // Handled explicitly in read code
631
632 h = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE,
633 FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none,
634 OPEN_EXISTING, 0, 0);
635
636 if (h == INVALID_HANDLE_VALUE)
637 {
638 __seterrno ();
639 return 0;
640 }
641 set_output_handle (h);
642
643 if (dev_state->fillin_info (get_output_handle ()))
644 {
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 ();
649 }
650
651 DWORD cflags;
652 if (GetConsoleMode (get_io_handle (), &cflags))
653 {
654 cflags |= ENABLE_PROCESSED_INPUT;
655 SetConsoleMode (get_io_handle (), ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT | cflags);
656 }
657
658 tc->rstcons (false);
659 set_open_status ();
660 cygheap->manage_console_count ("fhandler_console::open", 1);
661 debug_printf ("opened conin$ %p, conout$ %p", get_io_handle (),
662 get_output_handle ());
663
664 return 1;
665 }
666
667 int
668 fhandler_console::close ()
669 {
670 CloseHandle (get_io_handle ());
671 CloseHandle (get_output_handle ());
672 if (!hExeced)
673 cygheap->manage_console_count ("fhandler_console::close", -1);
674 return 0;
675 }
676
677 /* Special console dup to duplicate input and output handles. */
678
679 int
680 fhandler_console::dup (fhandler_base *child)
681 {
682 fhandler_console *fhc = (fhandler_console *) child;
683
684 if (!fhc->open (get_flags () & ~O_NOCTTY, 0))
685 system_printf ("error opening console, %E");
686
687 return 0;
688 }
689
690 int
691 fhandler_console::ioctl (unsigned int cmd, void *buf)
692 {
693 switch (cmd)
694 {
695 case TIOCGWINSZ:
696 int st;
697
698 st = dev_state->fillin_info (get_output_handle ());
699 if (st)
700 {
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);
708 return 0;
709 }
710 else
711 {
712 syscall_printf ("WINSZ failed");
713 __seterrno ();
714 return -1;
715 }
716 return 0;
717 case TIOCSWINSZ:
718 bg_check (SIGTTOU);
719 return 0;
720 case KDGKBMETA:
721 *(int *) buf = (dev_state->metabit) ? K_METABIT : K_ESCPREFIX;
722 return 0;
723 case KDSKBMETA:
724 if ((int) buf == K_METABIT)
725 dev_state->metabit = TRUE;
726 else if ((int) buf == K_ESCPREFIX)
727 dev_state->metabit = FALSE;
728 else
729 {
730 set_errno (EINVAL);
731 return -1;
732 }
733 return 0;
734 case TIOCLINUX:
735 if (* (int *) buf == 6)
736 {
737 * (int *) buf = dev_state->nModifiers;
738 return 0;
739 }
740 else
741 {
742 set_errno (EINVAL);
743 return -1;
744 }
745 }
746
747 return fhandler_base::ioctl (cmd, buf);
748 }
749
750 int
751 fhandler_console::tcflush (int queue)
752 {
753 int res = 0;
754 if (queue == TCIFLUSH
755 || queue == TCIOFLUSH)
756 {
757 if (!FlushConsoleInputBuffer (get_io_handle ()))
758 {
759 __seterrno ();
760 res = -1;
761 }
762 }
763 return res;
764 }
765
766 int
767 fhandler_console::output_tcsetattr (int, struct termios const *t)
768 {
769 /* All the output bits we can ignore */
770
771 DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
772
773 int res = SetConsoleMode (get_output_handle (), flags) ? 0 : -1;
774 syscall_printf ("%d = tcsetattr (,%x) (ENABLE FLAGS %x) (lflag %x oflag %x)",
775 res, t, flags, t->c_lflag, t->c_oflag);
776 return res;
777 }
778
779 int
780 fhandler_console::input_tcsetattr (int, struct termios const *t)
781 {
782 /* Ignore the optional_actions stuff, since all output is emitted
783 instantly */
784
785 DWORD oflags;
786
787 if (!GetConsoleMode (get_io_handle (), &oflags))
788 oflags = 0;
789 DWORD flags = 0;
790
791 #if 0
792 /* Enable/disable LF -> CRLF conversions */
793 rbinary ((t->c_iflag & INLCR) ? false : true);
794 #endif
795
796 /* There's some disparity between what we need and what's
797 available. We've got ECHO and ICANON, they've
798 got ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT. */
799
800 tc->ti = *t;
801
802 if (t->c_lflag & ECHO)
803 {
804 flags |= ENABLE_ECHO_INPUT;
805 }
806 if (t->c_lflag & ICANON)
807 {
808 flags |= ENABLE_LINE_INPUT;
809 }
810
811 if (flags & ENABLE_ECHO_INPUT
812 && !(flags & ENABLE_LINE_INPUT))
813 {
814 /* This is illegal, so turn off the echo here, and fake it
815 when we read the characters */
816
817 flags &= ~ENABLE_ECHO_INPUT;
818 }
819
820 if (t->c_lflag & ISIG)
821 {
822 flags |= ENABLE_PROCESSED_INPUT;
823 }
824
825 if (use_tty)
826 {
827 flags = 0; // ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
828 tc->ti.c_iflag = 0;
829 tc->ti.c_lflag = 0;
830 }
831
832 flags |= ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT;
833
834 int res;
835 if (flags == oflags)
836 res = 0;
837 else
838 {
839 res = SetConsoleMode (get_io_handle (), flags) ? 0 : -1;
840 if (res < 0)
841 __seterrno ();
842 syscall_printf ("%d = tcsetattr (,%x) enable flags %p, c_lflag %p iflag %p",
843 res, t, flags, t->c_lflag, t->c_iflag);
844 }
845
846 tc->rstcons (false);
847 return res;
848 }
849
850 int
851 fhandler_console::tcsetattr (int a, struct termios const *t)
852 {
853 int res = output_tcsetattr (a, t);
854 if (res != 0)
855 return res;
856 return input_tcsetattr (a, t);
857 }
858
859 int
860 fhandler_console::tcgetattr (struct termios *t)
861 {
862 int res;
863 *t = tc->ti;
864
865 t->c_cflag |= CS8;
866
867 DWORD flags;
868
869 if (!GetConsoleMode (get_io_handle (), &flags))
870 {
871 __seterrno ();
872 res = -1;
873 }
874 else
875 {
876 if (flags & ENABLE_ECHO_INPUT)
877 t->c_lflag |= ECHO;
878
879 if (flags & ENABLE_LINE_INPUT)
880 t->c_lflag |= ICANON;
881
882 if (flags & ENABLE_PROCESSED_INPUT)
883 t->c_lflag |= ISIG;
884
885 /* What about ENABLE_WINDOW_INPUT
886 and ENABLE_MOUSE_INPUT ? */
887
888 /* All the output bits we can ignore */
889 res = 0;
890 }
891 syscall_printf ("%d = tcgetattr (%p) enable flags %p, t->lflag %p, t->iflag %p",
892 res, t, flags, t->c_lflag, t->c_iflag);
893 return res;
894 }
895
896 fhandler_console::fhandler_console () :
897 fhandler_termios ()
898 {
899 trunc_buf.len = 0;
900 }
901
902 void
903 dev_console::set_color (HANDLE h)
904 {
905 WORD win_fg = fg;
906 WORD win_bg = bg;
907 if (reverse)
908 {
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);
918 }
919
920 /* apply attributes */
921 if (underline)
922 win_fg = underline_color;
923 /* emulate blink with bright background */
924 if (blink)
925 win_bg |= BACKGROUND_INTENSITY;
926 if (intensity == INTENSITY_INVISIBLE)
927 win_fg = win_bg;
928 else if (intensity == INTENSITY_BOLD)
929 /* apply foreground intensity only in non-reverse mode! */
930 if (reverse)
931 win_bg |= BACKGROUND_INTENSITY;
932 else
933 win_fg |= FOREGROUND_INTENSITY;
934
935 current_win32_attr = win_fg | win_bg;
936 if (h)
937 SetConsoleTextAttribute (h, current_win32_attr);
938 }
939
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)
944 void
945 dev_console::set_default_attr ()
946 {
947 blink = underline = reverse = false;
948 intensity = INTENSITY_NORMAL;
949 fg = default_color & FOREGROUND_ATTR_MASK;
950 bg = default_color & BACKGROUND_ATTR_MASK;
951 set_color (NULL);
952 }
953
954 /*
955 * Clear the screen context from x1/y1 to x2/y2 cell.
956 * Negative values represents current screen dimensions
957 */
958 void
959 fhandler_console::clear_screen (int x1, int y1, int x2, int y2)
960 {
961 COORD tlc;
962 DWORD done;
963 int num;
964
965 dev_state->fillin_info (get_output_handle ());
966
967 if (x1 < 0)
968 x1 = dev_state->info.dwWinSize.X - 1;
969 if (y1 < 0)
970 y1 = dev_state->info.winBottom;
971 if (x2 < 0)
972 x2 = dev_state->info.dwWinSize.X - 1;
973 if (y2 < 0)
974 y2 = dev_state->info.winBottom;
975
976 num = abs (y1 - y2) * dev_state->info.dwBufferSize.X + abs (x1 - x2) + 1;
977
978 if ((y2 * dev_state->info.dwBufferSize.X + x2) > (y1 * dev_state->info.dwBufferSize.X + x1))
979 {
980 tlc.X = x1;
981 tlc.Y = y1;
982 }
983 else
984 {
985 tlc.X = x2;
986 tlc.Y = y2;
987 }
988 FillConsoleOutputCharacterA (get_output_handle (), ' ',
989 num,
990 tlc,
991 &done);
992 FillConsoleOutputAttribute (get_output_handle (),
993 dev_state->current_win32_attr,
994 num,
995 tlc,
996 &done);
997 }
998
999 void
1000 fhandler_console::cursor_set (bool rel_to_top, int x, int y)
1001 {
1002 COORD pos;
1003
1004 dev_state->fillin_info (get_output_handle ());
1005 if (y > dev_state->info.winBottom)
1006 y = dev_state->info.winBottom;
1007 else if (y < 0)
1008 y = 0;
1009 else if (rel_to_top)
1010 y += dev_state->info.winTop;
1011
1012 if (x > dev_state->info.dwWinSize.X)
1013 x = dev_state->info.dwWinSize.X - 1;
1014 else if (x < 0)
1015 x = 0;
1016
1017 pos.X = x;
1018 pos.Y = y;
1019 SetConsoleCursorPosition (get_output_handle (), pos);
1020 }
1021
1022 void
1023 fhandler_console::cursor_rel (int x, int y)
1024 {
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);
1029 }
1030
1031 void
1032 fhandler_console::cursor_get (int *x, int *y)
1033 {
1034 dev_state->fillin_info (get_output_handle ());
1035 *y = dev_state->info.dwCursorPosition.Y;
1036 *x = dev_state->info.dwCursorPosition.X;
1037 }
1038
1039 #define BAK 1
1040 #define ESC 2
1041 #define NOR 0
1042 #define IGN 4
1043 #if 1
1044 #define ERR 5
1045 #else
1046 #define ERR NOR
1047 #endif
1048 #define DWN 6
1049 #define BEL 7
1050 #define TAB 8 /* We should't let the console deal with these */
1051 #define CR 13
1052 #define LF 10
1053
1054 static const char base_chars[256] =
1055 {
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 };
1088
1089 void
1090 fhandler_console::char_command (char c)
1091 {
1092 int x, y;
1093 char buf[40];
1094
1095 switch (c)
1096 {
1097 case 'm': /* Set Graphics Rendition */
1098 for (int i = 0; i <= dev_state->nargs_; i++)
1099 switch (dev_state->args_[i])
1100 {
1101 case 0: /* normal color */
1102 dev_state->set_default_attr ();
1103 break;
1104 case 1: /* bold */
1105 dev_state->intensity = INTENSITY_BOLD;
1106 break;
1107 case 4:
1108 dev_state->underline = 1;
1109 break;
1110 case 5: /* blink mode */
1111 dev_state->blink = true;
1112 break;
1113 case 7: /* reverse */
1114 dev_state->reverse = true;
1115 break;
1116 case 8: /* invisible */
1117 dev_state->intensity = INTENSITY_INVISIBLE;
1118 break;
1119 case 9: /* dim */
1120 dev_state->intensity = INTENSITY_DIM;
1121 break;
1122 case 10: /* end alternate charset */
1123 dev_state->alternate_charset_active = false;
1124 break;
1125 case 11: /* start alternate charset */
1126 dev_state->alternate_charset_active = true;
1127 break;
1128 case 24:
1129 dev_state->underline = false;
1130 break;
1131 case 27:
1132 dev_state->reverse = false;
1133 break;
1134 case 30: /* BLACK foreground */
1135 dev_state->fg = 0;
1136 break;
1137 case 31: /* RED foreground */
1138 dev_state->fg = FOREGROUND_RED;
1139 break;
1140 case 32: /* GREEN foreground */
1141 dev_state->fg = FOREGROUND_GREEN;
1142 break;
1143 case 33: /* YELLOW foreground */
1144 dev_state->fg = FOREGROUND_RED | FOREGROUND_GREEN;
1145 break;
1146 case 34: /* BLUE foreground */
1147 dev_state->fg = FOREGROUND_BLUE;
1148 break;
1149 case 35: /* MAGENTA foreground */
1150 dev_state->fg = FOREGROUND_RED | FOREGROUND_BLUE;
1151 break;
1152 case 36: /* CYAN foreground */
1153 dev_state->fg = FOREGROUND_BLUE | FOREGROUND_GREEN;
1154 break;
1155 case 37: /* WHITE foreg */
1156 dev_state->fg = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
1157 break;
1158 case 39:
1159 dev_state->fg = dev_state->default_color & FOREGROUND_ATTR_MASK;
1160 break;
1161 case 40: /* BLACK background */
1162 dev_state->bg = 0;
1163 break;
1164 case 41: /* RED background */
1165 dev_state->bg = BACKGROUND_RED;
1166 break;
1167 case 42: /* GREEN background */
1168 dev_state->bg = BACKGROUND_GREEN;
1169 break;
1170 case 43: /* YELLOW background */
1171 dev_state->bg = BACKGROUND_RED | BACKGROUND_GREEN;
1172 break;
1173 case 44: /* BLUE background */
1174 dev_state->bg = BACKGROUND_BLUE;
1175 break;
1176 case 45: /* MAGENTA background */
1177 dev_state->bg = BACKGROUND_RED | BACKGROUND_BLUE;
1178 break;
1179 case 46: /* CYAN background */
1180 dev_state->bg = BACKGROUND_BLUE | BACKGROUND_GREEN;
1181 break;
1182 case 47: /* WHITE background */
1183 dev_state->bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
1184 break;
1185 case 49:
1186 dev_state->bg = dev_state->default_color & BACKGROUND_ATTR_MASK;
1187 break;
1188 }
1189 dev_state->set_color (get_output_handle ());
1190 break;
1191 case 'h':
1192 case 'l':
1193 if (!dev_state->saw_question_mark)
1194 {
1195 switch (dev_state->args_[0])
1196 {
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");
1200 break;
1201 }
1202 break;
1203 }
1204 switch (dev_state->args_[0])
1205 {
1206 case 47: /* Save/Restore screen */
1207 if (c == 'h') /* save */
1208 {
1209 CONSOLE_SCREEN_BUFFER_INFO now;
1210 COORD cob = { 0, 0 };
1211
1212 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now))
1213 break;
1214
1215 dev_state->savebufsiz.X = now.srWindow.Right - now.srWindow.Left + 1;
1216 dev_state->savebufsiz.Y = now.srWindow.Bottom - now.srWindow.Top + 1;
1217
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);
1222
1223 ReadConsoleOutputW (get_output_handle (), dev_state->savebuf,
1224 dev_state->savebufsiz, cob, &now.srWindow);
1225 }
1226 else /* restore */
1227 {
1228 CONSOLE_SCREEN_BUFFER_INFO now;
1229 COORD cob = { 0, 0 };
1230
1231 if (!GetConsoleScreenBufferInfo (get_output_handle (), &now))
1232 break;
1233
1234 if (!dev_state->savebuf)
1235 break;
1236
1237 WriteConsoleOutputW (get_output_handle (), dev_state->savebuf,
1238 dev_state->savebufsiz, cob, &now.srWindow);
1239
1240 cfree (dev_state->savebuf);
1241 dev_state->savebuf = NULL;
1242 dev_state->savebufsiz.X = dev_state->savebufsiz.Y = 0;
1243 }
1244 break;
1245
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");
1249 break;
1250
1251 case 2000: /* Raw keyboard mode */
1252 set_raw_win32_keyboard_mode ((c == 'h') ? true : false);
1253 break;
1254
1255 default: /* Ignore */
1256 syscall_printf ("unknown h/l command: %d", dev_state->args_[0]);
1257 break;
1258 }
1259 break;
1260 case 'J':
1261 switch (dev_state->args_[0])
1262 {
1263 case 0: /* Clear to end of screen */
1264 cursor_get (&x, &y);
1265 clear_screen (x, y, -1, -1);
1266 break;
1267 case 1: /* Clear from beginning of screen to cursor */
1268 cursor_get (&x, &y);
1269 clear_screen (0, 0, x, y);
1270 break;
1271 case 2: /* Clear screen */
1272 clear_screen (0, 0, -1, -1);
1273 cursor_set (true, 0,0);
1274 break;
1275 default:
1276 goto bad_escape;
1277 }
1278 break;
1279
1280 case 'A':
1281 cursor_rel (0, -(dev_state->args_[0] ? dev_state->args_[0] : 1));
1282 break;
1283 case 'B':
1284 cursor_rel (0, dev_state->args_[0] ? dev_state->args_[0] : 1);
1285 break;
1286 case 'C':
1287 cursor_rel (dev_state->args_[0] ? dev_state->args_[0] : 1, 0);
1288 break;
1289 case 'D':
1290 cursor_rel (-(dev_state->args_[0] ? dev_state->args_[0] : 1),0);
1291 break;
1292 case 'K':
1293 switch (dev_state->args_[0])
1294 {
1295 case 0: /* Clear to end of line */
1296 cursor_get (&x, &y);
1297 clear_screen (x, y, -1, y);
1298 break;
1299 case 2: /* Clear line */
1300 cursor_get (&x, &y);
1301 clear_screen (0, y, -1, y);
1302 break;
1303 case 1: /* Clear from bol to cursor */
1304 cursor_get (&x, &y);
1305 clear_screen (0, y, x, y);
1306 break;
1307 default:
1308 goto bad_escape;
1309 }
1310 break;
1311 case 'H':
1312 case 'f':
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);
1315 break;
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);
1319 break;
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));
1323 break;
1324 case 's': /* Save cursor position */
1325 cursor_get (&dev_state->savex, &dev_state->savey);
1326 dev_state->savey -= dev_state->info.winTop;
1327 break;
1328 case 'u': /* Restore cursor position */
1329 cursor_set (true, dev_state->savex, dev_state->savey);
1330 break;
1331 case 'I': /* TAB */
1332 cursor_get (&x, &y);
1333 cursor_set (false, 8 * (x / 8 + 1), y);
1334 break;
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]);
1339 break;
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);
1344 break;
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);
1349 break;
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);
1354 break;
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);
1358 break;
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]);
1363 break;
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);
1369 break;
1370 case 'Z': /* Back tab */
1371 cursor_get (&x, &y);
1372 cursor_set (false, ((8 * (x / 8 + 1)) - 8), y);
1373 break;
1374 case 'b': /* Repeat char #1 #2 times */
1375 if (dev_state->insert_mode)
1376 {
1377 cursor_get (&x, &y);
1378 scroll_screen (x, y, -1, y, x + dev_state->args_[1], y);
1379 }
1380 while (dev_state->args_[1]--)
1381 WriteFile (get_output_handle (), &dev_state->args_[0], 1, (DWORD *) &x, 0);
1382 break;
1383 case 'c': /* u9 - Terminal enquire string */
1384 strcpy (buf, "\033[?6c");
1385 puts_readahead (buf);
1386 break;
1387 case 'n':
1388 switch (dev_state->args_[0])
1389 {
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);
1396 break;
1397 default:
1398 goto bad_escape;
1399 }
1400 break;
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);
1405 break;
1406 case 'g': /* TAB set/clear */
1407 break;
1408 default:
1409 bad_escape:
1410 break;
1411 }
1412 }
1413
1414 static void
1415 beep ()
1416 {
1417 reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS, "AppEvents", "Schemes", "Apps",
1418 ".Default", ".Default", ".Current", NULL);
1419 if (r.created ())
1420 {
1421 char *buf = 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"));
1427 }
1428 MessageBeep (MB_OK);
1429 }
1430
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. */
1434 void
1435 fhandler_console::write_replacement_char (const unsigned char *char_p)
1436 {
1437 int n;
1438 WCHAR def_cp_chars[2];
1439 DWORD done;
1440
1441 n = MultiByteToWideChar (GetACP (), 0, (const CHAR *) char_p, 1,
1442 def_cp_chars, 2);
1443 if (n)
1444 WriteConsoleW (get_output_handle (), def_cp_chars, n, &done, 0);
1445 else
1446 WriteConsoleW (get_output_handle (), L"?", 1, &done, 0);
1447 }
1448
1449 const unsigned char *
1450 fhandler_console::write_normal (const unsigned char *src,
1451 const unsigned char *end)
1452 {
1453 /* Scan forward to see what a char which needs special treatment */
1454 DWORD done;
1455 DWORD buf_len;
1456 const unsigned char *found = src;
1457 const unsigned char *nfound;
1458 UINT cp = dev_state->get_console_cp ();
1459
1460 /* First check if we have cached lead bytes of a former try to write
1461 a truncated multibyte sequence. If so, process it. */
1462 if (trunc_buf.len)
1463 {
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)
1470 {
1471 trunc_buf.len += cp_len;
1472 return end;
1473 }
1474 /* Valid multibyte sequence? Process. */
1475 if (nfound)
1476 {
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);
1482 trunc_buf.len = 0;
1483 return found;
1484 }
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... */
1489 trunc_buf.len = 0;
1490 /* ... and proceed. */
1491 }
1492
1493 while (found < end
1494 && found - src < CONVERT_LIMIT
1495 && base_chars[*found] == NOR)
1496 {
1497 nfound = next_char (cp, found, end);
1498 if (!nfound) /* Invalid multibyte sequence. */
1499 break;
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);
1504 return end;
1505 }
1506 found = nfound;
1507 }
1508
1509 /* Print all the base ones out */
1510 if (found != src)
1511 {
1512 DWORD len = found - src;
1513 buf_len = dev_state->str_to_con (write_buf, (const char *) src, len);
1514 if (!buf_len)
1515 {
1516 debug_printf ("conversion error, handle %p",
1517 get_output_handle ());
1518 __seterrno ();
1519 return 0;
1520 }
1521
1522 if (dev_state->insert_mode)
1523 {
1524 int x, y;
1525 cursor_get (&x, &y);
1526 scroll_screen (x, y, -1, y, x + buf_len, y);
1527 }
1528
1529 register PWCHAR buf = write_buf;
1530 do
1531 {
1532 if (!WriteConsoleW (get_output_handle (), buf, buf_len, &done, 0))
1533 {
1534 debug_printf ("write failed, handle %p", get_output_handle ());
1535 __seterrno ();
1536 return 0;
1537 }
1538 buf_len -= done;
1539 buf += done;
1540 }
1541 while (buf_len > 0);
1542 if (len >= CONVERT_LIMIT)
1543 return found;
1544 }
1545
1546 if (found < end)
1547 {
1548 int x, y;
1549 switch (base_chars[*found])
1550 {
1551 case BEL:
1552 beep ();
1553 break;
1554 case ESC:
1555 dev_state->state_ = gotesc;
1556 break;
1557 case DWN:
1558 cursor_get (&x, &y);
1559 if (y >= srBottom)
1560 {
1561 if (y >= dev_state->info.winBottom && !dev_state->scroll_region.Top)
1562 WriteConsoleW (get_output_handle (), L"\n", 1, &done, 0);
1563 else
1564 {
1565 scroll_screen (0, srTop + 1, -1, srBottom, 0, srTop);
1566 y--;
1567 }
1568 }
1569 cursor_set (false, ((tc->ti.c_oflag & ONLCR) ? 0 : x), y + 1);
1570 break;
1571 case BAK:
1572 cursor_rel (-1, 0);
1573 break;
1574 case IGN:
1575 cursor_rel (1, 0);
1576 break;
1577 case CR:
1578 cursor_get (&x, &y);
1579 cursor_set (false, 0, y);
1580 break;
1581 case ERR:
1582 /* Don't print chars marked as ERR chars. */
1583 break;
1584 case TAB:
1585 cursor_get (&x, &y);
1586 cursor_set (false, 8 * (x / 8 + 1), y);
1587 break;
1588 case NOR:
1589 write_replacement_char (found);
1590 break;
1591 }
1592 found++;
1593 }
1594 return found;
1595 }
1596
1597 int
1598 fhandler_console::write (const void *vsrc, size_t len)
1599 {
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. */
1606 tmp_pathbuf tp;
1607 write_buf = tp.w_get ();
1608
1609 debug_printf ("%x, %d", vsrc, len);
1610
1611 while (src < end)
1612 {
1613 debug_printf ("at %d(%c) state is %d", *src, isprint (*src) ? *src : ' ',
1614 dev_state->state_);
1615 switch (dev_state->state_)
1616 {
1617 case normal:
1618 src = write_normal (src, end);
1619 if (!src) /* write_normal failed */
1620 return -1;
1621 break;
1622 case gotesc:
1623 if (*src == '[')
1624 {
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;
1630 }
1631 else if (*src == ']')
1632 {
1633 dev_state->rarg = 0;
1634 dev_state->my_title_buf[0] = '\0';
1635 dev_state->state_ = gotrsquare;
1636 }
1637 else if (*src == 'M') /* Reverse Index */
1638 {
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;
1642 }
1643 else if (*src == 'c') /* Reset Linux terminal */
1644 {
1645 dev_state->set_default_attr ();
1646 clear_screen (0, 0, -1, -1);
1647 cursor_set (true, 0, 0);
1648 dev_state->state_ = normal;
1649 }
1650 else if (*src == '8') /* Restore cursor position */
1651 {
1652 cursor_set (true, dev_state->savex, dev_state->savey);
1653 dev_state->state_ = normal;
1654 }
1655 else if (*src == '7') /* Save cursor position */
1656 {
1657 cursor_get (&dev_state->savex, &dev_state->savey);
1658 dev_state->savey -= dev_state->info.winTop;
1659 dev_state->state_ = normal;
1660 }
1661 else if (*src == 'R')
1662 dev_state->state_ = normal;
1663 else
1664 {
1665 dev_state->state_ = normal;
1666 }
1667 src++;
1668 break;
1669 case gotarg1:
1670 if (isdigit (*src))
1671 {
1672 dev_state->args_[dev_state->nargs_] = dev_state->args_[dev_state->nargs_] * 10 + *src - '0';
1673 src++;
1674 }
1675 else if (*src == ';')
1676 {
1677 src++;
1678 dev_state->nargs_++;
1679 if (dev_state->nargs_ >= MAXARGS)
1680 dev_state->nargs_--;
1681 }
1682 else
1683 {
1684 dev_state->state_ = gotcommand;
1685 }
1686 break;
1687 case gotcommand:
1688 char_command (*src++);
1689 dev_state->state_ = normal;
1690 break;
1691 case gotrsquare:
1692 if (isdigit (*src))
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;
1696 else
1697 dev_state->state_ = eattitle;
1698 src++;
1699 break;
1700 case eattitle:
1701 case gettitle:
1702 {
1703 int n = strlen (dev_state->my_title_buf);
1704 if (*src < ' ')
1705 {
1706 if (*src == '\007' && dev_state->state_ == gettitle)
1707 {
1708 if (old_title)
1709 strcpy (old_title, dev_state->my_title_buf);
1710 set_console_title (dev_state->my_title_buf);
1711 }
1712 dev_state->state_ = normal;
1713 }
1714 else if (n < TITLESIZE)
1715 {
1716 dev_state->my_title_buf[n++] = *src;
1717 dev_state->my_title_buf[n] = '\0';
1718 }
1719 src++;
1720 break;
1721 }
1722 case gotsquare:
1723 if (*src == ';')
1724 {
1725 dev_state->state_ = gotarg1;
1726 dev_state->nargs_++;
1727 src++;
1728 }
1729 else if (isalpha (*src))
1730 dev_state->state_ = gotcommand;
1731 else if (*src != '@' && !isalpha (*src) && !isdigit (*src))
1732 {
1733 if (*src == '?')
1734 dev_state->saw_question_mark = true;
1735 /* ignore any extra chars between [ and first arg or command */
1736 src++;
1737 }
1738 else
1739 dev_state->state_ = gotarg1;
1740 break;
1741 }
1742 }
1743
1744 syscall_printf ("%d = write_console (,..%d)", len, len);
1745
1746 return len;
1747 }
1748
1749 static struct {
1750 int vk;
1751 const char *val[4];
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}}
1780 };
1781
1782 const char *
1783 get_nonascii_key (INPUT_RECORD& input_rec, char *tmp)
1784 {
1785 #define NORMAL 0
1786 #define SHIFT 1
1787 #define CONTROL 2
1788 #define ALT 3
1789 int modifier_index = NORMAL;
1790
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;
1799
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];
1803
1804 if (input_rec.Event.KeyEvent.uChar.AsciiChar)
1805 {
1806 tmp[0] = input_rec.Event.KeyEvent.uChar.AsciiChar;
1807 tmp[1] = '\0';
1808 return tmp;
1809 }
1810 return NULL;
1811 }
1812
1813 void
1814 fhandler_console::init (HANDLE f, DWORD a, mode_t bin)
1815 {
1816 // this->fhandler_termios::init (f, mode, bin);
1817 /* Ensure both input and output console handles are open */
1818 int flags = 0;
1819
1820 a &= GENERIC_READ | GENERIC_WRITE;
1821 if (a == GENERIC_READ)
1822 flags = O_RDONLY;
1823 if (a == GENERIC_WRITE)
1824 flags = O_WRONLY;
1825 if (a == (GENERIC_READ | GENERIC_WRITE))
1826 flags = O_RDWR;
1827 open (flags | O_BINARY);
1828 if (f != INVALID_HANDLE_VALUE)
1829 CloseHandle (f); /* Reopened by open */
1830
1831 tcsetattr (0, &tc->ti);
1832 }
1833
1834 int
1835 fhandler_console::igncr_enabled ()
1836 {
1837 return tc->ti.c_iflag & IGNCR;
1838 }
1839
1840 void
1841 fhandler_console::set_close_on_exec (bool val)
1842 {
1843 fhandler_base::set_close_on_exec (val);
1844 set_no_inheritance (output_handle, val);
1845 }
1846
1847 void __stdcall
1848 set_console_title (char *title)
1849 {
1850 char buf[257];
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);
1856 }
1857
1858 void
1859 fhandler_console::fixup_after_fork_exec (bool execing)
1860 {
1861 HANDLE h = get_handle ();
1862 HANDLE oh = get_output_handle ();
1863
1864 if ((execing && close_on_exec ()) || open (O_NOCTTY | get_flags (), 0))
1865 cygheap->manage_console_count ("fhandler_console::fixup_after_fork_exec", -1);
1866 else
1867 {
1868 bool sawerr = false;
1869 if (!get_io_handle ())
1870 {
1871 system_printf ("error opening input console handle for %s after fork/exec, errno %d, %E", get_name (), get_errno ());
1872 sawerr = true;
1873 }
1874 if (!get_output_handle ())
1875 {
1876 system_printf ("error opening output console handle for %s after fork/exec, errno %d, %E", get_name (), get_errno ());
1877 sawerr = true;
1878 }
1879
1880 if (!sawerr)
1881 system_printf ("error opening console after fork/exec, errno %d, %E", get_errno ());
1882 }
1883
1884 if (!close_on_exec ())
1885 {
1886 CloseHandle (h);
1887 CloseHandle (oh);
1888 }
1889 }
1890
1891 bool NO_COPY fhandler_console::invisible_console;
1892
1893 // #define WINSTA_ACCESS (WINSTA_READATTRIBUTES | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE | WINSTA_CREATEDESKTOP | WINSTA_EXITWINDOWS)
1894 #define WINSTA_ACCESS STANDARD_RIGHTS_READ
1895
1896 bool
1897 fhandler_console::need_invisible ()
1898 {
1899 BOOL b = false;
1900 if (GetConsoleCP ())
1901 invisible_console = false;
1902 else
1903 {
1904 HWINSTA h, horig;
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.
1916
1917 Things to watch out for if you make changes in this code:
1918
1919 - Flashing, black consoles showing up when you start, e.g., ssh in
1920 an xterm.
1921 - Non-displaying of characters in rxvt or xemacs if you start a
1922 process using setsid: bash -lc "setsid rxvt". */
1923
1924 h = horig = GetProcessWindowStation ();
1925
1926 USEROBJECTFLAGS oi;
1927 DWORD len;
1928 if (!horig
1929 || !GetUserObjectInformationW (horig, UOI_FLAGS, &oi, sizeof (oi), &len)
1930 || !(oi.dwFlags & WSF_VISIBLE))
1931 {
1932 b = true;
1933 debug_printf ("window station is not visible");
1934 invisible_console = true;
1935 }
1936 else
1937 {
1938 if (myself->ctty != TTY_CONSOLE)
1939 {
1940 h = CreateWindowStationW (NULL, 0, WINSTA_ACCESS, NULL);
1941 termios_printf ("%p = CreateWindowStation(NULL), %E", h);
1942 if (h)
1943 {
1944 b = SetProcessWindowStation (h);
1945 termios_printf ("SetProcessWindowStation %d, %E", b);
1946 }
1947 }
1948 b = AllocConsole (); /* will cause flashing if CreateWindowStation
1949 failed */
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;
1955 }
1956 }
1957
1958 debug_printf ("invisible_console %d", invisible_console);
1959 return b;
1960 }
This page took 0.125933 seconds and 5 git commands to generate.