2000-02-18 03:38:33 +08:00
|
|
|
/* fhandler_console.cc
|
|
|
|
|
|
|
|
This file is part of Cygwin.
|
|
|
|
|
|
|
|
This software is a copyrighted work licensed under the terms of the
|
|
|
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
|
|
|
details. */
|
|
|
|
|
2000-08-03 00:28:18 +08:00
|
|
|
#include "winsup.h"
|
2008-04-08 00:15:45 +08:00
|
|
|
#include "miscfuncs.h"
|
2000-02-18 03:38:33 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2009-03-24 20:18:34 +08:00
|
|
|
#include <wchar.h>
|
2000-02-18 03:38:33 +08:00
|
|
|
#include <ctype.h>
|
2012-03-08 17:36:11 +08:00
|
|
|
#include <sys/param.h>
|
2000-09-08 10:56:55 +08:00
|
|
|
#include <sys/cygwin.h>
|
2006-07-03 23:29:10 +08:00
|
|
|
#include <cygwin/kd.h>
|
2019-03-31 23:47:46 +08:00
|
|
|
#include <unistd.h>
|
2000-08-22 11:58:47 +08:00
|
|
|
#include "cygerrno.h"
|
2001-07-27 03:22:24 +08:00
|
|
|
#include "security.h"
|
2001-10-01 12:10:07 +08:00
|
|
|
#include "path.h"
|
* devices.cc: New file.
* devices.gperf: New file.
* devices.shilka: New file.
* cygwin-gperf: New file.
* cygwin-shilka: New file.
* fhandler_fifo.cc: New file.
* fhandler_nodevice.cc : New file. Reorganize headers so that path.h precedes
fhandler.h throughout. Remove device argument and unit arguments from fhandler
constructors throughout. Remove pc arguments to fhandler functions and use
internal pc element instead, throughout. Use dev element in pc throughout.
Use major/minor elements rather than units and device numbers previously in
fhandler class. Use correct methods for fhandler file names rather than
directly accessing file name variables, throughout.
* Makefile.in (DLL_OFILES): Add devices.o, fhandler_fifo.o
* dcrt0.cc (dll_crt0_1): Call device::init.
* devices.h: Renumber devices based on more Linux-like major/minor numbers.
Add more devices. Declare standard device storage.
(device): Declare struct.
* dir.cc (opendir): Use new 'build_fh_name' to construct a fhandler_* type.
* dtable.cc (dtable::get_debugger_info): Ditto.
(cygwin_attach_handle_to_fd): Ditto.
(dtable::release): Remove special FH_SOCKET case in favor of generic
"need_fixup_before" test.
(dtable::init_std_file_from_handle): Use either build_fh_dev or build_fh_name
to build standard fhandler.
(dtable::build_fh_name): Renamed from dtable::build_fhandler_from_name. Move
out of dtable class. Don't accept a path_conv argument. Just build it here
and pass it to:
(build_fh_pc): Renamed from dtable::build_fhandler. Move out of dtable class.
Use intrinsic device type in path_conv to create new fhandler.
(build_fh_dev): Renamed from dtable::build_fhandler. Move out of dtable class.
Simplify arguments to just take new 'device' type and a name. Just return
pointer to fhandler rather than trying to insert into dtable.
(dtable::dup_worker): Accommodate above build_fh name changes.
(dtable::find_fifo): New (currently broken) function.
(handle_to_fn): Use strechr for efficiency.
* dtable.h: Reflect above build_fh name changes and argument differences.
(fhandler_base *&operator []): Return self rather than copy of self.
* fhandler.cc (fhandler_base::operator =): Use pc element to set normalized
path.
(fhandler_base::set_name): Ditto.
(fhandler_base::raw_read): Use method to access name.
(fhandler_base::write): Correctly use get_output_handle rather than get_handle.
(handler_base::device_access_denied): New function.
(fhandler_base::open): Eliminate pc argument and use pc element of
fhandler_base throughout.
(fhandler_base::fstat): Detect if device is based in filesystem and use
fstat_fs to calculate stat, if so.
(fhandler_base::fhandler_base): Eliminate handling of file names and, instead,
just free appropriate component from pc.
(fhandler_base::opendir): Remove path_conv parameter.
* fhandler.h: Remove all device flags.
(fhandler_base::pc): New element.
(fhandler_base::set_name): Change argument to path_conv.
(fhandler_base::error): New function.
(fhandler_base::exists): New function.
(fhandler_base::pc_binmode): New function.
(fhandler_base::dev): New function.
(fhandler_base::open_fs): New function.
(fhandler_base::fstat_fs): New function.
(fhandler_base::fstat_by_name): New function.
(fhandler_base::fstat_by_handle): New function.
(fhandler_base::isfifo): New function.
(fhandler_base::is_slow): New function.
(fhandler_base::is_auto_device): New function.
(fhandler_base::is_fs_special): New function.
(fhandler_base::device_access_denied): New function.
(fhandler_base::operator DWORD&): New operator.
(fhandler_base::get_name): Return normalized path from pc.
(fhandler_base::get_win32_name): Return windows path from pc.
(fhandler_base::isdevice): Renamed from is_device.
(fhandler_base::get_native_name): Return device format.
(fhandler_fifo): New class.
(fhandler_nodevice): New class.
(select_stuff::device_specific): Remove array.
(select_stuff::device_specific_pipe): New class element.
(select_stuff::device_specific_socket): New class element.
(select_stuff::device_specific_serial): New class element.
(select_stuff::select_stuff): Initialize new elements.
* fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Move to base class
from fhandler_disk_file.
(fhandler_base::fstat_by_name): Ditto.
(fhandler_base::fstat_by_name): Ditto.
(fhandler_disk_file::open): Move most functionality into
fhandler_base::open_fs.
(fhandler_base::open_fs): New function.
(fhandler_disk_file::close): Move most functionality into
fhandler_base::close_fs.
(fhandler_base::close_fs): New function.
* fhandler_mem.cc (fhandler_dev_mem::open): Use device name in debugging
output.
* fhandler_socket.cc (fhandler_socket::set_connect_secret): Copy standard
urandom device into appropriate place.
(fhandler_socket::accept): Reflect change in fdsock return value.
* fhandler_tty.cc: See "throughouts" above.
* net.cc: Accommodate fdsock change throughout.
(fdsock): Return success or failure, accept fd argument and device argument.
* path.cc (symlink_info::major): New element.
(symlink_info::minor): New element.
(symlink_info::parse_device): Declare new function.
(fs_info::update): Accommodate changes in path_conv class.
(path_conv::fillin): Ditto.
(path_conv::return_and_clear_normalized_path): Eliminate.
(path_conv::set_normalized_path): New function.
(path_conv::path_conv): Set info in dev element. Use path_conv methods Check
for FH_FS rather than FH_BAD to indicate when to fill in filesystem stuff.
where appropriate rather than direct access. Use set_normalized_path to set
normalized path.
(windows_device_names): Eliminate.
(get_dev): Ditto.
(get_raw_device_number): Ditto.
(get_device_number): Ditto.
(win32_device_name): Call new device name parser to do most of the heavy
lifting.
(mount_info::conv_to_win32_path): Fill in dev field as appropriate.
(symlink_worker): Handle new device files.
(symlink_info::check): Ditto.
(symlink_info::parse_device): Define new function.
* path.h (executable_states): Move here from fhandler.h.
(fs_info): Rename variables to *_storage and create methods for accessing same.
(path_conv): Add dev element, remove devn and unit and adjust inline methods to
accommodate.
(set_normalized_path): Declare new function.
* pinfo.cc (_pinfo::commune_recv): Add broken support for handling fifos.
(_pinfo::commune_send): Ditto.
* pipe.cc (fhandler_pipe::close): check for existence of handle before closing
it.
(handler_pipe::create): Rename from make_pipe. Change arguments to accept
fhandler_pipe array. Accommodate fifos.
(pipe): Rework to deal with fhandler_pipe::create changes.
(_pipe): Ditto.
* select.cc: Use individual device_specific types throughout rather than
indexing with obsolete device number.
(set_bits): Use is_socket call rather than checking device number.
* shared_info.h (CURR_MOUNT_MAGIC): Update.
(conv_to_win32_path): Reflect addition of device argument.
* syscalls.cc (mknod_worker): New function.
(open): Use build_fh_name to build fhandler.
(chown_worker): Detect if this is an 'auto' device rather than an on-filesystem
device and handle appropriately.
(chmod_device): New function.
(chmod): Detect if this is an 'auto' device rather than an on-filesystem device
and handle appropriately. Use chmod_device to set mode of in-filesystem
devices.
(stat_worker): Eliminate path_conv argument. Call build_fh_name to construct
fhandler. Use fh->error() rather than pc->error to detect errors in fhandler
construction.
(access_worker): New function pulled from access. Accommodate in-filesystem
devices.
(access): Use access_worker.
(fpathconf): Detect if this is an 'auto' device rather than an on-filesystem
device and handle appropriately.
(mknod_worker): New function.
(mknod32): New function.
(chroot): Free normalized path -- assuming it was actually cmalloced.
* tty.cc (create_tty_master): Tweak for new device class.
(tty::common_init): Ditto.
* winsup.h (stat_worker): Remove.
(symlink_worker): Declare.
* exceptions.cc (set_process_mask): Just call sig_dispatch_pending and don't
worry about pending_signals since sig_dispatch_pending should always do the
right thing now.
(sig_handle): Reorganize SIGCONT handling to more closely conform to SUSv3.
* pinfo.h: Move __SIG enum to sigproc.h.
(PICOM_FIFO): New enum element.
(_pinfo): Remove 'thread2signal' stuff throughout class.
(_pinfo::commune_send): Make varargs.
(_pinfo::sigtodo): Eliminate.
(_pinfo::thread2signal): Ditto.
* signal.cc (kill_worker): Eliminate call to setthread2signal.
* sigproc.cc (local_sigtodo): Eliminate.
(getlocal_sigtodo): Ditto.
(sigelem): New class.
(pending_signals): New class.
(sigqueue): New variable, start of sigqueue linked list.
(sigcatch_nonmain): Eliminate.
(sigcatch_main): Eliminate.
(sigcatch_nosync): Eliminate.
(sigcomplete_nonmain): Eliminate.
(pending_signals): Eliminate.
(sig_clear): Call signal thread to clear pending signals, unless already in
signal thread.
(sigpending): Call signal thread to get pending signals.
(sig_dispatch_pending): Eliminate use of pending_signals and just check
sigqueue.
(sigproc_terminate): Eliminate all of the obsolete semaphore stuff. Close
signal pipe handle.
(sig_send): Eliminate all of the obsolete semaphore stuff and use pipe to send
signals.
(getevent): Eliminate.
(pending_signals::add): New function.
(pending_signals::del): New function.
(pending_signals::next): New function.
(wait_sig): Eliminate all of the obsolete semaphore stuff. Use pipe to
communicate and maintain a linked list of signals.
* sigproc.h: Move __SIG defines here. Add __SIGPENDING.
(sig_dispatch_pending): Remove "C" specifier.
(sig_handle): Accept a mask argument.
* thread.cc: Remove signal handling considerations throughout.
2003-09-25 08:37:18 +08:00
|
|
|
#include "fhandler.h"
|
2001-04-19 05:10:15 +08:00
|
|
|
#include "dtable.h"
|
|
|
|
#include "cygheap.h"
|
2000-08-22 13:10:20 +08:00
|
|
|
#include "sigproc.h"
|
|
|
|
#include "pinfo.h"
|
2000-09-08 00:23:51 +08:00
|
|
|
#include "shared_info.h"
|
2004-05-16 12:18:50 +08:00
|
|
|
#include "cygtls.h"
|
2008-03-11 01:23:50 +08:00
|
|
|
#include "tls_pbuf.h"
|
2006-01-03 09:15:29 +08:00
|
|
|
#include "registry.h"
|
2011-07-23 02:50:42 +08:00
|
|
|
#include <asm/socket.h>
|
2011-11-14 09:29:49 +08:00
|
|
|
#include "sync.h"
|
|
|
|
#include "child_info.h"
|
2012-06-18 04:50:24 +08:00
|
|
|
#include "cygwait.h"
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2008-03-11 01:23:50 +08:00
|
|
|
/* Don't make this bigger than NT_MAX_PATH as long as the temporary buffer
|
|
|
|
is allocated using tmp_pathbuf!!! */
|
|
|
|
#define CONVERT_LIMIT NT_MAX_PATH
|
2001-04-09 08:44:25 +08:00
|
|
|
|
2012-04-24 22:39:22 +08:00
|
|
|
#define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
|
|
|
|
#define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
|
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
#define con (shared_console_info->con)
|
|
|
|
#define srTop (con.b.srWindow.Top + con.scroll_region.Top)
|
2019-03-31 23:47:47 +08:00
|
|
|
#define srBottom ((con.scroll_region.Bottom < 0) ? \
|
|
|
|
con.b.srWindow.Bottom : \
|
|
|
|
con.b.srWindow.Top + con.scroll_region.Bottom)
|
2019-11-13 02:04:59 +08:00
|
|
|
#define con_is_legacy (shared_console_info && con.is_legacy)
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2009-05-04 11:51:16 +08:00
|
|
|
const unsigned fhandler_console::MAX_WRITE_CHARS = 16384;
|
|
|
|
|
2011-06-04 08:12:29 +08:00
|
|
|
fhandler_console::console_state NO_COPY *fhandler_console::shared_console_info;
|
2002-10-08 14:16:16 +08:00
|
|
|
|
2011-05-07 04:12:20 +08:00
|
|
|
bool NO_COPY fhandler_console::invisible_console;
|
|
|
|
|
2021-01-18 21:10:57 +08:00
|
|
|
/* Mutex for AttachConsole()/FreeConsole() in fhandler_tty.cc */
|
|
|
|
HANDLE NO_COPY attach_mutex;
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
acquire_attach_mutex (DWORD t)
|
|
|
|
{
|
|
|
|
if (attach_mutex)
|
|
|
|
WaitForSingleObject (attach_mutex, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
release_attach_mutex ()
|
|
|
|
{
|
|
|
|
if (attach_mutex)
|
|
|
|
ReleaseMutex (attach_mutex);
|
|
|
|
}
|
|
|
|
|
2020-01-27 20:14:32 +08:00
|
|
|
/* con_ra is shared in the same process.
|
|
|
|
Only one console can exist in a process, therefore, static is suitable. */
|
|
|
|
static struct fhandler_base::rabuf_t con_ra;
|
|
|
|
|
2020-02-26 23:32:59 +08:00
|
|
|
/* Write pending buffer for ESC sequence handling
|
|
|
|
in xterm compatible mode */
|
2020-08-27 11:35:03 +08:00
|
|
|
static wchar_t last_char;
|
2020-03-03 03:30:09 +08:00
|
|
|
|
2020-03-09 04:41:13 +08:00
|
|
|
/* simple helper class to accumulate output in a buffer
|
|
|
|
and send that to the console on request: */
|
|
|
|
static class write_pending_buffer
|
2020-03-03 03:30:09 +08:00
|
|
|
{
|
2020-03-09 04:41:13 +08:00
|
|
|
private:
|
|
|
|
static const size_t WPBUF_LEN = 256u;
|
2020-08-27 11:35:03 +08:00
|
|
|
char buf[WPBUF_LEN];
|
2020-03-09 04:41:13 +08:00
|
|
|
size_t ixput;
|
|
|
|
public:
|
2020-08-27 11:35:03 +08:00
|
|
|
inline void put (char x)
|
2020-03-09 04:41:13 +08:00
|
|
|
{
|
|
|
|
if (ixput < WPBUF_LEN)
|
|
|
|
buf[ixput++] = x;
|
|
|
|
}
|
|
|
|
inline void empty () { ixput = 0u; }
|
2020-08-27 11:35:03 +08:00
|
|
|
inline void send (HANDLE &handle)
|
2020-03-09 04:41:13 +08:00
|
|
|
{
|
2020-08-27 11:35:03 +08:00
|
|
|
wchar_t bufw[WPBUF_LEN];
|
|
|
|
DWORD len = sys_mbstowcs (bufw, WPBUF_LEN, buf, ixput);
|
|
|
|
WriteConsoleW (handle, bufw, len, NULL, 0);
|
2020-03-09 04:41:13 +08:00
|
|
|
}
|
|
|
|
} wpbuf;
|
2020-02-26 23:32:59 +08:00
|
|
|
|
2009-09-30 17:23:45 +08:00
|
|
|
static void
|
|
|
|
beep ()
|
|
|
|
{
|
2011-04-19 18:02:06 +08:00
|
|
|
const WCHAR ding[] = L"\\media\\ding.wav";
|
|
|
|
reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS, L"AppEvents", L"Schemes",
|
|
|
|
L"Apps", L".Default", L".Default", L".Current", NULL);
|
2009-09-30 17:23:45 +08:00
|
|
|
if (r.created ())
|
|
|
|
{
|
2011-04-19 18:02:06 +08:00
|
|
|
PWCHAR buf = NULL;
|
2011-04-19 18:15:09 +08:00
|
|
|
UINT len = GetSystemWindowsDirectoryW (buf, 0) * sizeof (WCHAR);
|
2011-04-19 18:02:06 +08:00
|
|
|
buf = (PWCHAR) alloca (len += sizeof (ding));
|
2011-04-19 18:15:09 +08:00
|
|
|
UINT res = GetSystemWindowsDirectoryW (buf, len);
|
2009-09-30 17:23:45 +08:00
|
|
|
if (res && res <= len)
|
2011-04-19 18:02:06 +08:00
|
|
|
r.set_string (L"", wcscat (buf, ding));
|
2009-09-30 17:23:45 +08:00
|
|
|
}
|
|
|
|
MessageBeep (MB_OK);
|
|
|
|
}
|
|
|
|
|
2011-06-04 08:12:29 +08:00
|
|
|
fhandler_console::console_state *
|
|
|
|
fhandler_console::open_shared_console (HWND hw, HANDLE& h, bool& create)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2011-05-29 02:17:09 +08:00
|
|
|
wchar_t namebuf[(sizeof "XXXXXXXXXXXXXXXXXX-consNNNNNNNNNN")];
|
2012-02-14 19:27:43 +08:00
|
|
|
__small_swprintf (namebuf, L"%S-cons%p", &cygheap->installation_key, hw);
|
2011-06-04 08:12:29 +08:00
|
|
|
|
2011-06-08 04:55:10 +08:00
|
|
|
shared_locations m = create ? SH_SHARED_CONSOLE : SH_JUSTOPEN;
|
2011-06-04 08:12:29 +08:00
|
|
|
console_state *res = (console_state *)
|
2011-06-06 13:02:13 +08:00
|
|
|
open_shared (namebuf, 0, h, sizeof (*shared_console_info), &m);
|
2011-06-08 04:55:10 +08:00
|
|
|
create = m != SH_JUSTOPEN;
|
2011-06-04 08:12:29 +08:00
|
|
|
return res;
|
2011-05-29 02:17:09 +08:00
|
|
|
}
|
2014-05-09 22:28:48 +08:00
|
|
|
|
2011-05-29 02:17:09 +08:00
|
|
|
class console_unit
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
unsigned long bitmask;
|
|
|
|
HWND me;
|
|
|
|
|
|
|
|
public:
|
|
|
|
operator int () const {return n;}
|
|
|
|
console_unit (HWND);
|
|
|
|
friend BOOL CALLBACK enum_windows (HWND, LPARAM);
|
|
|
|
};
|
2002-10-09 12:08:05 +08:00
|
|
|
|
2011-05-29 02:17:09 +08:00
|
|
|
BOOL CALLBACK
|
|
|
|
enum_windows (HWND hw, LPARAM lp)
|
|
|
|
{
|
|
|
|
console_unit *this1 = (console_unit *) lp;
|
|
|
|
if (hw == this1->me)
|
|
|
|
return TRUE;
|
2011-06-05 10:10:31 +08:00
|
|
|
HANDLE h = NULL;
|
2011-06-04 08:12:29 +08:00
|
|
|
fhandler_console::console_state *cs;
|
|
|
|
if ((cs = fhandler_console::open_shared_console (hw, h)))
|
2001-08-07 13:15:59 +08:00
|
|
|
{
|
2011-05-29 02:17:09 +08:00
|
|
|
this1->bitmask ^= 1 << cs->tty_min_state.getntty ();
|
|
|
|
UnmapViewOfFile ((void *) cs);
|
|
|
|
CloseHandle (h);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
2002-10-08 14:16:16 +08:00
|
|
|
|
2011-05-29 02:17:09 +08:00
|
|
|
console_unit::console_unit (HWND me0):
|
|
|
|
bitmask (0xffffffff), me (me0)
|
|
|
|
{
|
|
|
|
EnumWindows (enum_windows, (LPARAM) this);
|
|
|
|
n = (_minor_t) ffs (bitmask) - 1;
|
|
|
|
if (n < 0)
|
|
|
|
api_fatal ("console device allocation failure - too many consoles in use, max consoles is 32");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
fhandler_console::set_unit ()
|
|
|
|
{
|
2011-06-04 08:12:29 +08:00
|
|
|
bool created;
|
2011-06-13 04:15:26 +08:00
|
|
|
fh_devices devset;
|
2012-03-11 01:51:33 +08:00
|
|
|
lock_ttys here;
|
2012-03-30 01:34:55 +08:00
|
|
|
HWND me;
|
2012-04-13 10:30:51 +08:00
|
|
|
fh_devices this_unit = dev ();
|
|
|
|
bool generic_console = this_unit == FH_CONIN || this_unit == FH_CONOUT;
|
2011-05-29 02:17:09 +08:00
|
|
|
if (shared_console_info)
|
2011-06-13 04:15:26 +08:00
|
|
|
{
|
2011-12-18 07:39:47 +08:00
|
|
|
fh_devices shared_unit =
|
2011-06-13 04:15:26 +08:00
|
|
|
(fh_devices) shared_console_info->tty_min_state.getntty ();
|
|
|
|
devset = (shared_unit == this_unit || this_unit == FH_CONSOLE
|
2012-04-13 10:30:51 +08:00
|
|
|
|| generic_console
|
2011-06-13 04:15:26 +08:00
|
|
|
|| this_unit == FH_TTY) ?
|
|
|
|
shared_unit : FH_ERROR;
|
2012-04-02 06:28:39 +08:00
|
|
|
created = false;
|
2011-06-13 04:15:26 +08:00
|
|
|
}
|
2019-03-31 23:47:47 +08:00
|
|
|
else if ((!generic_console &&
|
|
|
|
(myself->ctty != -1 && !iscons_dev (myself->ctty)))
|
2012-03-30 01:34:55 +08:00
|
|
|
|| !(me = GetConsoleWindow ()))
|
2012-04-02 06:28:39 +08:00
|
|
|
devset = FH_ERROR;
|
2011-05-29 02:17:09 +08:00
|
|
|
else
|
|
|
|
{
|
2011-06-04 08:12:29 +08:00
|
|
|
created = true;
|
2019-03-31 23:47:47 +08:00
|
|
|
shared_console_info =
|
|
|
|
open_shared_console (me, cygheap->console_h, created);
|
2011-05-29 02:17:09 +08:00
|
|
|
ProtectHandleINH (cygheap->console_h);
|
2011-06-04 08:12:29 +08:00
|
|
|
if (created)
|
2019-03-31 23:47:47 +08:00
|
|
|
shared_console_info->
|
|
|
|
tty_min_state.setntty (DEV_CONS_MAJOR, console_unit (me));
|
2011-06-13 04:15:26 +08:00
|
|
|
devset = (fh_devices) shared_console_info->tty_min_state.getntty ();
|
2019-03-31 23:47:46 +08:00
|
|
|
if (created)
|
2021-01-15 16:32:10 +08:00
|
|
|
con.owner = myself->pid;
|
2001-08-07 13:15:59 +08:00
|
|
|
}
|
2019-08-12 21:46:23 +08:00
|
|
|
if (!created && shared_console_info)
|
|
|
|
{
|
|
|
|
pinfo p (con.owner);
|
|
|
|
if (!p)
|
2020-02-18 17:12:54 +08:00
|
|
|
con.owner = myself->pid;
|
2019-08-12 21:46:23 +08:00
|
|
|
}
|
2002-10-08 14:16:16 +08:00
|
|
|
|
2011-06-13 04:15:26 +08:00
|
|
|
dev ().parse (devset);
|
2011-06-17 07:00:00 +08:00
|
|
|
if (devset != FH_ERROR)
|
|
|
|
pc.file_attributes (FILE_ATTRIBUTE_NORMAL);
|
2012-04-02 06:28:39 +08:00
|
|
|
else
|
|
|
|
{
|
2019-03-30 15:12:02 +08:00
|
|
|
set_handle (NULL);
|
2012-04-02 06:28:39 +08:00
|
|
|
set_output_handle (NULL);
|
|
|
|
created = false;
|
|
|
|
}
|
2011-06-04 08:12:29 +08:00
|
|
|
return created;
|
2011-05-29 02:17:09 +08:00
|
|
|
}
|
|
|
|
|
2011-06-13 04:15:26 +08:00
|
|
|
/* Allocate and initialize the shared record for the current console. */
|
|
|
|
void
|
2011-10-16 06:37:30 +08:00
|
|
|
fhandler_console::setup ()
|
2011-05-29 02:17:09 +08:00
|
|
|
{
|
|
|
|
if (set_unit ())
|
2019-03-31 23:47:46 +08:00
|
|
|
{
|
|
|
|
con.scroll_region.Bottom = -1;
|
|
|
|
con.dwLastCursorPosition.X = -1;
|
|
|
|
con.dwLastCursorPosition.Y = -1;
|
|
|
|
con.dwLastMousePosition.X = -1;
|
|
|
|
con.dwLastMousePosition.Y = -1;
|
2020-03-02 09:12:57 +08:00
|
|
|
con.savex = con.savey = -1;
|
|
|
|
con.screen_alternated = false;
|
2019-03-31 23:47:46 +08:00
|
|
|
con.dwLastButtonState = 0; /* none pressed */
|
|
|
|
con.last_button_code = 3; /* released */
|
|
|
|
con.underline_color = FOREGROUND_GREEN | FOREGROUND_BLUE;
|
|
|
|
con.dim_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
|
|
|
con.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)
|
|
|
|
con.meta_mask |= RIGHT_ALT_PRESSED;
|
|
|
|
con.set_default_attr ();
|
|
|
|
con.backspace_keycode = CERASE;
|
|
|
|
con.cons_rapoi = NULL;
|
|
|
|
shared_console_info->tty_min_state.is_console = true;
|
2020-05-30 17:25:03 +08:00
|
|
|
con.cursor_key_app_mode = false;
|
2019-03-31 23:47:46 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2020-01-27 20:14:32 +08:00
|
|
|
char *&
|
|
|
|
fhandler_console::rabuf ()
|
|
|
|
{
|
|
|
|
return con_ra.rabuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t &
|
|
|
|
fhandler_console::ralen ()
|
|
|
|
{
|
|
|
|
return con_ra.ralen;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t &
|
|
|
|
fhandler_console::raixget ()
|
|
|
|
{
|
|
|
|
return con_ra.raixget;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t &
|
|
|
|
fhandler_console::raixput ()
|
|
|
|
{
|
|
|
|
return con_ra.raixput;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t &
|
|
|
|
fhandler_console::rabuflen ()
|
|
|
|
{
|
|
|
|
return con_ra.rabuflen;
|
|
|
|
}
|
|
|
|
|
2021-01-15 16:32:10 +08:00
|
|
|
/* The function request_xterm_mode_{in,out}put() should be static so that
|
|
|
|
they can be called even after the fhandler_console instance is deleted. */
|
2020-02-18 17:12:54 +08:00
|
|
|
void
|
2021-01-15 16:32:10 +08:00
|
|
|
fhandler_console::request_xterm_mode_input (bool req, const handle_set_t *p)
|
2020-02-18 17:12:54 +08:00
|
|
|
{
|
|
|
|
if (con_is_legacy)
|
|
|
|
return;
|
2021-01-15 16:32:10 +08:00
|
|
|
WaitForSingleObject (p->input_mutex, INFINITE);
|
|
|
|
DWORD dwMode;
|
|
|
|
GetConsoleMode (p->input_handle, &dwMode);
|
2020-02-18 17:12:54 +08:00
|
|
|
if (req)
|
|
|
|
{
|
2021-01-15 16:32:10 +08:00
|
|
|
if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_INPUT))
|
2020-02-18 17:12:54 +08:00
|
|
|
{
|
|
|
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
|
2021-01-15 16:32:10 +08:00
|
|
|
SetConsoleMode (p->input_handle, dwMode);
|
2020-05-30 17:25:03 +08:00
|
|
|
if (con.cursor_key_app_mode) /* Restore DECCKM */
|
2021-01-15 16:32:10 +08:00
|
|
|
{
|
|
|
|
request_xterm_mode_output (true, p);
|
|
|
|
WriteConsoleW (p->output_handle, L"\033[?1h", 5, NULL, 0);
|
|
|
|
}
|
2020-02-18 17:12:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-01-15 16:32:10 +08:00
|
|
|
if (dwMode & ENABLE_VIRTUAL_TERMINAL_INPUT)
|
2020-02-18 17:12:54 +08:00
|
|
|
{
|
|
|
|
dwMode &= ~ENABLE_VIRTUAL_TERMINAL_INPUT;
|
2021-01-15 16:32:10 +08:00
|
|
|
SetConsoleMode (p->input_handle, dwMode);
|
2020-02-18 17:12:54 +08:00
|
|
|
}
|
|
|
|
}
|
2021-01-15 16:32:10 +08:00
|
|
|
ReleaseMutex (p->input_mutex);
|
2020-02-18 17:12:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-01-15 16:32:10 +08:00
|
|
|
fhandler_console::request_xterm_mode_output (bool req, const handle_set_t *p)
|
2020-02-18 17:12:54 +08:00
|
|
|
{
|
|
|
|
if (con_is_legacy)
|
|
|
|
return;
|
2021-01-15 16:32:10 +08:00
|
|
|
WaitForSingleObject (p->output_mutex, INFINITE);
|
|
|
|
DWORD dwMode;
|
|
|
|
GetConsoleMode (p->output_handle, &dwMode);
|
2020-02-18 17:12:54 +08:00
|
|
|
if (req)
|
|
|
|
{
|
2021-01-15 16:32:10 +08:00
|
|
|
if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
|
2020-02-18 17:12:54 +08:00
|
|
|
{
|
|
|
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
2021-01-15 16:32:10 +08:00
|
|
|
SetConsoleMode (p->output_handle, dwMode);
|
2020-02-18 17:12:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-01-15 16:32:10 +08:00
|
|
|
if (dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
2020-02-18 17:12:54 +08:00
|
|
|
{
|
|
|
|
dwMode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
2021-01-15 16:32:10 +08:00
|
|
|
SetConsoleMode (p->output_handle, dwMode);
|
2020-02-18 17:12:54 +08:00
|
|
|
}
|
|
|
|
}
|
2021-01-15 16:32:10 +08:00
|
|
|
ReleaseMutex (p->output_mutex);
|
2020-02-18 17:12:54 +08:00
|
|
|
}
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
/* Return the tty structure associated with a given tty number. If the
|
|
|
|
tty number is < 0, just return a dummy record. */
|
|
|
|
tty_min *
|
2011-05-29 02:17:09 +08:00
|
|
|
tty_list::get_cttyp ()
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2013-04-23 17:44:36 +08:00
|
|
|
dev_t n = myself->ctty;
|
2011-05-29 02:17:09 +08:00
|
|
|
if (iscons_dev (n))
|
2011-06-04 08:12:29 +08:00
|
|
|
return fhandler_console::shared_console_info ?
|
|
|
|
&fhandler_console::shared_console_info->tty_min_state : NULL;
|
2011-06-01 09:47:51 +08:00
|
|
|
else if (istty_slave_dev (n))
|
2011-05-29 02:17:09 +08:00
|
|
|
return &ttys[device::minor (n)];
|
2000-02-18 03:38:33 +08:00
|
|
|
else
|
2011-06-01 09:47:51 +08:00
|
|
|
return NULL;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2019-03-31 23:47:48 +08:00
|
|
|
void
|
|
|
|
fhandler_console::setup_io_mutex (void)
|
|
|
|
{
|
|
|
|
char buf[MAX_PATH];
|
|
|
|
DWORD res;
|
|
|
|
|
|
|
|
res = WAIT_FAILED;
|
|
|
|
if (!input_mutex || WAIT_FAILED == (res = acquire_input_mutex (0)))
|
|
|
|
{
|
|
|
|
shared_name (buf, "cygcons.input.mutex", get_minor ());
|
|
|
|
input_mutex = OpenMutex (MAXIMUM_ALLOWED, TRUE, buf);
|
|
|
|
if (!input_mutex)
|
|
|
|
input_mutex = CreateMutex (&sec_none, FALSE, buf);
|
|
|
|
if (!input_mutex)
|
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (res == WAIT_OBJECT_0)
|
|
|
|
release_input_mutex ();
|
|
|
|
|
|
|
|
res = WAIT_FAILED;
|
|
|
|
if (!output_mutex || WAIT_FAILED == (res = acquire_output_mutex (0)))
|
|
|
|
{
|
|
|
|
shared_name (buf, "cygcons.output.mutex", get_minor ());
|
|
|
|
output_mutex = OpenMutex (MAXIMUM_ALLOWED, TRUE, buf);
|
|
|
|
if (!output_mutex)
|
|
|
|
output_mutex = CreateMutex (&sec_none, FALSE, buf);
|
|
|
|
if (!output_mutex)
|
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (res == WAIT_OBJECT_0)
|
|
|
|
release_output_mutex ();
|
|
|
|
}
|
|
|
|
|
2008-03-11 00:22:38 +08:00
|
|
|
inline DWORD
|
2008-02-06 01:37:10 +08:00
|
|
|
dev_console::con_to_str (char *d, int dlen, WCHAR w)
|
2003-10-16 22:08:28 +08:00
|
|
|
{
|
2015-12-18 19:42:40 +08:00
|
|
|
return sys_wcstombs (d, dlen, &w, 1);
|
2003-10-16 22:08:28 +08:00
|
|
|
}
|
|
|
|
|
2008-02-06 01:37:10 +08:00
|
|
|
inline UINT
|
|
|
|
dev_console::get_console_cp ()
|
2003-10-16 22:08:28 +08:00
|
|
|
{
|
2009-09-28 20:10:32 +08:00
|
|
|
/* The alternate charset is always 437, just as in the Linux console. */
|
|
|
|
return alternate_charset_active ? 437 : 0;
|
2008-02-06 01:37:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline DWORD
|
2016-07-21 04:05:59 +08:00
|
|
|
dev_console::str_to_con (mbtowc_p f_mbtowc, PWCHAR d, const char *s, DWORD sz)
|
2008-02-06 01:37:10 +08:00
|
|
|
{
|
2020-07-10 16:29:33 +08:00
|
|
|
return _sys_mbstowcs (f_mbtowc, d, CONVERT_LIMIT, s, sz);
|
2003-10-16 22:08:28 +08:00
|
|
|
}
|
|
|
|
|
2003-12-08 06:37:12 +08:00
|
|
|
bool
|
|
|
|
fhandler_console::set_raw_win32_keyboard_mode (bool new_mode)
|
2001-02-27 17:14:35 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
bool old_mode = con.raw_win32_keyboard_mode;
|
|
|
|
con.raw_win32_keyboard_mode = new_mode;
|
2019-03-31 23:47:47 +08:00
|
|
|
syscall_printf ("raw keyboard mode %sabled",
|
|
|
|
con.raw_win32_keyboard_mode ? "en" : "dis");
|
2001-02-27 17:14:35 +08:00
|
|
|
return old_mode;
|
|
|
|
};
|
|
|
|
|
2000-07-30 00:24:59 +08:00
|
|
|
void
|
|
|
|
fhandler_console::set_cursor_maybe ()
|
|
|
|
{
|
2021-01-25 17:18:11 +08:00
|
|
|
acquire_attach_mutex (INFINITE);
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fillin (get_output_handle ());
|
2021-01-25 17:18:11 +08:00
|
|
|
release_attach_mutex ();
|
2019-08-12 21:48:45 +08:00
|
|
|
/* Nothing to do for xterm compatible mode. */
|
2019-11-13 02:04:59 +08:00
|
|
|
if (wincap.has_con_24bit_colors () && !con_is_legacy)
|
2019-08-12 21:48:45 +08:00
|
|
|
return;
|
2014-03-10 06:49:56 +08:00
|
|
|
if (con.dwLastCursorPosition.X != con.b.dwCursorPosition.X ||
|
|
|
|
con.dwLastCursorPosition.Y != con.b.dwCursorPosition.Y)
|
2000-07-30 00:24:59 +08:00
|
|
|
{
|
2021-01-25 17:18:11 +08:00
|
|
|
acquire_attach_mutex (INFINITE);
|
2014-03-10 06:49:56 +08:00
|
|
|
SetConsoleCursorPosition (get_output_handle (), con.b.dwCursorPosition);
|
2021-01-25 17:18:11 +08:00
|
|
|
release_attach_mutex ();
|
2014-03-10 06:49:56 +08:00
|
|
|
con.dwLastCursorPosition = con.b.dwCursorPosition;
|
2000-07-30 00:24:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-15 13:02:05 +08:00
|
|
|
/* Workaround for a bug of windows xterm compatible mode. */
|
|
|
|
/* The horizontal tab positions are broken after resize. */
|
2020-02-18 17:12:54 +08:00
|
|
|
void
|
|
|
|
fhandler_console::fix_tab_position (void)
|
2019-08-15 13:02:05 +08:00
|
|
|
{
|
2020-03-02 09:12:54 +08:00
|
|
|
/* Re-setting ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
|
|
|
fixes the tab position. */
|
2021-01-15 16:32:10 +08:00
|
|
|
request_xterm_mode_output (false, &handle_set);
|
|
|
|
request_xterm_mode_output (true, &handle_set);
|
2019-08-15 13:02:05 +08:00
|
|
|
}
|
|
|
|
|
2019-03-31 23:47:47 +08:00
|
|
|
bool
|
2002-08-19 12:43:58 +08:00
|
|
|
fhandler_console::send_winch_maybe ()
|
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
SHORT y = con.dwWinSize.Y;
|
|
|
|
SHORT x = con.dwWinSize.X;
|
|
|
|
con.fillin (get_output_handle ());
|
2002-09-19 11:30:20 +08:00
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
if (y != con.dwWinSize.Y || x != con.dwWinSize.X)
|
2002-12-27 13:31:30 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.scroll_region.Top = 0;
|
|
|
|
con.scroll_region.Bottom = -1;
|
2019-11-13 02:04:59 +08:00
|
|
|
if (wincap.has_con_24bit_colors () && !con_is_legacy)
|
2020-02-18 17:12:54 +08:00
|
|
|
fix_tab_position ();
|
2011-10-16 06:37:30 +08:00
|
|
|
get_ttyp ()->kill_pgrp (SIGWINCH);
|
2019-03-31 23:47:47 +08:00
|
|
|
return true;
|
2002-12-27 13:31:30 +08:00
|
|
|
}
|
2019-03-31 23:47:47 +08:00
|
|
|
return false;
|
2002-08-19 12:43:58 +08:00
|
|
|
}
|
|
|
|
|
2009-12-16 22:56:10 +08:00
|
|
|
/* Check whether a mouse event is to be reported as an escape sequence */
|
|
|
|
bool
|
|
|
|
fhandler_console::mouse_aware (MOUSE_EVENT_RECORD& mouse_event)
|
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
if (!con.use_mouse)
|
2009-12-16 22:56:10 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Adjust mouse position by window scroll buffer offset
|
|
|
|
and remember adjusted position in state for use by read() */
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFO now;
|
2014-01-05 07:58:32 +08:00
|
|
|
if (!GetConsoleScreenBufferInfo (get_output_handle (), &now))
|
|
|
|
/* Cannot adjust position by window scroll buffer offset */
|
|
|
|
return 0;
|
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
con.dwMousePosition.X = mouse_event.dwMousePosition.X - now.srWindow.Left;
|
|
|
|
con.dwMousePosition.Y = mouse_event.dwMousePosition.Y - now.srWindow.Top;
|
2009-12-16 22:56:10 +08:00
|
|
|
|
2019-03-31 23:47:47 +08:00
|
|
|
return ((mouse_event.dwEventFlags == 0
|
|
|
|
|| mouse_event.dwEventFlags == DOUBLE_CLICK)
|
2014-03-10 06:49:56 +08:00
|
|
|
&& mouse_event.dwButtonState != con.dwLastButtonState)
|
2009-12-16 22:56:10 +08:00
|
|
|
|| mouse_event.dwEventFlags == MOUSE_WHEELED
|
|
|
|
|| (mouse_event.dwEventFlags == MOUSE_MOVED
|
2014-03-10 06:49:56 +08:00
|
|
|
&& (con.dwMousePosition.X != con.dwLastMousePosition.X
|
|
|
|
|| con.dwMousePosition.Y != con.dwLastMousePosition.Y)
|
|
|
|
&& ((con.use_mouse >= 2 && mouse_event.dwButtonState)
|
|
|
|
|| con.use_mouse >= 3));
|
2009-12-16 22:56:10 +08:00
|
|
|
}
|
|
|
|
|
2013-05-01 09:20:37 +08:00
|
|
|
void __reg3
|
2002-12-14 12:01:32 +08:00
|
|
|
fhandler_console::read (void *pv, size_t& buflen)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2019-03-31 23:47:47 +08:00
|
|
|
termios_printf ("read(%p,%d)", pv, buflen);
|
|
|
|
|
2011-05-06 03:43:04 +08:00
|
|
|
push_process_state process_state (PID_TTYIN);
|
|
|
|
|
2019-03-31 23:47:47 +08:00
|
|
|
int copied_chars = 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2019-03-31 23:47:47 +08:00
|
|
|
DWORD timeout = is_nonblocking () ? 0 : INFINITE;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
set_input_state ();
|
2000-03-12 14:29:54 +08:00
|
|
|
|
2020-02-17 18:29:07 +08:00
|
|
|
/* if system has 24 bit color capability, use xterm compatible mode. */
|
2020-02-18 17:12:54 +08:00
|
|
|
if (wincap.has_con_24bit_colors ())
|
2021-01-15 16:32:10 +08:00
|
|
|
request_xterm_mode_input (true, &handle_set);
|
2020-02-17 18:29:07 +08:00
|
|
|
|
2019-03-31 23:47:47 +08:00
|
|
|
while (!input_ready && !get_cons_readahead_valid ())
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
int bgres;
|
2001-01-17 22:57:09 +08:00
|
|
|
if ((bgres = bg_check (SIGTTIN)) <= bg_eof)
|
2002-12-14 12:01:32 +08:00
|
|
|
{
|
|
|
|
buflen = bgres;
|
|
|
|
return;
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2019-03-31 23:47:47 +08:00
|
|
|
set_cursor_maybe (); /* to make cursor appear on the screen immediately */
|
2021-01-25 17:18:11 +08:00
|
|
|
wait_retry:
|
2019-03-31 23:47:47 +08:00
|
|
|
switch (cygwait (get_handle (), timeout))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
case WAIT_OBJECT_0:
|
|
|
|
break;
|
2012-06-18 04:50:24 +08:00
|
|
|
case WAIT_SIGNALED:
|
2001-03-05 14:28:25 +08:00
|
|
|
goto sig_exit;
|
2012-06-18 04:50:24 +08:00
|
|
|
case WAIT_CANCELED:
|
2011-05-06 03:43:04 +08:00
|
|
|
process_state.pop ();
|
2011-05-03 01:38:16 +08:00
|
|
|
pthread::static_cancel_self ();
|
|
|
|
/*NOTREACHED*/
|
|
|
|
case WAIT_TIMEOUT:
|
|
|
|
set_sig_errno (EAGAIN);
|
|
|
|
buflen = (size_t) -1;
|
|
|
|
return;
|
2000-02-18 03:38:33 +08:00
|
|
|
default:
|
2021-01-25 17:18:11 +08:00
|
|
|
if (GetLastError () == ERROR_INVALID_HANDLE)
|
|
|
|
{ /* Confirm the handle is still valid */
|
|
|
|
DWORD mode;
|
|
|
|
acquire_attach_mutex (INFINITE);
|
|
|
|
BOOL res = GetConsoleMode (get_handle (), &mode);
|
|
|
|
release_attach_mutex ();
|
|
|
|
if (res)
|
|
|
|
goto wait_retry;
|
|
|
|
}
|
2002-12-14 12:01:32 +08:00
|
|
|
goto err;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2000-07-10 23:30:04 +08:00
|
|
|
|
2019-03-31 23:47:47 +08:00
|
|
|
#define buf ((char *) pv)
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2019-03-31 23:47:47 +08:00
|
|
|
int ret;
|
2019-03-31 23:47:48 +08:00
|
|
|
acquire_input_mutex (INFINITE);
|
2021-01-28 22:11:32 +08:00
|
|
|
acquire_attach_mutex (INFINITE);
|
2019-03-31 23:47:47 +08:00
|
|
|
ret = process_input_message ();
|
2021-01-20 17:16:20 +08:00
|
|
|
release_attach_mutex ();
|
2019-03-31 23:47:47 +08:00
|
|
|
switch (ret)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2019-03-31 23:47:47 +08:00
|
|
|
case input_error:
|
2021-01-28 22:11:32 +08:00
|
|
|
release_input_mutex ();
|
2019-03-31 23:47:47 +08:00
|
|
|
goto err;
|
|
|
|
case input_processing:
|
2021-01-28 22:11:32 +08:00
|
|
|
release_input_mutex ();
|
2019-03-31 23:47:47 +08:00
|
|
|
continue;
|
|
|
|
case input_ok: /* input ready */
|
|
|
|
break;
|
|
|
|
case input_signalled: /* signalled */
|
|
|
|
case input_winch:
|
2021-01-28 22:11:32 +08:00
|
|
|
release_input_mutex ();
|
2021-02-14 17:42:50 +08:00
|
|
|
if (global_sigs[get_ttyp ()->last_sig].sa_flags & SA_RESTART)
|
|
|
|
continue;
|
|
|
|
goto sig_exit;
|
2019-03-31 23:47:47 +08:00
|
|
|
default:
|
|
|
|
/* Should not come here */
|
2021-01-28 22:11:32 +08:00
|
|
|
release_input_mutex ();
|
2019-03-31 23:47:47 +08:00
|
|
|
goto err;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2019-03-31 23:47:47 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2019-03-31 23:47:47 +08:00
|
|
|
/* Check console read-ahead buffer filled from terminal requests */
|
|
|
|
while (con.cons_rapoi && *con.cons_rapoi && buflen)
|
|
|
|
{
|
|
|
|
buf[copied_chars++] = *con.cons_rapoi++;
|
|
|
|
buflen --;
|
|
|
|
}
|
2017-01-20 04:58:05 +08:00
|
|
|
|
2019-03-31 23:47:47 +08:00
|
|
|
copied_chars +=
|
|
|
|
get_readahead_into_buffer (buf + copied_chars, buflen);
|
2001-02-27 17:14:35 +08:00
|
|
|
|
2020-01-27 20:14:32 +08:00
|
|
|
if (!con_ra.ralen)
|
2019-03-31 23:47:47 +08:00
|
|
|
input_ready = false;
|
2019-03-31 23:47:48 +08:00
|
|
|
release_input_mutex ();
|
2019-03-31 23:47:47 +08:00
|
|
|
|
|
|
|
#undef buf
|
|
|
|
|
|
|
|
buflen = copied_chars;
|
|
|
|
return;
|
|
|
|
|
|
|
|
err:
|
|
|
|
__seterrno ();
|
|
|
|
buflen = (size_t) -1;
|
|
|
|
return;
|
|
|
|
|
|
|
|
sig_exit:
|
|
|
|
set_sig_errno (EINTR);
|
|
|
|
buflen = (size_t) -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fhandler_console::input_states
|
|
|
|
fhandler_console::process_input_message (void)
|
|
|
|
{
|
|
|
|
char tmp[60];
|
|
|
|
|
|
|
|
if (!shared_console_info)
|
|
|
|
return input_error;
|
|
|
|
|
|
|
|
termios *ti = &(get_ttyp ()->ti);
|
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
fhandler_console::input_states stat = input_processing;
|
|
|
|
DWORD total_read, i;
|
|
|
|
INPUT_RECORD input_rec[INREC_SIZE];
|
|
|
|
|
|
|
|
if (!PeekConsoleInputW (get_handle (), input_rec, INREC_SIZE, &total_read))
|
2019-03-31 23:47:47 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
termios_printf ("PeekConsoleInput failed, %E");
|
2019-03-31 23:47:47 +08:00
|
|
|
return input_error;
|
|
|
|
}
|
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
for (i = 0; i < total_read; i ++)
|
2019-03-31 23:47:47 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
DWORD nread = 1;
|
|
|
|
const char *toadd = NULL;
|
2019-03-31 23:47:47 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
const WCHAR &unicode_char =
|
|
|
|
input_rec[i].Event.KeyEvent.uChar.UnicodeChar;
|
|
|
|
const DWORD &ctrl_key_state =
|
|
|
|
input_rec[i].Event.KeyEvent.dwControlKeyState;
|
2003-09-27 10:36:50 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
/* check the event that occurred */
|
|
|
|
switch (input_rec[i].EventType)
|
2019-03-31 23:47:47 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
case KEY_EVENT:
|
2001-02-27 17:14:35 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
con.nModifiers = 0;
|
2019-03-31 23:47:47 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
#ifdef DEBUGGING
|
|
|
|
/* allow manual switching to/from raw mode via ctrl-alt-scrolllock */
|
|
|
|
if (input_rec[i].Event.KeyEvent.bKeyDown
|
|
|
|
&& input_rec[i].Event.KeyEvent.wVirtualKeyCode == VK_SCROLL
|
|
|
|
&& (ctrl_key_state & (LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED))
|
|
|
|
== (LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED))
|
2001-03-03 11:56:34 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
set_raw_win32_keyboard_mode (!con.raw_win32_keyboard_mode);
|
|
|
|
continue;
|
2001-03-03 11:56:34 +08:00
|
|
|
}
|
2019-09-14 03:34:39 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (con.raw_win32_keyboard_mode)
|
2009-06-03 19:07:38 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
__small_sprintf (tmp, "\033{%u;%u;%u;%u;%u;%luK",
|
|
|
|
input_rec[i].Event.KeyEvent.bKeyDown,
|
|
|
|
input_rec[i].Event.KeyEvent.wRepeatCount,
|
|
|
|
input_rec[i].Event.KeyEvent.wVirtualKeyCode,
|
|
|
|
input_rec[i].Event.KeyEvent.wVirtualScanCode,
|
|
|
|
input_rec[i].Event.KeyEvent.uChar.UnicodeChar,
|
|
|
|
input_rec[i].Event.KeyEvent.dwControlKeyState);
|
|
|
|
toadd = tmp;
|
|
|
|
nread = strlen (toadd);
|
|
|
|
break;
|
2009-06-03 19:07:38 +08:00
|
|
|
}
|
2019-09-14 03:34:39 +08:00
|
|
|
|
|
|
|
/* Ignore key up events, except for Alt+Numpad events. */
|
|
|
|
if (!input_rec[i].Event.KeyEvent.bKeyDown &&
|
|
|
|
!is_alt_numpad_event (&input_rec[i]))
|
|
|
|
continue;
|
|
|
|
/* Ignore Alt+Numpad keys. They are eventually handled below after
|
|
|
|
releasing the Alt key. */
|
|
|
|
if (input_rec[i].Event.KeyEvent.bKeyDown
|
|
|
|
&& is_alt_numpad_key (&input_rec[i]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ctrl_key_state & SHIFT_PRESSED)
|
|
|
|
con.nModifiers |= 1;
|
|
|
|
if (ctrl_key_state & RIGHT_ALT_PRESSED)
|
|
|
|
con.nModifiers |= 2;
|
|
|
|
if (ctrl_key_state & CTRL_PRESSED)
|
|
|
|
con.nModifiers |= 4;
|
|
|
|
if (ctrl_key_state & LEFT_ALT_PRESSED)
|
|
|
|
con.nModifiers |= 8;
|
|
|
|
|
|
|
|
/* Allow Backspace to emit ^? and escape sequences. */
|
|
|
|
if (input_rec[i].Event.KeyEvent.wVirtualKeyCode == VK_BACK)
|
2000-12-16 11:11:02 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
char c = con.backspace_keycode;
|
|
|
|
nread = 0;
|
|
|
|
if (ctrl_key_state & ALT_PRESSED)
|
|
|
|
{
|
|
|
|
if (con.metabit)
|
|
|
|
c |= 0x80;
|
|
|
|
else
|
|
|
|
tmp[nread++] = '\e';
|
|
|
|
}
|
|
|
|
tmp[nread++] = c;
|
|
|
|
tmp[nread] = 0;
|
|
|
|
toadd = tmp;
|
2019-03-31 23:47:47 +08:00
|
|
|
}
|
2019-09-14 03:34:39 +08:00
|
|
|
/* Allow Ctrl-Space to emit ^@ */
|
|
|
|
else if (input_rec[i].Event.KeyEvent.wVirtualKeyCode
|
2019-11-13 02:04:59 +08:00
|
|
|
== ((wincap.has_con_24bit_colors () && !con_is_legacy) ?
|
2019-11-07 00:29:29 +08:00
|
|
|
'2' : VK_SPACE)
|
2019-09-14 03:34:39 +08:00
|
|
|
&& (ctrl_key_state & CTRL_PRESSED)
|
|
|
|
&& !(ctrl_key_state & ALT_PRESSED))
|
|
|
|
toadd = "";
|
|
|
|
else if (unicode_char == 0
|
|
|
|
/* arrow/function keys */
|
|
|
|
|| (input_rec[i].Event.KeyEvent.dwControlKeyState
|
|
|
|
& ENHANCED_KEY))
|
2019-03-31 23:47:47 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
toadd = get_nonascii_key (input_rec[i], tmp);
|
|
|
|
if (!toadd)
|
|
|
|
{
|
|
|
|
con.nModifiers = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
nread = strlen (toadd);
|
2000-12-16 11:11:02 +08:00
|
|
|
}
|
2001-03-03 11:56:34 +08:00
|
|
|
else
|
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
nread = con.con_to_str (tmp + 1, 59, unicode_char);
|
|
|
|
/* 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 =
|
|
|
|
/* Alt but not AltGr (= left ctrl + right alt)? */
|
|
|
|
(ctrl_key_state & ALT_PRESSED) != 0
|
|
|
|
&& ((ctrl_key_state & CTRL_PRESSED) == 0
|
|
|
|
/* but also allow Alt-AltGr: */
|
|
|
|
|| (ctrl_key_state & ALT_PRESSED) == ALT_PRESSED
|
|
|
|
|| (unicode_char <= 0x1f || unicode_char == 0x7f));
|
|
|
|
if (!meta)
|
2009-09-30 17:23:45 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
/* Determine if the character is in the current multibyte
|
|
|
|
charset. The test is easy. If the multibyte sequence
|
|
|
|
is > 1 and the first byte is ASCII CAN, the character
|
|
|
|
has been translated into the ASCII CAN + UTF-8 replacement
|
|
|
|
sequence. If so, just ignore the keypress.
|
|
|
|
FIXME: Is there a better solution? */
|
|
|
|
if (nread > 1 && tmp[1] == 0x18)
|
|
|
|
beep ();
|
|
|
|
else
|
|
|
|
toadd = tmp + 1;
|
2009-09-30 17:23:45 +08:00
|
|
|
}
|
2019-09-14 03:34:39 +08:00
|
|
|
else if (con.metabit)
|
2006-07-03 23:29:10 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
tmp[1] |= 0x80;
|
|
|
|
toadd = tmp + 1;
|
2009-11-11 04:02:20 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
tmp[0] = '\033';
|
|
|
|
tmp[1] = cyg_tolower (tmp[1]);
|
|
|
|
toadd = tmp;
|
|
|
|
nread++;
|
|
|
|
con.nModifiers &= ~4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2019-03-31 23:47:47 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
case MOUSE_EVENT:
|
|
|
|
send_winch_maybe ();
|
|
|
|
{
|
|
|
|
MOUSE_EVENT_RECORD& mouse_event = input_rec[i].Event.MouseEvent;
|
|
|
|
/* As a unique guard for mouse report generation,
|
|
|
|
call mouse_aware() which is common with select(), so the result
|
|
|
|
of select() and the actual read() will be consistent on the
|
|
|
|
issue of whether input (i.e. a mouse escape sequence) will
|
|
|
|
be available or not */
|
|
|
|
if (mouse_aware (mouse_event))
|
|
|
|
{
|
|
|
|
/* Note: Reported mouse position was already retrieved by
|
|
|
|
mouse_aware() and adjusted by window scroll buffer offset */
|
|
|
|
|
|
|
|
/* Treat the double-click event like a regular button press */
|
|
|
|
if (mouse_event.dwEventFlags == DOUBLE_CLICK)
|
2019-03-31 23:47:47 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
syscall_printf ("mouse: double-click -> click");
|
|
|
|
mouse_event.dwEventFlags = 0;
|
2019-03-31 23:47:47 +08:00
|
|
|
}
|
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
/* This code assumes Windows never reports multiple button
|
|
|
|
events at the same time. */
|
|
|
|
int b = 0;
|
|
|
|
char sz[32];
|
|
|
|
char mode6_term = 'M';
|
2019-03-31 23:47:47 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
if (mouse_event.dwEventFlags == MOUSE_WHEELED)
|
2019-03-31 23:47:47 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
if (mouse_event.dwButtonState & 0xFF800000)
|
|
|
|
{
|
|
|
|
b = 0x41;
|
|
|
|
strcpy (sz, "wheel down");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
b = 0x40;
|
|
|
|
strcpy (sz, "wheel up");
|
|
|
|
}
|
2019-03-31 23:47:47 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
/* Ignore unimportant mouse buttons */
|
|
|
|
mouse_event.dwButtonState &= 0x7;
|
|
|
|
|
|
|
|
if (mouse_event.dwEventFlags == MOUSE_MOVED)
|
|
|
|
{
|
|
|
|
b = con.last_button_code;
|
|
|
|
}
|
|
|
|
else if (mouse_event.dwButtonState < con.dwLastButtonState
|
|
|
|
&& !con.ext_mouse_mode6)
|
|
|
|
{
|
|
|
|
b = 3;
|
|
|
|
strcpy (sz, "btn up");
|
|
|
|
}
|
|
|
|
else if ((mouse_event.dwButtonState & 1)
|
|
|
|
!= (con.dwLastButtonState & 1))
|
|
|
|
{
|
|
|
|
b = 0;
|
|
|
|
strcpy (sz, "btn1 down");
|
|
|
|
}
|
|
|
|
else if ((mouse_event.dwButtonState & 2)
|
|
|
|
!= (con.dwLastButtonState & 2))
|
|
|
|
{
|
|
|
|
b = 2;
|
|
|
|
strcpy (sz, "btn2 down");
|
|
|
|
}
|
|
|
|
else if ((mouse_event.dwButtonState & 4)
|
|
|
|
!= (con.dwLastButtonState & 4))
|
|
|
|
{
|
|
|
|
b = 1;
|
|
|
|
strcpy (sz, "btn3 down");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (con.ext_mouse_mode6 /* distinguish release */
|
|
|
|
&& mouse_event.dwButtonState < con.dwLastButtonState)
|
|
|
|
mode6_term = 'm';
|
|
|
|
|
|
|
|
con.last_button_code = b;
|
|
|
|
|
|
|
|
if (mouse_event.dwEventFlags == MOUSE_MOVED)
|
|
|
|
{
|
|
|
|
b += 32;
|
|
|
|
strcpy (sz, "move");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Remember the modified button state */
|
|
|
|
con.dwLastButtonState = mouse_event.dwButtonState;
|
|
|
|
}
|
2019-03-31 23:47:47 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
/* Remember mouse position */
|
|
|
|
con.dwLastMousePosition.X = con.dwMousePosition.X;
|
|
|
|
con.dwLastMousePosition.Y = con.dwMousePosition.Y;
|
2009-12-16 22:56:10 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
/* Remember the modifiers */
|
|
|
|
con.nModifiers = 0;
|
|
|
|
if (mouse_event.dwControlKeyState & SHIFT_PRESSED)
|
|
|
|
con.nModifiers |= 0x4;
|
|
|
|
if (mouse_event.dwControlKeyState & ALT_PRESSED)
|
|
|
|
con.nModifiers |= 0x8;
|
|
|
|
if (mouse_event.dwControlKeyState & CTRL_PRESSED)
|
|
|
|
con.nModifiers |= 0x10;
|
2012-04-24 22:29:37 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
/* Indicate the modifiers */
|
|
|
|
b |= con.nModifiers;
|
2009-12-16 22:56:10 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
/* We can now create the code. */
|
|
|
|
if (con.ext_mouse_mode6)
|
2019-03-31 23:47:47 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
__small_sprintf (tmp, "\033[<%d;%d;%d%c", b,
|
|
|
|
con.dwMousePosition.X + 1,
|
|
|
|
con.dwMousePosition.Y + 1,
|
|
|
|
mode6_term);
|
|
|
|
nread = strlen (tmp);
|
2019-03-31 23:47:47 +08:00
|
|
|
}
|
2019-09-14 03:34:39 +08:00
|
|
|
else if (con.ext_mouse_mode15)
|
|
|
|
{
|
|
|
|
__small_sprintf (tmp, "\033[%d;%d;%dM", b + 32,
|
|
|
|
con.dwMousePosition.X + 1,
|
|
|
|
con.dwMousePosition.Y + 1);
|
|
|
|
nread = strlen (tmp);
|
|
|
|
}
|
|
|
|
else if (con.ext_mouse_mode5)
|
2019-03-31 23:47:47 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
unsigned int xcode = con.dwMousePosition.X + ' ' + 1;
|
|
|
|
unsigned int ycode = con.dwMousePosition.Y + ' ' + 1;
|
|
|
|
|
|
|
|
__small_sprintf (tmp, "\033[M%c", b + ' ');
|
|
|
|
nread = 4;
|
|
|
|
/* the neat nested encoding function of mintty
|
|
|
|
does not compile in g++, so let's unfold it: */
|
|
|
|
if (xcode < 0x80)
|
|
|
|
tmp [nread++] = xcode;
|
|
|
|
else if (xcode < 0x800)
|
|
|
|
{
|
|
|
|
tmp [nread++] = 0xC0 + (xcode >> 6);
|
|
|
|
tmp [nread++] = 0x80 + (xcode & 0x3F);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tmp [nread++] = 0;
|
|
|
|
if (ycode < 0x80)
|
|
|
|
tmp [nread++] = ycode;
|
|
|
|
else if (ycode < 0x800)
|
|
|
|
{
|
|
|
|
tmp [nread++] = 0xC0 + (ycode >> 6);
|
|
|
|
tmp [nread++] = 0x80 + (ycode & 0x3F);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tmp [nread++] = 0;
|
2019-03-31 23:47:47 +08:00
|
|
|
}
|
|
|
|
else
|
2019-09-14 03:34:39 +08:00
|
|
|
{
|
|
|
|
unsigned int xcode = con.dwMousePosition.X + ' ' + 1;
|
|
|
|
unsigned int ycode = con.dwMousePosition.Y + ' ' + 1;
|
|
|
|
if (xcode >= 256)
|
|
|
|
xcode = 0;
|
|
|
|
if (ycode >= 256)
|
|
|
|
ycode = 0;
|
|
|
|
__small_sprintf (tmp, "\033[M%c%c%c", b + ' ',
|
|
|
|
xcode, ycode);
|
|
|
|
nread = 6; /* tmp may contain NUL bytes */
|
|
|
|
}
|
|
|
|
syscall_printf ("mouse: %s at (%d,%d)", sz,
|
|
|
|
con.dwMousePosition.X,
|
|
|
|
con.dwMousePosition.Y);
|
|
|
|
|
|
|
|
toadd = tmp;
|
2019-03-31 23:47:47 +08:00
|
|
|
}
|
2019-09-14 03:34:39 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FOCUS_EVENT:
|
|
|
|
if (con.use_focus)
|
|
|
|
{
|
|
|
|
if (input_rec[i].Event.FocusEvent.bSetFocus)
|
|
|
|
__small_sprintf (tmp, "\033[I");
|
2012-04-24 22:29:37 +08:00
|
|
|
else
|
2019-09-14 03:34:39 +08:00
|
|
|
__small_sprintf (tmp, "\033[O");
|
2012-04-24 22:29:37 +08:00
|
|
|
|
|
|
|
toadd = tmp;
|
2019-09-14 03:34:39 +08:00
|
|
|
nread = 3;
|
2012-04-24 22:29:37 +08:00
|
|
|
}
|
2019-09-14 03:34:39 +08:00
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
case WINDOW_BUFFER_SIZE_EVENT:
|
|
|
|
if (send_winch_maybe ())
|
|
|
|
{
|
|
|
|
stat = input_winch;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
default:
|
|
|
|
continue;
|
2019-03-31 23:47:47 +08:00
|
|
|
}
|
2001-03-05 14:28:25 +08:00
|
|
|
|
2019-09-14 03:34:39 +08:00
|
|
|
if (toadd)
|
2019-03-31 23:47:47 +08:00
|
|
|
{
|
2019-09-14 03:34:39 +08:00
|
|
|
ssize_t ret;
|
|
|
|
line_edit_status res = line_edit (toadd, nread, *ti, &ret);
|
|
|
|
if (res == line_edit_signalled)
|
|
|
|
{
|
|
|
|
stat = input_signalled;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
else if (res == line_edit_input_done)
|
|
|
|
{
|
|
|
|
input_ready = true;
|
|
|
|
stat = input_ok;
|
|
|
|
if (ti->c_lflag & ICANON)
|
|
|
|
goto out;
|
|
|
|
}
|
2019-03-31 23:47:47 +08:00
|
|
|
}
|
|
|
|
}
|
2019-09-14 03:34:39 +08:00
|
|
|
out:
|
|
|
|
/* Discard processed recored. */
|
|
|
|
DWORD dummy;
|
2021-01-20 17:16:20 +08:00
|
|
|
DWORD discard_len = min (total_read, i + 1);
|
|
|
|
if (discard_len)
|
|
|
|
ReadConsoleInputW (get_handle (), input_rec, discard_len, &dummy);
|
2019-09-14 03:34:39 +08:00
|
|
|
return stat;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2000-09-08 00:23:51 +08:00
|
|
|
void
|
|
|
|
fhandler_console::set_input_state ()
|
|
|
|
{
|
2011-10-16 06:37:30 +08:00
|
|
|
if (get_ttyp ()->rstcons ())
|
|
|
|
input_tcsetattr (0, &get_ttyp ()->ti);
|
2000-09-08 00:23:51 +08:00
|
|
|
}
|
|
|
|
|
2003-12-08 06:37:12 +08:00
|
|
|
bool
|
2014-02-16 09:48:25 +08:00
|
|
|
dev_console::fillin (HANDLE h)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2003-12-08 06:37:12 +08:00
|
|
|
bool ret;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2014-03-11 02:18:56 +08:00
|
|
|
if ((ret = GetConsoleScreenBufferInfo (h, &b)))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
dwWinSize.Y = 1 + b.srWindow.Bottom - b.srWindow.Top;
|
|
|
|
dwWinSize.X = 1 + b.srWindow.Right - b.srWindow.Left;
|
|
|
|
if (b.dwCursorPosition.Y > dwEnd.Y
|
2019-03-31 23:47:47 +08:00
|
|
|
|| (b.dwCursorPosition.Y >= dwEnd.Y
|
|
|
|
&& b.dwCursorPosition.X > dwEnd.X))
|
2014-03-10 06:49:56 +08:00
|
|
|
dwEnd = b.dwCursorPosition;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
memset (&b, 0, sizeof (b));
|
2014-02-16 09:48:25 +08:00
|
|
|
dwWinSize.Y = 25;
|
|
|
|
dwWinSize.X = 80;
|
2014-03-10 06:49:56 +08:00
|
|
|
b.srWindow.Bottom = 24;
|
|
|
|
b.srWindow.Right = 79;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-02-23 11:38:52 +08:00
|
|
|
void __reg3
|
2019-03-31 23:47:47 +08:00
|
|
|
dev_console::scroll_buffer (HANDLE h, int x1, int y1, int x2, int y2,
|
|
|
|
int xn, int yn)
|
2014-02-23 11:38:52 +08:00
|
|
|
{
|
2014-01-31 12:23:22 +08:00
|
|
|
/* Scroll the screen context.
|
|
|
|
x1, y1 - ul corner
|
|
|
|
x2, y2 - dr corner
|
|
|
|
xn, yn - new ul corner
|
|
|
|
Negative values represents current screen dimensions
|
|
|
|
*/
|
2000-02-18 03:38:33 +08:00
|
|
|
SMALL_RECT sr1, sr2;
|
|
|
|
CHAR_INFO fill;
|
|
|
|
COORD dest;
|
2018-09-05 19:08:33 +08:00
|
|
|
fill.Char.UnicodeChar = L' ';
|
2014-02-23 11:38:52 +08:00
|
|
|
fill.Attributes = current_win32_attr;
|
|
|
|
|
|
|
|
fillin (h);
|
|
|
|
sr1.Left = x1 >= 0 ? x1 : dwWinSize.X - 1;
|
2014-03-10 06:49:56 +08:00
|
|
|
sr1.Top = y1 >= 0 ? y1 : b.srWindow.Bottom;
|
2014-02-23 11:38:52 +08:00
|
|
|
sr1.Right = x2 >= 0 ? x2 : dwWinSize.X - 1;
|
2014-03-10 06:49:56 +08:00
|
|
|
sr1.Bottom = y2 >= 0 ? y2 : b.srWindow.Bottom;
|
|
|
|
sr2.Top = b.srWindow.Top + scroll_region.Top;
|
2000-02-18 03:38:33 +08:00
|
|
|
sr2.Left = 0;
|
2019-03-31 23:47:47 +08:00
|
|
|
sr2.Bottom = (scroll_region.Bottom < 0) ?
|
|
|
|
b.srWindow.Bottom : b.srWindow.Top + scroll_region.Bottom;
|
2014-02-23 11:38:52 +08:00
|
|
|
sr2.Right = dwWinSize.X - 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
if (sr1.Bottom > sr2.Bottom && sr1.Top <= sr2.Bottom)
|
|
|
|
sr1.Bottom = sr2.Bottom;
|
2014-02-23 11:38:52 +08:00
|
|
|
dest.X = xn >= 0 ? xn : dwWinSize.X - 1;
|
2014-03-10 06:49:56 +08:00
|
|
|
dest.Y = yn >= 0 ? yn : b.srWindow.Bottom;
|
2018-09-05 19:08:33 +08:00
|
|
|
ScrollConsoleScreenBufferW (h, &sr1, &sr2, dest, &fill);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2014-02-23 11:38:52 +08:00
|
|
|
inline void
|
2019-03-31 23:47:47 +08:00
|
|
|
fhandler_console::scroll_buffer (int x1, int y1, int x2, int y2,
|
|
|
|
int xn, int yn)
|
2014-02-23 11:38:52 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.scroll_buffer (get_output_handle (), x1, y1, x2, y2, xn, yn);
|
2014-02-23 11:38:52 +08:00
|
|
|
}
|
|
|
|
|
2014-02-26 11:58:37 +08:00
|
|
|
inline void
|
2019-03-31 23:47:47 +08:00
|
|
|
fhandler_console::scroll_buffer_screen (int x1, int y1, int x2, int y2,
|
|
|
|
int xn, int yn)
|
2014-02-26 11:58:37 +08:00
|
|
|
{
|
|
|
|
if (y1 >= 0)
|
2014-03-10 06:49:56 +08:00
|
|
|
y1 += con.b.srWindow.Top;
|
2014-02-26 11:58:37 +08:00
|
|
|
if (y2 >= 0)
|
2016-11-24 21:43:52 +08:00
|
|
|
y2 += con.b.srWindow.Top;
|
2014-02-26 11:58:37 +08:00
|
|
|
if (yn >= 0)
|
2014-03-10 06:49:56 +08:00
|
|
|
yn += con.b.srWindow.Top;
|
|
|
|
con.scroll_buffer (get_output_handle (), x1, y1, x2, y2, xn, yn);
|
2014-02-26 11:58:37 +08:00
|
|
|
}
|
|
|
|
|
2011-10-16 06:37:30 +08:00
|
|
|
int
|
|
|
|
fhandler_console::dup (fhandler_base *child, int flags)
|
|
|
|
{
|
2012-03-04 05:35:30 +08:00
|
|
|
/* See comments in fhandler_pty_slave::dup */
|
|
|
|
if (myself->ctty != -2)
|
|
|
|
myself->set_ctty (this, flags);
|
2011-10-16 06:37:30 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
int
|
* devices.cc: New file.
* devices.gperf: New file.
* devices.shilka: New file.
* cygwin-gperf: New file.
* cygwin-shilka: New file.
* fhandler_fifo.cc: New file.
* fhandler_nodevice.cc : New file. Reorganize headers so that path.h precedes
fhandler.h throughout. Remove device argument and unit arguments from fhandler
constructors throughout. Remove pc arguments to fhandler functions and use
internal pc element instead, throughout. Use dev element in pc throughout.
Use major/minor elements rather than units and device numbers previously in
fhandler class. Use correct methods for fhandler file names rather than
directly accessing file name variables, throughout.
* Makefile.in (DLL_OFILES): Add devices.o, fhandler_fifo.o
* dcrt0.cc (dll_crt0_1): Call device::init.
* devices.h: Renumber devices based on more Linux-like major/minor numbers.
Add more devices. Declare standard device storage.
(device): Declare struct.
* dir.cc (opendir): Use new 'build_fh_name' to construct a fhandler_* type.
* dtable.cc (dtable::get_debugger_info): Ditto.
(cygwin_attach_handle_to_fd): Ditto.
(dtable::release): Remove special FH_SOCKET case in favor of generic
"need_fixup_before" test.
(dtable::init_std_file_from_handle): Use either build_fh_dev or build_fh_name
to build standard fhandler.
(dtable::build_fh_name): Renamed from dtable::build_fhandler_from_name. Move
out of dtable class. Don't accept a path_conv argument. Just build it here
and pass it to:
(build_fh_pc): Renamed from dtable::build_fhandler. Move out of dtable class.
Use intrinsic device type in path_conv to create new fhandler.
(build_fh_dev): Renamed from dtable::build_fhandler. Move out of dtable class.
Simplify arguments to just take new 'device' type and a name. Just return
pointer to fhandler rather than trying to insert into dtable.
(dtable::dup_worker): Accommodate above build_fh name changes.
(dtable::find_fifo): New (currently broken) function.
(handle_to_fn): Use strechr for efficiency.
* dtable.h: Reflect above build_fh name changes and argument differences.
(fhandler_base *&operator []): Return self rather than copy of self.
* fhandler.cc (fhandler_base::operator =): Use pc element to set normalized
path.
(fhandler_base::set_name): Ditto.
(fhandler_base::raw_read): Use method to access name.
(fhandler_base::write): Correctly use get_output_handle rather than get_handle.
(handler_base::device_access_denied): New function.
(fhandler_base::open): Eliminate pc argument and use pc element of
fhandler_base throughout.
(fhandler_base::fstat): Detect if device is based in filesystem and use
fstat_fs to calculate stat, if so.
(fhandler_base::fhandler_base): Eliminate handling of file names and, instead,
just free appropriate component from pc.
(fhandler_base::opendir): Remove path_conv parameter.
* fhandler.h: Remove all device flags.
(fhandler_base::pc): New element.
(fhandler_base::set_name): Change argument to path_conv.
(fhandler_base::error): New function.
(fhandler_base::exists): New function.
(fhandler_base::pc_binmode): New function.
(fhandler_base::dev): New function.
(fhandler_base::open_fs): New function.
(fhandler_base::fstat_fs): New function.
(fhandler_base::fstat_by_name): New function.
(fhandler_base::fstat_by_handle): New function.
(fhandler_base::isfifo): New function.
(fhandler_base::is_slow): New function.
(fhandler_base::is_auto_device): New function.
(fhandler_base::is_fs_special): New function.
(fhandler_base::device_access_denied): New function.
(fhandler_base::operator DWORD&): New operator.
(fhandler_base::get_name): Return normalized path from pc.
(fhandler_base::get_win32_name): Return windows path from pc.
(fhandler_base::isdevice): Renamed from is_device.
(fhandler_base::get_native_name): Return device format.
(fhandler_fifo): New class.
(fhandler_nodevice): New class.
(select_stuff::device_specific): Remove array.
(select_stuff::device_specific_pipe): New class element.
(select_stuff::device_specific_socket): New class element.
(select_stuff::device_specific_serial): New class element.
(select_stuff::select_stuff): Initialize new elements.
* fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Move to base class
from fhandler_disk_file.
(fhandler_base::fstat_by_name): Ditto.
(fhandler_base::fstat_by_name): Ditto.
(fhandler_disk_file::open): Move most functionality into
fhandler_base::open_fs.
(fhandler_base::open_fs): New function.
(fhandler_disk_file::close): Move most functionality into
fhandler_base::close_fs.
(fhandler_base::close_fs): New function.
* fhandler_mem.cc (fhandler_dev_mem::open): Use device name in debugging
output.
* fhandler_socket.cc (fhandler_socket::set_connect_secret): Copy standard
urandom device into appropriate place.
(fhandler_socket::accept): Reflect change in fdsock return value.
* fhandler_tty.cc: See "throughouts" above.
* net.cc: Accommodate fdsock change throughout.
(fdsock): Return success or failure, accept fd argument and device argument.
* path.cc (symlink_info::major): New element.
(symlink_info::minor): New element.
(symlink_info::parse_device): Declare new function.
(fs_info::update): Accommodate changes in path_conv class.
(path_conv::fillin): Ditto.
(path_conv::return_and_clear_normalized_path): Eliminate.
(path_conv::set_normalized_path): New function.
(path_conv::path_conv): Set info in dev element. Use path_conv methods Check
for FH_FS rather than FH_BAD to indicate when to fill in filesystem stuff.
where appropriate rather than direct access. Use set_normalized_path to set
normalized path.
(windows_device_names): Eliminate.
(get_dev): Ditto.
(get_raw_device_number): Ditto.
(get_device_number): Ditto.
(win32_device_name): Call new device name parser to do most of the heavy
lifting.
(mount_info::conv_to_win32_path): Fill in dev field as appropriate.
(symlink_worker): Handle new device files.
(symlink_info::check): Ditto.
(symlink_info::parse_device): Define new function.
* path.h (executable_states): Move here from fhandler.h.
(fs_info): Rename variables to *_storage and create methods for accessing same.
(path_conv): Add dev element, remove devn and unit and adjust inline methods to
accommodate.
(set_normalized_path): Declare new function.
* pinfo.cc (_pinfo::commune_recv): Add broken support for handling fifos.
(_pinfo::commune_send): Ditto.
* pipe.cc (fhandler_pipe::close): check for existence of handle before closing
it.
(handler_pipe::create): Rename from make_pipe. Change arguments to accept
fhandler_pipe array. Accommodate fifos.
(pipe): Rework to deal with fhandler_pipe::create changes.
(_pipe): Ditto.
* select.cc: Use individual device_specific types throughout rather than
indexing with obsolete device number.
(set_bits): Use is_socket call rather than checking device number.
* shared_info.h (CURR_MOUNT_MAGIC): Update.
(conv_to_win32_path): Reflect addition of device argument.
* syscalls.cc (mknod_worker): New function.
(open): Use build_fh_name to build fhandler.
(chown_worker): Detect if this is an 'auto' device rather than an on-filesystem
device and handle appropriately.
(chmod_device): New function.
(chmod): Detect if this is an 'auto' device rather than an on-filesystem device
and handle appropriately. Use chmod_device to set mode of in-filesystem
devices.
(stat_worker): Eliminate path_conv argument. Call build_fh_name to construct
fhandler. Use fh->error() rather than pc->error to detect errors in fhandler
construction.
(access_worker): New function pulled from access. Accommodate in-filesystem
devices.
(access): Use access_worker.
(fpathconf): Detect if this is an 'auto' device rather than an on-filesystem
device and handle appropriately.
(mknod_worker): New function.
(mknod32): New function.
(chroot): Free normalized path -- assuming it was actually cmalloced.
* tty.cc (create_tty_master): Tweak for new device class.
(tty::common_init): Ditto.
* winsup.h (stat_worker): Remove.
(symlink_worker): Declare.
* exceptions.cc (set_process_mask): Just call sig_dispatch_pending and don't
worry about pending_signals since sig_dispatch_pending should always do the
right thing now.
(sig_handle): Reorganize SIGCONT handling to more closely conform to SUSv3.
* pinfo.h: Move __SIG enum to sigproc.h.
(PICOM_FIFO): New enum element.
(_pinfo): Remove 'thread2signal' stuff throughout class.
(_pinfo::commune_send): Make varargs.
(_pinfo::sigtodo): Eliminate.
(_pinfo::thread2signal): Ditto.
* signal.cc (kill_worker): Eliminate call to setthread2signal.
* sigproc.cc (local_sigtodo): Eliminate.
(getlocal_sigtodo): Ditto.
(sigelem): New class.
(pending_signals): New class.
(sigqueue): New variable, start of sigqueue linked list.
(sigcatch_nonmain): Eliminate.
(sigcatch_main): Eliminate.
(sigcatch_nosync): Eliminate.
(sigcomplete_nonmain): Eliminate.
(pending_signals): Eliminate.
(sig_clear): Call signal thread to clear pending signals, unless already in
signal thread.
(sigpending): Call signal thread to get pending signals.
(sig_dispatch_pending): Eliminate use of pending_signals and just check
sigqueue.
(sigproc_terminate): Eliminate all of the obsolete semaphore stuff. Close
signal pipe handle.
(sig_send): Eliminate all of the obsolete semaphore stuff and use pipe to send
signals.
(getevent): Eliminate.
(pending_signals::add): New function.
(pending_signals::del): New function.
(pending_signals::next): New function.
(wait_sig): Eliminate all of the obsolete semaphore stuff. Use pipe to
communicate and maintain a linked list of signals.
* sigproc.h: Move __SIG defines here. Add __SIGPENDING.
(sig_dispatch_pending): Remove "C" specifier.
(sig_handle): Accept a mask argument.
* thread.cc: Remove signal handling considerations throughout.
2003-09-25 08:37:18 +08:00
|
|
|
fhandler_console::open (int flags, mode_t)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
HANDLE h;
|
|
|
|
|
2011-06-13 04:15:26 +08:00
|
|
|
if (dev () == FH_ERROR)
|
|
|
|
{
|
|
|
|
set_errno (EPERM); /* constructor found an error */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-04 08:12:29 +08:00
|
|
|
tcinit (false);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2019-03-30 15:12:02 +08:00
|
|
|
set_handle (NULL);
|
2002-09-22 11:38:57 +08:00
|
|
|
set_output_handle (NULL);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
/* Open the input handle as handle_ */
|
2018-09-05 19:08:33 +08:00
|
|
|
h = CreateFileW (L"CONIN$", GENERIC_READ | GENERIC_WRITE,
|
2011-10-23 00:26:30 +08:00
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none,
|
2002-09-19 23:12:48 +08:00
|
|
|
OPEN_EXISTING, 0, 0);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
return 0;
|
|
|
|
}
|
2019-03-30 15:12:02 +08:00
|
|
|
set_handle (h);
|
2021-01-15 16:32:10 +08:00
|
|
|
handle_set.input_handle = h;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2018-09-05 19:08:33 +08:00
|
|
|
h = CreateFileW (L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
|
2011-10-23 00:26:30 +08:00
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none,
|
2002-09-19 23:12:48 +08:00
|
|
|
OPEN_EXISTING, 0, 0);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
set_output_handle (h);
|
2021-01-15 16:32:10 +08:00
|
|
|
handle_set.output_handle = h;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2019-03-31 23:47:48 +08:00
|
|
|
setup_io_mutex ();
|
2021-01-15 16:32:10 +08:00
|
|
|
handle_set.input_mutex = input_mutex;
|
|
|
|
handle_set.output_mutex = output_mutex;
|
2019-03-31 23:47:48 +08:00
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
if (con.fillin (get_output_handle ()))
|
2005-04-23 01:03:38 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.current_win32_attr = con.b.wAttributes;
|
|
|
|
if (!con.default_color)
|
|
|
|
con.default_color = con.b.wAttributes;
|
|
|
|
con.set_default_attr ();
|
2005-04-23 01:03:38 +08:00
|
|
|
}
|
2001-02-27 17:14:35 +08:00
|
|
|
|
2011-10-16 06:37:30 +08:00
|
|
|
get_ttyp ()->rstcons (false);
|
2001-04-24 10:07:58 +08:00
|
|
|
set_open_status ();
|
2008-06-12 23:57:23 +08:00
|
|
|
|
2020-02-18 17:12:54 +08:00
|
|
|
if (myself->pid == con.owner && wincap.has_con_24bit_colors ())
|
2019-03-31 23:47:46 +08:00
|
|
|
{
|
2020-02-17 18:29:07 +08:00
|
|
|
bool is_legacy = false;
|
2019-03-31 23:47:46 +08:00
|
|
|
DWORD dwMode;
|
2020-02-17 18:29:07 +08:00
|
|
|
/* Check xterm compatible mode in output */
|
2019-03-31 23:47:46 +08:00
|
|
|
GetConsoleMode (get_output_handle (), &dwMode);
|
2020-02-17 18:29:07 +08:00
|
|
|
if (!SetConsoleMode (get_output_handle (),
|
|
|
|
dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING))
|
|
|
|
is_legacy = true;
|
|
|
|
SetConsoleMode (get_output_handle (), dwMode);
|
|
|
|
/* Check xterm compatible mode in input */
|
|
|
|
GetConsoleMode (get_handle (), &dwMode);
|
|
|
|
if (!SetConsoleMode (get_handle (),
|
|
|
|
dwMode | ENABLE_VIRTUAL_TERMINAL_INPUT))
|
|
|
|
is_legacy = true;
|
|
|
|
SetConsoleMode (get_handle (), dwMode);
|
|
|
|
con.is_legacy = is_legacy;
|
2019-11-07 00:29:29 +08:00
|
|
|
extern int sawTERM;
|
2019-11-13 02:04:59 +08:00
|
|
|
if (con_is_legacy && !sawTERM)
|
2019-11-07 00:29:29 +08:00
|
|
|
setenv ("TERM", "cygwin", 1);
|
2019-03-31 23:47:46 +08:00
|
|
|
}
|
|
|
|
|
2008-06-12 23:57:23 +08:00
|
|
|
DWORD cflags;
|
2019-03-30 15:12:02 +08:00
|
|
|
if (GetConsoleMode (get_handle (), &cflags))
|
2019-03-31 23:47:46 +08:00
|
|
|
SetConsoleMode (get_handle (), ENABLE_WINDOW_INPUT
|
2019-11-13 02:04:59 +08:00
|
|
|
| ((wincap.has_con_24bit_colors () && !con_is_legacy) ?
|
2019-11-07 00:29:29 +08:00
|
|
|
0 : ENABLE_MOUSE_INPUT)
|
2019-03-31 23:47:46 +08:00
|
|
|
| cflags);
|
2008-06-12 23:57:23 +08:00
|
|
|
|
2019-03-30 15:12:02 +08:00
|
|
|
debug_printf ("opened conin$ %p, conout$ %p", get_handle (),
|
2003-12-30 09:57:16 +08:00
|
|
|
get_output_handle ());
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-05-06 06:30:53 +08:00
|
|
|
void
|
|
|
|
fhandler_console::open_setup (int flags)
|
|
|
|
{
|
|
|
|
set_flags ((flags & ~O_TEXT) | O_BINARY);
|
2012-03-02 19:56:06 +08:00
|
|
|
if (myself->set_ctty (this, flags) && !myself->cygstarted)
|
|
|
|
init_console_handler (true);
|
2013-10-24 23:26:21 +08:00
|
|
|
fhandler_base::open_setup (flags);
|
2011-05-06 06:30:53 +08:00
|
|
|
}
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
int
|
2005-07-05 11:16:46 +08:00
|
|
|
fhandler_console::close ()
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2019-03-31 23:47:46 +08:00
|
|
|
debug_printf ("closing: %p, %p", get_handle (), get_output_handle ());
|
|
|
|
|
2020-02-17 18:29:07 +08:00
|
|
|
acquire_output_mutex (INFINITE);
|
2019-03-31 23:47:48 +08:00
|
|
|
|
2020-02-25 00:12:16 +08:00
|
|
|
if (shared_console_info && wincap.has_con_24bit_colors ())
|
|
|
|
{
|
|
|
|
/* Restore console mode if this is the last closure. */
|
|
|
|
OBJECT_BASIC_INFORMATION obi;
|
|
|
|
NTSTATUS status;
|
|
|
|
status = NtQueryObject (get_handle (), ObjectBasicInformation,
|
|
|
|
&obi, sizeof obi, NULL);
|
|
|
|
if ((NT_SUCCESS (status) && obi.HandleCount == 1)
|
|
|
|
|| myself->pid == con.owner)
|
2021-01-15 16:32:10 +08:00
|
|
|
{
|
|
|
|
request_xterm_mode_output (false, &handle_set);
|
|
|
|
request_xterm_mode_input (false, &handle_set);
|
|
|
|
}
|
2020-02-25 00:12:16 +08:00
|
|
|
}
|
2020-02-17 18:29:07 +08:00
|
|
|
|
|
|
|
release_output_mutex ();
|
|
|
|
|
|
|
|
CloseHandle (input_mutex);
|
|
|
|
input_mutex = NULL;
|
|
|
|
CloseHandle (output_mutex);
|
|
|
|
output_mutex = NULL;
|
2020-01-02 21:17:16 +08:00
|
|
|
|
2019-03-30 15:12:02 +08:00
|
|
|
CloseHandle (get_handle ());
|
2000-02-18 03:38:33 +08:00
|
|
|
CloseHandle (get_output_handle ());
|
2019-08-28 02:04:02 +08:00
|
|
|
|
2020-01-27 20:14:32 +08:00
|
|
|
if (con_ra.rabuf)
|
|
|
|
free (con_ra.rabuf);
|
|
|
|
|
2011-11-14 09:29:49 +08:00
|
|
|
if (!have_execed)
|
2012-02-08 00:54:14 +08:00
|
|
|
free_console ();
|
2000-02-18 03:38:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2011-10-12 07:20:38 +08:00
|
|
|
fhandler_console::ioctl (unsigned int cmd, void *arg)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2011-10-16 06:37:30 +08:00
|
|
|
int res = fhandler_termios::ioctl (cmd, arg);
|
2011-10-12 07:20:38 +08:00
|
|
|
if (res <= 0)
|
|
|
|
return res;
|
2019-03-31 23:47:48 +08:00
|
|
|
acquire_output_mutex (INFINITE);
|
2000-02-18 03:38:33 +08:00
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case TIOCGWINSZ:
|
|
|
|
int st;
|
|
|
|
|
2021-01-25 17:18:11 +08:00
|
|
|
acquire_attach_mutex (INFINITE);
|
2014-03-10 06:49:56 +08:00
|
|
|
st = con.fillin (get_output_handle ());
|
2021-01-25 17:18:11 +08:00
|
|
|
release_attach_mutex ();
|
2000-02-18 03:38:33 +08:00
|
|
|
if (st)
|
|
|
|
{
|
|
|
|
/* *not* the buffer size, the actual screen size... */
|
|
|
|
/* based on Left Top Right Bottom of srWindow */
|
2014-03-10 06:49:56 +08:00
|
|
|
((struct winsize *) arg)->ws_row = con.dwWinSize.Y;
|
|
|
|
((struct winsize *) arg)->ws_col = con.dwWinSize.X;
|
2000-02-18 03:38:33 +08:00
|
|
|
syscall_printf ("WINSZ: (row=%d,col=%d)",
|
2011-10-12 07:20:38 +08:00
|
|
|
((struct winsize *) arg)->ws_row,
|
|
|
|
((struct winsize *) arg)->ws_col);
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2000-02-18 03:38:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
syscall_printf ("WINSZ failed");
|
|
|
|
__seterrno ();
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2000-02-18 03:38:33 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2000-02-18 03:38:33 +08:00
|
|
|
return 0;
|
|
|
|
case TIOCSWINSZ:
|
2005-07-07 04:05:03 +08:00
|
|
|
bg_check (SIGTTOU);
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2000-02-18 03:38:33 +08:00
|
|
|
return 0;
|
2006-07-03 23:29:10 +08:00
|
|
|
case KDGKBMETA:
|
2014-03-10 06:49:56 +08:00
|
|
|
*(int *) arg = (con.metabit) ? K_METABIT : K_ESCPREFIX;
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2006-07-03 23:29:10 +08:00
|
|
|
return 0;
|
|
|
|
case KDSKBMETA:
|
2013-04-23 17:44:36 +08:00
|
|
|
if ((intptr_t) arg == K_METABIT)
|
2014-03-10 06:49:56 +08:00
|
|
|
con.metabit = TRUE;
|
2013-04-23 17:44:36 +08:00
|
|
|
else if ((intptr_t) arg == K_ESCPREFIX)
|
2014-03-10 06:49:56 +08:00
|
|
|
con.metabit = FALSE;
|
2006-07-03 23:29:10 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2006-07-03 23:29:10 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2006-07-03 23:29:10 +08:00
|
|
|
return 0;
|
2003-09-27 10:36:50 +08:00
|
|
|
case TIOCLINUX:
|
2011-10-12 07:20:38 +08:00
|
|
|
if (*(unsigned char *) arg == 6)
|
2003-09-27 10:36:50 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
*(unsigned char *) arg = (unsigned char) con.nModifiers;
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2003-09-27 10:36:50 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2011-07-23 02:50:42 +08:00
|
|
|
set_errno (EINVAL);
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2011-07-23 02:50:42 +08:00
|
|
|
return -1;
|
|
|
|
case FIONREAD:
|
|
|
|
{
|
|
|
|
DWORD n;
|
2011-07-25 23:19:35 +08:00
|
|
|
int ret = 0;
|
|
|
|
INPUT_RECORD inp[INREC_SIZE];
|
2021-01-25 17:18:11 +08:00
|
|
|
acquire_attach_mutex (INFINITE);
|
2019-03-30 15:12:02 +08:00
|
|
|
if (!PeekConsoleInputW (get_handle (), inp, INREC_SIZE, &n))
|
2011-07-23 02:50:42 +08:00
|
|
|
{
|
2011-07-25 23:19:35 +08:00
|
|
|
set_errno (EINVAL);
|
2021-01-25 17:18:11 +08:00
|
|
|
release_attach_mutex ();
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2011-07-23 02:50:42 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2021-01-25 17:18:11 +08:00
|
|
|
release_attach_mutex ();
|
2020-02-18 12:05:07 +08:00
|
|
|
bool saw_eol = false;
|
|
|
|
for (DWORD i=0; i<n; i++)
|
|
|
|
if (inp[i].EventType == KEY_EVENT &&
|
|
|
|
inp[i].Event.KeyEvent.bKeyDown &&
|
|
|
|
inp[i].Event.KeyEvent.uChar.UnicodeChar)
|
|
|
|
{
|
|
|
|
WCHAR wc = inp[i].Event.KeyEvent.uChar.UnicodeChar;
|
|
|
|
char mbs[8];
|
|
|
|
int len = con.con_to_str (mbs, sizeof (mbs), wc);
|
|
|
|
if ((get_ttyp ()->ti.c_lflag & ICANON) &&
|
|
|
|
len == 1 && CCEQ (get_ttyp ()->ti.c_cc[VEOF], mbs[0]))
|
|
|
|
{
|
|
|
|
saw_eol = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret += len;
|
|
|
|
const char eols[] = {
|
|
|
|
'\n',
|
|
|
|
'\r',
|
|
|
|
(char) get_ttyp ()->ti.c_cc[VEOL],
|
|
|
|
(char) get_ttyp ()->ti.c_cc[VEOL2]
|
|
|
|
};
|
|
|
|
if ((get_ttyp ()->ti.c_lflag & ICANON) &&
|
|
|
|
len == 1 && memchr (eols, mbs[0], sizeof (eols)))
|
|
|
|
{
|
|
|
|
saw_eol = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((get_ttyp ()->ti.c_lflag & ICANON) && !saw_eol)
|
|
|
|
*(int *) arg = 0;
|
|
|
|
else
|
|
|
|
*(int *) arg = ret;
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2011-07-23 02:50:42 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2011-10-12 07:20:38 +08:00
|
|
|
return fhandler_base::ioctl (cmd, arg);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fhandler_console::tcflush (int queue)
|
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
if (queue == TCIFLUSH
|
|
|
|
|| queue == TCIOFLUSH)
|
|
|
|
{
|
2021-01-25 17:18:11 +08:00
|
|
|
acquire_attach_mutex (INFINITE);
|
2019-03-30 15:12:02 +08:00
|
|
|
if (!FlushConsoleInputBuffer (get_handle ()))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
res = -1;
|
|
|
|
}
|
2021-01-25 17:18:11 +08:00
|
|
|
release_attach_mutex ();
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fhandler_console::output_tcsetattr (int, struct termios const *t)
|
|
|
|
{
|
|
|
|
/* All the output bits we can ignore */
|
|
|
|
|
2019-03-31 23:47:48 +08:00
|
|
|
acquire_output_mutex (INFINITE);
|
2000-02-18 03:38:33 +08:00
|
|
|
DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
|
|
|
|
|
2021-01-15 16:32:10 +08:00
|
|
|
DWORD oflags;
|
2021-01-25 17:18:11 +08:00
|
|
|
acquire_attach_mutex (INFINITE);
|
2021-01-15 16:32:10 +08:00
|
|
|
GetConsoleMode (get_output_handle (), &oflags);
|
|
|
|
if (wincap.has_con_24bit_colors () && !con_is_legacy
|
|
|
|
&& (oflags & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
|
|
|
|
flags |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
int res = SetConsoleMode (get_output_handle (), flags) ? 0 : -1;
|
2021-01-25 17:18:11 +08:00
|
|
|
release_attach_mutex ();
|
2011-05-29 02:17:09 +08:00
|
|
|
if (res)
|
2011-05-06 06:30:53 +08:00
|
|
|
__seterrno_from_win_error (GetLastError ());
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2013-04-23 17:44:36 +08:00
|
|
|
syscall_printf ("%d = tcsetattr(,%p) (ENABLE FLAGS %y) (lflag %y oflag %y)",
|
2000-02-18 03:38:33 +08:00
|
|
|
res, t, flags, t->c_lflag, t->c_oflag);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fhandler_console::input_tcsetattr (int, struct termios const *t)
|
|
|
|
{
|
|
|
|
/* Ignore the optional_actions stuff, since all output is emitted
|
|
|
|
instantly */
|
2019-03-31 23:47:48 +08:00
|
|
|
acquire_input_mutex (INFINITE);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
DWORD oflags;
|
|
|
|
|
2021-01-25 17:18:11 +08:00
|
|
|
acquire_attach_mutex (INFINITE);
|
2019-03-30 15:12:02 +08:00
|
|
|
if (!GetConsoleMode (get_handle (), &oflags))
|
2000-02-18 03:38:33 +08:00
|
|
|
oflags = 0;
|
|
|
|
DWORD flags = 0;
|
|
|
|
|
2002-06-05 12:01:43 +08:00
|
|
|
#if 0
|
2000-02-18 03:38:33 +08:00
|
|
|
/* Enable/disable LF -> CRLF conversions */
|
2004-04-10 21:45:10 +08:00
|
|
|
rbinary ((t->c_iflag & INLCR) ? false : true);
|
2002-06-05 12:01:43 +08:00
|
|
|
#endif
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
/* There's some disparity between what we need and what's
|
|
|
|
available. We've got ECHO and ICANON, they've
|
|
|
|
got ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT. */
|
|
|
|
|
2011-10-16 06:37:30 +08:00
|
|
|
termios_printf ("this %p, get_ttyp () %p, t %p", this, get_ttyp (), t);
|
|
|
|
get_ttyp ()->ti = *t;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
if (t->c_lflag & ECHO)
|
|
|
|
{
|
|
|
|
flags |= ENABLE_ECHO_INPUT;
|
|
|
|
}
|
|
|
|
if (t->c_lflag & ICANON)
|
|
|
|
{
|
|
|
|
flags |= ENABLE_LINE_INPUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & ENABLE_ECHO_INPUT
|
|
|
|
&& !(flags & ENABLE_LINE_INPUT))
|
|
|
|
{
|
|
|
|
/* This is illegal, so turn off the echo here, and fake it
|
|
|
|
when we read the characters */
|
|
|
|
|
|
|
|
flags &= ~ENABLE_ECHO_INPUT;
|
|
|
|
}
|
|
|
|
|
2011-07-14 18:02:11 +08:00
|
|
|
if ((t->c_lflag & ISIG) && !(t->c_iflag & IGNBRK))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
flags |= ENABLE_PROCESSED_INPUT;
|
|
|
|
}
|
|
|
|
|
2019-03-31 23:47:46 +08:00
|
|
|
flags |= ENABLE_WINDOW_INPUT |
|
2019-11-13 02:04:59 +08:00
|
|
|
((wincap.has_con_24bit_colors () && !con_is_legacy) ?
|
2019-11-07 00:29:29 +08:00
|
|
|
0 : ENABLE_MOUSE_INPUT);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2021-01-15 16:32:10 +08:00
|
|
|
if (wincap.has_con_24bit_colors () && !con_is_legacy
|
|
|
|
&& (oflags & ENABLE_VIRTUAL_TERMINAL_INPUT))
|
|
|
|
flags |= ENABLE_VIRTUAL_TERMINAL_INPUT;
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
int res;
|
|
|
|
if (flags == oflags)
|
|
|
|
res = 0;
|
|
|
|
else
|
|
|
|
{
|
2019-03-30 15:12:02 +08:00
|
|
|
res = SetConsoleMode (get_handle (), flags) ? 0 : -1;
|
2000-02-18 03:38:33 +08:00
|
|
|
if (res < 0)
|
|
|
|
__seterrno ();
|
2013-04-23 17:44:36 +08:00
|
|
|
syscall_printf ("%d = tcsetattr(,%p) enable flags %y, c_lflag %y iflag %y",
|
2000-02-18 03:38:33 +08:00
|
|
|
res, t, flags, t->c_lflag, t->c_iflag);
|
|
|
|
}
|
2021-01-25 17:18:11 +08:00
|
|
|
release_attach_mutex ();
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2011-10-16 06:37:30 +08:00
|
|
|
get_ttyp ()->rstcons (false);
|
2019-03-31 23:47:48 +08:00
|
|
|
release_input_mutex ();
|
2000-02-18 03:38:33 +08:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fhandler_console::tcsetattr (int a, struct termios const *t)
|
|
|
|
{
|
|
|
|
int res = output_tcsetattr (a, t);
|
|
|
|
if (res != 0)
|
|
|
|
return res;
|
|
|
|
return input_tcsetattr (a, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fhandler_console::tcgetattr (struct termios *t)
|
|
|
|
{
|
|
|
|
int res;
|
2011-10-16 06:37:30 +08:00
|
|
|
*t = get_ttyp ()->ti;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
t->c_cflag |= CS8;
|
|
|
|
|
|
|
|
DWORD flags;
|
|
|
|
|
2021-01-25 17:18:11 +08:00
|
|
|
acquire_attach_mutex (INFINITE);
|
2019-03-30 15:12:02 +08:00
|
|
|
if (!GetConsoleMode (get_handle (), &flags))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
res = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (flags & ENABLE_ECHO_INPUT)
|
|
|
|
t->c_lflag |= ECHO;
|
|
|
|
|
|
|
|
if (flags & ENABLE_LINE_INPUT)
|
|
|
|
t->c_lflag |= ICANON;
|
|
|
|
|
2011-07-14 18:02:11 +08:00
|
|
|
if (flags & ENABLE_PROCESSED_INPUT)
|
|
|
|
t->c_lflag |= ISIG;
|
|
|
|
else
|
2011-07-06 02:01:13 +08:00
|
|
|
t->c_iflag |= IGNBRK;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
/* What about ENABLE_WINDOW_INPUT
|
|
|
|
and ENABLE_MOUSE_INPUT ? */
|
|
|
|
|
|
|
|
/* All the output bits we can ignore */
|
|
|
|
res = 0;
|
|
|
|
}
|
2021-01-25 17:18:11 +08:00
|
|
|
release_attach_mutex ();
|
2013-04-23 17:44:36 +08:00
|
|
|
syscall_printf ("%d = tcgetattr(%p) enable flags %y, t->lflag %y, t->iflag %y",
|
2000-02-18 03:38:33 +08:00
|
|
|
res, t, flags, t->c_lflag, t->c_iflag);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2011-06-13 04:15:26 +08:00
|
|
|
fhandler_console::fhandler_console (fh_devices unit) :
|
2019-03-31 23:47:48 +08:00
|
|
|
fhandler_termios (), input_ready (false),
|
|
|
|
input_mutex (NULL), output_mutex (NULL)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2011-06-13 04:15:26 +08:00
|
|
|
if (unit > 0)
|
|
|
|
dev ().parse (unit);
|
2011-10-16 06:37:30 +08:00
|
|
|
setup ();
|
2008-02-07 02:24:50 +08:00
|
|
|
trunc_buf.len = 0;
|
2011-10-16 06:37:30 +08:00
|
|
|
_tc = &(shared_console_info->tty_min_state);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2008-02-07 02:24:50 +08:00
|
|
|
|
2001-02-27 17:14:35 +08:00
|
|
|
void
|
2005-04-23 01:03:38 +08:00
|
|
|
dev_console::set_color (HANDLE h)
|
2001-02-27 17:14:35 +08:00
|
|
|
{
|
2005-04-23 01:03:38 +08:00
|
|
|
WORD win_fg = fg;
|
|
|
|
WORD win_bg = bg;
|
|
|
|
if (reverse)
|
2001-03-03 11:56:34 +08:00
|
|
|
{
|
2001-02-27 17:14:35 +08:00
|
|
|
WORD save_fg = win_fg;
|
2001-03-03 11:56:34 +08:00
|
|
|
win_fg = (win_bg & BACKGROUND_RED ? FOREGROUND_RED : 0) |
|
|
|
|
(win_bg & BACKGROUND_GREEN ? FOREGROUND_GREEN : 0) |
|
|
|
|
(win_bg & BACKGROUND_BLUE ? FOREGROUND_BLUE : 0) |
|
2004-12-16 21:19:08 +08:00
|
|
|
(win_bg & BACKGROUND_INTENSITY ? FOREGROUND_INTENSITY : 0);
|
2001-03-03 11:56:34 +08:00
|
|
|
win_bg = (save_fg & FOREGROUND_RED ? BACKGROUND_RED : 0) |
|
|
|
|
(save_fg & FOREGROUND_GREEN ? BACKGROUND_GREEN : 0) |
|
|
|
|
(save_fg & FOREGROUND_BLUE ? BACKGROUND_BLUE : 0) |
|
2004-12-16 21:19:08 +08:00
|
|
|
(save_fg & FOREGROUND_INTENSITY ? BACKGROUND_INTENSITY : 0);
|
2001-02-27 17:14:35 +08:00
|
|
|
}
|
2006-11-23 18:08:04 +08:00
|
|
|
|
|
|
|
/* apply attributes */
|
2005-04-23 01:03:38 +08:00
|
|
|
if (underline)
|
|
|
|
win_fg = underline_color;
|
2001-02-27 17:14:35 +08:00
|
|
|
/* emulate blink with bright background */
|
2005-04-23 01:03:38 +08:00
|
|
|
if (blink)
|
2002-10-08 14:16:16 +08:00
|
|
|
win_bg |= BACKGROUND_INTENSITY;
|
2005-04-23 01:03:38 +08:00
|
|
|
if (intensity == INTENSITY_INVISIBLE)
|
2001-02-27 17:14:35 +08:00
|
|
|
win_fg = win_bg;
|
2008-09-11 12:34:24 +08:00
|
|
|
else if (intensity != INTENSITY_BOLD)
|
|
|
|
/* nothing to do */;
|
2006-11-23 18:08:04 +08:00
|
|
|
/* apply foreground intensity only in non-reverse mode! */
|
2008-09-11 12:34:24 +08:00
|
|
|
else if (reverse)
|
|
|
|
win_bg |= BACKGROUND_INTENSITY;
|
|
|
|
else
|
|
|
|
win_fg |= FOREGROUND_INTENSITY;
|
2006-11-23 18:08:04 +08:00
|
|
|
|
2005-04-23 01:03:38 +08:00
|
|
|
current_win32_attr = win_fg | win_bg;
|
|
|
|
if (h)
|
|
|
|
SetConsoleTextAttribute (h, current_win32_attr);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define FOREGROUND_ATTR_MASK (FOREGROUND_RED | FOREGROUND_GREEN | \
|
|
|
|
FOREGROUND_BLUE | FOREGROUND_INTENSITY)
|
|
|
|
#define BACKGROUND_ATTR_MASK (BACKGROUND_RED | BACKGROUND_GREEN | \
|
|
|
|
BACKGROUND_BLUE | BACKGROUND_INTENSITY)
|
|
|
|
void
|
|
|
|
dev_console::set_default_attr ()
|
|
|
|
{
|
|
|
|
blink = underline = reverse = false;
|
|
|
|
intensity = INTENSITY_NORMAL;
|
|
|
|
fg = default_color & FOREGROUND_ATTR_MASK;
|
|
|
|
bg = default_color & BACKGROUND_ATTR_MASK;
|
|
|
|
set_color (NULL);
|
2001-02-27 17:14:35 +08:00
|
|
|
}
|
|
|
|
|
2014-01-05 07:58:32 +08:00
|
|
|
int
|
2014-02-16 09:48:25 +08:00
|
|
|
dev_console::set_cl_x (cltype x)
|
2014-01-05 07:58:32 +08:00
|
|
|
{
|
2014-01-31 12:23:22 +08:00
|
|
|
if (x == cl_disp_beg || x == cl_buf_beg)
|
2014-01-05 07:58:32 +08:00
|
|
|
return 0;
|
|
|
|
if (x == cl_disp_end)
|
|
|
|
return dwWinSize.X - 1;
|
2014-01-31 12:23:22 +08:00
|
|
|
if (x == cl_buf_end)
|
2014-03-10 06:49:56 +08:00
|
|
|
return b.dwSize.X - 1;
|
|
|
|
return b.dwCursorPosition.X;
|
2014-01-05 07:58:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2014-02-16 09:48:25 +08:00
|
|
|
dev_console::set_cl_y (cltype y)
|
2014-01-05 07:58:32 +08:00
|
|
|
{
|
2014-01-31 12:23:22 +08:00
|
|
|
if (y == cl_buf_beg)
|
|
|
|
return 0;
|
2014-01-05 07:58:32 +08:00
|
|
|
if (y == cl_disp_beg)
|
2014-03-10 06:49:56 +08:00
|
|
|
return b.srWindow.Top;
|
2014-01-31 12:23:22 +08:00
|
|
|
if (y == cl_disp_end)
|
2014-03-10 06:49:56 +08:00
|
|
|
return b.srWindow.Bottom;
|
2014-01-31 12:23:22 +08:00
|
|
|
if (y == cl_buf_end)
|
2014-03-10 06:49:56 +08:00
|
|
|
return b.dwSize.Y - 1;
|
|
|
|
return b.dwCursorPosition.Y;
|
2014-01-05 07:58:32 +08:00
|
|
|
}
|
2014-02-16 09:48:25 +08:00
|
|
|
|
|
|
|
bool
|
2014-02-23 11:38:52 +08:00
|
|
|
dev_console::scroll_window (HANDLE h, int x1, int y1, int x2, int y2)
|
2014-02-16 09:48:25 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
if (save_buf || x1 != 0 || x2 != dwWinSize.X - 1 || y1 != b.srWindow.Top
|
|
|
|
|| y2 != b.srWindow.Bottom || b.dwSize.Y <= dwWinSize.Y)
|
2014-02-23 11:38:52 +08:00
|
|
|
return false;
|
2014-02-16 09:48:25 +08:00
|
|
|
|
|
|
|
SMALL_RECT sr;
|
2016-07-28 02:39:24 +08:00
|
|
|
int toscroll = dwEnd.Y - b.srWindow.Top + 1;
|
2014-02-23 11:38:52 +08:00
|
|
|
sr.Left = sr.Right = dwEnd.X = 0;
|
2016-07-28 02:39:24 +08:00
|
|
|
|
|
|
|
if (b.srWindow.Bottom + toscroll >= b.dwSize.Y)
|
2014-02-23 11:38:52 +08:00
|
|
|
{
|
2016-07-28 02:39:24 +08:00
|
|
|
/* So we're at the end of the buffer and scrolling the console window
|
|
|
|
would move us beyond the buffer. What we do here is to scroll the
|
|
|
|
console buffer upward by just as much so that the current last line
|
|
|
|
becomes the last line just prior to the first window line. That
|
2016-08-03 20:34:01 +08:00
|
|
|
keeps the end of the console buffer intact, as desired. */
|
2016-07-28 02:39:24 +08:00
|
|
|
SMALL_RECT br;
|
|
|
|
COORD dest;
|
|
|
|
CHAR_INFO fill;
|
|
|
|
|
|
|
|
br.Left = 0;
|
2016-08-03 20:34:01 +08:00
|
|
|
br.Top = (b.srWindow.Bottom - b.srWindow.Top) + 1
|
|
|
|
- (b.dwSize.Y - dwEnd.Y - 1);
|
2016-07-28 02:39:24 +08:00
|
|
|
br.Right = b.dwSize.X - 1;
|
|
|
|
br.Bottom = b.dwSize.Y - 1;
|
|
|
|
dest.X = dest.Y = 0;
|
2018-09-05 19:08:33 +08:00
|
|
|
fill.Char.UnicodeChar = L' ';
|
2016-07-28 02:39:24 +08:00
|
|
|
fill.Attributes = current_win32_attr;
|
2018-09-05 19:08:33 +08:00
|
|
|
ScrollConsoleScreenBufferW (h, &br, NULL, dest, &fill);
|
2016-08-03 20:34:01 +08:00
|
|
|
/* Since we're moving the console buffer under the console window
|
|
|
|
we only have to move the console window if the user scrolled the
|
|
|
|
window upwards. The number of lines is the distance to the
|
|
|
|
buffer bottom. */
|
|
|
|
toscroll = b.dwSize.Y - b.srWindow.Bottom - 1;
|
|
|
|
/* Fix dwEnd to reflect the new cursor line. Take the above scrolling
|
|
|
|
into account and subtract 1 to account for the increment below. */
|
|
|
|
dwEnd.Y = b.dwCursorPosition.Y + toscroll - 1;
|
2014-02-23 11:38:52 +08:00
|
|
|
}
|
2016-08-03 20:34:01 +08:00
|
|
|
if (toscroll)
|
2016-07-28 02:39:24 +08:00
|
|
|
{
|
2016-08-03 20:34:01 +08:00
|
|
|
/* FIXME: For some reason SetConsoleWindowInfo does not correctly
|
|
|
|
set the scrollbars. Calling SetConsoleCursorPosition here is
|
|
|
|
just a workaround which doesn't cover all cases. In some scenarios
|
|
|
|
the scrollbars are still off by one console window size. */
|
|
|
|
|
2016-07-28 02:39:24 +08:00
|
|
|
/* The reminder of the console buffer is big enough to simply move
|
2016-07-29 18:07:46 +08:00
|
|
|
the console window. We have to set the cursor first, otherwise
|
|
|
|
the scroll bars will not be corrected. */
|
|
|
|
SetConsoleCursorPosition (h, dwEnd);
|
2016-08-03 20:34:01 +08:00
|
|
|
/* If the user scolled manually, setting the cursor position might scroll
|
|
|
|
the console window so that the cursor is not at the top. Correct
|
2016-07-29 18:07:46 +08:00
|
|
|
the action by moving the window down again so the cursor is one line
|
|
|
|
above the new window position. */
|
2016-08-03 20:34:01 +08:00
|
|
|
GetConsoleScreenBufferInfo (h, &b);
|
|
|
|
if (b.dwCursorPosition.Y >= b.srWindow.Top)
|
|
|
|
toscroll = b.dwCursorPosition.Y - b.srWindow.Top + 1;
|
2016-07-29 18:07:46 +08:00
|
|
|
/* Move the window accordingly. */
|
2016-07-28 02:39:24 +08:00
|
|
|
sr.Top = sr.Bottom = toscroll;
|
|
|
|
SetConsoleWindowInfo (h, FALSE, &sr);
|
|
|
|
}
|
|
|
|
/* Eventually set cursor to new end position at the top of the window. */
|
2014-02-23 11:38:52 +08:00
|
|
|
dwEnd.Y++;
|
2014-02-16 09:48:25 +08:00
|
|
|
SetConsoleCursorPosition (h, dwEnd);
|
2016-07-28 02:39:24 +08:00
|
|
|
/* Fix up console buffer info. */
|
2014-02-23 11:38:52 +08:00
|
|
|
fillin (h);
|
|
|
|
return true;
|
2014-02-16 09:48:25 +08:00
|
|
|
}
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
/*
|
|
|
|
* Clear the screen context from x1/y1 to x2/y2 cell.
|
|
|
|
* Negative values represents current screen dimensions
|
|
|
|
*/
|
2014-02-23 11:38:52 +08:00
|
|
|
void __reg3
|
2014-01-05 07:58:32 +08:00
|
|
|
fhandler_console::clear_screen (cltype xc1, cltype yc1, cltype xc2, cltype yc2)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2014-02-23 11:38:52 +08:00
|
|
|
HANDLE h = get_output_handle ();
|
2016-07-29 18:07:46 +08:00
|
|
|
SHORT oldEndY = con.dwEnd.Y;
|
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fillin (h);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
int x1 = con.set_cl_x (xc1);
|
|
|
|
int y1 = con.set_cl_y (yc1);
|
|
|
|
int x2 = con.set_cl_x (xc2);
|
|
|
|
int y2 = con.set_cl_y (yc2);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2016-07-29 18:07:46 +08:00
|
|
|
/* Make correction for the following situation: The console buffer
|
|
|
|
is only partially used and the user scrolled down into the as yet
|
2016-08-01 18:35:51 +08:00
|
|
|
unused area so far that the cursor is outside the window buffer. */
|
|
|
|
if (oldEndY < con.dwEnd.Y && oldEndY < con.b.srWindow.Top)
|
2016-07-29 18:07:46 +08:00
|
|
|
{
|
|
|
|
con.dwEnd.Y = con.b.dwCursorPosition.Y = oldEndY;
|
|
|
|
y1 = con.b.srWindow.Top;
|
|
|
|
}
|
|
|
|
|
2014-02-23 11:38:52 +08:00
|
|
|
/* Detect special case - scroll the screen if we have a buffer in order to
|
2014-02-16 09:48:25 +08:00
|
|
|
preserve the buffer. */
|
2014-03-10 06:49:56 +08:00
|
|
|
if (!con.scroll_window (h, x1, y1, x2, y2))
|
|
|
|
con.clear_screen (h, x1, y1, x2, y2);
|
2014-02-23 11:38:52 +08:00
|
|
|
}
|
2014-02-16 09:48:25 +08:00
|
|
|
|
2014-02-23 11:38:52 +08:00
|
|
|
void __reg3
|
|
|
|
dev_console::clear_screen (HANDLE h, int x1, int y1, int x2, int y2)
|
|
|
|
{
|
|
|
|
COORD tlc;
|
|
|
|
DWORD done;
|
|
|
|
int num;
|
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
num = abs (y1 - y2) * b.dwSize.X + abs (x1 - x2) + 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
if ((y2 * b.dwSize.X + x2) > (y1 * b.dwSize.X + x1))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
tlc.X = x1;
|
|
|
|
tlc.Y = y1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tlc.X = x2;
|
|
|
|
tlc.Y = y2;
|
|
|
|
}
|
2017-07-31 17:43:35 +08:00
|
|
|
FillConsoleOutputCharacterW (h, L' ', num, tlc, &done);
|
2014-02-23 11:38:52 +08:00
|
|
|
FillConsoleOutputAttribute (h, current_win32_attr, num, tlc, &done);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2014-02-23 11:38:52 +08:00
|
|
|
void __reg3
|
2003-12-08 06:37:12 +08:00
|
|
|
fhandler_console::cursor_set (bool rel_to_top, int x, int y)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
COORD pos;
|
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fillin (get_output_handle ());
|
2011-10-12 22:19:20 +08:00
|
|
|
#if 0
|
2014-03-10 06:49:56 +08:00
|
|
|
/* Setting y to the current b.srWindow.Bottom here is the reason that the window
|
2011-10-12 22:19:20 +08:00
|
|
|
isn't scrolled back to the current cursor position like it's done in
|
|
|
|
any other terminal. Rather, the curser is forced to the bottom of the
|
|
|
|
currently scrolled region. This breaks the console buffer content if
|
|
|
|
output is generated while the user had the window scrolled back. This
|
|
|
|
behaviour is very old, it has no matching ChangeLog entry.
|
|
|
|
Just disable for now but keep the code in for future reference. */
|
2014-03-10 06:49:56 +08:00
|
|
|
if (y > con.b.srWindow.Bottom)
|
|
|
|
y = con.b.srWindow.Bottom;
|
2011-10-12 22:19:20 +08:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
if (y < 0)
|
2000-02-18 03:38:33 +08:00
|
|
|
y = 0;
|
|
|
|
else if (rel_to_top)
|
2014-03-10 06:49:56 +08:00
|
|
|
y += con.b.srWindow.Top;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
if (x > con.dwWinSize.X)
|
|
|
|
x = con.dwWinSize.X - 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
else if (x < 0)
|
|
|
|
x = 0;
|
|
|
|
|
|
|
|
pos.X = x;
|
|
|
|
pos.Y = y;
|
|
|
|
SetConsoleCursorPosition (get_output_handle (), pos);
|
|
|
|
}
|
|
|
|
|
2014-02-23 11:38:52 +08:00
|
|
|
void __reg3
|
2000-02-18 03:38:33 +08:00
|
|
|
fhandler_console::cursor_rel (int x, int y)
|
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fillin (get_output_handle ());
|
|
|
|
x += con.b.dwCursorPosition.X;
|
|
|
|
y += con.b.dwCursorPosition.Y;
|
2003-12-08 06:37:12 +08:00
|
|
|
cursor_set (false, x, y);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2014-02-23 11:38:52 +08:00
|
|
|
void __reg3
|
2000-02-18 03:38:33 +08:00
|
|
|
fhandler_console::cursor_get (int *x, int *y)
|
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fillin (get_output_handle ());
|
|
|
|
*y = con.b.dwCursorPosition.Y;
|
|
|
|
*x = con.b.dwCursorPosition.X;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2009-12-19 23:37:10 +08:00
|
|
|
/* VT100 line drawing graphics mode maps `abcdefghijklmnopqrstuvwxyz{|}~ to
|
|
|
|
graphical characters */
|
2011-08-20 02:19:22 +08:00
|
|
|
static const wchar_t __vt100_conv[31] = {
|
2009-12-19 23:37:10 +08:00
|
|
|
0x25C6, /* Black Diamond */
|
|
|
|
0x2592, /* Medium Shade */
|
|
|
|
0x2409, /* Symbol for Horizontal Tabulation */
|
|
|
|
0x240C, /* Symbol for Form Feed */
|
|
|
|
0x240D, /* Symbol for Carriage Return */
|
|
|
|
0x240A, /* Symbol for Line Feed */
|
|
|
|
0x00B0, /* Degree Sign */
|
|
|
|
0x00B1, /* Plus-Minus Sign */
|
|
|
|
0x2424, /* Symbol for Newline */
|
|
|
|
0x240B, /* Symbol for Vertical Tabulation */
|
|
|
|
0x2518, /* Box Drawings Light Up And Left */
|
|
|
|
0x2510, /* Box Drawings Light Down And Left */
|
|
|
|
0x250C, /* Box Drawings Light Down And Right */
|
|
|
|
0x2514, /* Box Drawings Light Up And Right */
|
|
|
|
0x253C, /* Box Drawings Light Vertical And Horizontal */
|
|
|
|
0x23BA, /* Horizontal Scan Line-1 */
|
|
|
|
0x23BB, /* Horizontal Scan Line-3 */
|
|
|
|
0x2500, /* Box Drawings Light Horizontal */
|
|
|
|
0x23BC, /* Horizontal Scan Line-7 */
|
|
|
|
0x23BD, /* Horizontal Scan Line-9 */
|
|
|
|
0x251C, /* Box Drawings Light Vertical And Right */
|
|
|
|
0x2524, /* Box Drawings Light Vertical And Left */
|
|
|
|
0x2534, /* Box Drawings Light Up And Horizontal */
|
|
|
|
0x252C, /* Box Drawings Light Down And Horizontal */
|
|
|
|
0x2502, /* Box Drawings Light Vertical */
|
|
|
|
0x2264, /* Less-Than Or Equal To */
|
|
|
|
0x2265, /* Greater-Than Or Equal To */
|
|
|
|
0x03C0, /* Greek Small Letter Pi */
|
|
|
|
0x2260, /* Not Equal To */
|
|
|
|
0x00A3, /* Pound Sign */
|
|
|
|
0x00B7, /* Middle Dot */
|
|
|
|
};
|
|
|
|
|
2020-02-20 21:57:26 +08:00
|
|
|
inline bool
|
|
|
|
fhandler_console::write_console (PWCHAR buf, DWORD len, DWORD& done)
|
2009-05-04 11:51:16 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
if (con.iso_2022_G1
|
|
|
|
? con.vt100_graphics_mode_G1
|
|
|
|
: con.vt100_graphics_mode_G0)
|
2009-12-19 23:37:10 +08:00
|
|
|
for (DWORD i = 0; i < len; i ++)
|
|
|
|
if (buf[i] >= (unsigned char) '`' && buf[i] <= (unsigned char) '~')
|
2011-06-06 13:02:13 +08:00
|
|
|
buf[i] = __vt100_conv[buf[i] - (unsigned char) '`'];
|
2009-12-19 23:37:10 +08:00
|
|
|
|
2020-08-27 11:35:03 +08:00
|
|
|
if (len > 0)
|
|
|
|
last_char = buf[len-1];
|
|
|
|
|
2009-05-04 11:51:16 +08:00
|
|
|
while (len > 0)
|
|
|
|
{
|
|
|
|
DWORD nbytes = len > MAX_WRITE_CHARS ? MAX_WRITE_CHARS : len;
|
|
|
|
if (!WriteConsoleW (get_output_handle (), buf, nbytes, &done, 0))
|
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
len -= done;
|
|
|
|
buf += done;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-01-05 07:58:32 +08:00
|
|
|
/* The following three functions were adapted (i.e., mildly modified) from
|
|
|
|
http://stackoverflow.com/questions/14699043/replacement-to-systemcolor */
|
|
|
|
|
|
|
|
/* Split a rectangular region into two smaller rectangles based on the
|
|
|
|
largest dimension. */
|
|
|
|
static void
|
|
|
|
region_split (PCHAR_INFO& buf, COORD& bufsiz, SMALL_RECT& region,
|
|
|
|
PCHAR_INFO& buf_b, COORD& bufsiz_b, SMALL_RECT& region_b)
|
|
|
|
{
|
|
|
|
region_b = region;
|
|
|
|
bufsiz_b = bufsiz;
|
|
|
|
|
|
|
|
SHORT half = (1 + region.Bottom - region.Top) / 2;
|
|
|
|
region_b.Top += half;
|
|
|
|
region.Bottom = (bufsiz.Y = region_b.Top) - 1;
|
|
|
|
buf_b = buf + (half * (1 + region.Right));
|
|
|
|
bufsiz_b.Y = region_b.Bottom - region_b.Top;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Utility function to figure out the distance between two points. */
|
|
|
|
static SHORT
|
|
|
|
delta (SHORT first, SHORT second)
|
|
|
|
{
|
|
|
|
return (second >= first) ? (second - first + 1) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Subdivide the ReadConsoleInput operation into smaller and smaller chunks as
|
|
|
|
needed until it succeeds in reading the entire screen buffer. */
|
|
|
|
static BOOL
|
|
|
|
ReadConsoleOutputWrapper (HANDLE h, PCHAR_INFO buf, COORD bufsiz,
|
2014-03-10 06:49:56 +08:00
|
|
|
SMALL_RECT region)
|
2014-01-05 07:58:32 +08:00
|
|
|
{
|
|
|
|
COORD coord = {};
|
|
|
|
SHORT width = delta (region.Left, region.Right);
|
|
|
|
SHORT height = delta (region.Top, region.Bottom);
|
|
|
|
|
|
|
|
if ((width == 0) || (height == 0))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
BOOL success = ReadConsoleOutputW (h, buf, bufsiz, coord, ®ion);
|
|
|
|
if (success)
|
|
|
|
/* it worked */;
|
|
|
|
else if (GetLastError () == ERROR_NOT_ENOUGH_MEMORY && (width * height) > 1)
|
|
|
|
{
|
|
|
|
PCHAR_INFO buf_b;
|
|
|
|
COORD bufsiz_b;
|
|
|
|
SMALL_RECT region_b;
|
|
|
|
region_split (buf, bufsiz, region, buf_b, bufsiz_b, region_b);
|
|
|
|
success = ReadConsoleOutputWrapper (h, buf, bufsiz, region)
|
|
|
|
&& ReadConsoleOutputWrapper (h, buf_b, bufsiz_b, region_b);
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
void
|
|
|
|
dev_console::save_restore (HANDLE h, char c)
|
|
|
|
{
|
|
|
|
if (c == 'h') /* save */
|
|
|
|
{
|
|
|
|
fillin (h);
|
2014-03-10 11:15:39 +08:00
|
|
|
save_bufsize.X = b.dwSize.X;
|
2014-05-09 22:28:48 +08:00
|
|
|
if ((save_bufsize.Y = dwEnd.Y + 1) > b.dwSize.Y)
|
2014-03-11 01:33:17 +08:00
|
|
|
save_bufsize.X = b.dwSize.Y;
|
2014-03-10 06:49:56 +08:00
|
|
|
|
|
|
|
if (save_buf)
|
|
|
|
cfree (save_buf);
|
|
|
|
size_t screen_size = sizeof (CHAR_INFO) * save_bufsize.X * save_bufsize.Y;
|
|
|
|
save_buf = (PCHAR_INFO) cmalloc_abort (HEAP_1_BUF, screen_size);
|
|
|
|
|
|
|
|
save_cursor = b.dwCursorPosition; /* Remember where we were. */
|
2014-04-27 01:38:22 +08:00
|
|
|
save_top = b.srWindow.Top;
|
2014-03-10 06:49:56 +08:00
|
|
|
|
|
|
|
SMALL_RECT now = {}; /* Read the whole buffer */
|
2014-03-10 11:15:39 +08:00
|
|
|
now.Bottom = save_bufsize.Y - 1;
|
|
|
|
now.Right = save_bufsize.X - 1;
|
2014-03-10 06:49:56 +08:00
|
|
|
if (!ReadConsoleOutputWrapper (h, save_buf, save_bufsize, now))
|
|
|
|
debug_printf ("ReadConsoleOutputWrapper(h, ...) failed during save, %E");
|
|
|
|
|
|
|
|
/* Position at top of buffer */
|
|
|
|
COORD cob = {};
|
|
|
|
if (!SetConsoleCursorPosition (h, cob))
|
|
|
|
debug_printf ("SetConsoleCursorInfo(%p, ...) failed during save, %E", h);
|
|
|
|
|
|
|
|
/* Clear entire buffer */
|
|
|
|
clear_screen (h, 0, 0, now.Right, now.Bottom);
|
|
|
|
b.dwCursorPosition.X = b.dwCursorPosition.Y = dwEnd.X = dwEnd.Y = 0;
|
|
|
|
}
|
|
|
|
else if (save_buf)
|
|
|
|
{
|
|
|
|
COORD cob = {};
|
|
|
|
SMALL_RECT now = {};
|
2014-03-10 11:15:39 +08:00
|
|
|
now.Bottom = save_bufsize.Y - 1;
|
|
|
|
now.Right = save_bufsize.X - 1;
|
2014-03-10 06:49:56 +08:00
|
|
|
/* Restore whole buffer */
|
2014-04-27 01:38:22 +08:00
|
|
|
clear_screen (h, 0, 0, b.dwSize.X - 1, b.dwSize.Y - 1);
|
2014-03-10 06:49:56 +08:00
|
|
|
BOOL res = WriteConsoleOutputW (h, save_buf, save_bufsize, cob, &now);
|
|
|
|
if (!res)
|
|
|
|
debug_printf ("WriteConsoleOutputW failed, %E");
|
|
|
|
|
|
|
|
cfree (save_buf);
|
|
|
|
save_buf = NULL;
|
2014-03-10 11:15:39 +08:00
|
|
|
|
2014-04-27 01:38:22 +08:00
|
|
|
cob.X = 0;
|
|
|
|
cob.Y = save_top;
|
2014-05-09 22:28:48 +08:00
|
|
|
/* CGF: NOOP? Doesn't seem to position screen as expected */
|
2014-04-27 01:38:22 +08:00
|
|
|
/* Temporarily position at top of screen */
|
|
|
|
if (!SetConsoleCursorPosition (h, cob))
|
|
|
|
debug_printf ("SetConsoleCursorInfo(%p, cob) failed during restore, %E", h);
|
2014-03-10 11:15:39 +08:00
|
|
|
/* Position where we were previously */
|
|
|
|
if (!SetConsoleCursorPosition (h, save_cursor))
|
2014-04-27 01:38:22 +08:00
|
|
|
debug_printf ("SetConsoleCursorInfo(%p, save_cursor) failed during restore, %E", h);
|
2014-03-10 11:15:39 +08:00
|
|
|
/* Get back correct version of buffer information */
|
|
|
|
dwEnd.X = dwEnd.Y = 0;
|
|
|
|
fillin (h);
|
2014-03-10 06:49:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
#define BAK 1
|
|
|
|
#define ESC 2
|
|
|
|
#define NOR 0
|
|
|
|
#define IGN 4
|
2008-02-07 02:24:50 +08:00
|
|
|
#if 1
|
2000-02-18 03:38:33 +08:00
|
|
|
#define ERR 5
|
|
|
|
#else
|
|
|
|
#define ERR NOR
|
|
|
|
#endif
|
|
|
|
#define DWN 6
|
|
|
|
#define BEL 7
|
|
|
|
#define TAB 8 /* We should't let the console deal with these */
|
|
|
|
#define CR 13
|
|
|
|
#define LF 10
|
2009-12-19 23:37:10 +08:00
|
|
|
#define SO 14
|
|
|
|
#define SI 15
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
static const char base_chars[256] =
|
|
|
|
{
|
|
|
|
/*00 01 02 03 04 05 06 07 */ IGN, ERR, ERR, NOR, NOR, NOR, NOR, BEL,
|
2009-12-19 23:37:10 +08:00
|
|
|
/*08 09 0A 0B 0C 0D 0E 0F */ BAK, TAB, DWN, ERR, ERR, CR, SO, SI,
|
2000-02-18 03:38:33 +08:00
|
|
|
/*10 11 12 13 14 15 16 17 */ NOR, NOR, ERR, ERR, ERR, ERR, ERR, ERR,
|
|
|
|
/*18 19 1A 1B 1C 1D 1E 1F */ NOR, NOR, ERR, ESC, ERR, ERR, ERR, ERR,
|
|
|
|
/* ! " # $ % & ' */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
2008-02-06 01:37:10 +08:00
|
|
|
/*( ) * + , - . / */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
2000-02-18 03:38:33 +08:00
|
|
|
/*0 1 2 3 4 5 6 7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*8 9 : ; < = > ? */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*@ A B C D E F G */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*H I J K L M N O */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*P Q R S T U V W */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*X Y Z [ \ ] ^ _ */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*` a b c d e f g */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*h i j k l m n o */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*p q r s t u v w */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*x y z { | } ~ 7F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*80 81 82 83 84 85 86 87 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*88 89 8A 8B 8C 8D 8E 8F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*90 91 92 93 94 95 96 97 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*98 99 9A 9B 9C 9D 9E 9F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*A0 A1 A2 A3 A4 A5 A6 A7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*A8 A9 AA AB AC AD AE AF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*B0 B1 B2 B3 B4 B5 B6 B7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*B8 B9 BA BB BC BD BE BF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*C0 C1 C2 C3 C4 C5 C6 C7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*C8 C9 CA CB CC CD CE CF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*D0 D1 D2 D3 D4 D5 D6 D7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*D8 D9 DA DB DC DD DE DF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*E0 E1 E2 E3 E4 E5 E6 E7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*E8 E9 EA EB EC ED EE EF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*F0 F1 F2 F3 F4 F5 F6 F7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR,
|
|
|
|
/*F8 F9 FA FB FC FD FE FF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR };
|
|
|
|
|
2019-03-31 23:47:46 +08:00
|
|
|
static const char table256[256] =
|
|
|
|
{
|
|
|
|
0, 4, 2, 6, 1, 5, 3, 7, 8,12,10,14, 9,13,11,15,
|
|
|
|
0, 1, 1, 1, 9, 9, 2, 3, 3, 3, 3, 9, 2, 3, 3, 3,
|
|
|
|
3,11, 2, 3, 3, 3,11,11,10, 3, 3,11,11,11,10,10,
|
|
|
|
11,11,11,11, 4, 5, 5, 5, 5, 9, 6, 8, 8, 8, 8, 9,
|
|
|
|
6, 8, 8, 8, 8, 7, 6, 8, 8, 8, 7, 7, 6, 8, 8, 7,
|
|
|
|
7,11,10,10, 7, 7,11,11, 4, 5, 5, 5, 5,13, 6, 8,
|
|
|
|
8, 8, 8, 7, 6, 8, 8, 8, 7, 7, 6, 8, 8, 7, 7, 7,
|
|
|
|
6, 8, 7, 7, 7, 7,14, 7, 7, 7, 7, 7, 4, 5, 5, 5,
|
|
|
|
13,13, 6, 8, 8, 8, 7, 7, 6, 8, 8, 7, 7, 7, 6, 8,
|
|
|
|
7, 7, 7, 7,14, 7, 7, 7, 7, 7,14, 7, 7, 7, 7,15,
|
|
|
|
12, 5, 5,13,13,13, 6, 8, 8, 7, 7,13, 6, 8, 7, 7,
|
|
|
|
7, 7,14, 7, 7, 7, 7, 7,14, 7, 7, 7, 7,15,14,14,
|
|
|
|
7, 7,15,15,12,12,13,13,13,13,12,12, 7, 7,13,13,
|
|
|
|
14, 7, 7, 7, 7, 7,14, 7, 7, 7, 7,15,14,14, 7, 7,
|
|
|
|
15,15,14,14, 7,15,15,15, 0, 0, 0, 0, 0, 0, 8, 8,
|
|
|
|
8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7,15,15
|
|
|
|
};
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
void
|
2001-02-27 17:14:35 +08:00
|
|
|
fhandler_console::char_command (char c)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2014-02-16 09:48:25 +08:00
|
|
|
int x, y, n;
|
2000-02-18 03:38:33 +08:00
|
|
|
char buf[40];
|
2020-08-27 11:35:03 +08:00
|
|
|
wchar_t bufw[40];
|
2019-03-31 23:47:46 +08:00
|
|
|
int r, g, b;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2020-02-26 23:32:59 +08:00
|
|
|
if (wincap.has_con_24bit_colors () && !con_is_legacy)
|
|
|
|
{
|
|
|
|
/* For xterm compatible mode */
|
|
|
|
switch (c)
|
|
|
|
{
|
2020-02-26 23:33:01 +08:00
|
|
|
#if 0 /* These sequences, which are supported by real xterm, are
|
|
|
|
not supported by xterm compatible mode. Therefore they
|
|
|
|
were implemented once. However, these are not declared
|
|
|
|
in terminfo of xterm-256color, therefore, do not appear
|
|
|
|
to be necessary. */
|
|
|
|
case '`': /* HPA */
|
|
|
|
if (con.args[0] == 0)
|
|
|
|
con.args[0] = 1;
|
|
|
|
cursor_get (&x, &y);
|
|
|
|
cursor_set (false, con.args[0]-1, y);
|
|
|
|
break;
|
|
|
|
case 'a': /* HPR */
|
|
|
|
if (con.args[0] == 0)
|
|
|
|
con.args[0] = 1;
|
|
|
|
cursor_rel (con.args[0], 0);
|
|
|
|
break;
|
|
|
|
case 'e': /* VPR */
|
|
|
|
if (con.args[0] == 0)
|
|
|
|
con.args[0] = 1;
|
|
|
|
cursor_rel (0, con.args[0]);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case 'b': /* REP */
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (c);
|
2020-02-26 23:33:01 +08:00
|
|
|
if (wincap.has_con_esc_rep ())
|
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-08-27 11:35:03 +08:00
|
|
|
else if (last_char && last_char != L'\n')
|
2020-02-26 23:33:01 +08:00
|
|
|
for (int i = 0; i < con.args[0]; i++)
|
2020-08-27 11:35:03 +08:00
|
|
|
WriteConsoleW (get_output_handle (), &last_char, 1, 0, 0);
|
2020-02-26 23:33:01 +08:00
|
|
|
break;
|
2020-02-26 23:32:59 +08:00
|
|
|
case 'r': /* DECSTBM */
|
|
|
|
con.scroll_region.Top = con.args[0] ? con.args[0] - 1 : 0;
|
|
|
|
con.scroll_region.Bottom = con.args[1] ? con.args[1] - 1 : -1;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (c);
|
2020-02-26 23:32:59 +08:00
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-02-26 23:32:59 +08:00
|
|
|
break;
|
|
|
|
case 'L': /* IL */
|
|
|
|
if (wincap.has_con_broken_il_dl ())
|
|
|
|
{
|
|
|
|
/* Use "CSI Ps T" instead */
|
|
|
|
cursor_get (&x, &y);
|
2020-02-27 10:33:50 +08:00
|
|
|
if (y < srTop || y > srBottom)
|
|
|
|
break;
|
|
|
|
if (y == con.b.srWindow.Top
|
|
|
|
&& srBottom == con.b.srWindow.Bottom)
|
|
|
|
{
|
|
|
|
/* Erase scroll down area */
|
|
|
|
n = con.args[0] ? : 1;
|
2020-08-27 11:35:03 +08:00
|
|
|
__small_swprintf (bufw, L"\033[%d;1H\033[J\033[%d;%dH",
|
|
|
|
srBottom - (n-1) - con.b.srWindow.Top + 1,
|
|
|
|
y + 1 - con.b.srWindow.Top, x + 1);
|
|
|
|
WriteConsoleW (get_output_handle (),
|
|
|
|
bufw, wcslen (bufw), 0, 0);
|
2020-02-27 10:33:50 +08:00
|
|
|
}
|
2020-08-27 11:35:03 +08:00
|
|
|
__small_swprintf (bufw, L"\033[%d;%dr",
|
|
|
|
y + 1 - con.b.srWindow.Top,
|
|
|
|
srBottom + 1 - con.b.srWindow.Top);
|
|
|
|
WriteConsoleW (get_output_handle (), bufw, wcslen (bufw), 0, 0);
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put ('T');
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-08-27 11:35:03 +08:00
|
|
|
__small_swprintf (bufw, L"\033[%d;%dr",
|
|
|
|
srTop + 1 - con.b.srWindow.Top,
|
|
|
|
srBottom + 1 - con.b.srWindow.Top);
|
|
|
|
WriteConsoleW (get_output_handle (), bufw, wcslen (bufw), 0, 0);
|
|
|
|
__small_swprintf (bufw, L"\033[%d;%dH",
|
|
|
|
y + 1 - con.b.srWindow.Top, x + 1);
|
|
|
|
WriteConsoleW (get_output_handle (), bufw, wcslen (bufw), 0, 0);
|
2020-02-26 23:32:59 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (c);
|
2020-02-26 23:32:59 +08:00
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-02-26 23:32:59 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'M': /* DL */
|
|
|
|
if (wincap.has_con_broken_il_dl ())
|
|
|
|
{
|
|
|
|
/* Use "CSI Ps S" instead */
|
|
|
|
cursor_get (&x, &y);
|
2020-02-27 10:33:50 +08:00
|
|
|
if (y < srTop || y > srBottom)
|
|
|
|
break;
|
2020-08-27 11:35:03 +08:00
|
|
|
__small_swprintf (bufw, L"\033[%d;%dr",
|
|
|
|
y + 1 - con.b.srWindow.Top,
|
|
|
|
srBottom + 1 - con.b.srWindow.Top);
|
|
|
|
WriteConsoleW (get_output_handle (), bufw, wcslen (bufw), 0, 0);
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put ('S');
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-08-27 11:35:03 +08:00
|
|
|
__small_swprintf (bufw, L"\033[%d;%dr",
|
|
|
|
srTop + 1 - con.b.srWindow.Top,
|
|
|
|
srBottom + 1 - con.b.srWindow.Top);
|
|
|
|
WriteConsoleW (get_output_handle (), bufw, wcslen (bufw), 0, 0);
|
|
|
|
__small_swprintf (bufw, L"\033[%d;%dH",
|
|
|
|
y + 1 - con.b.srWindow.Top, x + 1);
|
|
|
|
WriteConsoleW (get_output_handle (), bufw, wcslen (bufw), 0, 0);
|
2020-02-26 23:32:59 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (c);
|
2020-02-26 23:32:59 +08:00
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-02-26 23:32:59 +08:00
|
|
|
}
|
|
|
|
break;
|
2020-02-26 23:33:00 +08:00
|
|
|
case 'J': /* ED */
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (c);
|
2020-03-09 09:38:36 +08:00
|
|
|
if (con.args[0] == 3 && con.savey >= 0)
|
|
|
|
{
|
|
|
|
con.fillin (get_output_handle ());
|
|
|
|
con.savey -= con.b.srWindow.Top;
|
|
|
|
}
|
2020-02-26 23:33:02 +08:00
|
|
|
if (con.args[0] == 3 && wincap.has_con_broken_csi3j ())
|
|
|
|
{ /* Workaround for broken CSI3J in Win10 1809 */
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
|
|
|
GetConsoleScreenBufferInfo (get_output_handle (), &sbi);
|
|
|
|
SMALL_RECT r = {0, sbi.srWindow.Top,
|
|
|
|
(SHORT) (sbi.dwSize.X - 1), (SHORT) (sbi.dwSize.Y - 1)};
|
|
|
|
CHAR_INFO f = {' ', sbi.wAttributes};
|
|
|
|
COORD d = {0, 0};
|
|
|
|
ScrollConsoleScreenBufferA (get_output_handle (),
|
|
|
|
&r, NULL, d, &f);
|
|
|
|
SetConsoleCursorPosition (get_output_handle (), d);
|
|
|
|
d = sbi.dwCursorPosition;
|
|
|
|
d.Y -= sbi.srWindow.Top;
|
|
|
|
SetConsoleCursorPosition (get_output_handle (), d);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-02-26 23:33:00 +08:00
|
|
|
break;
|
|
|
|
case 'h': /* DECSET */
|
|
|
|
case 'l': /* DECRST */
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (c);
|
2020-02-26 23:33:00 +08:00
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-02-26 23:33:00 +08:00
|
|
|
if (con.saw_question_mark)
|
|
|
|
{
|
|
|
|
bool need_fix_tab_position = false;
|
|
|
|
for (int i = 0; i < con.nargs; i++)
|
2020-05-30 17:25:03 +08:00
|
|
|
{
|
|
|
|
if (con.args[i] == 1049)
|
|
|
|
{
|
|
|
|
con.screen_alternated = (c == 'h');
|
|
|
|
need_fix_tab_position = true;
|
|
|
|
}
|
|
|
|
if (con.args[i] == 1) /* DECCKM */
|
|
|
|
con.cursor_key_app_mode = (c == 'h');
|
|
|
|
}
|
2020-02-26 23:33:00 +08:00
|
|
|
/* Call fix_tab_position() if screen has been alternated. */
|
|
|
|
if (need_fix_tab_position)
|
|
|
|
fix_tab_position ();
|
|
|
|
}
|
|
|
|
break;
|
2020-02-27 10:33:50 +08:00
|
|
|
case 'p':
|
|
|
|
if (con.saw_exclamation_mark) /* DECSTR Soft reset */
|
|
|
|
{
|
|
|
|
con.scroll_region.Top = 0;
|
|
|
|
con.scroll_region.Bottom = -1;
|
2020-03-09 09:38:36 +08:00
|
|
|
con.savex = con.savey = -1;
|
2020-05-30 17:25:03 +08:00
|
|
|
con.cursor_key_app_mode = false;
|
2020-02-27 10:33:50 +08:00
|
|
|
}
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (c);
|
2020-02-27 10:33:50 +08:00
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-02-27 10:33:50 +08:00
|
|
|
break;
|
2020-05-31 13:53:18 +08:00
|
|
|
case 'm':
|
|
|
|
if (con.saw_greater_than_sign)
|
|
|
|
break; /* Ignore unsupported CSI > Pm m */
|
|
|
|
/* Text attribute settings */
|
|
|
|
wpbuf.put (c);
|
|
|
|
/* Just send the sequence */
|
|
|
|
wpbuf.send (get_output_handle ());
|
|
|
|
break;
|
2020-02-26 23:32:59 +08:00
|
|
|
default:
|
|
|
|
/* Other escape sequences */
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (c);
|
2020-02-26 23:32:59 +08:00
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-02-26 23:32:59 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For legacy cygwin treminal */
|
2000-02-18 03:38:33 +08:00
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case 'm': /* Set Graphics Rendition */
|
2020-02-01 12:28:39 +08:00
|
|
|
for (int i = 0; i < con.nargs; i++)
|
2014-03-10 06:49:56 +08:00
|
|
|
switch (con.args[i])
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
case 0: /* normal color */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.set_default_attr ();
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 1: /* bold */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.intensity = INTENSITY_BOLD;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
2009-12-15 20:46:40 +08:00
|
|
|
case 2: /* dim */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.intensity = INTENSITY_DIM;
|
2009-12-15 20:46:40 +08:00
|
|
|
break;
|
|
|
|
case 4: /* underlined */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.underline = 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 5: /* blink mode */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.blink = true;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 7: /* reverse */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.reverse = true;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 8: /* invisible */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.intensity = INTENSITY_INVISIBLE;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
2004-05-29 03:50:07 +08:00
|
|
|
case 10: /* end alternate charset */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.alternate_charset_active = false;
|
2003-10-15 16:23:26 +08:00
|
|
|
break;
|
2004-05-29 03:50:07 +08:00
|
|
|
case 11: /* start alternate charset */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.alternate_charset_active = true;
|
2003-10-15 16:23:26 +08:00
|
|
|
break;
|
2009-12-15 20:46:40 +08:00
|
|
|
case 22:
|
|
|
|
case 28:
|
2014-03-10 06:49:56 +08:00
|
|
|
con.intensity = INTENSITY_NORMAL;
|
2009-12-15 20:46:40 +08:00
|
|
|
break;
|
2001-03-03 11:56:34 +08:00
|
|
|
case 24:
|
2014-03-10 06:49:56 +08:00
|
|
|
con.underline = false;
|
2001-03-03 11:56:34 +08:00
|
|
|
break;
|
2009-12-15 20:46:40 +08:00
|
|
|
case 25:
|
2014-03-10 06:49:56 +08:00
|
|
|
con.blink = false;
|
2009-12-15 20:46:40 +08:00
|
|
|
break;
|
2001-03-03 11:56:34 +08:00
|
|
|
case 27:
|
2014-03-10 06:49:56 +08:00
|
|
|
con.reverse = false;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 30: /* BLACK foreground */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fg = 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 31: /* RED foreground */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fg = FOREGROUND_RED;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 32: /* GREEN foreground */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fg = FOREGROUND_GREEN;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 33: /* YELLOW foreground */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fg = FOREGROUND_RED | FOREGROUND_GREEN;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 34: /* BLUE foreground */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fg = FOREGROUND_BLUE;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 35: /* MAGENTA foreground */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fg = FOREGROUND_RED | FOREGROUND_BLUE;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 36: /* CYAN foreground */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fg = FOREGROUND_BLUE | FOREGROUND_GREEN;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 37: /* WHITE foreg */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fg = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
2019-03-31 23:47:46 +08:00
|
|
|
case 38:
|
2020-02-01 12:28:39 +08:00
|
|
|
if (con.nargs < i + 2)
|
2019-03-31 23:47:46 +08:00
|
|
|
/* Sequence error (abort) */
|
|
|
|
break;
|
2020-02-01 12:28:39 +08:00
|
|
|
switch (con.args[i + 1])
|
2019-03-31 23:47:46 +08:00
|
|
|
{
|
|
|
|
case 2:
|
2020-02-01 12:28:39 +08:00
|
|
|
if (con.nargs < i + 5)
|
2019-03-31 23:47:46 +08:00
|
|
|
/* Sequence error (abort) */
|
|
|
|
break;
|
2020-02-01 12:28:39 +08:00
|
|
|
r = con.args[i + 2];
|
|
|
|
g = con.args[i + 3];
|
|
|
|
b = con.args[i + 4];
|
2019-03-31 23:47:46 +08:00
|
|
|
r = r < (95 + 1) / 2 ? 0 : r > 255 ? 5 : (r - 55 + 20) / 40;
|
|
|
|
g = g < (95 + 1) / 2 ? 0 : g > 255 ? 5 : (g - 55 + 20) / 40;
|
|
|
|
b = b < (95 + 1) / 2 ? 0 : b > 255 ? 5 : (b - 55 + 20) / 40;
|
|
|
|
con.fg = table256[16 + r*36 + g*6 + b];
|
2020-02-01 12:28:39 +08:00
|
|
|
i += 4;
|
2019-03-31 23:47:46 +08:00
|
|
|
break;
|
|
|
|
case 5:
|
2020-02-01 12:28:39 +08:00
|
|
|
if (con.nargs < i + 3)
|
2019-03-31 23:47:46 +08:00
|
|
|
/* Sequence error (abort) */
|
|
|
|
break;
|
|
|
|
{
|
2020-02-01 12:28:39 +08:00
|
|
|
int idx = con.args[i + 2];
|
2019-03-31 23:47:46 +08:00
|
|
|
if (idx < 0)
|
|
|
|
idx = 0;
|
|
|
|
if (idx > 255)
|
|
|
|
idx = 255;
|
|
|
|
con.fg = table256[idx];
|
2020-02-01 12:28:39 +08:00
|
|
|
i += 2;
|
2019-03-31 23:47:46 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2001-03-03 11:56:34 +08:00
|
|
|
case 39:
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fg = con.default_color & FOREGROUND_ATTR_MASK;
|
2001-03-03 11:56:34 +08:00
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
case 40: /* BLACK background */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.bg = 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 41: /* RED background */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.bg = BACKGROUND_RED;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 42: /* GREEN background */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.bg = BACKGROUND_GREEN;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 43: /* YELLOW background */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.bg = BACKGROUND_RED | BACKGROUND_GREEN;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 44: /* BLUE background */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.bg = BACKGROUND_BLUE;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 45: /* MAGENTA background */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.bg = BACKGROUND_RED | BACKGROUND_BLUE;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 46: /* CYAN background */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.bg = BACKGROUND_BLUE | BACKGROUND_GREEN;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 47: /* WHITE background */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
2019-03-31 23:47:46 +08:00
|
|
|
case 48:
|
2020-02-01 12:28:39 +08:00
|
|
|
if (con.nargs < i + 2)
|
2019-03-31 23:47:46 +08:00
|
|
|
/* Sequence error (abort) */
|
|
|
|
break;
|
2020-02-01 12:28:39 +08:00
|
|
|
switch (con.args[i + 1])
|
2019-03-31 23:47:46 +08:00
|
|
|
{
|
|
|
|
case 2:
|
2020-02-01 12:28:39 +08:00
|
|
|
if (con.nargs < i + 5)
|
2019-03-31 23:47:46 +08:00
|
|
|
/* Sequence error (abort) */
|
|
|
|
break;
|
2020-02-01 12:28:39 +08:00
|
|
|
r = con.args[i + 2];
|
|
|
|
g = con.args[i + 3];
|
|
|
|
b = con.args[i + 4];
|
2019-03-31 23:47:46 +08:00
|
|
|
r = r < (95 + 1) / 2 ? 0 : r > 255 ? 5 : (r - 55 + 20) / 40;
|
|
|
|
g = g < (95 + 1) / 2 ? 0 : g > 255 ? 5 : (g - 55 + 20) / 40;
|
|
|
|
b = b < (95 + 1) / 2 ? 0 : b > 255 ? 5 : (b - 55 + 20) / 40;
|
|
|
|
con.bg = table256[16 + r*36 + g*6 + b] << 4;
|
2020-02-01 12:28:39 +08:00
|
|
|
i += 4;
|
2019-03-31 23:47:46 +08:00
|
|
|
break;
|
|
|
|
case 5:
|
2020-02-01 12:28:39 +08:00
|
|
|
if (con.nargs < i + 3)
|
2019-03-31 23:47:46 +08:00
|
|
|
/* Sequence error (abort) */
|
|
|
|
break;
|
|
|
|
{
|
2020-02-01 12:28:39 +08:00
|
|
|
int idx = con.args[i + 2];
|
2019-03-31 23:47:46 +08:00
|
|
|
if (idx < 0)
|
|
|
|
idx = 0;
|
|
|
|
if (idx > 255)
|
|
|
|
idx = 255;
|
|
|
|
con.bg = table256[idx] << 4;
|
2020-02-01 12:28:39 +08:00
|
|
|
i += 2;
|
2019-03-31 23:47:46 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2001-03-03 11:56:34 +08:00
|
|
|
case 49:
|
2014-03-10 06:49:56 +08:00
|
|
|
con.bg = con.default_color & BACKGROUND_ATTR_MASK;
|
2001-03-03 11:56:34 +08:00
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2014-03-10 06:49:56 +08:00
|
|
|
con.set_color (get_output_handle ());
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
2013-01-11 19:04:50 +08:00
|
|
|
case 'q': /* Set cursor style (DECSCUSR) */
|
2014-03-10 06:49:56 +08:00
|
|
|
if (con.saw_space)
|
2013-01-11 19:04:50 +08:00
|
|
|
{
|
|
|
|
CONSOLE_CURSOR_INFO console_cursor_info;
|
2014-05-09 22:28:48 +08:00
|
|
|
GetConsoleCursorInfo (get_output_handle (), &console_cursor_info);
|
2014-03-10 06:49:56 +08:00
|
|
|
switch (con.args[0])
|
2013-01-11 19:04:50 +08:00
|
|
|
{
|
|
|
|
case 0: /* blinking block */
|
|
|
|
case 1: /* blinking block (default) */
|
|
|
|
case 2: /* steady block */
|
|
|
|
console_cursor_info.dwSize = 100;
|
2019-03-31 23:47:47 +08:00
|
|
|
SetConsoleCursorInfo (get_output_handle (),
|
|
|
|
&console_cursor_info);
|
2013-01-11 19:04:50 +08:00
|
|
|
break;
|
|
|
|
case 3: /* blinking underline */
|
|
|
|
case 4: /* steady underline */
|
2019-03-31 23:47:47 +08:00
|
|
|
console_cursor_info.dwSize = 10; /* or Windows default 25? */
|
|
|
|
SetConsoleCursorInfo (get_output_handle (),
|
|
|
|
&console_cursor_info);
|
2013-01-11 19:04:50 +08:00
|
|
|
break;
|
|
|
|
default: /* use value as percentage */
|
2014-03-10 06:49:56 +08:00
|
|
|
console_cursor_info.dwSize = con.args[0];
|
2019-03-31 23:47:47 +08:00
|
|
|
SetConsoleCursorInfo (get_output_handle (),
|
|
|
|
&console_cursor_info);
|
2013-01-11 19:04:50 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
case 'h':
|
|
|
|
case 'l':
|
2014-03-10 06:49:56 +08:00
|
|
|
if (!con.saw_question_mark)
|
2001-04-09 08:44:25 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
switch (con.args[0])
|
2001-03-31 17:19:32 +08:00
|
|
|
{
|
|
|
|
case 4: /* Insert mode */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.insert_mode = (c == 'h') ? true : false;
|
2019-03-31 23:47:47 +08:00
|
|
|
syscall_printf ("insert mode %sabled",
|
|
|
|
con.insert_mode ? "en" : "dis");
|
2001-03-31 17:19:32 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2014-03-10 06:49:56 +08:00
|
|
|
switch (con.args[0])
|
2000-12-16 11:11:02 +08:00
|
|
|
{
|
2013-01-11 19:04:50 +08:00
|
|
|
case 25: /* Show/Hide Cursor (DECTCEM) */
|
|
|
|
{
|
|
|
|
CONSOLE_CURSOR_INFO console_cursor_info;
|
|
|
|
GetConsoleCursorInfo (get_output_handle (), & console_cursor_info);
|
|
|
|
if (c == 'h')
|
|
|
|
console_cursor_info.bVisible = TRUE;
|
|
|
|
else
|
|
|
|
console_cursor_info.bVisible = FALSE;
|
|
|
|
SetConsoleCursorInfo (get_output_handle (), & console_cursor_info);
|
|
|
|
break;
|
|
|
|
}
|
2001-03-30 19:10:13 +08:00
|
|
|
case 47: /* Save/Restore screen */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.save_restore (get_output_handle (), c);
|
2001-03-30 19:10:13 +08:00
|
|
|
break;
|
|
|
|
|
2010-04-12 03:11:17 +08:00
|
|
|
case 67: /* DECBKM ("DEC Backarrow Key Mode") */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.backspace_keycode = (c == 'h' ? CTRL('H') : CERASE);
|
2010-04-12 03:11:17 +08:00
|
|
|
break;
|
|
|
|
|
2009-12-16 22:56:10 +08:00
|
|
|
case 1000: /* Mouse tracking */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.use_mouse = (c == 'h') ? 1 : 0;
|
2009-12-16 22:56:10 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 1002: /* Mouse button event tracking */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.use_mouse = (c == 'h') ? 2 : 0;
|
2009-12-16 22:56:10 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 1003: /* Mouse any event tracking */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.use_mouse = (c == 'h') ? 3 : 0;
|
2009-12-16 22:56:10 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 1004: /* Focus in/out event reporting */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.use_focus = (c == 'h') ? true : false;
|
2012-04-24 22:29:37 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 1005: /* Extended mouse mode */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.ext_mouse_mode5 = c == 'h';
|
2012-04-24 22:29:37 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 1006: /* SGR extended mouse mode */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.ext_mouse_mode6 = c == 'h';
|
2012-04-24 22:29:37 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 1015: /* Urxvt extended mouse mode */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.ext_mouse_mode15 = c == 'h';
|
2000-12-16 11:11:02 +08:00
|
|
|
break;
|
|
|
|
|
2001-03-03 11:56:34 +08:00
|
|
|
case 2000: /* Raw keyboard mode */
|
2003-12-08 06:37:12 +08:00
|
|
|
set_raw_win32_keyboard_mode ((c == 'h') ? true : false);
|
2001-03-03 11:56:34 +08:00
|
|
|
break;
|
|
|
|
|
2000-12-16 11:11:02 +08:00
|
|
|
default: /* Ignore */
|
2014-03-10 06:49:56 +08:00
|
|
|
syscall_printf ("unknown h/l command: %d", con.args[0]);
|
2000-12-16 11:11:02 +08:00
|
|
|
break;
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'J':
|
2014-03-10 06:49:56 +08:00
|
|
|
switch (con.args[0])
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
case 0: /* Clear to end of screen */
|
2014-01-05 07:58:32 +08:00
|
|
|
clear_screen (cl_curr_pos, cl_curr_pos, cl_disp_end, cl_disp_end);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 1: /* Clear from beginning of screen to cursor */
|
2014-01-05 07:58:32 +08:00
|
|
|
clear_screen (cl_disp_beg, cl_disp_beg, cl_curr_pos, cl_curr_pos);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 2: /* Clear screen */
|
2014-02-16 09:48:25 +08:00
|
|
|
cursor_get (&x, &y);
|
2014-01-05 07:58:32 +08:00
|
|
|
clear_screen (cl_disp_beg, cl_disp_beg, cl_disp_end, cl_disp_end);
|
2014-02-16 09:48:25 +08:00
|
|
|
cursor_set (false, x, y);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto bad_escape;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'A':
|
2014-03-10 06:49:56 +08:00
|
|
|
cursor_rel (0, -(con.args[0] ?: 1));
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'B':
|
2014-03-10 06:49:56 +08:00
|
|
|
cursor_rel (0, con.args[0] ?: 1);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'C':
|
2014-03-10 06:49:56 +08:00
|
|
|
cursor_rel (con.args[0] ?: 1, 0);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'D':
|
2014-03-10 06:49:56 +08:00
|
|
|
cursor_rel (-(con.args[0] ?: 1),0);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'K':
|
2014-03-10 06:49:56 +08:00
|
|
|
switch (con.args[0])
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
case 0: /* Clear to end of line */
|
2014-01-05 07:58:32 +08:00
|
|
|
clear_screen (cl_curr_pos, cl_curr_pos, cl_disp_end, cl_curr_pos);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 2: /* Clear line */
|
2014-01-05 07:58:32 +08:00
|
|
|
clear_screen (cl_disp_beg, cl_curr_pos, cl_disp_end, cl_curr_pos);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 1: /* Clear from bol to cursor */
|
2014-01-05 07:58:32 +08:00
|
|
|
clear_screen (cl_disp_beg, cl_curr_pos, cl_curr_pos, cl_curr_pos);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto bad_escape;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'H':
|
|
|
|
case 'f':
|
2014-03-10 06:49:56 +08:00
|
|
|
cursor_set (true, (con.args[1] ?: 1) - 1,
|
|
|
|
(con.args[0] ?: 1) - 1);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'G': /* hpa - position cursor at column n - 1 */
|
|
|
|
cursor_get (&x, &y);
|
2014-03-10 06:49:56 +08:00
|
|
|
cursor_set (false, (con.args[0] ? con.args[0] - 1 : 0), y);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'd': /* vpa - position cursor at line n */
|
|
|
|
cursor_get (&x, &y);
|
2014-03-10 06:49:56 +08:00
|
|
|
cursor_set (true, x, (con.args[0] ? con.args[0] - 1 : 0));
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 's': /* Save cursor position */
|
2014-03-10 06:49:56 +08:00
|
|
|
cursor_get (&con.savex, &con.savey);
|
|
|
|
con.savey -= con.b.srWindow.Top;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'u': /* Restore cursor position */
|
2014-03-10 06:49:56 +08:00
|
|
|
cursor_set (true, con.savex, con.savey);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'I': /* TAB */
|
|
|
|
cursor_get (&x, &y);
|
2003-12-08 06:37:12 +08:00
|
|
|
cursor_set (false, 8 * (x / 8 + 1), y);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'L': /* AL - insert blank lines */
|
2014-03-10 06:49:56 +08:00
|
|
|
n = con.args[0] ?: 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
cursor_get (&x, &y);
|
2014-02-16 09:48:25 +08:00
|
|
|
scroll_buffer (0, y, -1, -1, 0, y + n);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'M': /* DL - delete lines */
|
2014-03-10 06:49:56 +08:00
|
|
|
n = con.args[0] ?: 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
cursor_get (&x, &y);
|
2014-03-10 02:46:30 +08:00
|
|
|
scroll_buffer (0, y + n, -1, -1, 0, y);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case '@': /* IC - insert chars */
|
2014-03-10 06:49:56 +08:00
|
|
|
n = con.args[0] ?: 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
cursor_get (&x, &y);
|
2014-02-16 09:48:25 +08:00
|
|
|
scroll_buffer (x, y, -1, y, x + n, y);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'P': /* DC - delete chars */
|
2014-03-10 06:49:56 +08:00
|
|
|
n = con.args[0] ?: 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
cursor_get (&x, &y);
|
2014-02-16 09:48:25 +08:00
|
|
|
scroll_buffer (x + n, y, -1, y, x, y);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'S': /* SF - Scroll forward */
|
2014-03-10 06:49:56 +08:00
|
|
|
n = con.args[0] ?: 1;
|
2014-02-26 11:58:37 +08:00
|
|
|
scroll_buffer_screen (0, n, -1, -1, 0, 0);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'T': /* SR - Scroll down */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fillin (get_output_handle ());
|
|
|
|
n = con.b.srWindow.Top + con.args[0] ?: 1;
|
2014-02-26 11:58:37 +08:00
|
|
|
scroll_buffer_screen (0, 0, -1, -1, 0, n);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'X': /* ec - erase chars */
|
2014-03-10 06:49:56 +08:00
|
|
|
n = con.args[0] ?: 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
cursor_get (&x, &y);
|
2014-02-16 09:48:25 +08:00
|
|
|
scroll_buffer (x + n, y, -1, y, x, y);
|
|
|
|
scroll_buffer (x, y, -1, y, x + n, y);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'Z': /* Back tab */
|
|
|
|
cursor_get (&x, &y);
|
2003-12-08 06:37:12 +08:00
|
|
|
cursor_set (false, ((8 * (x / 8 + 1)) - 8), y);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'b': /* Repeat char #1 #2 times */
|
2014-03-10 06:49:56 +08:00
|
|
|
if (con.insert_mode)
|
2001-03-31 17:19:32 +08:00
|
|
|
{
|
2001-04-09 08:44:25 +08:00
|
|
|
cursor_get (&x, &y);
|
2014-03-10 06:49:56 +08:00
|
|
|
scroll_buffer (x, y, -1, y, x + con.args[1], y);
|
2001-03-31 17:19:32 +08:00
|
|
|
}
|
2014-03-10 06:49:56 +08:00
|
|
|
while (con.args[1]--)
|
|
|
|
WriteFile (get_output_handle (), &con.args[0], 1, (DWORD *) &x, 0);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'c': /* u9 - Terminal enquire string */
|
2014-03-10 06:49:56 +08:00
|
|
|
if (con.saw_greater_than_sign)
|
2011-06-06 13:02:13 +08:00
|
|
|
/* Generate Secondary Device Attribute report, using 67 = ASCII 'C'
|
|
|
|
to indicate Cygwin (convention used by Rxvt, Urxvt, Screen, Mintty),
|
2009-12-19 23:37:10 +08:00
|
|
|
and cygwin version for terminal version. */
|
2019-03-31 23:47:47 +08:00
|
|
|
__small_sprintf (buf, "\033[>67;%d%02d;0c",
|
|
|
|
CYGWIN_VERSION_DLL_MAJOR, CYGWIN_VERSION_DLL_MINOR);
|
2009-12-19 23:37:10 +08:00
|
|
|
else
|
|
|
|
strcpy (buf, "\033[?6c");
|
2011-06-06 13:02:13 +08:00
|
|
|
/* The generated report needs to be injected for read-ahead into the
|
|
|
|
fhandler_console object associated with standard input.
|
2016-03-16 17:25:16 +08:00
|
|
|
So puts_readahead does not work.
|
|
|
|
Use a common console read-ahead buffer instead. */
|
2019-03-31 23:47:48 +08:00
|
|
|
acquire_input_mutex (INFINITE);
|
2016-03-16 17:25:16 +08:00
|
|
|
con.cons_rapoi = NULL;
|
|
|
|
strcpy (con.cons_rabuf, buf);
|
|
|
|
con.cons_rapoi = con.cons_rabuf;
|
2019-03-31 23:47:48 +08:00
|
|
|
release_input_mutex ();
|
2019-03-31 23:47:47 +08:00
|
|
|
/* Wake up read() or select() by sending a message
|
|
|
|
which has no effect */
|
|
|
|
PostMessageW (GetConsoleWindow (), WM_SETFOCUS, 0, 0);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'n':
|
2014-03-10 06:49:56 +08:00
|
|
|
switch (con.args[0])
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
case 6: /* u7 - Cursor position request */
|
|
|
|
cursor_get (&x, &y);
|
2014-03-10 06:49:56 +08:00
|
|
|
y -= con.b.srWindow.Top;
|
|
|
|
/* x -= con.b.srWindow.Left; // not available yet */
|
2000-02-18 03:38:33 +08:00
|
|
|
__small_sprintf (buf, "\033[%d;%dR", y + 1, x + 1);
|
2019-03-31 23:47:48 +08:00
|
|
|
acquire_input_mutex (INFINITE);
|
2016-03-16 17:25:16 +08:00
|
|
|
con.cons_rapoi = NULL;
|
|
|
|
strcpy (con.cons_rabuf, buf);
|
|
|
|
con.cons_rapoi = con.cons_rabuf;
|
2019-03-31 23:47:48 +08:00
|
|
|
release_input_mutex ();
|
2019-03-31 23:47:47 +08:00
|
|
|
/* Wake up read() or select() by sending a message
|
|
|
|
which has no effect */
|
|
|
|
PostMessageW (GetConsoleWindow (), WM_SETFOCUS, 0, 0);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
2016-03-16 17:25:16 +08:00
|
|
|
default:
|
2000-02-18 03:38:33 +08:00
|
|
|
goto bad_escape;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'r': /* Set Scroll region */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.scroll_region.Top = con.args[0] ? con.args[0] - 1 : 0;
|
|
|
|
con.scroll_region.Bottom = con.args[1] ? con.args[1] - 1 : -1;
|
2003-12-08 06:37:12 +08:00
|
|
|
cursor_set (true, 0, 0);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case 'g': /* TAB set/clear */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
bad_escape:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-06 05:39:25 +08:00
|
|
|
#define NUM_REPLACEMENT_CHARS 3
|
|
|
|
|
|
|
|
static const wchar_t replacement_char[NUM_REPLACEMENT_CHARS] =
|
|
|
|
{
|
|
|
|
0xfffd, /* REPLACEMENT CHARACTER */
|
|
|
|
0x25a1, /* WHITE SQUARE */
|
|
|
|
0x2592 /* MEDIUM SHADE */
|
|
|
|
};
|
|
|
|
/* nFont member is always 0 so we have to use the facename. */
|
|
|
|
static WCHAR cons_facename[LF_FACESIZE];
|
2018-09-07 19:48:35 +08:00
|
|
|
static WCHAR rp_char;
|
2018-09-06 19:05:55 +08:00
|
|
|
static NO_COPY HDC cdc;
|
2018-09-06 05:39:25 +08:00
|
|
|
|
|
|
|
static int CALLBACK
|
|
|
|
enum_proc (const LOGFONTW *lf, const TEXTMETRICW *tm,
|
|
|
|
DWORD FontType, LPARAM lParam)
|
|
|
|
{
|
|
|
|
int *done = (int *) lParam;
|
|
|
|
*done = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
check_font (HANDLE hdl)
|
|
|
|
{
|
|
|
|
CONSOLE_FONT_INFOEX cfi;
|
|
|
|
LOGFONTW lf;
|
|
|
|
|
|
|
|
cfi.cbSize = sizeof cfi;
|
|
|
|
if (!GetCurrentConsoleFontEx (hdl, 0, &cfi))
|
|
|
|
return;
|
|
|
|
/* Switched font? */
|
|
|
|
if (wcscmp (cons_facename, cfi.FaceName) == 0)
|
|
|
|
return;
|
|
|
|
if (!cdc && !(cdc = GetDC (GetConsoleWindow ())))
|
|
|
|
return;
|
|
|
|
/* Some FaceNames like DejaVu Sans Mono are sometimes returned with stray
|
|
|
|
trailing chars. Fix it. */
|
2018-09-07 19:43:48 +08:00
|
|
|
lf.lfCharSet = DEFAULT_CHARSET;
|
2018-09-06 05:39:25 +08:00
|
|
|
lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
|
|
|
|
wchar_t *cp = wcpcpy (lf.lfFaceName, cfi.FaceName) - 1;
|
|
|
|
int done = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
EnumFontFamiliesExW (cdc, &lf, enum_proc, (LPARAM) &done, 0);
|
2018-09-07 19:49:54 +08:00
|
|
|
if (!done)
|
2018-09-06 05:39:25 +08:00
|
|
|
*cp-- = L'\0';
|
|
|
|
}
|
2018-09-07 19:49:54 +08:00
|
|
|
while (!done && cp >= lf.lfFaceName);
|
|
|
|
/* What, really? No recognizable font? */
|
|
|
|
if (!done)
|
|
|
|
{
|
|
|
|
rp_char = L'?';
|
|
|
|
return;
|
|
|
|
}
|
2018-09-06 05:39:25 +08:00
|
|
|
/* Yes. Check for the best replacement char. */
|
|
|
|
HFONT f = CreateFontW (0, 0, 0, 0,
|
|
|
|
cfi.FontWeight, FALSE, FALSE, FALSE,
|
2018-09-07 19:43:48 +08:00
|
|
|
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
|
2018-09-06 05:39:25 +08:00
|
|
|
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
|
|
|
|
FIXED_PITCH | FF_DONTCARE, lf.lfFaceName);
|
|
|
|
if (!f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
HFONT old_f = (HFONT) SelectObject(cdc, f);
|
|
|
|
if (old_f)
|
|
|
|
{
|
|
|
|
WORD glyph_idx[NUM_REPLACEMENT_CHARS];
|
|
|
|
|
|
|
|
if (GetGlyphIndicesW (cdc, replacement_char,
|
|
|
|
NUM_REPLACEMENT_CHARS, glyph_idx,
|
|
|
|
GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_REPLACEMENT_CHARS; ++i)
|
|
|
|
if (glyph_idx[i] != 0xffff)
|
|
|
|
break;
|
|
|
|
if (i == NUM_REPLACEMENT_CHARS)
|
|
|
|
i = 0;
|
2018-09-07 19:48:35 +08:00
|
|
|
rp_char = replacement_char[i];
|
2018-09-06 05:39:25 +08:00
|
|
|
/* Note that we copy the original name returned by
|
|
|
|
GetCurrentConsoleFontEx, even if it was broken.
|
|
|
|
This allows an early return, rather than to store
|
|
|
|
the fixed name and then having to enum font families
|
|
|
|
all over again. */
|
|
|
|
wcscpy (cons_facename, cfi.FaceName);
|
|
|
|
}
|
|
|
|
SelectObject (cdc, old_f);
|
|
|
|
}
|
|
|
|
DeleteObject (f);
|
|
|
|
}
|
|
|
|
|
2018-09-02 03:34:34 +08:00
|
|
|
/* This gets called when we found an invalid input character.
|
2018-09-06 05:39:25 +08:00
|
|
|
Print one of the above Unicode chars as replacement char. */
|
2009-05-04 11:51:16 +08:00
|
|
|
inline void
|
2009-03-24 20:18:34 +08:00
|
|
|
fhandler_console::write_replacement_char ()
|
2008-02-07 02:24:50 +08:00
|
|
|
{
|
2018-09-06 05:39:25 +08:00
|
|
|
check_font (get_output_handle ());
|
|
|
|
|
2008-02-07 02:24:50 +08:00
|
|
|
DWORD done;
|
2018-09-07 19:48:35 +08:00
|
|
|
WriteConsoleW (get_output_handle (), &rp_char, 1, &done, 0);
|
2008-02-07 02:24:50 +08:00
|
|
|
}
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
const unsigned char *
|
|
|
|
fhandler_console::write_normal (const unsigned char *src,
|
|
|
|
const unsigned char *end)
|
|
|
|
{
|
|
|
|
/* Scan forward to see what a char which needs special treatment */
|
|
|
|
DWORD done;
|
2008-02-07 02:24:50 +08:00
|
|
|
DWORD buf_len;
|
|
|
|
const unsigned char *found = src;
|
2020-09-19 22:55:09 +08:00
|
|
|
int ret;
|
2009-03-24 20:18:34 +08:00
|
|
|
mbstate_t ps;
|
2009-04-07 20:13:37 +08:00
|
|
|
mbtowc_p f_mbtowc;
|
2009-03-24 20:18:34 +08:00
|
|
|
|
2016-07-21 04:05:59 +08:00
|
|
|
/* The alternate charset is always 437, just as in the Linux console. */
|
|
|
|
f_mbtowc = con.get_console_cp () ? __cp_mbtowc (437) : __MBTOWC;
|
2016-10-19 18:48:40 +08:00
|
|
|
if (f_mbtowc == __ascii_mbtowc)
|
|
|
|
f_mbtowc = __utf8_mbtowc;
|
2008-02-07 02:24:50 +08:00
|
|
|
|
2008-02-16 01:53:11 +08:00
|
|
|
/* First check if we have cached lead bytes of a former try to write
|
2008-02-07 02:24:50 +08:00
|
|
|
a truncated multibyte sequence. If so, process it. */
|
|
|
|
if (trunc_buf.len)
|
|
|
|
{
|
2009-03-24 20:18:34 +08:00
|
|
|
const unsigned char *nfound;
|
2012-03-08 17:36:11 +08:00
|
|
|
int cp_len = MIN (end - src, 4 - trunc_buf.len);
|
2008-02-07 02:24:50 +08:00
|
|
|
memcpy (trunc_buf.buf + trunc_buf.len, src, cp_len);
|
2009-03-24 20:18:34 +08:00
|
|
|
memset (&ps, 0, sizeof ps);
|
|
|
|
switch (ret = f_mbtowc (_REENT, NULL, (const char *) trunc_buf.buf,
|
2016-07-21 04:05:59 +08:00
|
|
|
trunc_buf.len + cp_len, &ps))
|
2008-03-11 00:22:38 +08:00
|
|
|
{
|
2009-03-24 20:18:34 +08:00
|
|
|
case -2:
|
|
|
|
/* Still truncated multibyte sequence? Keep in trunc_buf. */
|
2008-02-07 02:24:50 +08:00
|
|
|
trunc_buf.len += cp_len;
|
|
|
|
return end;
|
2009-03-24 20:18:34 +08:00
|
|
|
case -1:
|
|
|
|
/* Give up, print replacement chars for trunc_buf... */
|
|
|
|
for (int i = 0; i < trunc_buf.len; ++i)
|
|
|
|
write_replacement_char ();
|
|
|
|
/* ... mark trunc_buf as unused... */
|
|
|
|
trunc_buf.len = 0;
|
|
|
|
/* ... and proceed. */
|
|
|
|
nfound = NULL;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
nfound = trunc_buf.buf + 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
nfound = trunc_buf.buf + ret;
|
|
|
|
break;
|
2008-02-07 02:24:50 +08:00
|
|
|
}
|
2008-03-11 00:22:38 +08:00
|
|
|
/* Valid multibyte sequence? Process. */
|
|
|
|
if (nfound)
|
2008-02-07 02:24:50 +08:00
|
|
|
{
|
2016-07-21 04:05:59 +08:00
|
|
|
buf_len = con.str_to_con (f_mbtowc, write_buf,
|
|
|
|
(const char *) trunc_buf.buf,
|
|
|
|
nfound - trunc_buf.buf);
|
2009-05-04 11:51:16 +08:00
|
|
|
if (!write_console (write_buf, buf_len, done))
|
|
|
|
{
|
2019-03-31 23:47:47 +08:00
|
|
|
debug_printf ("multibyte sequence write failed, handle %p",
|
|
|
|
get_output_handle ());
|
2009-05-04 11:51:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2008-02-07 02:24:50 +08:00
|
|
|
found = src + (nfound - trunc_buf.buf - trunc_buf.len);
|
2008-03-11 00:22:38 +08:00
|
|
|
trunc_buf.len = 0;
|
|
|
|
return found;
|
2008-02-07 02:24:50 +08:00
|
|
|
}
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2011-02-07 19:18:19 +08:00
|
|
|
/* Loop over src buffer as long as we have just simple characters. Stop
|
|
|
|
as soon as we reach the conversion limit, or if we encounter a control
|
|
|
|
character or a truncated or invalid mutibyte sequence. */
|
2019-03-31 23:47:46 +08:00
|
|
|
/* If system has 24 bit color capability, just write all control
|
|
|
|
sequences to console since xterm compatible mode is enabled. */
|
2009-03-24 20:18:34 +08:00
|
|
|
memset (&ps, 0, sizeof ps);
|
2008-02-06 01:37:10 +08:00
|
|
|
while (found < end
|
|
|
|
&& found - src < CONVERT_LIMIT
|
2020-02-20 21:48:03 +08:00
|
|
|
&& base_chars[*found] != IGN
|
2020-02-26 23:32:59 +08:00
|
|
|
&& base_chars[*found] != ESC
|
2019-11-13 02:04:59 +08:00
|
|
|
&& ((wincap.has_con_24bit_colors () && !con_is_legacy)
|
2020-02-20 21:57:26 +08:00
|
|
|
|| base_chars[*found] == NOR))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2009-03-24 20:18:34 +08:00
|
|
|
switch (ret = f_mbtowc (_REENT, NULL, (const char *) found,
|
2016-07-21 04:05:59 +08:00
|
|
|
end - found, &ps))
|
2009-03-24 20:18:34 +08:00
|
|
|
{
|
2011-02-07 19:18:19 +08:00
|
|
|
case -2: /* Truncated multibyte sequence. Store for next write. */
|
2008-02-07 02:24:50 +08:00
|
|
|
trunc_buf.len = end - found;
|
|
|
|
memcpy (trunc_buf.buf, found, trunc_buf.len);
|
2011-02-07 19:18:19 +08:00
|
|
|
goto do_print;
|
|
|
|
case -1: /* Invalid multibyte sequence. Handled below. */
|
|
|
|
goto do_print;
|
2009-03-24 20:18:34 +08:00
|
|
|
case 0:
|
|
|
|
found++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
found += ret;
|
|
|
|
break;
|
2008-02-06 01:37:10 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2001-04-09 08:44:25 +08:00
|
|
|
|
2011-02-07 19:18:19 +08:00
|
|
|
do_print:
|
|
|
|
|
|
|
|
/* Print all the base characters out */
|
2000-02-18 03:38:33 +08:00
|
|
|
if (found != src)
|
|
|
|
{
|
2001-04-09 08:44:25 +08:00
|
|
|
DWORD len = found - src;
|
2016-07-21 04:05:59 +08:00
|
|
|
buf_len = con.str_to_con (f_mbtowc, write_buf, (const char *) src, len);
|
2008-02-06 01:37:10 +08:00
|
|
|
if (!buf_len)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2008-02-06 01:37:10 +08:00
|
|
|
debug_printf ("conversion error, handle %p",
|
|
|
|
get_output_handle ());
|
|
|
|
__seterrno ();
|
|
|
|
return 0;
|
|
|
|
}
|
2001-04-09 08:44:25 +08:00
|
|
|
|
2014-03-10 06:49:56 +08:00
|
|
|
if (con.insert_mode)
|
2008-02-06 01:37:10 +08:00
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
cursor_get (&x, &y);
|
2014-02-16 09:48:25 +08:00
|
|
|
scroll_buffer (x, y, -1, y, x + buf_len, y);
|
2008-02-06 01:37:10 +08:00
|
|
|
}
|
2001-04-09 08:44:25 +08:00
|
|
|
|
2009-05-04 11:51:16 +08:00
|
|
|
if (!write_console (write_buf, buf_len, done))
|
2008-02-06 01:37:10 +08:00
|
|
|
{
|
2009-05-04 11:51:16 +08:00
|
|
|
debug_printf ("write failed, handle %p", get_output_handle ());
|
|
|
|
return 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2011-02-07 19:18:19 +08:00
|
|
|
/* Stop here if we reached the conversion limit. */
|
2008-02-07 02:24:50 +08:00
|
|
|
if (len >= CONVERT_LIMIT)
|
2011-02-07 19:18:19 +08:00
|
|
|
return found + trunc_buf.len;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2011-02-07 19:18:19 +08:00
|
|
|
/* If there's still something in the src buffer, but it's not a truncated
|
|
|
|
multibyte sequence, then we stumbled over a control character or an
|
|
|
|
invalid multibyte sequence. Print it. */
|
|
|
|
if (found < end && trunc_buf.len == 0)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
int x, y;
|
2008-02-07 02:24:50 +08:00
|
|
|
switch (base_chars[*found])
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2010-03-31 00:17:34 +08:00
|
|
|
case SO: /* Shift Out: Invoke G1 character set (ISO 2022) */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.iso_2022_G1 = true;
|
2009-12-19 23:37:10 +08:00
|
|
|
break;
|
2010-03-31 00:17:34 +08:00
|
|
|
case SI: /* Shift In: Invoke G0 character set (ISO 2022) */
|
2014-03-10 06:49:56 +08:00
|
|
|
con.iso_2022_G1 = false;
|
2009-12-19 23:37:10 +08:00
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
case BEL:
|
2006-01-03 09:15:29 +08:00
|
|
|
beep ();
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case ESC:
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = gotesc;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*found);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
2002-06-01 06:35:57 +08:00
|
|
|
case DWN:
|
2000-02-18 03:38:33 +08:00
|
|
|
cursor_get (&x, &y);
|
|
|
|
if (y >= srBottom)
|
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
if (y >= con.b.srWindow.Bottom && !con.scroll_region.Top)
|
2008-02-06 01:37:10 +08:00
|
|
|
WriteConsoleW (get_output_handle (), L"\n", 1, &done, 0);
|
2002-06-01 06:35:57 +08:00
|
|
|
else
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2014-02-16 09:48:25 +08:00
|
|
|
scroll_buffer (0, srTop + 1, -1, srBottom, 0, srTop);
|
2000-02-18 03:38:33 +08:00
|
|
|
y--;
|
|
|
|
}
|
|
|
|
}
|
2019-03-31 23:47:47 +08:00
|
|
|
cursor_set (false,
|
|
|
|
((get_ttyp ()->ti.c_oflag & ONLCR) ? 0 : x), y + 1);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case BAK:
|
|
|
|
cursor_rel (-1, 0);
|
|
|
|
break;
|
|
|
|
case IGN:
|
2020-02-21 17:26:25 +08:00
|
|
|
/* Up to release 3.1.3 we called cursor_rel (1, 0); to move the cursor
|
|
|
|
one step to the right. However, that neither matches the terminfo
|
|
|
|
for the cygwin terminal, nor the one for the xterm terminal. */
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case CR:
|
|
|
|
cursor_get (&x, &y);
|
2003-12-08 06:37:12 +08:00
|
|
|
cursor_set (false, 0, y);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case ERR:
|
2009-09-28 20:10:32 +08:00
|
|
|
/* Don't print chars marked as ERR chars, except for a ASCII CAN
|
|
|
|
sequence which is printed as singlebyte chars from the UTF
|
|
|
|
Basic Latin and Latin 1 Supplement plains. */
|
|
|
|
if (*found == 0x18)
|
2009-03-25 20:29:04 +08:00
|
|
|
{
|
|
|
|
write_replacement_char ();
|
|
|
|
if (found + 1 < end)
|
|
|
|
{
|
|
|
|
ret = __utf8_mbtowc (_REENT, NULL, (const char *) found + 1,
|
2016-07-21 04:05:59 +08:00
|
|
|
end - found - 1, &ps);
|
2020-09-19 22:55:09 +08:00
|
|
|
if (ret != -1)
|
2009-03-25 20:29:04 +08:00
|
|
|
while (ret-- > 0)
|
|
|
|
{
|
|
|
|
WCHAR w = *(found + 1);
|
|
|
|
WriteConsoleW (get_output_handle (), &w, 1, &done, 0);
|
|
|
|
found++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case TAB:
|
|
|
|
cursor_get (&x, &y);
|
2003-12-08 06:37:12 +08:00
|
|
|
cursor_set (false, 8 * (x / 8 + 1), y);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
2008-02-07 02:24:50 +08:00
|
|
|
case NOR:
|
2009-03-24 20:18:34 +08:00
|
|
|
write_replacement_char ();
|
2008-02-07 02:24:50 +08:00
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2008-02-07 02:24:50 +08:00
|
|
|
found++;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2011-02-07 19:18:19 +08:00
|
|
|
return found + trunc_buf.len;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2009-07-25 04:54:33 +08:00
|
|
|
ssize_t __stdcall
|
2000-02-18 03:38:33 +08:00
|
|
|
fhandler_console::write (const void *vsrc, size_t len)
|
|
|
|
{
|
2011-05-06 03:43:04 +08:00
|
|
|
bg_check_types bg = bg_check (SIGTTOU);
|
|
|
|
if (bg <= bg_eof)
|
|
|
|
return (ssize_t) bg;
|
|
|
|
|
2021-01-18 21:10:57 +08:00
|
|
|
acquire_attach_mutex (INFINITE);
|
2011-05-06 03:43:04 +08:00
|
|
|
push_process_state process_state (PID_TTYOU);
|
2019-03-31 23:47:48 +08:00
|
|
|
acquire_output_mutex (INFINITE);
|
2011-05-06 03:43:04 +08:00
|
|
|
|
2020-02-17 18:29:07 +08:00
|
|
|
/* If system has 24 bit color capability, use xterm compatible mode. */
|
2020-02-18 17:12:54 +08:00
|
|
|
if (wincap.has_con_24bit_colors ())
|
2021-01-15 16:32:10 +08:00
|
|
|
request_xterm_mode_output (true, &handle_set);
|
2020-02-17 18:29:07 +08:00
|
|
|
if (wincap.has_con_24bit_colors () && !con_is_legacy)
|
|
|
|
{
|
|
|
|
DWORD dwMode;
|
|
|
|
GetConsoleMode (get_output_handle (), &dwMode);
|
|
|
|
if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
|
|
|
|
!(get_ttyp ()->ti.c_oflag & ONLCR))
|
|
|
|
dwMode |= DISABLE_NEWLINE_AUTO_RETURN;
|
|
|
|
else
|
|
|
|
dwMode &= ~DISABLE_NEWLINE_AUTO_RETURN;
|
|
|
|
SetConsoleMode (get_output_handle (), dwMode);
|
|
|
|
}
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
/* Run and check for ansi sequences */
|
|
|
|
unsigned const char *src = (unsigned char *) vsrc;
|
|
|
|
unsigned const char *end = src + len;
|
2008-03-11 01:23:50 +08:00
|
|
|
/* This might look a bit far fetched, but using the TLS path buffer allows
|
|
|
|
to allocate a big buffer without using the stack too much. Doing it here
|
|
|
|
in write instead of in write_normal should be faster, too. */
|
|
|
|
tmp_pathbuf tp;
|
|
|
|
write_buf = tp.w_get ();
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2013-04-23 17:44:36 +08:00
|
|
|
debug_printf ("%p, %ld", vsrc, len);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
while (src < end)
|
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
paranoid_printf ("char %0c state is %d", *src, con.state);
|
|
|
|
switch (con.state)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
case normal:
|
|
|
|
src = write_normal (src, end);
|
2000-10-23 11:35:50 +08:00
|
|
|
if (!src) /* write_normal failed */
|
2019-03-31 23:47:48 +08:00
|
|
|
{
|
|
|
|
release_output_mutex ();
|
|
|
|
return -1;
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case gotesc:
|
2009-12-19 23:37:10 +08:00
|
|
|
if (*src == '[') /* CSI Control Sequence Introducer */
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = gotsquare;
|
2017-07-31 17:44:02 +08:00
|
|
|
memset (con.args, 0, sizeof con.args);
|
|
|
|
con.nargs = 0;
|
2014-03-10 06:49:56 +08:00
|
|
|
con.saw_question_mark = false;
|
|
|
|
con.saw_greater_than_sign = false;
|
|
|
|
con.saw_space = false;
|
2020-02-27 10:33:50 +08:00
|
|
|
con.saw_exclamation_mark = false;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2020-03-02 09:12:57 +08:00
|
|
|
else if (*src == '8') /* DECRC Restore cursor position */
|
|
|
|
{
|
|
|
|
if (con.screen_alternated)
|
|
|
|
{
|
|
|
|
/* For xterm mode only */
|
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-03-02 09:12:57 +08:00
|
|
|
}
|
|
|
|
else if (con.savex >= 0 && con.savey >= 0)
|
|
|
|
cursor_set (false, con.savex, con.savey);
|
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2020-03-02 09:12:57 +08:00
|
|
|
}
|
|
|
|
else if (*src == '7') /* DECSC Save cursor position */
|
|
|
|
{
|
|
|
|
if (con.screen_alternated)
|
|
|
|
{
|
|
|
|
/* For xterm mode only */
|
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-03-02 09:12:57 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
cursor_get (&con.savex, &con.savey);
|
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2020-03-02 09:12:57 +08:00
|
|
|
}
|
2020-02-26 23:32:59 +08:00
|
|
|
else if (wincap.has_con_24bit_colors () && !con_is_legacy
|
|
|
|
&& wincap.has_con_broken_il_dl () && *src == 'M')
|
|
|
|
{ /* Reverse Index (scroll down) */
|
|
|
|
int x, y;
|
|
|
|
cursor_get (&x, &y);
|
|
|
|
if (y == srTop)
|
|
|
|
{
|
2020-02-27 10:33:50 +08:00
|
|
|
if (y == con.b.srWindow.Top
|
|
|
|
&& srBottom == con.b.srWindow.Bottom)
|
|
|
|
{
|
|
|
|
/* Erase scroll down area */
|
2020-08-27 11:35:03 +08:00
|
|
|
wchar_t buf[] = L"\033[32768;1H\033[J\033[32768;32768";
|
|
|
|
__small_swprintf (buf, L"\033[%d;1H\033[J\033[%d;%dH",
|
|
|
|
srBottom - con.b.srWindow.Top + 1,
|
|
|
|
y + 1 - con.b.srWindow.Top, x + 1);
|
|
|
|
WriteConsoleW (get_output_handle (),
|
|
|
|
buf, wcslen (buf), 0, 0);
|
2020-02-27 10:33:50 +08:00
|
|
|
}
|
2020-02-26 23:32:59 +08:00
|
|
|
/* Substitute "CSI Ps T" */
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put ('[');
|
|
|
|
wpbuf.put ('T');
|
2020-02-26 23:32:59 +08:00
|
|
|
}
|
|
|
|
else
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-02-26 23:32:59 +08:00
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2020-02-26 23:32:59 +08:00
|
|
|
}
|
2020-05-31 13:53:18 +08:00
|
|
|
else if (*src == ']') /* OSC Operating System Command */
|
|
|
|
{
|
|
|
|
wpbuf.put (*src);
|
|
|
|
con.rarg = 0;
|
|
|
|
con.my_title_buf[0] = '\0';
|
|
|
|
con.state = gotrsquare;
|
|
|
|
}
|
2020-02-26 23:32:59 +08:00
|
|
|
else if (wincap.has_con_24bit_colors () && !con_is_legacy)
|
2020-03-02 09:12:57 +08:00
|
|
|
{
|
2020-02-27 10:33:50 +08:00
|
|
|
if (*src == 'c') /* RIS Full reset */
|
|
|
|
{
|
|
|
|
con.scroll_region.Top = 0;
|
|
|
|
con.scroll_region.Bottom = -1;
|
2020-03-09 09:38:36 +08:00
|
|
|
con.savex = con.savey = -1;
|
2020-05-30 17:25:03 +08:00
|
|
|
con.cursor_key_app_mode = false;
|
2020-02-27 10:33:50 +08:00
|
|
|
}
|
2020-03-02 09:12:57 +08:00
|
|
|
/* ESC sequences below (e.g. OSC, etc) are left to xterm
|
|
|
|
emulation in xterm compatible mode, therefore, are not
|
|
|
|
handled and just sent them. */
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2020-02-26 23:32:59 +08:00
|
|
|
/* Just send the sequence */
|
2020-03-09 04:41:14 +08:00
|
|
|
wpbuf.send (get_output_handle ());
|
2020-02-26 23:32:59 +08:00
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2020-02-26 23:32:59 +08:00
|
|
|
}
|
2009-12-19 23:37:10 +08:00
|
|
|
else if (*src == '(') /* Designate G0 character set */
|
|
|
|
{
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = gotparen;
|
2009-12-19 23:37:10 +08:00
|
|
|
}
|
|
|
|
else if (*src == ')') /* Designate G1 character set */
|
|
|
|
{
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = gotrparen;
|
2009-12-19 23:37:10 +08:00
|
|
|
}
|
|
|
|
else if (*src == 'M') /* Reverse Index (scroll down) */
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.fillin (get_output_handle ());
|
2014-02-26 11:58:37 +08:00
|
|
|
scroll_buffer_screen (0, 0, -1, -1, 0, 1);
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2009-12-19 23:37:10 +08:00
|
|
|
else if (*src == 'c') /* RIS Full Reset */
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.set_default_attr ();
|
|
|
|
con.vt100_graphics_mode_G0 = false;
|
|
|
|
con.vt100_graphics_mode_G1 = false;
|
|
|
|
con.iso_2022_G1 = false;
|
2014-01-31 12:23:22 +08:00
|
|
|
cursor_set (false, 0, 0);
|
|
|
|
clear_screen (cl_buf_beg, cl_buf_beg, cl_buf_end, cl_buf_end);
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2009-12-19 23:37:10 +08:00
|
|
|
else if (*src == 'R') /* ? */
|
2020-02-26 23:32:59 +08:00
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2020-02-26 23:32:59 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
else
|
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
src++;
|
|
|
|
break;
|
|
|
|
case gotarg1:
|
|
|
|
if (isdigit (*src))
|
|
|
|
{
|
2020-03-02 09:12:56 +08:00
|
|
|
if (con.nargs < MAXARGS)
|
|
|
|
con.args[con.nargs] = con.args[con.nargs] * 10 + *src - '0';
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2000-02-18 03:38:33 +08:00
|
|
|
src++;
|
|
|
|
}
|
|
|
|
else if (*src == ';')
|
|
|
|
{
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2000-02-18 03:38:33 +08:00
|
|
|
src++;
|
2020-03-02 09:12:56 +08:00
|
|
|
if (con.nargs < MAXARGS)
|
|
|
|
con.nargs++;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2013-01-11 19:04:50 +08:00
|
|
|
else if (*src == ' ')
|
|
|
|
{
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2013-01-11 19:04:50 +08:00
|
|
|
src++;
|
2014-03-10 06:49:56 +08:00
|
|
|
con.saw_space = true;
|
|
|
|
con.state = gotcommand;
|
2013-01-11 19:04:50 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
else
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = gotcommand;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case gotcommand:
|
2020-03-02 09:12:56 +08:00
|
|
|
if (con.nargs < MAXARGS)
|
|
|
|
con.nargs++;
|
2001-02-27 17:14:35 +08:00
|
|
|
char_command (*src++);
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case gotrsquare:
|
2001-04-09 08:44:25 +08:00
|
|
|
if (isdigit (*src))
|
2014-03-10 06:49:56 +08:00
|
|
|
con.rarg = con.rarg * 10 + (*src - '0');
|
|
|
|
else if (*src == ';' && (con.rarg == 2 || con.rarg == 0))
|
|
|
|
con.state = gettitle;
|
2020-05-31 13:53:18 +08:00
|
|
|
else if (*src == ';' && (con.rarg == 4 || con.rarg == 104
|
|
|
|
|| (con.rarg >= 10 && con.rarg <= 19)))
|
2019-03-31 23:47:46 +08:00
|
|
|
con.state = eatpalette;
|
2000-02-18 03:38:33 +08:00
|
|
|
else
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = eattitle;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2000-02-18 03:38:33 +08:00
|
|
|
src++;
|
|
|
|
break;
|
|
|
|
case eattitle:
|
|
|
|
case gettitle:
|
|
|
|
{
|
2020-05-31 13:53:18 +08:00
|
|
|
wpbuf.put (*src);
|
2014-03-10 06:49:56 +08:00
|
|
|
int n = strlen (con.my_title_buf);
|
2002-11-15 02:02:05 +08:00
|
|
|
if (*src < ' ')
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2020-05-31 13:53:18 +08:00
|
|
|
if (wincap.has_con_24bit_colors () && !con_is_legacy)
|
|
|
|
wpbuf.send (get_output_handle ());
|
|
|
|
else if (*src == '\007' && con.state == gettitle)
|
2014-03-10 06:49:56 +08:00
|
|
|
set_console_title (con.my_title_buf);
|
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
else if (n < TITLESIZE)
|
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.my_title_buf[n++] = *src;
|
|
|
|
con.my_title_buf[n] = '\0';
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
src++;
|
|
|
|
break;
|
|
|
|
}
|
2019-03-31 23:47:46 +08:00
|
|
|
case eatpalette:
|
2020-05-31 13:53:18 +08:00
|
|
|
wpbuf.put (*src);
|
|
|
|
if (*src == '?')
|
|
|
|
con.saw_question_mark = true;
|
|
|
|
else if (*src == '\033')
|
|
|
|
con.state = endpalette;
|
2019-03-31 23:47:46 +08:00
|
|
|
else if (*src == '\a')
|
2020-02-26 23:32:59 +08:00
|
|
|
{
|
2020-05-31 13:53:18 +08:00
|
|
|
/* Send OSC Ps; Pt BEL other than OSC Ps; ? BEL */
|
|
|
|
if (wincap.has_con_24bit_colors () && !con_is_legacy
|
|
|
|
&& !con.saw_question_mark)
|
|
|
|
wpbuf.send (get_output_handle ());
|
2020-02-26 23:32:59 +08:00
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2020-02-26 23:32:59 +08:00
|
|
|
}
|
2019-03-31 23:47:46 +08:00
|
|
|
src++;
|
|
|
|
break;
|
|
|
|
case endpalette:
|
2020-05-31 13:53:18 +08:00
|
|
|
wpbuf.put (*src);
|
2019-03-31 23:47:46 +08:00
|
|
|
if (*src == '\\')
|
2020-05-31 13:53:18 +08:00
|
|
|
{
|
|
|
|
/* Send OSC Ps; Pt ST other than OSC Ps; ? ST */
|
|
|
|
if (wincap.has_con_24bit_colors () && !con_is_legacy
|
|
|
|
&& !con.saw_question_mark)
|
|
|
|
wpbuf.send (get_output_handle ());
|
|
|
|
con.state = normal;
|
|
|
|
}
|
2019-03-31 23:47:46 +08:00
|
|
|
else
|
|
|
|
/* Sequence error (abort) */
|
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2019-03-31 23:47:46 +08:00
|
|
|
src++;
|
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
case gotsquare:
|
|
|
|
if (*src == ';')
|
|
|
|
{
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = gotarg1;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2020-03-02 09:12:56 +08:00
|
|
|
if (con.nargs < MAXARGS)
|
|
|
|
con.nargs++;
|
2000-02-18 03:38:33 +08:00
|
|
|
src++;
|
|
|
|
}
|
|
|
|
else if (isalpha (*src))
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = gotcommand;
|
2000-02-18 03:38:33 +08:00
|
|
|
else if (*src != '@' && !isalpha (*src) && !isdigit (*src))
|
|
|
|
{
|
2000-12-15 12:42:20 +08:00
|
|
|
if (*src == '?')
|
2014-03-10 06:49:56 +08:00
|
|
|
con.saw_question_mark = true;
|
2009-12-19 23:37:10 +08:00
|
|
|
else if (*src == '>')
|
2014-03-10 06:49:56 +08:00
|
|
|
con.saw_greater_than_sign = true;
|
2020-02-27 10:33:50 +08:00
|
|
|
else if (*src == '!')
|
|
|
|
con.saw_exclamation_mark = true;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.put (*src);
|
2000-02-18 03:38:33 +08:00
|
|
|
/* ignore any extra chars between [ and first arg or command */
|
|
|
|
src++;
|
|
|
|
}
|
|
|
|
else
|
2014-03-10 06:49:56 +08:00
|
|
|
con.state = gotarg1;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
2010-03-31 00:17:34 +08:00
|
|
|
case gotparen: /* Designate G0 Character Set (ISO 2022) */
|
2009-12-19 23:37:10 +08:00
|
|
|
if (*src == '0')
|
2014-03-10 06:49:56 +08:00
|
|
|
con.vt100_graphics_mode_G0 = true;
|
2009-12-19 23:37:10 +08:00
|
|
|
else
|
2014-03-10 06:49:56 +08:00
|
|
|
con.vt100_graphics_mode_G0 = false;
|
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2009-12-19 23:37:10 +08:00
|
|
|
src++;
|
|
|
|
break;
|
2010-03-31 00:17:34 +08:00
|
|
|
case gotrparen: /* Designate G1 Character Set (ISO 2022) */
|
2009-12-19 23:37:10 +08:00
|
|
|
if (*src == '0')
|
2014-03-10 06:49:56 +08:00
|
|
|
con.vt100_graphics_mode_G1 = true;
|
2009-12-19 23:37:10 +08:00
|
|
|
else
|
2014-03-10 06:49:56 +08:00
|
|
|
con.vt100_graphics_mode_G1 = false;
|
|
|
|
con.state = normal;
|
2020-03-09 04:41:13 +08:00
|
|
|
wpbuf.empty();
|
2009-12-19 23:37:10 +08:00
|
|
|
src++;
|
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
}
|
2019-03-31 23:47:48 +08:00
|
|
|
release_output_mutex ();
|
2000-07-30 00:24:59 +08:00
|
|
|
|
2013-04-23 17:44:36 +08:00
|
|
|
syscall_printf ("%ld = fhandler_console::write(...)", len);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2021-01-18 21:10:57 +08:00
|
|
|
release_attach_mutex ();
|
2000-02-18 03:38:33 +08:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2013-04-23 17:44:36 +08:00
|
|
|
static const struct {
|
2000-02-18 03:38:33 +08:00
|
|
|
int vk;
|
|
|
|
const char *val[4];
|
2013-04-23 17:44:36 +08:00
|
|
|
} keytable[] = {
|
2009-12-21 18:11:27 +08:00
|
|
|
/* NORMAL */ /* SHIFT */ /* CTRL */ /* CTRL-SHIFT */
|
|
|
|
/* Unmodified and Alt-modified keypad keys comply with linux console
|
|
|
|
SHIFT, CTRL, CTRL-SHIFT modifiers comply with xterm modifier usage */
|
|
|
|
{VK_NUMPAD5, {"\033[G", "\033[1;2G", "\033[1;5G", "\033[1;6G"}},
|
|
|
|
{VK_CLEAR, {"\033[G", "\033[1;2G", "\033[1;5G", "\033[1;6G"}},
|
|
|
|
{VK_LEFT, {"\033[D", "\033[1;2D", "\033[1;5D", "\033[1;6D"}},
|
|
|
|
{VK_RIGHT, {"\033[C", "\033[1;2C", "\033[1;5C", "\033[1;6C"}},
|
|
|
|
{VK_UP, {"\033[A", "\033[1;2A", "\033[1;5A", "\033[1;6A"}},
|
|
|
|
{VK_DOWN, {"\033[B", "\033[1;2B", "\033[1;5B", "\033[1;6B"}},
|
|
|
|
{VK_PRIOR, {"\033[5~", "\033[5;2~", "\033[5;5~", "\033[5;6~"}},
|
|
|
|
{VK_NEXT, {"\033[6~", "\033[6;2~", "\033[6;5~", "\033[6;6~"}},
|
|
|
|
{VK_HOME, {"\033[1~", "\033[1;2~", "\033[1;5~", "\033[1;6~"}},
|
|
|
|
{VK_END, {"\033[4~", "\033[4;2~", "\033[4;5~", "\033[4;6~"}},
|
|
|
|
{VK_INSERT, {"\033[2~", "\033[2;2~", "\033[2;5~", "\033[2;6~"}},
|
|
|
|
{VK_DELETE, {"\033[3~", "\033[3;2~", "\033[3;5~", "\033[3;6~"}},
|
|
|
|
/* F1...F12, SHIFT-F1...SHIFT-F10 comply with linux console
|
|
|
|
F6...F12, and all modified F-keys comply with rxvt (compatible extension) */
|
|
|
|
{VK_F1, {"\033[[A", "\033[23~", "\033[11^", "\033[23^"}},
|
|
|
|
{VK_F2, {"\033[[B", "\033[24~", "\033[12^", "\033[24^"}},
|
|
|
|
{VK_F3, {"\033[[C", "\033[25~", "\033[13^", "\033[25^"}},
|
|
|
|
{VK_F4, {"\033[[D", "\033[26~", "\033[14^", "\033[26^"}},
|
|
|
|
{VK_F5, {"\033[[E", "\033[28~", "\033[15^", "\033[28^"}},
|
|
|
|
{VK_F6, {"\033[17~", "\033[29~", "\033[17^", "\033[29^"}},
|
|
|
|
{VK_F7, {"\033[18~", "\033[31~", "\033[18^", "\033[31^"}},
|
|
|
|
{VK_F8, {"\033[19~", "\033[32~", "\033[19^", "\033[32^"}},
|
|
|
|
{VK_F9, {"\033[20~", "\033[33~", "\033[20^", "\033[33^"}},
|
|
|
|
{VK_F10, {"\033[21~", "\033[34~", "\033[21^", "\033[34^"}},
|
|
|
|
{VK_F11, {"\033[23~", "\033[23$", "\033[23^", "\033[23@"}},
|
|
|
|
{VK_F12, {"\033[24~", "\033[24$", "\033[24^", "\033[24@"}},
|
|
|
|
/* CTRL-6 complies with Windows cmd console but should be fixed */
|
2000-02-18 03:38:33 +08:00
|
|
|
{'6', {NULL, NULL, "\036", NULL}},
|
2009-12-21 18:11:27 +08:00
|
|
|
/* Table end marker */
|
|
|
|
{0}
|
2000-02-18 03:38:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
const char *
|
2016-01-31 06:33:36 +08:00
|
|
|
fhandler_console::get_nonascii_key (INPUT_RECORD& input_rec, char *tmp)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
#define NORMAL 0
|
|
|
|
#define SHIFT 1
|
|
|
|
#define CONTROL 2
|
2009-12-21 18:11:27 +08:00
|
|
|
/*#define CONTROLSHIFT 3*/
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2009-12-21 18:11:27 +08:00
|
|
|
int modifier_index = NORMAL;
|
2000-02-18 03:38:33 +08:00
|
|
|
if (input_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
|
|
|
|
modifier_index = SHIFT;
|
2012-04-24 22:39:22 +08:00
|
|
|
if (input_rec.Event.KeyEvent.dwControlKeyState & CTRL_PRESSED)
|
2009-12-21 18:11:27 +08:00
|
|
|
modifier_index += CONTROL;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
for (int i = 0; keytable[i].vk; i++)
|
|
|
|
if (input_rec.Event.KeyEvent.wVirtualKeyCode == keytable[i].vk)
|
2009-12-21 18:11:27 +08:00
|
|
|
{
|
2012-04-24 22:39:22 +08:00
|
|
|
if ((input_rec.Event.KeyEvent.dwControlKeyState & ALT_PRESSED)
|
2009-12-21 18:11:27 +08:00
|
|
|
&& keytable[i].val[modifier_index] != NULL)
|
2011-06-06 13:02:13 +08:00
|
|
|
{ /* Generic ESC prefixing if Alt is pressed */
|
2009-12-21 18:11:27 +08:00
|
|
|
tmp[0] = '\033';
|
|
|
|
strcpy (tmp + 1, keytable[i].val[modifier_index]);
|
|
|
|
return tmp;
|
2011-06-06 13:02:13 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return keytable[i].val[modifier_index];
|
2009-12-21 18:11:27 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2000-07-31 01:58:48 +08:00
|
|
|
if (input_rec.Event.KeyEvent.uChar.AsciiChar)
|
2000-07-30 03:07:15 +08:00
|
|
|
{
|
2000-07-31 01:58:48 +08:00
|
|
|
tmp[0] = input_rec.Event.KeyEvent.uChar.AsciiChar;
|
|
|
|
tmp[1] = '\0';
|
|
|
|
return tmp;
|
2000-07-30 03:07:15 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-07-04 02:05:51 +08:00
|
|
|
int
|
2011-04-18 03:56:25 +08:00
|
|
|
fhandler_console::init (HANDLE h, DWORD a, mode_t bin)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2011-04-18 03:56:25 +08:00
|
|
|
// this->fhandler_termios::init (h, mode, bin);
|
2000-02-18 03:38:33 +08:00
|
|
|
/* Ensure both input and output console handles are open */
|
2002-06-05 09:42:28 +08:00
|
|
|
int flags = 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
a &= GENERIC_READ | GENERIC_WRITE;
|
|
|
|
if (a == GENERIC_READ)
|
2002-06-05 09:42:28 +08:00
|
|
|
flags = O_RDONLY;
|
2000-02-18 03:38:33 +08:00
|
|
|
if (a == GENERIC_WRITE)
|
2002-06-05 09:42:28 +08:00
|
|
|
flags = O_WRONLY;
|
2000-02-18 03:38:33 +08:00
|
|
|
if (a == (GENERIC_READ | GENERIC_WRITE))
|
2002-06-05 09:42:28 +08:00
|
|
|
flags = O_RDWR;
|
2011-05-06 06:30:53 +08:00
|
|
|
open_with_arch (flags | O_BINARY | (h ? 0 : O_NOCTTY));
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2011-10-16 06:37:30 +08:00
|
|
|
return !tcsetattr (0, &get_ttyp ()->ti);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2005-07-05 11:16:46 +08:00
|
|
|
fhandler_console::igncr_enabled ()
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2011-10-16 06:37:30 +08:00
|
|
|
return get_ttyp ()->ti.c_iflag & IGNCR;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-04-10 21:45:10 +08:00
|
|
|
fhandler_console::set_close_on_exec (bool val)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2011-05-07 04:12:20 +08:00
|
|
|
close_on_exec (val);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void __stdcall
|
|
|
|
set_console_title (char *title)
|
|
|
|
{
|
2009-07-25 16:27:10 +08:00
|
|
|
wchar_t buf[TITLESIZE + 1];
|
|
|
|
sys_mbstowcs (buf, TITLESIZE + 1, title);
|
2006-06-04 04:32:07 +08:00
|
|
|
lock_ttys here (15000);
|
2009-06-04 22:59:47 +08:00
|
|
|
SetConsoleTitleW (buf);
|
|
|
|
debug_printf ("title '%W'", buf);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2000-09-03 12:16:35 +08:00
|
|
|
void
|
2005-11-14 22:15:51 +08:00
|
|
|
fhandler_console::fixup_after_fork_exec (bool execing)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2011-06-04 08:12:29 +08:00
|
|
|
set_unit ();
|
2019-03-31 23:47:48 +08:00
|
|
|
setup_io_mutex ();
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2005-12-19 12:34:13 +08:00
|
|
|
|
2006-01-08 01:57:26 +08:00
|
|
|
// #define WINSTA_ACCESS (WINSTA_READATTRIBUTES | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE | WINSTA_CREATEDESKTOP | WINSTA_EXITWINDOWS)
|
2009-07-05 07:51:10 +08:00
|
|
|
#define WINSTA_ACCESS WINSTA_ALL_ACCESS
|
|
|
|
|
2009-07-06 00:49:56 +08:00
|
|
|
/* Create a console in an invisible window station. This should work
|
2009-07-05 07:51:10 +08:00
|
|
|
in all versions of Windows NT except Windows 7 (so far). */
|
|
|
|
bool
|
|
|
|
fhandler_console::create_invisible_console (HWINSTA horig)
|
|
|
|
{
|
|
|
|
HWINSTA h = CreateWindowStationW (NULL, 0, WINSTA_ACCESS, NULL);
|
|
|
|
termios_printf ("%p = CreateWindowStation(NULL), %E", h);
|
|
|
|
BOOL b;
|
|
|
|
if (h)
|
|
|
|
{
|
|
|
|
b = SetProcessWindowStation (h);
|
|
|
|
termios_printf ("SetProcessWindowStation %d, %E", b);
|
|
|
|
}
|
|
|
|
b = AllocConsole (); /* will cause flashing if CreateWindowStation
|
2011-06-06 13:02:13 +08:00
|
|
|
failed */
|
2009-07-05 07:51:10 +08:00
|
|
|
if (!h)
|
|
|
|
SetParent (GetConsoleWindow (), HWND_MESSAGE);
|
|
|
|
if (horig && h && h != horig && SetProcessWindowStation (horig))
|
|
|
|
CloseWindowStation (h);
|
|
|
|
termios_printf ("%d = AllocConsole (), %E", b);
|
|
|
|
invisible_console = true;
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
2013-04-23 17:44:36 +08:00
|
|
|
/* Ugly workaround for Windows 7 and later.
|
2009-07-05 07:51:10 +08:00
|
|
|
|
|
|
|
First try to just attach to any console which may have started this
|
|
|
|
app. If that works use this as our "invisible console".
|
|
|
|
|
|
|
|
This will fail if not started from the command prompt. In that case, start
|
|
|
|
a dummy console application in a hidden state so that we can use its console
|
|
|
|
as our invisible console. This probably works everywhere but process
|
2009-07-06 00:49:56 +08:00
|
|
|
creation is slow and to be avoided if possible so the window station method
|
2009-07-05 07:51:10 +08:00
|
|
|
is vastly preferred.
|
|
|
|
|
|
|
|
FIXME: This is not completely thread-safe since it creates two inheritable
|
|
|
|
handles which are known only to this function. If another thread starts
|
|
|
|
a process the new process will inherit these handles. However, since this
|
|
|
|
function is currently only called at startup and during exec, it shouldn't
|
|
|
|
be a big deal. */
|
|
|
|
bool
|
2021-01-18 21:10:57 +08:00
|
|
|
fhandler_console::create_invisible_console_workaround (bool force)
|
2009-07-05 07:51:10 +08:00
|
|
|
{
|
2021-01-18 21:10:57 +08:00
|
|
|
/* If force is set, avoid to reattach to existing console. */
|
|
|
|
if (force || !AttachConsole (-1))
|
2009-07-05 07:51:10 +08:00
|
|
|
{
|
|
|
|
bool taskbar;
|
2021-01-18 21:10:57 +08:00
|
|
|
DWORD err = force ? 0 : GetLastError ();
|
2009-07-05 07:51:10 +08:00
|
|
|
path_conv helper ("/bin/cygwin-console-helper.exe");
|
|
|
|
HANDLE hello = NULL;
|
|
|
|
HANDLE goodbye = NULL;
|
|
|
|
/* If err == ERROR_PROC_FOUND then this method won't work. But that's
|
2009-07-06 00:49:56 +08:00
|
|
|
ok. The window station method should work ok when AttachConsole doesn't
|
2009-07-05 07:51:10 +08:00
|
|
|
work.
|
|
|
|
|
|
|
|
If the helper doesn't exist or we can't create event handles then we
|
|
|
|
can't use this method. */
|
|
|
|
if (err == ERROR_PROC_NOT_FOUND || !helper.exists ()
|
|
|
|
|| !(hello = CreateEvent (&sec_none, true, false, NULL))
|
|
|
|
|| !(goodbye = CreateEvent (&sec_none, true, false, NULL)))
|
|
|
|
{
|
|
|
|
AllocConsole (); /* This is just sanity check code. We should
|
|
|
|
never actually hit here unless we're running
|
|
|
|
in an environment which lacks the helper
|
|
|
|
app. */
|
|
|
|
taskbar = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
STARTUPINFOW si = {};
|
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
size_t len = helper.get_wide_win32_path_len ();
|
2019-11-05 18:29:02 +08:00
|
|
|
WCHAR cmd[len + 1];
|
|
|
|
WCHAR args[len + 1 + (2 * sizeof (" 0xffffffffffffffff")) + 1];
|
2009-07-05 07:51:10 +08:00
|
|
|
WCHAR title[] = L"invisible cygwin console";
|
|
|
|
|
2019-11-05 18:29:02 +08:00
|
|
|
/* Create a new hidden process. Use the two event handles as
|
|
|
|
argv[1] and argv[2]. */
|
|
|
|
|
2009-07-05 07:51:10 +08:00
|
|
|
helper.get_wide_win32_path (cmd);
|
2019-11-05 18:29:02 +08:00
|
|
|
__small_swprintf (args, L"\"%W\" %p %p", cmd, hello, goodbye);
|
2009-07-05 07:51:10 +08:00
|
|
|
|
|
|
|
si.cb = sizeof (si);
|
|
|
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
|
|
|
si.wShowWindow = SW_HIDE;
|
|
|
|
si.lpTitle = title;
|
|
|
|
|
2019-11-05 18:29:02 +08:00
|
|
|
BOOL x = CreateProcessW (cmd, args,
|
2019-03-31 23:47:47 +08:00
|
|
|
&sec_none_nih, &sec_none_nih, true,
|
2009-07-05 07:51:10 +08:00
|
|
|
CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
|
|
|
|
if (x)
|
|
|
|
{
|
|
|
|
CloseHandle (pi.hProcess); /* Don't need */
|
|
|
|
CloseHandle (pi.hThread); /* these. */
|
|
|
|
}
|
|
|
|
taskbar = false;
|
|
|
|
/* Wait for subprocess to indicate that it is live. This may not
|
|
|
|
actually be needed but it's hard to say since it is possible that
|
|
|
|
there will be no console for a brief time after the process
|
|
|
|
returns and there is no easy way to determine if/when this happens
|
|
|
|
in Windows. So play it safe. */
|
|
|
|
if (!x || (WaitForSingleObject (hello, 10000) != WAIT_OBJECT_0)
|
|
|
|
|| !AttachConsole (pi.dwProcessId))
|
|
|
|
AllocConsole (); /* Oh well. Watch the flash. */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!taskbar)
|
|
|
|
/* Setting the owner of the console window to HWND_MESSAGE seems to
|
|
|
|
hide it from the taskbar. Don't know if this method is faster than
|
|
|
|
calling ShowWindowAsync but it should guarantee no taskbar presence
|
|
|
|
for the hidden console. */
|
|
|
|
SetParent (GetConsoleWindow (), HWND_MESSAGE);
|
|
|
|
if (hello)
|
|
|
|
CloseHandle (hello);
|
|
|
|
if (goodbye)
|
|
|
|
{
|
|
|
|
SetEvent (goodbye); /* Tell helper process it's ok to exit. */
|
|
|
|
CloseHandle (goodbye);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return invisible_console = true;
|
|
|
|
}
|
2006-01-08 01:57:26 +08:00
|
|
|
|
2012-02-08 00:54:14 +08:00
|
|
|
void
|
|
|
|
fhandler_console::free_console ()
|
|
|
|
{
|
|
|
|
BOOL res = FreeConsole ();
|
|
|
|
debug_printf ("freed console, res %d", res);
|
|
|
|
init_console_handler (false);
|
|
|
|
}
|
|
|
|
|
2005-12-19 12:34:13 +08:00
|
|
|
bool
|
2021-01-18 21:10:57 +08:00
|
|
|
fhandler_console::need_invisible (bool force)
|
2005-12-19 12:34:13 +08:00
|
|
|
{
|
|
|
|
BOOL b = false;
|
2021-01-18 21:10:57 +08:00
|
|
|
/* If force is set, forcibly create a new invisible console
|
|
|
|
even if a console device already exists. */
|
|
|
|
if (exists () && !force)
|
2005-12-19 12:34:13 +08:00
|
|
|
invisible_console = false;
|
|
|
|
else
|
|
|
|
{
|
2009-07-05 07:51:10 +08:00
|
|
|
HWINSTA h;
|
2005-12-19 12:34:13 +08:00
|
|
|
/* The intent here is to allocate an "invisible" console if we have no
|
|
|
|
controlling tty or to reuse the existing console if we already have
|
2009-07-06 00:49:56 +08:00
|
|
|
a tty. So, first get the old window station. If there is no controlling
|
|
|
|
terminal, create a new window station and then set it as the current
|
|
|
|
window station. The subsequent AllocConsole will then be allocated
|
2005-12-19 12:34:13 +08:00
|
|
|
invisibly. But, after doing that we have to restore any existing windows
|
|
|
|
station or, strangely, characters will not be displayed in any windows
|
|
|
|
drawn on the current screen. We only do this if we have changed to
|
2009-07-06 00:49:56 +08:00
|
|
|
a new window station and if we had an existing windows station previously.
|
|
|
|
We also close the previously opened window station even though AllocConsole
|
2005-12-19 12:34:13 +08:00
|
|
|
is now "using" it. This doesn't seem to cause any problems.
|
|
|
|
|
|
|
|
Things to watch out for if you make changes in this code:
|
|
|
|
|
|
|
|
- Flashing, black consoles showing up when you start, e.g., ssh in
|
|
|
|
an xterm.
|
|
|
|
- Non-displaying of characters in rxvt or xemacs if you start a
|
|
|
|
process using setsid: bash -lc "setsid rxvt". */
|
|
|
|
|
2009-07-05 07:51:10 +08:00
|
|
|
h = GetProcessWindowStation ();
|
2006-01-08 01:57:26 +08:00
|
|
|
|
|
|
|
USEROBJECTFLAGS oi;
|
|
|
|
DWORD len;
|
2009-07-05 07:51:10 +08:00
|
|
|
if (!h
|
|
|
|
|| !GetUserObjectInformationW (h, UOI_FLAGS, &oi, sizeof (oi), &len)
|
2006-01-08 01:57:26 +08:00
|
|
|
|| !(oi.dwFlags & WSF_VISIBLE))
|
|
|
|
{
|
|
|
|
b = true;
|
|
|
|
debug_printf ("window station is not visible");
|
2009-07-05 07:51:10 +08:00
|
|
|
AllocConsole ();
|
2006-01-08 01:57:26 +08:00
|
|
|
invisible_console = true;
|
|
|
|
}
|
2009-07-05 07:51:10 +08:00
|
|
|
else if (wincap.has_broken_alloc_console ())
|
2021-01-18 21:10:57 +08:00
|
|
|
b = create_invisible_console_workaround (force);
|
2009-07-05 07:51:10 +08:00
|
|
|
else
|
|
|
|
b = create_invisible_console (h);
|
2005-12-19 12:34:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
debug_printf ("invisible_console %d", invisible_console);
|
|
|
|
return b;
|
|
|
|
}
|
2019-03-31 23:47:48 +08:00
|
|
|
|
|
|
|
DWORD
|
|
|
|
fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
|
|
|
|
{
|
|
|
|
#ifdef DEBUGGING
|
|
|
|
strace.prntf (_STRACE_TERMIOS, fn, "(%d): trying to get input_mutex", ln);
|
|
|
|
#endif
|
|
|
|
DWORD res = WaitForSingleObject (input_mutex, ms);
|
|
|
|
if (res != WAIT_OBJECT_0)
|
|
|
|
strace.prntf (_STRACE_TERMIOS, fn,
|
|
|
|
"(%d): Failed to acquire input_mutex %08x",
|
|
|
|
ln, GetLastError ());
|
|
|
|
#ifdef DEBUGGING
|
|
|
|
else
|
|
|
|
strace.prntf (_STRACE_TERMIOS, fn, "(%d): got input_mutex", ln);
|
|
|
|
#endif
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fhandler_console::__release_input_mutex (const char *fn, int ln)
|
|
|
|
{
|
|
|
|
ReleaseMutex (input_mutex);
|
|
|
|
#ifdef DEBUGGING
|
|
|
|
strace.prntf (_STRACE_TERMIOS, fn, "(%d): release input_mutex", ln);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
|
|
fhandler_console::__acquire_output_mutex (const char *fn, int ln, DWORD ms)
|
|
|
|
{
|
|
|
|
#ifdef DEBUGGING
|
|
|
|
strace.prntf (_STRACE_TERMIOS, fn, "(%d): trying to get output_mutex", ln);
|
|
|
|
#endif
|
|
|
|
DWORD res = WaitForSingleObject (output_mutex, ms);
|
|
|
|
if (res != WAIT_OBJECT_0)
|
|
|
|
strace.prntf (_STRACE_TERMIOS, fn,
|
|
|
|
"(%d): Failed to acquire output_mutex %08x",
|
|
|
|
ln, GetLastError ());
|
|
|
|
#ifdef DEBUGGING
|
|
|
|
else
|
|
|
|
strace.prntf (_STRACE_TERMIOS, fn, "(%d): got output_mutex", ln);
|
|
|
|
#endif
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fhandler_console::__release_output_mutex (const char *fn, int ln)
|
|
|
|
{
|
|
|
|
ReleaseMutex (output_mutex);
|
|
|
|
#ifdef DEBUGGING
|
|
|
|
strace.prntf (_STRACE_TERMIOS, fn, "(%d): release output_mutex", ln);
|
|
|
|
#endif
|
|
|
|
}
|
2021-01-15 16:32:10 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
fhandler_console::get_duplicated_handle_set (handle_set_t *p)
|
|
|
|
{
|
|
|
|
DuplicateHandle (GetCurrentProcess (), get_handle (),
|
|
|
|
GetCurrentProcess (), &p->input_handle,
|
|
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
|
|
DuplicateHandle (GetCurrentProcess (), get_output_handle (),
|
|
|
|
GetCurrentProcess (), &p->output_handle,
|
|
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
|
|
DuplicateHandle (GetCurrentProcess (), input_mutex,
|
|
|
|
GetCurrentProcess (), &p->input_mutex,
|
|
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
|
|
DuplicateHandle (GetCurrentProcess (), output_mutex,
|
|
|
|
GetCurrentProcess (), &p->output_mutex,
|
|
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The function close_handle_set() should be static so that they can
|
|
|
|
be called even after the fhandler_console instance is deleted. */
|
|
|
|
void
|
|
|
|
fhandler_console::close_handle_set (handle_set_t *p)
|
|
|
|
{
|
|
|
|
CloseHandle (p->input_handle);
|
|
|
|
p->input_handle = NULL;
|
|
|
|
CloseHandle (p->output_handle);
|
|
|
|
p->output_handle = NULL;
|
|
|
|
CloseHandle (p->input_mutex);
|
|
|
|
p->input_mutex = NULL;
|
|
|
|
CloseHandle (p->output_mutex);
|
|
|
|
p->output_mutex = NULL;
|
|
|
|
}
|