📄 fhandler_console.cc
字号:
/* fhandler_console.cc Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license. Please consult the file "CYGWIN_LICENSE" fordetails. */#include "winsup.h"#include <sys/termios.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <unistd.h>#include <wingdi.h>#include <winuser.h>#include <wincon.h>#include <winnls.h>#include <ctype.h>#include <sys/cygwin.h>#include "cygerrno.h"#include "security.h"#include "fhandler.h"#include "path.h"#include "dtable.h"#include "cygheap.h"#include "sigproc.h"#include "pinfo.h"#include "shared_info.h"#include "cygthread.h"#define CONVERT_LIMIT 4096static BOOLcp_convert (UINT destcp, char *dest, UINT srccp, const char *src, DWORD size){ if (!size) /* no action */; else if (destcp == srccp) { if (dest != src) memcpy (dest, src, size); } else { WCHAR wbuffer[CONVERT_LIMIT]; /* same size as the maximum input, s.b. */ if (!MultiByteToWideChar (srccp, 0, src, size, wbuffer, sizeof (wbuffer))) return FALSE; if (!WideCharToMultiByte (destcp, 0, wbuffer, size, dest, size, NULL, NULL)) return FALSE; } return TRUE;}/* The results of GetConsoleCP() and GetConsoleOutputCP() cannot be cached, because a program or the user can change these values at any time. */inline BOOLcon_to_str (char *d, const char *s, DWORD sz){ return cp_convert (get_cp (), d, GetConsoleCP (), s, sz);}inline BOOLstr_to_con (char *d, const char *s, DWORD sz){ return cp_convert (GetConsoleOutputCP (), d, get_cp (), s, sz);}/* * Scroll the screen context. * x1, y1 - ul corner * x2, y2 - dr corner * xn, yn - new ul corner * Negative values represents current screen dimensions */#define srTop (dev_state->info.winTop + dev_state->scroll_region.Top)#define srBottom ((dev_state->scroll_region.Bottom < 0) ? dev_state->info.winBottom : dev_state->info.winTop + dev_state->scroll_region.Bottom)#define use_tty ISSTATE (myself, PID_USETTY)const char * get_nonascii_key (INPUT_RECORD&, char *);static console_state NO_COPY *shared_console_info;dev_console NO_COPY *fhandler_console::dev_state;/* Allocate and initialize the shared record for the current console. Returns a pointer to shared_console_info. */tty_min *fhandler_console::get_tty_stuff (int flags = 0){ if (dev_state) return &shared_console_info->tty_min_state; shared_console_info = (console_state *) open_shared (NULL, 0, cygheap->console_h, sizeof (*shared_console_info), SH_SHARED_CONSOLE); dev_state = &shared_console_info->dev_state; ProtectHandleINH (cygheap->console_h); if (!shared_console_info->tty_min_state.ntty) { shared_console_info->tty_min_state.setntty (TTY_CONSOLE); shared_console_info->tty_min_state.setsid (myself->sid); shared_console_info->tty_min_state.set_ctty (TTY_CONSOLE, flags); dev_state->scroll_region.Bottom = -1; dev_state->dwLastCursorPosition.X = -1; dev_state->dwLastCursorPosition.Y = -1; dev_state->default_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; dev_state->underline_color = FOREGROUND_GREEN | FOREGROUND_BLUE; dev_state->dim_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; dev_state->meta_mask = LEFT_ALT_PRESSED; /* Set the mask that determines if an input keystroke is modified by META. We set this based on the keyboard layout language loaded for the current thread. The left <ALT> key always generates META, but the right <ALT> key only generates META if we are using an English keyboard because many "international" keyboards replace common shell symbols ('[', '{', etc.) with accented language-specific characters (umlaut, accent grave, etc.). On these keyboards right <ALT> (called AltGr) is used to produce the shell symbols and should not be interpreted as META. */ if (PRIMARYLANGID (LOWORD (GetKeyboardLayout (0))) == LANG_ENGLISH) dev_state->meta_mask |= RIGHT_ALT_PRESSED; } return &shared_console_info->tty_min_state;}voidset_console_ctty (){ (void) fhandler_console::get_tty_stuff ();}/* Return the tty structure associated with a given tty number. If the tty number is < 0, just return a dummy record. */tty_min *tty_list::get_tty (int n){ static tty_min nada; if (n == TTY_CONSOLE) return fhandler_console::get_tty_stuff (); else if (n >= 0) return &cygwin_shared->tty.ttys[n]; else return &nada;}/* Determine if a console is associated with this process prior to a spawn. If it is, then we'll return 1. If the console has been initialized, then set it into a more friendly state for non-cygwin apps. */int __stdcallset_console_state_for_spawn (){ HANDLE h = CreateFile ("CONIN$", GENERIC_READ, FILE_SHARE_WRITE, &sec_none_nih, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) return 0; if (shared_console_info != NULL) { /* ACK. Temporarily define for use in TTYSETF macro */# define tc &shared_console_info->tty_min_state SetConsoleMode (h, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT); TTYSETF (RSTCONS);# undef tc } CloseHandle (h); return 1;}BOOLfhandler_console::set_raw_win32_keyboard_mode (BOOL new_mode){ BOOL old_mode = dev_state->raw_win32_keyboard_mode; dev_state->raw_win32_keyboard_mode = new_mode; syscall_printf ("raw keyboard mode %sabled", dev_state->raw_win32_keyboard_mode ? "en" : "dis"); return old_mode;};voidfhandler_console::set_cursor_maybe (){ CONSOLE_SCREEN_BUFFER_INFO now; if (!GetConsoleScreenBufferInfo (get_output_handle (), &now)) return; if (dev_state->dwLastCursorPosition.X != now.dwCursorPosition.X || dev_state->dwLastCursorPosition.Y != now.dwCursorPosition.Y) { SetConsoleCursorPosition (get_output_handle (), now.dwCursorPosition); dev_state->dwLastCursorPosition = now.dwCursorPosition; }}voidfhandler_console::send_winch_maybe (){ SHORT y = dev_state->info.dwWinSize.Y; SHORT x = dev_state->info.dwWinSize.X; fillin_info (); if (y != dev_state->info.dwWinSize.Y || x != dev_state->info.dwWinSize.X) tc->kill_pgrp (SIGWINCH);}int __stdcallfhandler_console::read (void *pv, size_t buflen){ HANDLE h = get_io_handle ();#define buf ((char *) pv) int ch; set_input_state (); int copied_chars = get_readahead_into_buffer (buf, buflen); if (copied_chars) return copied_chars; HANDLE w4[2]; DWORD nwait; char tmp[60]; w4[0] = h; if (cygthread::is ()) nwait = 1; else { w4[1] = signal_arrived; nwait = 2; } for (;;) { int bgres; if ((bgres = bg_check (SIGTTIN)) <= bg_eof) return bgres; set_cursor_maybe (); /* to make cursor appear on the screen immediately */ switch (WaitForMultipleObjects (nwait, w4, FALSE, INFINITE)) { case WAIT_OBJECT_0: break; case WAIT_OBJECT_0 + 1: goto sig_exit; default: __seterrno (); return -1; } DWORD nread; INPUT_RECORD input_rec; const char *toadd = NULL; if (!ReadConsoleInput (h, &input_rec, 1, &nread)) { __seterrno (); syscall_printf ("ReadConsoleInput failed, %E"); return -1; /* seems to be failure */ } /* check the event that occurred */ switch (input_rec.EventType) { case KEY_EVENT:#define virtual_key_code (input_rec.Event.KeyEvent.wVirtualKeyCode)#define control_key_state (input_rec.Event.KeyEvent.dwControlKeyState)#ifdef DEBUGGING /* allow manual switching to/from raw mode via ctrl-alt-scrolllock */ if (input_rec.Event.KeyEvent.bKeyDown && virtual_key_code == VK_SCROLL && control_key_state & (LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED) == LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED ) { set_raw_win32_keyboard_mode (!dev_state->raw_win32_keyboard_mode); continue; }#endif if (dev_state->raw_win32_keyboard_mode) { __small_sprintf (tmp, "\033{%u;%u;%u;%u;%u;%luK", input_rec.Event.KeyEvent.bKeyDown, input_rec.Event.KeyEvent.wRepeatCount, input_rec.Event.KeyEvent.wVirtualKeyCode, input_rec.Event.KeyEvent.wVirtualScanCode, input_rec.Event.KeyEvent.uChar.UnicodeChar, input_rec.Event.KeyEvent.dwControlKeyState); toadd = tmp; nread = strlen (toadd); break; } if (!input_rec.Event.KeyEvent.bKeyDown) continue;#define ich (input_rec.Event.KeyEvent.uChar.AsciiChar)#define wch (input_rec.Event.KeyEvent.uChar.UnicodeChar)#define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)#define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) if (wch == 0 || /* arrow/function keys */ (input_rec.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY)) { toadd = get_nonascii_key (input_rec, tmp); if (!toadd) continue; nread = strlen (toadd); } else { tmp[1] = ich; /* Need this check since US code page seems to have a bug when converting a CTRL-U. */ if ((unsigned char) ich > 0x7f) con_to_str (tmp + 1, tmp + 1, 1); /* Determine if the keystroke is modified by META. The tricky part is to distinguish whether the right Alt key should be recognized as Alt, or as AltGr. */ bool meta; if (wincap.altgr_is_ctrl_alt ()) /* WinNT: AltGr is reported as Ctrl+Alt, and Ctrl+Alt is treated just like AltGr. However, if Ctrl+Alt+key generates an ASCII control character, interpret is as META. */ meta = (control_key_state & ALT_PRESSED) != 0 && ((control_key_state & CTRL_PRESSED) == 0 || (ich >= 0 && ich <= 0x1f || ich == 0x7f)); else /* Win9x: there's no way to distinguish Alt from AltGr, so rely on dev_state->meta_mask heuristic (see fhandler_console constructor). */ meta = (control_key_state & dev_state->meta_mask) != 0; if (!meta) toadd = tmp + 1; else { tmp[0] = '\033'; tmp[1] = cyg_tolower (tmp[1]); toadd = tmp; nread++; } }#undef ich#undef wch#undef ALT_PRESSED#undef CTRL_PRESSED break; case MOUSE_EVENT: send_winch_maybe (); if (dev_state->use_mouse) { MOUSE_EVENT_RECORD& mouse_event = input_rec.Event.MouseEvent; /* Treat the double-click event like a regular button press */ if (mouse_event.dwEventFlags == DOUBLE_CLICK) { syscall_printf ("mouse: double-click -> click"); mouse_event.dwEventFlags = 0; } /* Did something other than a click occur? */ if (mouse_event.dwEventFlags) continue; /* If the mouse event occurred out of the area we can handle, ignore it. */ int x = mouse_event.dwMousePosition.X; int y = mouse_event.dwMousePosition.Y; if ((x + ' ' + 1 > 0xFF) || (y + ' ' + 1 > 0xFF)) { syscall_printf ("mouse: position out of range"); continue; } /* Ignore unimportant mouse buttons */ mouse_event.dwButtonState &= 0x7; /* This code assumes Windows never reports multiple button events at the same time. */ int b = 0; char sz[32]; if (mouse_event.dwButtonState == dev_state->dwLastButtonState) { syscall_printf ("mouse: button state unchanged"); continue; } else if (mouse_event.dwButtonState < dev_state->dwLastButtonState) { b = 3; strcpy (sz, "btn up"); } else if ((mouse_event.dwButtonState & 1) != (dev_state->dwLastButtonState & 1)) { b = 0; strcpy (sz, "btn1 down"); } else if ((mouse_event.dwButtonState & 2) != (dev_state->dwLastButtonState & 2)) { b = 2; strcpy (sz, "btn2 down"); } else if ((mouse_event.dwButtonState & 4) != (dev_state->dwLastButtonState & 4)) { b = 1; strcpy (sz, "btn3 down"); } /* Remember the current button state */ dev_state->dwLastButtonState = mouse_event.dwButtonState; /* If a button was pressed, remember the modifiers */ if (b != 3) { dev_state->nModifiers = 0; if (mouse_event.dwControlKeyState & SHIFT_PRESSED) dev_state->nModifiers |= 0x4; if (mouse_event.dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) dev_state->nModifiers |= 0x8; if (mouse_event.dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -