summaryrefslogtreecommitdiffstats
path: root/lib/tty
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tty')
-rw-r--r--lib/tty/Makefile.am36
-rw-r--r--lib/tty/Makefile.in801
-rw-r--r--lib/tty/color-internal.c244
-rw-r--r--lib/tty/color-internal.h61
-rw-r--r--lib/tty/color-ncurses.c251
-rw-r--r--lib/tty/color-slang.c260
-rw-r--r--lib/tty/color-slang.h56
-rw-r--r--lib/tty/color.c244
-rw-r--r--lib/tty/color.h54
-rw-r--r--lib/tty/key.c2252
-rw-r--r--lib/tty/key.h121
-rw-r--r--lib/tty/keyxdef.c455
-rw-r--r--lib/tty/mouse.c216
-rw-r--r--lib/tty/mouse.h117
-rw-r--r--lib/tty/tty-internal.c110
-rw-r--r--lib/tty/tty-internal.h49
-rw-r--r--lib/tty/tty-ncurses.c772
-rw-r--r--lib/tty/tty-ncurses.h50
-rw-r--r--lib/tty/tty-slang.c781
-rw-r--r--lib/tty/tty-slang.h48
-rw-r--r--lib/tty/tty.c416
-rw-r--r--lib/tty/tty.h146
-rw-r--r--lib/tty/win.c168
-rw-r--r--lib/tty/win.h24
-rw-r--r--lib/tty/x11conn.c266
-rw-r--r--lib/tty/x11conn.h40
26 files changed, 8038 insertions, 0 deletions
diff --git a/lib/tty/Makefile.am b/lib/tty/Makefile.am
new file mode 100644
index 0000000..d4260fe
--- /dev/null
+++ b/lib/tty/Makefile.am
@@ -0,0 +1,36 @@
+
+noinst_LTLIBRARIES = libmctty.la
+
+if USE_SCREEN_SLANG
+ TTY_SCREEN_SRC = \
+ color-slang.c color-slang.h \
+ tty-slang.c tty-slang.h
+else
+ TTY_SCREEN_SRC = \
+ color-ncurses.c \
+ tty-ncurses.c tty-ncurses.h
+endif
+
+TTY_SRC = \
+ color-internal.c color-internal.h \
+ color.c color.h \
+ key.c key.h keyxdef.c \
+ mouse.c mouse.h \
+ tty-internal.c tty-internal.h \
+ tty.c tty.h \
+ win.c win.h
+
+if HAVE_TEXTMODE_X11_SUPPORT
+TTY_SRC += x11conn.c x11conn.h
+endif
+
+libmctty_la_SOURCES = $(TTY_SRC) $(TTY_SCREEN_SRC)
+
+AM_CPPFLAGS = -I$(top_srcdir)
+
+if HAVE_GMODULE
+AM_CPPFLAGS += $(GMODULE_CFLAGS)
+else
+AM_CPPFLAGS += $(GLIB_CFLAGS)
+endif
+
diff --git a/lib/tty/Makefile.in b/lib/tty/Makefile.in
new file mode 100644
index 0000000..0aa0af8
--- /dev/null
+++ b/lib/tty/Makefile.in
@@ -0,0 +1,801 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_TEXTMODE_X11_SUPPORT_TRUE@am__append_1 = x11conn.c x11conn.h
+@HAVE_GMODULE_TRUE@am__append_2 = $(GMODULE_CFLAGS)
+@HAVE_GMODULE_FALSE@am__append_3 = $(GLIB_CFLAGS)
+subdir = lib/tty
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4.include/gnulib/mode_t.m4 \
+ $(top_srcdir)/m4.include/gnulib/stat-size.m4 \
+ $(top_srcdir)/m4.include/gnulib/fstypename.m4 \
+ $(top_srcdir)/m4.include/gnulib/fsusage.m4 \
+ $(top_srcdir)/m4.include/gnulib/mountlist.m4 \
+ $(top_srcdir)/m4.include/gnulib/windows-stat-inodes.m4 \
+ $(top_srcdir)/m4.include/gnulib/sys_types_h.m4 \
+ $(top_srcdir)/m4.include/ax_path_lib_pcre.m4 \
+ $(top_srcdir)/m4.include/ax_check_pcre2.m4 \
+ $(top_srcdir)/m4.include/dx_doxygen.m4 \
+ $(top_srcdir)/m4.include/ax_require_defined.m4 \
+ $(top_srcdir)/m4.include/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4.include/ax_append_flag.m4 \
+ $(top_srcdir)/m4.include/ax_append_compile_flags.m4 \
+ $(top_srcdir)/m4.include/mc-cflags.m4 \
+ $(top_srcdir)/m4.include/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4.include/mc-check-search-type.m4 \
+ $(top_srcdir)/m4.include/mc-get-fs-info.m4 \
+ $(top_srcdir)/m4.include/mc-with-x.m4 \
+ $(top_srcdir)/m4.include/mc-use-termcap.m4 \
+ $(top_srcdir)/m4.include/mc-with-screen.m4 \
+ $(top_srcdir)/m4.include/mc-with-screen-ncurses.m4 \
+ $(top_srcdir)/m4.include/mc-with-screen-slang.m4 \
+ $(top_srcdir)/m4.include/mc-with-internal-edit.m4 \
+ $(top_srcdir)/m4.include/mc-subshell.m4 \
+ $(top_srcdir)/m4.include/mc-background.m4 \
+ $(top_srcdir)/m4.include/mc-ext2fs-attr.m4 \
+ $(top_srcdir)/m4.include/mc-glib.m4 \
+ $(top_srcdir)/m4.include/mc-vfs.m4 \
+ $(top_srcdir)/m4.include/vfs/rpc.m4 \
+ $(top_srcdir)/m4.include/vfs/socket.m4 \
+ $(top_srcdir)/m4.include/vfs/mc-vfs-extfs.m4 \
+ $(top_srcdir)/m4.include/vfs/mc-vfs-sfs.m4 \
+ $(top_srcdir)/m4.include/vfs/mc-vfs-ftp.m4 \
+ $(top_srcdir)/m4.include/vfs/mc-vfs-sftp.m4 \
+ $(top_srcdir)/m4.include/vfs/mc-vfs-fish.m4 \
+ $(top_srcdir)/m4.include/vfs/mc-vfs-undelfs.m4 \
+ $(top_srcdir)/m4.include/vfs/mc-vfs-tarfs.m4 \
+ $(top_srcdir)/m4.include/vfs/mc-vfs-cpiofs.m4 \
+ $(top_srcdir)/m4.include/mc-version.m4 \
+ $(top_srcdir)/m4.include/mc-tests.m4 \
+ $(top_srcdir)/m4.include/mc-i18n.m4 \
+ $(top_srcdir)/m4.include/mc-assert.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libmctty_la_LIBADD =
+am__libmctty_la_SOURCES_DIST = color-internal.c color-internal.h \
+ color.c color.h key.c key.h keyxdef.c mouse.c mouse.h \
+ tty-internal.c tty-internal.h tty.c tty.h win.c win.h \
+ x11conn.c x11conn.h color-ncurses.c tty-ncurses.c \
+ tty-ncurses.h color-slang.c color-slang.h tty-slang.c \
+ tty-slang.h
+@HAVE_TEXTMODE_X11_SUPPORT_TRUE@am__objects_1 = x11conn.lo
+am__objects_2 = color-internal.lo color.lo key.lo keyxdef.lo mouse.lo \
+ tty-internal.lo tty.lo win.lo $(am__objects_1)
+@USE_SCREEN_SLANG_FALSE@am__objects_3 = color-ncurses.lo \
+@USE_SCREEN_SLANG_FALSE@ tty-ncurses.lo
+@USE_SCREEN_SLANG_TRUE@am__objects_3 = color-slang.lo tty-slang.lo
+am_libmctty_la_OBJECTS = $(am__objects_2) $(am__objects_3)
+libmctty_la_OBJECTS = $(am_libmctty_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/color-internal.Plo \
+ ./$(DEPDIR)/color-ncurses.Plo ./$(DEPDIR)/color-slang.Plo \
+ ./$(DEPDIR)/color.Plo ./$(DEPDIR)/key.Plo \
+ ./$(DEPDIR)/keyxdef.Plo ./$(DEPDIR)/mouse.Plo \
+ ./$(DEPDIR)/tty-internal.Plo ./$(DEPDIR)/tty-ncurses.Plo \
+ ./$(DEPDIR)/tty-slang.Plo ./$(DEPDIR)/tty.Plo \
+ ./$(DEPDIR)/win.Plo ./$(DEPDIR)/x11conn.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libmctty_la_SOURCES)
+DIST_SOURCES = $(am__libmctty_la_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+COM_ERR_CFLAGS = @COM_ERR_CFLAGS@
+COM_ERR_LIBS = @COM_ERR_LIBS@
+CP1251 = @CP1251@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOC_LINGUAS = @DOC_LINGUAS@
+DOXYGEN_PAPER_SIZE = @DOXYGEN_PAPER_SIZE@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DX_CONFIG = @DX_CONFIG@
+DX_DOCDIR = @DX_DOCDIR@
+DX_DOT = @DX_DOT@
+DX_DOXYGEN = @DX_DOXYGEN@
+DX_DVIPS = @DX_DVIPS@
+DX_EGREP = @DX_EGREP@
+DX_ENV = @DX_ENV@
+DX_FLAG_chi = @DX_FLAG_chi@
+DX_FLAG_chm = @DX_FLAG_chm@
+DX_FLAG_doc = @DX_FLAG_doc@
+DX_FLAG_dot = @DX_FLAG_dot@
+DX_FLAG_html = @DX_FLAG_html@
+DX_FLAG_man = @DX_FLAG_man@
+DX_FLAG_pdf = @DX_FLAG_pdf@
+DX_FLAG_ps = @DX_FLAG_ps@
+DX_FLAG_rtf = @DX_FLAG_rtf@
+DX_FLAG_xml = @DX_FLAG_xml@
+DX_HHC = @DX_HHC@
+DX_LATEX = @DX_LATEX@
+DX_MAKEINDEX = @DX_MAKEINDEX@
+DX_PDFLATEX = @DX_PDFLATEX@
+DX_PERL = @DX_PERL@
+DX_PROJECT = @DX_PROJECT@
+E2P_CFLAGS = @E2P_CFLAGS@
+E2P_LIBS = @E2P_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+EXT2FS_CFLAGS = @EXT2FS_CFLAGS@
+EXT2FS_LIBS = @EXT2FS_LIBS@
+EXTHELPERSDIR = @EXTHELPERSDIR@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GMODULE_CFLAGS = @GMODULE_CFLAGS@
+GMODULE_LIBS = @GMODULE_LIBS@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+HAVE_FILECMD = @HAVE_FILECMD@
+HAVE_ZIPINFO = @HAVE_ZIPINFO@
+HAVE_nroff = @HAVE_nroff@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMC_RELEASE = @LIBMC_RELEASE@
+LIBMC_VERSION = @LIBMC_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSSH_CFLAGS = @LIBSSH_CFLAGS@
+LIBSSH_LIBS = @LIBSSH_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANDOC = @MANDOC@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAN_DATE = @MAN_DATE@
+MAN_FLAGS = @MAN_FLAGS@
+MAN_VERSION = @MAN_VERSION@
+MCLIBS = @MCLIBS@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PCRE_CFLAGS = @PCRE_CFLAGS@
+PCRE_LIBS = @PCRE_LIBS@
+PERL = @PERL@
+PERL_FOR_BUILD = @PERL_FOR_BUILD@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POSUB = @POSUB@
+PYTHON = @PYTHON@
+RANLIB = @RANLIB@
+RUBY = @RUBY@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SLANG_CFLAGS = @SLANG_CFLAGS@
+SLANG_LIBS = @SLANG_LIBS@
+STRIP = @STRIP@
+TESTS_LDFLAGS = @TESTS_LDFLAGS@
+UNZIP = @UNZIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+X11_WWW = @X11_WWW@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZIP = @ZIP@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libmctty.la
+@USE_SCREEN_SLANG_FALSE@TTY_SCREEN_SRC = \
+@USE_SCREEN_SLANG_FALSE@ color-ncurses.c \
+@USE_SCREEN_SLANG_FALSE@ tty-ncurses.c tty-ncurses.h
+
+@USE_SCREEN_SLANG_TRUE@TTY_SCREEN_SRC = \
+@USE_SCREEN_SLANG_TRUE@ color-slang.c color-slang.h \
+@USE_SCREEN_SLANG_TRUE@ tty-slang.c tty-slang.h
+
+TTY_SRC = color-internal.c color-internal.h color.c color.h key.c \
+ key.h keyxdef.c mouse.c mouse.h tty-internal.c tty-internal.h \
+ tty.c tty.h win.c win.h $(am__append_1)
+libmctty_la_SOURCES = $(TTY_SRC) $(TTY_SCREEN_SRC)
+AM_CPPFLAGS = -I$(top_srcdir) $(am__append_2) $(am__append_3)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/tty/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lib/tty/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libmctty.la: $(libmctty_la_OBJECTS) $(libmctty_la_DEPENDENCIES) $(EXTRA_libmctty_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libmctty_la_OBJECTS) $(libmctty_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/color-internal.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/color-ncurses.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/color-slang.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/color.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/key.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keyxdef.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mouse.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tty-internal.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tty-ncurses.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tty-slang.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tty.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x11conn.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/color-internal.Plo
+ -rm -f ./$(DEPDIR)/color-ncurses.Plo
+ -rm -f ./$(DEPDIR)/color-slang.Plo
+ -rm -f ./$(DEPDIR)/color.Plo
+ -rm -f ./$(DEPDIR)/key.Plo
+ -rm -f ./$(DEPDIR)/keyxdef.Plo
+ -rm -f ./$(DEPDIR)/mouse.Plo
+ -rm -f ./$(DEPDIR)/tty-internal.Plo
+ -rm -f ./$(DEPDIR)/tty-ncurses.Plo
+ -rm -f ./$(DEPDIR)/tty-slang.Plo
+ -rm -f ./$(DEPDIR)/tty.Plo
+ -rm -f ./$(DEPDIR)/win.Plo
+ -rm -f ./$(DEPDIR)/x11conn.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/color-internal.Plo
+ -rm -f ./$(DEPDIR)/color-ncurses.Plo
+ -rm -f ./$(DEPDIR)/color-slang.Plo
+ -rm -f ./$(DEPDIR)/color.Plo
+ -rm -f ./$(DEPDIR)/key.Plo
+ -rm -f ./$(DEPDIR)/keyxdef.Plo
+ -rm -f ./$(DEPDIR)/mouse.Plo
+ -rm -f ./$(DEPDIR)/tty-internal.Plo
+ -rm -f ./$(DEPDIR)/tty-ncurses.Plo
+ -rm -f ./$(DEPDIR)/tty-slang.Plo
+ -rm -f ./$(DEPDIR)/tty.Plo
+ -rm -f ./$(DEPDIR)/win.Plo
+ -rm -f ./$(DEPDIR)/x11conn.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/tty/color-internal.c b/lib/tty/color-internal.c
new file mode 100644
index 0000000..8db2b6c
--- /dev/null
+++ b/lib/tty/color-internal.c
@@ -0,0 +1,244 @@
+/*
+ Internal stuff of color setup
+
+ Copyright (C) 1994-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Andrew Borodin <aborodin@vmail.ru>, 2009
+ Slava Zanko <slavazanko@gmail.com>, 2009, 2013
+ Egmont Koblinger <egmont@gmail.com>, 2010
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file color-internal.c
+ * \brief Source: Internal stuff of color setup
+ */
+
+#include <config.h>
+
+#include <string.h> /* strcmp */
+
+#include "color.h" /* colors and attributes */
+#include "color-internal.h"
+
+/*** global variables ****************************************************************************/
+
+gboolean mc_tty_color_disable;
+
+/*** file scope macro definitions ****************************************************************/
+
+#define COLOR_INTENSITY 8
+
+/*** file scope type declarations ****************************************************************/
+
+typedef struct mc_tty_color_table_struct
+{
+ const char *name;
+ int value;
+} mc_tty_color_table_t;
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** file scope variables ************************************************************************/
+
+static mc_tty_color_table_t const color_table[] = {
+ {"black", COLOR_BLACK},
+ {"gray", COLOR_BLACK + COLOR_INTENSITY},
+ {"red", COLOR_RED},
+ {"brightred", COLOR_RED + COLOR_INTENSITY},
+ {"green", COLOR_GREEN},
+ {"brightgreen", COLOR_GREEN + COLOR_INTENSITY},
+ {"brown", COLOR_YELLOW},
+ {"yellow", COLOR_YELLOW + COLOR_INTENSITY},
+ {"blue", COLOR_BLUE},
+ {"brightblue", COLOR_BLUE + COLOR_INTENSITY},
+ {"magenta", COLOR_MAGENTA},
+ {"brightmagenta", COLOR_MAGENTA + COLOR_INTENSITY},
+ {"cyan", COLOR_CYAN},
+ {"brightcyan", COLOR_CYAN + COLOR_INTENSITY},
+ {"lightgray", COLOR_WHITE},
+ {"white", COLOR_WHITE + COLOR_INTENSITY},
+ {"default", -1}, /* default color of the terminal */
+ /* special colors */
+ {"A_REVERSE", SPEC_A_REVERSE},
+ {"A_BOLD", SPEC_A_BOLD},
+ {"A_BOLD_REVERSE", SPEC_A_BOLD_REVERSE},
+ {"A_UNDERLINE", SPEC_A_UNDERLINE},
+ /* End of list */
+ {NULL, 0}
+};
+
+static mc_tty_color_table_t const attributes_table[] = {
+ {"bold", A_BOLD},
+#ifdef A_ITALIC /* available since ncurses-5.9-20130831 / slang-pre2.3.0-107 */
+ {"italic", A_ITALIC},
+#endif /* A_ITALIC */
+ {"underline", A_UNDERLINE},
+ {"reverse", A_REVERSE},
+ {"blink", A_BLINK},
+ /* End of list */
+ {NULL, 0}
+};
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+static inline int
+parse_hex_digit (char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ c |= 0x20;
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+parse_256_or_true_color_name (const char *color_name)
+{
+ int i;
+ char dummy;
+
+ /* cppcheck-suppress invalidscanf */
+ if (sscanf (color_name, "color%d%c", &i, &dummy) == 1 && i >= 0 && i < 256)
+ {
+ return i;
+ }
+ /* cppcheck-suppress invalidscanf */
+ if (sscanf (color_name, "gray%d%c", &i, &dummy) == 1 && i >= 0 && i < 24)
+ {
+ return 232 + i;
+ }
+ if (strncmp (color_name, "rgb", 3) == 0 &&
+ color_name[3] >= '0' && color_name[3] < '6' &&
+ color_name[4] >= '0' && color_name[4] < '6' &&
+ color_name[5] >= '0' && color_name[5] < '6' && color_name[6] == '\0')
+ {
+ return 16 + 36 * (color_name[3] - '0') + 6 * (color_name[4] - '0') + (color_name[5] - '0');
+ }
+ if (color_name[0] == '#')
+ {
+ int len;
+
+ color_name++;
+ len = (int) strlen (color_name);
+ if (len == 3 || len == 6)
+ {
+ int h[6];
+
+ for (i = 0; i < len; i++)
+ {
+ h[i] = parse_hex_digit (color_name[i]);
+ if (h[i] == -1)
+ return -1;
+ }
+
+ if (i == 3)
+ i = (h[0] << 20) | (h[0] << 16) | (h[1] << 12) | (h[1] << 8) | (h[2] << 4) | h[2];
+ else
+ i = (h[0] << 20) | (h[1] << 16) | (h[2] << 12) | (h[3] << 8) | (h[4] << 4) | h[5];
+ return (1 << 24) | i;
+ }
+ }
+
+ return -1;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+const char *
+tty_color_get_name_by_index (int idx)
+{
+ int i;
+
+ /* Find the real English name of the first 16 colors, */
+ /* as well as the A_* special values. */
+ for (i = 0; color_table[i].name != NULL; i++)
+ if (idx == color_table[i].value)
+ return color_table[i].name;
+
+ /* Create and return the strings in "colorNNN" or "#rrggbb" format. */
+ if ((idx >= 16 && idx < 256) || (idx & (1 << 24)) != 0)
+ {
+ char name[9];
+
+ if (idx < 256)
+ sprintf (name, "color%d", idx);
+ else
+ sprintf (name, "#%06X", (unsigned int) idx & 0xFFFFFF);
+ return g_intern_string (name);
+ }
+ return "default";
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_color_get_index_by_name (const char *color_name)
+{
+ if (color_name != NULL)
+ {
+ size_t i;
+
+ for (i = 0; color_table[i].name != NULL; i++)
+ if (strcmp (color_name, color_table[i].name) == 0)
+ return color_table[i].value;
+ return parse_256_or_true_color_name (color_name);
+ }
+ return -1;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_attr_get_bits (const char *attrs)
+{
+ int attr_bits = 0;
+
+ if (attrs != NULL)
+ {
+ gchar **attr_list;
+ int i;
+
+ attr_list = g_strsplit (attrs, "+", -1);
+
+ for (i = 0; attr_list[i] != NULL; i++)
+ {
+ int j;
+
+ for (j = 0; attributes_table[j].name != NULL; j++)
+ {
+ if (strcmp (attr_list[i], attributes_table[j].name) == 0)
+ {
+ attr_bits |= attributes_table[j].value;
+ break;
+ }
+ }
+ }
+ g_strfreev (attr_list);
+ }
+ return attr_bits;
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/color-internal.h b/lib/tty/color-internal.h
new file mode 100644
index 0000000..dc85225
--- /dev/null
+++ b/lib/tty/color-internal.h
@@ -0,0 +1,61 @@
+
+/** \file color-internal.h
+ * \brief Header: Internal stuff of color setup
+ */
+
+#ifndef MC__COLOR_INTERNAL_H
+#define MC__COLOR_INTERNAL_H
+
+#include <sys/types.h> /* size_t */
+
+#include "lib/global.h"
+
+#ifdef HAVE_SLANG
+#include "tty-slang.h"
+#else
+#include "tty-ncurses.h"
+#endif /* HAVE_SLANG */
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+/*** enums ***************************************************************************************/
+
+/* *INDENT-OFF* */
+typedef enum {
+ SPEC_A_REVERSE = -100,
+ SPEC_A_BOLD = -101,
+ SPEC_A_BOLD_REVERSE = -102,
+ SPEC_A_UNDERLINE = -103
+} tty_special_color_t;
+/* *INDENT-ON* */
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+typedef struct mc_color_pair_struct
+{
+ int ifg;
+ int ibg;
+ int attr;
+ size_t pair_index;
+ gboolean is_temp;
+} tty_color_pair_t;
+
+/*** global variables defined in .c file *********************************************************/
+
+extern gboolean use_colors;
+extern gboolean mc_tty_color_disable;
+
+/*** declarations of public functions ************************************************************/
+
+const char *tty_color_get_name_by_index (int idx);
+int tty_color_get_index_by_name (const char *color_name);
+int tty_attr_get_bits (const char *attrs);
+
+void tty_color_init_lib (gboolean disable, gboolean force);
+void tty_color_deinit_lib (void);
+
+void tty_color_try_alloc_pair_lib (tty_color_pair_t * mc_color_pair);
+
+/*** inline functions ****************************************************************************/
+
+#endif /* MC__COLOR_INTERNAL_H */
diff --git a/lib/tty/color-ncurses.c b/lib/tty/color-ncurses.c
new file mode 100644
index 0000000..f01d697
--- /dev/null
+++ b/lib/tty/color-ncurses.c
@@ -0,0 +1,251 @@
+/*
+ Color setup for NCurses screen library
+
+ Copyright (C) 1994-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Andrew Borodin <aborodin@vmail.ru>, 2009
+ Slava Zanko <slavazanko@gmail.com>, 2010
+ Egmont Koblinger <egmont@gmail.com>, 2010
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file color-ncurses.c
+ * \brief Source: NCUrses-specific color setup
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h> /* size_t */
+
+#include "lib/global.h"
+
+#include "tty-ncurses.h"
+#include "color.h" /* variables */
+#include "color-internal.h"
+
+/*** global variables ****************************************************************************/
+
+/*** file scope macro definitions ****************************************************************/
+
+/*** file scope type declarations ****************************************************************/
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** file scope variables ************************************************************************/
+
+static GHashTable *mc_tty_color_color_pair_attrs = NULL;
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+static inline void
+mc_tty_color_attr_destroy_cb (gpointer data)
+{
+ g_free (data);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+mc_tty_color_save_attr (int color_pair, int color_attr)
+{
+ int *attr, *key;
+
+ attr = g_try_new0 (int, 1);
+ if (attr == NULL)
+ return;
+
+ key = g_try_new (int, 1);
+ if (key == NULL)
+ {
+ g_free (attr);
+ return;
+ }
+
+ *key = color_pair;
+ *attr = color_attr;
+
+ g_hash_table_replace (mc_tty_color_color_pair_attrs, (gpointer) key, (gpointer) attr);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+color_get_attr (int color_pair)
+{
+ int *fnd = NULL;
+
+ if (mc_tty_color_color_pair_attrs != NULL)
+ fnd = (int *) g_hash_table_lookup (mc_tty_color_color_pair_attrs, (gpointer) & color_pair);
+ return (fnd != NULL) ? *fnd : 0;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+mc_tty_color_pair_init_special (tty_color_pair_t * mc_color_pair,
+ int fg1, int bg1, int fg2, int bg2, int attr)
+{
+ if (has_colors () && !mc_tty_color_disable)
+ init_pair (mc_color_pair->pair_index, fg1, bg1);
+ else
+ init_pair (mc_color_pair->pair_index, fg2, bg2);
+ mc_tty_color_save_attr (mc_color_pair->pair_index, attr);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_color_init_lib (gboolean disable, gboolean force)
+{
+ (void) force;
+
+ if (has_colors () && !disable)
+ {
+ use_colors = TRUE;
+ start_color ();
+ use_default_colors ();
+ }
+
+ mc_tty_color_color_pair_attrs = g_hash_table_new_full
+ (g_int_hash, g_int_equal, mc_tty_color_attr_destroy_cb, mc_tty_color_attr_destroy_cb);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_color_deinit_lib (void)
+{
+ g_hash_table_destroy (mc_tty_color_color_pair_attrs);
+ mc_tty_color_color_pair_attrs = NULL;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_color_try_alloc_pair_lib (tty_color_pair_t * mc_color_pair)
+{
+ if (mc_color_pair->ifg <= (int) SPEC_A_REVERSE)
+ {
+ switch (mc_color_pair->ifg)
+ {
+ case SPEC_A_REVERSE:
+ mc_tty_color_pair_init_special (mc_color_pair,
+ COLOR_BLACK, COLOR_WHITE,
+ COLOR_BLACK, COLOR_WHITE | A_BOLD, A_REVERSE);
+ break;
+ case SPEC_A_BOLD:
+ mc_tty_color_pair_init_special (mc_color_pair,
+ COLOR_WHITE, COLOR_BLACK,
+ COLOR_WHITE, COLOR_BLACK, A_BOLD);
+ break;
+ case SPEC_A_BOLD_REVERSE:
+ mc_tty_color_pair_init_special (mc_color_pair,
+ COLOR_WHITE, COLOR_WHITE,
+ COLOR_WHITE, COLOR_WHITE, A_BOLD | A_REVERSE);
+ break;
+ case SPEC_A_UNDERLINE:
+ mc_tty_color_pair_init_special (mc_color_pair,
+ COLOR_WHITE, COLOR_BLACK,
+ COLOR_WHITE, COLOR_BLACK, A_UNDERLINE);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ int ifg, ibg, attr;
+
+ ifg = mc_color_pair->ifg;
+ ibg = mc_color_pair->ibg;
+ attr = mc_color_pair->attr;
+
+ /* In legacy color mode, change bright colors into bold */
+ if (!tty_use_256colors (NULL) && !tty_use_truecolors (NULL))
+ {
+ if (ifg >= 8 && ifg < 16)
+ {
+ ifg &= 0x07;
+ attr |= A_BOLD;
+ }
+
+ if (ibg >= 8 && ibg < 16)
+ {
+ ibg &= 0x07;
+ /* attr | = A_BOLD | A_REVERSE ; */
+ }
+ }
+
+ init_pair (mc_color_pair->pair_index, ifg, ibg);
+ mc_tty_color_save_attr (mc_color_pair->pair_index, attr);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_setcolor (int color)
+{
+ attrset (COLOR_PAIR (color) | color_get_attr (color));
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_lowlevel_setcolor (int color)
+{
+ tty_setcolor (color);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_set_normal_attrs (void)
+{
+ standend ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+gboolean
+tty_use_256colors (GError ** error)
+{
+ (void) error;
+
+ return (COLORS == 256);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+gboolean
+tty_use_truecolors (GError ** error)
+{
+ /* Not yet supported in ncurses */
+ g_set_error (error, MC_ERROR, -1, _("True color not supported with ncurses."));
+ return FALSE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/color-slang.c b/lib/tty/color-slang.c
new file mode 100644
index 0000000..5dd2663
--- /dev/null
+++ b/lib/tty/color-slang.c
@@ -0,0 +1,260 @@
+/*
+ Color setup for S_Lang screen library
+
+ Copyright (C) 1994-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Andrew Borodin <aborodin@vmail.ru>, 2009
+ Egmont Koblinger <egmont@gmail.com>, 2010
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file color-slang.c
+ * \brief Source: S-Lang-specific color setup
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h> /* size_t */
+
+#include "lib/global.h"
+#include "lib/util.h" /* whitespace() */
+
+#include "tty-slang.h"
+#include "color.h" /* variables */
+#include "color-internal.h"
+
+/*** global variables ****************************************************************************/
+
+/*** file scope macro definitions ****************************************************************/
+
+/*** file scope type declarations ****************************************************************/
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** file scope variables ************************************************************************/
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+has_colors (gboolean disable, gboolean force)
+{
+ mc_tty_color_disable = disable;
+
+ if (force || (getenv ("COLORTERM") != NULL))
+ SLtt_Use_Ansi_Colors = 1;
+
+ if (!mc_tty_color_disable)
+ {
+ const char *terminal = getenv ("TERM");
+ const size_t len = strlen (terminal);
+ char *cts = mc_global.tty.color_terminal_string;
+
+ /* check mc_global.tty.color_terminal_string */
+ while (*cts != '\0')
+ {
+ char *s;
+ size_t i = 0;
+
+ while (whitespace (*cts))
+ cts++;
+ s = cts;
+
+ while (*cts != '\0' && *cts != ',')
+ {
+ cts++;
+ i++;
+ }
+
+ if ((i != 0) && (i == len) && (strncmp (s, terminal, i) == 0))
+ SLtt_Use_Ansi_Colors = 1;
+
+ if (*cts == ',')
+ cts++;
+ }
+ }
+ return SLtt_Use_Ansi_Colors;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+mc_tty_color_pair_init_special (tty_color_pair_t * mc_color_pair,
+ const char *fg1, const char *bg1,
+ const char *fg2, const char *bg2, SLtt_Char_Type mask)
+{
+ if (SLtt_Use_Ansi_Colors != 0)
+ {
+ if (!mc_tty_color_disable)
+ {
+ SLtt_set_color (mc_color_pair->pair_index, (char *) "", (char *) fg1, (char *) bg1);
+ }
+ else
+ {
+ SLtt_set_color (mc_color_pair->pair_index, (char *) "", (char *) fg2, (char *) bg2);
+ }
+ }
+ else
+ {
+ SLtt_set_mono (mc_color_pair->pair_index, NULL, mask);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_color_init_lib (gboolean disable, gboolean force)
+{
+ /* FIXME: if S-Lang is used, has_colors() must be called regardless
+ of whether we are interested in its result */
+ if (has_colors (disable, force) && !disable)
+ {
+ use_colors = TRUE;
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_color_deinit_lib (void)
+{
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_color_try_alloc_pair_lib (tty_color_pair_t * mc_color_pair)
+{
+ if (mc_color_pair->ifg <= (int) SPEC_A_REVERSE)
+ {
+ switch (mc_color_pair->ifg)
+ {
+ case SPEC_A_REVERSE:
+ mc_tty_color_pair_init_special (mc_color_pair,
+ "black", "white", "black", "lightgray", SLTT_REV_MASK);
+ break;
+ case SPEC_A_BOLD:
+ mc_tty_color_pair_init_special (mc_color_pair,
+ "white", "black", "white", "black", SLTT_BOLD_MASK);
+ break;
+ case SPEC_A_BOLD_REVERSE:
+ mc_tty_color_pair_init_special (mc_color_pair,
+ "white", "white",
+ "white", "white", SLTT_BOLD_MASK | SLTT_REV_MASK);
+ break;
+ case SPEC_A_UNDERLINE:
+ mc_tty_color_pair_init_special (mc_color_pair,
+ "white", "black", "white", "black", SLTT_ULINE_MASK);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ const char *fg, *bg;
+
+ fg = tty_color_get_name_by_index (mc_color_pair->ifg);
+ bg = tty_color_get_name_by_index (mc_color_pair->ibg);
+ SLtt_set_color (mc_color_pair->pair_index, (char *) "", (char *) fg, (char *) bg);
+ SLtt_add_color_attribute (mc_color_pair->pair_index, mc_color_pair->attr);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_setcolor (int color)
+{
+ SLsmg_set_color (color);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/**
+ * Set colorpair by index, don't interpret S-Lang "emulated attributes"
+ */
+
+void
+tty_lowlevel_setcolor (int color)
+{
+ SLsmg_set_color (color & 0x7F);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_set_normal_attrs (void)
+{
+ SLsmg_normal_video ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+gboolean
+tty_use_256colors (GError ** error)
+{
+ gboolean ret;
+
+ ret = (SLtt_Use_Ansi_Colors && SLtt_tgetnum ((char *) "Co") == 256);
+
+ if (!ret)
+ g_set_error (error, MC_ERROR, -1,
+ _("Your terminal doesn't even seem to support 256 colors."));
+
+ return ret;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+gboolean
+tty_use_truecolors (GError ** error)
+{
+ char *colorterm;
+
+ /* True color is supported since slang-2.3.1 on 64-bit machines,
+ and expected to be supported from slang-3 on 32-bit machines:
+ http://lists.jedsoft.org/lists/slang-users/2016/0000014.html.
+ Check for sizeof (long) being 8, exactly as slang does. */
+ if (SLang_Version < 20301 || (sizeof (long) != 8 && SLang_Version < 30000))
+ {
+ g_set_error (error, MC_ERROR, -1, _("True color not supported in this slang version."));
+ return FALSE;
+ }
+
+ /* Duplicate slang's check so that we can pop up an error message
+ rather than silently use wrong colors. */
+ colorterm = getenv ("COLORTERM");
+ if (colorterm == NULL
+ || (strcmp (colorterm, "truecolor") != 0 && strcmp (colorterm, "24bit") != 0))
+ {
+ g_set_error (error, MC_ERROR, -1,
+ _("Set COLORTERM=truecolor if your terminal really supports true colors."));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/color-slang.h b/lib/tty/color-slang.h
new file mode 100644
index 0000000..a1a8d55
--- /dev/null
+++ b/lib/tty/color-slang.h
@@ -0,0 +1,56 @@
+
+/** \file color-slang.h
+ * \brief Header: S-Lang-specific color setup
+ */
+
+#ifndef MC__COLOR_SLANG_H
+#define MC__COLOR_SLANG_H
+
+#include "tty-slang.h" /* S-Lang headers */
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+/* When using Slang with color, we have all the indexes free but
+ * those defined here (A_BOLD, A_ITALIC, A_UNDERLINE, A_REVERSE, A_BLINK)
+ */
+
+#ifndef A_BOLD
+#define A_BOLD SLTT_BOLD_MASK
+#endif /* A_BOLD */
+#ifdef SLTT_ITALIC_MASK /* available since slang-pre2.3.0-107 */
+#ifndef A_ITALIC
+#define A_ITALIC SLTT_ITALIC_MASK
+#endif /* A_ITALIC */
+#endif /* SLTT_ITALIC_MASK */
+#ifndef A_UNDERLINE
+#define A_UNDERLINE SLTT_ULINE_MASK
+#endif /* A_UNDERLINE */
+#ifndef A_REVERSE
+#define A_REVERSE SLTT_REV_MASK
+#endif /* A_REVERSE */
+#ifndef A_BLINK
+#define A_BLINK SLTT_BLINK_MASK
+#endif /* A_BLINK */
+
+/*** enums ***************************************************************************************/
+
+enum
+{
+ COLOR_BLACK = 0,
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW,
+ COLOR_BLUE,
+ COLOR_MAGENTA,
+ COLOR_CYAN,
+ COLOR_WHITE
+};
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+/*** global variables defined in .c file *********************************************************/
+
+/*** declarations of public functions ************************************************************/
+
+/*** inline functions ****************************************************************************/
+#endif /* MC_COLOR_SLANG_H */
diff --git a/lib/tty/color.c b/lib/tty/color.c
new file mode 100644
index 0000000..c79e13a
--- /dev/null
+++ b/lib/tty/color.c
@@ -0,0 +1,244 @@
+/*
+ Color setup.
+ Interface functions.
+
+ Copyright (C) 1994-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Andrew Borodin <aborodin@vmail.ru>, 2009
+ Slava Zanko <slavazanko@gmail.com>, 2009
+ Egmont Koblinger <egmont@gmail.com>, 2010
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file color.c
+ * \brief Source: color setup
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h> /* size_t */
+
+#include "lib/global.h"
+
+#include "tty.h"
+#include "color.h"
+
+#include "color-internal.h"
+
+/*** global variables ****************************************************************************/
+
+static char *tty_color_defaults__fg = NULL;
+static char *tty_color_defaults__bg = NULL;
+static char *tty_color_defaults__attrs = NULL;
+
+/* Set if we are actually using colors */
+gboolean use_colors = FALSE;
+
+/*** file scope macro definitions ****************************************************************/
+
+/*** file scope type declarations ****************************************************************/
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** file scope variables ************************************************************************/
+
+static GHashTable *mc_tty_color__hashtable = NULL;
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+static gboolean
+tty_color_free_condition_cb (gpointer key, gpointer value, gpointer user_data)
+{
+ tty_color_pair_t *mc_color_pair = (tty_color_pair_t *) value;
+ gboolean is_temp_color;
+
+ (void) key;
+
+ is_temp_color = user_data != NULL;
+ return (mc_color_pair->is_temp == is_temp_color);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+tty_color_free_all (gboolean is_temp_color)
+{
+ g_hash_table_foreach_remove (mc_tty_color__hashtable, tty_color_free_condition_cb,
+ is_temp_color ? GSIZE_TO_POINTER (1) : NULL);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static gboolean
+tty_color_get_next_cpn_cb (gpointer key, gpointer value, gpointer user_data)
+{
+ tty_color_pair_t *mc_color_pair = (tty_color_pair_t *) value;
+ size_t cp = GPOINTER_TO_SIZE (user_data);
+
+ (void) key;
+
+ return (cp == mc_color_pair->pair_index);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static size_t
+tty_color_get_next__color_pair_number (void)
+{
+ size_t cp_count, cp;
+
+ cp_count = g_hash_table_size (mc_tty_color__hashtable);
+ for (cp = 0; cp < cp_count; cp++)
+ if (g_hash_table_find (mc_tty_color__hashtable, tty_color_get_next_cpn_cb,
+ GSIZE_TO_POINTER (cp)) == NULL)
+ break;
+
+ return cp;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_init_colors (gboolean disable, gboolean force)
+{
+ tty_color_init_lib (disable, force);
+ mc_tty_color__hashtable = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_colors_done (void)
+{
+ tty_color_deinit_lib ();
+ g_free (tty_color_defaults__fg);
+ g_free (tty_color_defaults__bg);
+ g_free (tty_color_defaults__attrs);
+
+ g_hash_table_destroy (mc_tty_color__hashtable);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+gboolean
+tty_use_colors (void)
+{
+ return use_colors;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_try_alloc_color_pair2 (const char *fg, const char *bg, const char *attrs,
+ gboolean is_temp_color)
+{
+ gchar *color_pair;
+ tty_color_pair_t *mc_color_pair;
+ int ifg, ibg, attr;
+
+ if (fg == NULL || strcmp (fg, "base") == 0)
+ fg = tty_color_defaults__fg;
+ if (bg == NULL || strcmp (bg, "base") == 0)
+ bg = tty_color_defaults__bg;
+ if (attrs == NULL || strcmp (attrs, "base") == 0)
+ attrs = tty_color_defaults__attrs;
+
+ ifg = tty_color_get_index_by_name (fg);
+ ibg = tty_color_get_index_by_name (bg);
+ attr = tty_attr_get_bits (attrs);
+
+ color_pair = g_strdup_printf ("%d.%d.%d", ifg, ibg, attr);
+ if (color_pair == NULL)
+ return 0;
+
+ mc_color_pair =
+ (tty_color_pair_t *) g_hash_table_lookup (mc_tty_color__hashtable, (gpointer) color_pair);
+
+ if (mc_color_pair != NULL)
+ {
+ g_free (color_pair);
+ return mc_color_pair->pair_index;
+ }
+
+ mc_color_pair = g_try_new0 (tty_color_pair_t, 1);
+ if (mc_color_pair == NULL)
+ {
+ g_free (color_pair);
+ return 0;
+ }
+
+ mc_color_pair->is_temp = is_temp_color;
+ mc_color_pair->ifg = ifg;
+ mc_color_pair->ibg = ibg;
+ mc_color_pair->attr = attr;
+ mc_color_pair->pair_index = tty_color_get_next__color_pair_number ();
+
+ tty_color_try_alloc_pair_lib (mc_color_pair);
+
+ g_hash_table_insert (mc_tty_color__hashtable, (gpointer) color_pair, (gpointer) mc_color_pair);
+
+ return mc_color_pair->pair_index;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_try_alloc_color_pair (const char *fg, const char *bg, const char *attrs)
+{
+ return tty_try_alloc_color_pair2 (fg, bg, attrs, TRUE);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_color_free_all_tmp (void)
+{
+ tty_color_free_all (TRUE);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_color_free_all_non_tmp (void)
+{
+ tty_color_free_all (FALSE);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_color_set_defaults (const char *fgcolor, const char *bgcolor, const char *attrs)
+{
+ g_free (tty_color_defaults__fg);
+ g_free (tty_color_defaults__bg);
+ g_free (tty_color_defaults__attrs);
+
+ tty_color_defaults__fg = g_strdup (fgcolor);
+ tty_color_defaults__bg = g_strdup (bgcolor);
+ tty_color_defaults__attrs = g_strdup (attrs);
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/color.h b/lib/tty/color.h
new file mode 100644
index 0000000..583cce3
--- /dev/null
+++ b/lib/tty/color.h
@@ -0,0 +1,54 @@
+/** \file color.h
+ * \brief Header: color setup
+ *
+ * PLEASE FORGOT ABOUT tty/color.h!
+ * Use skin engine for getting needed color pairs.
+ *
+ * edit/syntax.c may use this file directly, I'm agree. :)
+ *
+ */
+
+#ifndef MC__COLOR_H
+#define MC__COLOR_H
+
+#include "lib/global.h" /* glib.h */
+
+#ifdef HAVE_SLANG
+#include "color-slang.h"
+#else
+#include "tty-ncurses.h"
+#endif
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+/*** enums ***************************************************************************************/
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+/*** global variables defined in .c file *********************************************************/
+
+/*** declarations of public functions ************************************************************/
+
+void tty_init_colors (gboolean disable, gboolean force);
+void tty_colors_done (void);
+
+gboolean tty_use_colors (void);
+int tty_try_alloc_color_pair (const char *fg, const char *bg, const char *attrs);
+int tty_try_alloc_color_pair2 (const char *fg, const char *bg, const char *attrs,
+ gboolean is_temp_color);
+
+void tty_color_free_all_tmp (void);
+void tty_color_free_all_non_tmp (void);
+
+void tty_setcolor (int color);
+void tty_lowlevel_setcolor (int color);
+void tty_set_normal_attrs (void);
+
+void tty_color_set_defaults (const char *fgcolor, const char *bgcolor, const char *attrs);
+
+extern gboolean tty_use_256colors (GError ** error);
+extern gboolean tty_use_truecolors (GError ** error);
+
+/*** inline functions ****************************************************************************/
+
+#endif /* MC__COLOR_H */
diff --git a/lib/tty/key.c b/lib/tty/key.c
new file mode 100644
index 0000000..5671666
--- /dev/null
+++ b/lib/tty/key.c
@@ -0,0 +1,2252 @@
+/*
+ Keyboard support routines.
+
+ Copyright (C) 1994-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Miguel de Icaza, 1994, 1995
+ Janne Kukonlehto, 1994, 1995
+ Jakub Jelinek, 1995
+ Norbert Warmuth, 1997
+ Denys Vlasenko <vda.linux@googlemail.com>, 2013
+ Slava Zanko <slavazanko@gmail.com>, 2013
+ Egmont Koblinger <egmont@gmail.com>, 2013
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file key.c
+ * \brief Source: keyboard support routines
+ */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#else
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include "lib/global.h"
+
+#include "lib/vfs/vfs.h"
+
+#include "tty.h"
+#include "tty-internal.h" /* mouse_enabled */
+#include "mouse.h"
+#include "key.h"
+
+#include "lib/widget.h" /* mc_refresh() */
+
+#ifdef HAVE_TEXTMODE_X11_SUPPORT
+#include "x11conn.h"
+#endif
+
+#ifdef __linux__
+#if defined(__GLIBC__) && (__GLIBC__ < 2)
+#include <linux/termios.h> /* TIOCLINUX */
+#else
+#include <termios.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#endif /* __linux__ */
+
+#ifdef __CYGWIN__
+#include <termios.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#endif /* __CYGWIN__ */
+
+#ifdef __QNXNTO__
+#include <dlfcn.h>
+#include <Ph.h>
+#include <sys/dcmd_chr.h>
+#endif /* __QNXNTO__ */
+
+/*** global variables ****************************************************************************/
+
+int mou_auto_repeat = 100; /* ms */
+int double_click_speed = 250; /* ms */
+gboolean old_esc_mode = TRUE;
+/* timeout for old_esc_mode in usec */
+int old_esc_mode_timeout = G_USEC_PER_SEC; /* us, settable via env */
+gboolean use_8th_bit_as_meta = FALSE;
+
+gboolean bracketed_pasting_in_progress = FALSE;
+
+/* This table is a mapping between names and the constants we use
+ * We use this to allow users to define alternate definitions for
+ * certain keys that may be missing from the terminal database
+ */
+const key_code_name_t key_name_conv_tab[] = {
+ {ESC_CHAR, "escape", N_("Escape"), "Esc"},
+ /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
+ to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
+ {KEY_F (1), "f1", N_("Function key 1"), "F1"},
+ {KEY_F (2), "f2", N_("Function key 2"), "F2"},
+ {KEY_F (3), "f3", N_("Function key 3"), "F3"},
+ {KEY_F (4), "f4", N_("Function key 4"), "F4"},
+ {KEY_F (5), "f5", N_("Function key 5"), "F5"},
+ {KEY_F (6), "f6", N_("Function key 6"), "F6"},
+ {KEY_F (7), "f7", N_("Function key 7"), "F7"},
+ {KEY_F (8), "f8", N_("Function key 8"), "F8"},
+ {KEY_F (9), "f9", N_("Function key 9"), "F9"},
+ {KEY_F (10), "f10", N_("Function key 10"), "F10"},
+ {KEY_F (11), "f11", N_("Function key 11"), "F11"},
+ {KEY_F (12), "f12", N_("Function key 12"), "F12"},
+ {KEY_F (13), "f13", N_("Function key 13"), "F13"},
+ {KEY_F (14), "f14", N_("Function key 14"), "F14"},
+ {KEY_F (15), "f15", N_("Function key 15"), "F15"},
+ {KEY_F (16), "f16", N_("Function key 16"), "F16"},
+ {KEY_F (17), "f17", N_("Function key 17"), "F17"},
+ {KEY_F (18), "f18", N_("Function key 18"), "F18"},
+ {KEY_F (19), "f19", N_("Function key 19"), "F19"},
+ {KEY_F (20), "f20", N_("Function key 20"), "F20"},
+ {ALT ('\t'), "complete", N_("Completion/M-tab"), "Meta-Tab"},
+ {KEY_BTAB, "backtab", N_("BackTab/S-tab"), "Shift-Tab"},
+ {KEY_BACKSPACE, "backspace", N_("Backspace"), "Backspace"},
+ {KEY_UP, "up", N_("Up arrow"), "Up"},
+ {KEY_DOWN, "down", N_("Down arrow"), "Down"},
+ {KEY_LEFT, "left", N_("Left arrow"), "Left"},
+ {KEY_RIGHT, "right", N_("Right arrow"), "Right"},
+ {KEY_IC, "insert", N_("Insert"), "Ins"},
+ {KEY_DC, "delete", N_("Delete"), "Del"},
+ {KEY_HOME, "home", N_("Home"), "Home"},
+ {KEY_END, "end", N_("End key"), "End"},
+ {KEY_PPAGE, "pgup", N_("Page Up"), "PgUp"},
+ {KEY_NPAGE, "pgdn", N_("Page Down"), "PgDn"},
+ {(int) '/', "kpslash", N_("/ on keypad"), "/"},
+ {KEY_KP_MULTIPLY, "kpasterisk", N_("* on keypad"), "*"},
+ {KEY_KP_SUBTRACT, "kpminus", N_("- on keypad"), "-"},
+ {KEY_KP_ADD, "kpplus", N_("+ on keypad"), "+"},
+
+ /* From here on, these won't be shown in Learn keys (no space) */
+ {KEY_LEFT, "kpleft", N_("Left arrow keypad"), "Left"},
+ {KEY_RIGHT, "kpright", N_("Right arrow keypad"), "Right"},
+ {KEY_UP, "kpup", N_("Up arrow keypad"), "Up"},
+ {KEY_DOWN, "kpdown", N_("Down arrow keypad"), "Down"},
+ {KEY_HOME, "kphome", N_("Home on keypad"), "Home"},
+ {KEY_END, "kpend", N_("End on keypad"), "End"},
+ {KEY_NPAGE, "kpnpage", N_("Page Down keypad"), "PgDn"},
+ {KEY_PPAGE, "kpppage", N_("Page Up keypad"), "PgUp"},
+ {KEY_IC, "kpinsert", N_("Insert on keypad"), "Ins"},
+ {KEY_DC, "kpdelete", N_("Delete on keypad"), "Del"},
+ {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
+ {KEY_F (21), "f21", N_("Function key 21"), "F21"},
+ {KEY_F (22), "f22", N_("Function key 22"), "F22"},
+ {KEY_F (23), "f23", N_("Function key 23"), "F23"},
+ {KEY_F (24), "f24", N_("Function key 24"), "F24"},
+ {KEY_A1, "a1", N_("A1 key"), "A1"},
+ {KEY_C1, "c1", N_("C1 key"), "C1"},
+
+ /* Alternative label */
+ {ESC_CHAR, "esc", N_("Escape"), "Esc"},
+ {KEY_BACKSPACE, "bs", N_("Backspace"), "Bakspace"},
+ {KEY_IC, "ins", N_("Insert"), "Ins"},
+ {KEY_DC, "del", N_("Delete"), "Del"},
+ {(int) '*', "asterisk", N_("Asterisk"), "*"},
+ {(int) '-', "minus", N_("Minus"), "-"},
+ {(int) '+', "plus", N_("Plus"), "+"},
+ {(int) '.', "dot", N_("Dot"), "."},
+ {(int) '<', "lt", N_("Less than"), "<"},
+ {(int) '>', "gt", N_("Great than"), ">"},
+ {(int) '=', "equal", N_("Equal"), "="},
+ {(int) ',', "comma", N_("Comma"), ","},
+ {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
+ {(int) ':', "colon", N_("Colon"), ":"},
+ {(int) ';', "semicolon", N_("Semicolon"), ";"},
+ {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
+ {(int) '?', "question", N_("Question mark"), "?"},
+ {(int) '&', "ampersand", N_("Ampersand"), "&"},
+ {(int) '$', "dollar", N_("Dollar sign"), "$"},
+ {(int) '"', "quota", N_("Quotation mark"), "\""},
+ {(int) '%', "percent", N_("Percent sign"), "%"},
+ {(int) '^', "caret", N_("Caret"), "^"},
+ {(int) '~', "tilda", N_("Tilda"), "~"},
+ {(int) '`', "prime", N_("Prime"), "`"},
+ {(int) '_', "underline", N_("Underline"), "_"},
+ {(int) '_', "understrike", N_("Understrike"), "_"},
+ {(int) '|', "pipe", N_("Pipe"), "|"},
+ {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
+ {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
+ {(int) '[', "lbracket", N_("Left bracket"), "["},
+ {(int) ']', "rbracket", N_("Right bracket"), "]"},
+ {(int) '{', "lbrace", N_("Left brace"), "{"},
+ {(int) '}', "rbrace", N_("Right brace"), "}"},
+ {(int) '\n', "enter", N_("Enter"), "Enter"},
+ {(int) '\t', "tab", N_("Tab key"), "Tab"},
+ {(int) ' ', "space", N_("Space key"), "Space"},
+ {(int) '/', "slash", N_("Slash key"), "/"},
+ {(int) '\\', "backslash", N_("Backslash key"), "\\"},
+ {(int) '#', "number", N_("Number sign #"), "#"},
+ {(int) '#', "hash", N_("Number sign #"), "#"},
+ /* TRANSLATORS: Please translate as in "at sign" (@). */
+ {(int) '@', "at", N_("At sign"), "@"},
+
+ /* meta keys */
+ {KEY_M_CTRL, "control", N_("Ctrl"), "C"},
+ {KEY_M_CTRL, "ctrl", N_("Ctrl"), "C"},
+ {KEY_M_ALT, "meta", N_("Alt"), "M"},
+ {KEY_M_ALT, "alt", N_("Alt"), "M"},
+ {KEY_M_ALT, "ralt", N_("Alt"), "M"},
+ {KEY_M_SHIFT, "shift", N_("Shift"), "S"},
+
+ {0, NULL, NULL, NULL}
+};
+
+/*** file scope macro definitions ****************************************************************/
+
+#define MC_USEC_PER_MSEC 1000
+
+/* The maximum sequence length (32 + null terminator) */
+#define SEQ_BUFFER_LEN 33
+
+/*** file scope type declarations ****************************************************************/
+
+/* Linux console keyboard modifiers */
+typedef enum
+{
+ SHIFT_PRESSED = (1 << 0),
+ ALTR_PRESSED = (1 << 1),
+ CONTROL_PRESSED = (1 << 2),
+ ALTL_PRESSED = (1 << 3)
+} mod_pressed_t;
+
+typedef struct key_def
+{
+ char ch; /* Holds the matching char code */
+ int code; /* The code returned, valid if child == NULL */
+ struct key_def *next;
+ struct key_def *child; /* sequence continuation */
+ int action; /* optional action to be done. Now used only
+ to mark that we are just after the first
+ Escape */
+} key_def;
+
+typedef struct
+{
+ int code;
+ const char *seq;
+ int action;
+} key_define_t;
+
+/* File descriptor monitoring add/remove routines */
+typedef struct
+{
+ int fd;
+ select_fn callback;
+ void *info;
+} select_t;
+
+typedef enum KeySortType
+{
+ KEY_NOSORT = 0,
+ KEY_SORTBYNAME,
+ KEY_SORTBYCODE
+} KeySortType;
+
+#ifdef __QNXNTO__
+typedef int (*ph_dv_f) (void *, void *);
+typedef int (*ph_ov_f) (void *);
+typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *);
+#endif
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** file scope variables ************************************************************************/
+
+static key_define_t mc_default_keys[] = {
+ {ESC_CHAR, ESC_STR, MCKEY_ESCAPE},
+ {ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION},
+ {MCKEY_BRACKETED_PASTING_START, ESC_STR "[200~", MCKEY_NOACTION},
+ {MCKEY_BRACKETED_PASTING_END, ESC_STR "[201~", MCKEY_NOACTION},
+ {0, NULL, MCKEY_NOACTION},
+};
+
+/* Broken terminfo and termcap databases on xterminals */
+static key_define_t xterm_key_defines[] = {
+ {KEY_F (1), ESC_STR "OP", MCKEY_NOACTION},
+ {KEY_F (2), ESC_STR "OQ", MCKEY_NOACTION},
+ {KEY_F (3), ESC_STR "OR", MCKEY_NOACTION},
+ {KEY_F (4), ESC_STR "OS", MCKEY_NOACTION},
+ {KEY_F (1), ESC_STR "[11~", MCKEY_NOACTION},
+ {KEY_F (2), ESC_STR "[12~", MCKEY_NOACTION},
+ {KEY_F (3), ESC_STR "[13~", MCKEY_NOACTION},
+ {KEY_F (4), ESC_STR "[14~", MCKEY_NOACTION},
+ {KEY_F (5), ESC_STR "[15~", MCKEY_NOACTION},
+ {KEY_F (6), ESC_STR "[17~", MCKEY_NOACTION},
+ {KEY_F (7), ESC_STR "[18~", MCKEY_NOACTION},
+ {KEY_F (8), ESC_STR "[19~", MCKEY_NOACTION},
+ {KEY_F (9), ESC_STR "[20~", MCKEY_NOACTION},
+ {KEY_F (10), ESC_STR "[21~", MCKEY_NOACTION},
+
+ /* old xterm Shift-arrows */
+ {KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION},
+
+ /* new xterm Shift-arrows */
+ {KEY_M_SHIFT | KEY_UP, ESC_STR "[1;2A", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[1;2B", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[1;2C", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[1;2D", MCKEY_NOACTION},
+
+ /* more xterm keys with modifiers */
+ {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_IC, ESC_STR "[2;5~", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_DC, ESC_STR "[3;5~", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_HOME, ESC_STR "[1;5H", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_END, ESC_STR "[1;5F", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_HOME, ESC_STR "[1;2H", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_END, ESC_STR "[1;2F", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_UP, ESC_STR "[1;5A", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;5B", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;5C", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;5D", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_IC, ESC_STR "[2;2~", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_DC, ESC_STR "[3;2~", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[1;6A", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;6B", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;6C", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;6D", MCKEY_NOACTION},
+ {KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION},
+
+ /* putty */
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[[1;6A", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[[1;6B", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[[1;6C", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[[1;6D", MCKEY_NOACTION},
+
+ /* putty alt-arrow keys */
+ /* removed as source esc esc esc trouble */
+ /*
+ { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
+ { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
+ { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
+ { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
+ { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
+ { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
+ { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
+ { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
+
+ { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
+ { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
+ { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
+ { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
+
+ { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
+ { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
+ { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
+ { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
+ */
+ /* xterm alt-arrow keys */
+ {KEY_M_ALT | KEY_UP, ESC_STR "[1;3A", MCKEY_NOACTION},
+ {KEY_M_ALT | KEY_DOWN, ESC_STR "[1;3B", MCKEY_NOACTION},
+ {KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;3C", MCKEY_NOACTION},
+ {KEY_M_ALT | KEY_LEFT, ESC_STR "[1;3D", MCKEY_NOACTION},
+ {KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;3~", MCKEY_NOACTION},
+ {KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;3~", MCKEY_NOACTION},
+ {KEY_M_ALT | KEY_HOME, ESC_STR "[1~", MCKEY_NOACTION},
+ {KEY_M_ALT | KEY_END, ESC_STR "[4~", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR "[1;7A", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;7B", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;7C", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;7D", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;7~", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;7~", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR "OH", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR "OF", MCKEY_NOACTION},
+
+ {KEY_M_SHIFT | KEY_M_ALT | KEY_UP, ESC_STR "[1;4A", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;4B", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;4C", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;4D", MCKEY_NOACTION},
+
+ /* rxvt keys with modifiers */
+ {KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_UP, ESC_STR "Oa", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_DOWN, ESC_STR "Ob", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_RIGHT, ESC_STR "Oc", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_LEFT, ESC_STR "Od", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_IC, ESC_STR "[2^", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_DC, ESC_STR "[3^", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_DC, ESC_STR "[3$", MCKEY_NOACTION},
+
+ /* konsole keys with modifiers */
+ {KEY_M_SHIFT | KEY_HOME, ESC_STR "O2H", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_END, ESC_STR "O2F", MCKEY_NOACTION},
+
+ /* gnome-terminal */
+ {KEY_M_SHIFT | KEY_UP, ESC_STR "[2A", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[2B", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[2C", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[2D", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_UP, ESC_STR "[5A", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_DOWN, ESC_STR "[5B", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[5C", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_LEFT, ESC_STR "[5D", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[6A", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[6B", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[6C", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[6D", MCKEY_NOACTION},
+
+ /* gnome-terminal - application mode */
+ {KEY_M_CTRL | KEY_UP, ESC_STR "O5A", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_DOWN, ESC_STR "O5B", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_RIGHT, ESC_STR "O5C", MCKEY_NOACTION},
+ {KEY_M_CTRL | KEY_LEFT, ESC_STR "O5D", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "O6A", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "O6B", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "O6C", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "O6D", MCKEY_NOACTION},
+
+ /* iTerm */
+ {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[5;2~", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[6;2~", MCKEY_NOACTION},
+
+ /* putty */
+ {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[[5;53~", MCKEY_NOACTION},
+ {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[[6;53~", MCKEY_NOACTION},
+
+ /* keypad keys */
+ {KEY_IC, ESC_STR "Op", MCKEY_NOACTION},
+ {KEY_DC, ESC_STR "On", MCKEY_NOACTION},
+ {'/', ESC_STR "Oo", MCKEY_NOACTION},
+ {'\n', ESC_STR "OM", MCKEY_NOACTION},
+
+ {0, NULL, MCKEY_NOACTION},
+};
+
+/* qansi-m terminals have a much more key combinations,
+ which are undefined in termcap/terminfo */
+static key_define_t qansi_key_defines[] = {
+ /* qansi-m terminal */
+ {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[u", MCKEY_NOACTION}, /* Ctrl-PgDown */
+ {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[v", MCKEY_NOACTION}, /* Ctrl-PgUp */
+ {KEY_M_CTRL | KEY_HOME, ESC_STR "[h", MCKEY_NOACTION}, /* Ctrl-Home */
+ {KEY_M_CTRL | KEY_END, ESC_STR "[y", MCKEY_NOACTION}, /* Ctrl-End */
+ {KEY_M_CTRL | KEY_IC, ESC_STR "[`", MCKEY_NOACTION}, /* Ctrl-Insert */
+ {KEY_M_CTRL | KEY_DC, ESC_STR "[p", MCKEY_NOACTION}, /* Ctrl-Delete */
+ {KEY_M_CTRL | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION}, /* Ctrl-Left */
+ {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION}, /* Ctrl-Right */
+ {KEY_M_CTRL | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION}, /* Ctrl-Down */
+ {KEY_M_CTRL | KEY_UP, ESC_STR "[a", MCKEY_NOACTION}, /* Ctrl-Up */
+ {KEY_M_CTRL | KEY_KP_ADD, ESC_STR "[s", MCKEY_NOACTION}, /* Ctrl-Gr-Plus */
+ {KEY_M_CTRL | KEY_KP_SUBTRACT, ESC_STR "[t", MCKEY_NOACTION}, /* Ctrl-Gr-Minus */
+ {KEY_M_CTRL | '\t', ESC_STR "[z", MCKEY_NOACTION}, /* Ctrl-Tab */
+ {KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION}, /* Shift-Tab */
+ {KEY_M_CTRL | KEY_F (1), ESC_STR "[1~", MCKEY_NOACTION}, /* Ctrl-F1 */
+ {KEY_M_CTRL | KEY_F (2), ESC_STR "[2~", MCKEY_NOACTION}, /* Ctrl-F2 */
+ {KEY_M_CTRL | KEY_F (3), ESC_STR "[3~", MCKEY_NOACTION}, /* Ctrl-F3 */
+ {KEY_M_CTRL | KEY_F (4), ESC_STR "[4~", MCKEY_NOACTION}, /* Ctrl-F4 */
+ {KEY_M_CTRL | KEY_F (5), ESC_STR "[5~", MCKEY_NOACTION}, /* Ctrl-F5 */
+ {KEY_M_CTRL | KEY_F (6), ESC_STR "[6~", MCKEY_NOACTION}, /* Ctrl-F6 */
+ {KEY_M_CTRL | KEY_F (7), ESC_STR "[7~", MCKEY_NOACTION}, /* Ctrl-F7 */
+ {KEY_M_CTRL | KEY_F (8), ESC_STR "[8~", MCKEY_NOACTION}, /* Ctrl-F8 */
+ {KEY_M_CTRL | KEY_F (9), ESC_STR "[9~", MCKEY_NOACTION}, /* Ctrl-F9 */
+ {KEY_M_CTRL | KEY_F (10), ESC_STR "[10~", MCKEY_NOACTION}, /* Ctrl-F10 */
+ {KEY_M_CTRL | KEY_F (11), ESC_STR "[11~", MCKEY_NOACTION}, /* Ctrl-F11 */
+ {KEY_M_CTRL | KEY_F (12), ESC_STR "[12~", MCKEY_NOACTION}, /* Ctrl-F12 */
+ {KEY_M_ALT | KEY_F (1), ESC_STR "[17~", MCKEY_NOACTION}, /* Alt-F1 */
+ {KEY_M_ALT | KEY_F (2), ESC_STR "[18~", MCKEY_NOACTION}, /* Alt-F2 */
+ {KEY_M_ALT | KEY_F (3), ESC_STR "[19~", MCKEY_NOACTION}, /* Alt-F3 */
+ {KEY_M_ALT | KEY_F (4), ESC_STR "[20~", MCKEY_NOACTION}, /* Alt-F4 */
+ {KEY_M_ALT | KEY_F (5), ESC_STR "[21~", MCKEY_NOACTION}, /* Alt-F5 */
+ {KEY_M_ALT | KEY_F (6), ESC_STR "[22~", MCKEY_NOACTION}, /* Alt-F6 */
+ {KEY_M_ALT | KEY_F (7), ESC_STR "[23~", MCKEY_NOACTION}, /* Alt-F7 */
+ {KEY_M_ALT | KEY_F (8), ESC_STR "[24~", MCKEY_NOACTION}, /* Alt-F8 */
+ {KEY_M_ALT | KEY_F (9), ESC_STR "[25~", MCKEY_NOACTION}, /* Alt-F9 */
+ {KEY_M_ALT | KEY_F (10), ESC_STR "[26~", MCKEY_NOACTION}, /* Alt-F10 */
+ {KEY_M_ALT | KEY_F (11), ESC_STR "[27~", MCKEY_NOACTION}, /* Alt-F11 */
+ {KEY_M_ALT | KEY_F (12), ESC_STR "[28~", MCKEY_NOACTION}, /* Alt-F12 */
+ {KEY_M_ALT | 'a', ESC_STR "Na", MCKEY_NOACTION}, /* Alt-a */
+ {KEY_M_ALT | 'b', ESC_STR "Nb", MCKEY_NOACTION}, /* Alt-b */
+ {KEY_M_ALT | 'c', ESC_STR "Nc", MCKEY_NOACTION}, /* Alt-c */
+ {KEY_M_ALT | 'd', ESC_STR "Nd", MCKEY_NOACTION}, /* Alt-d */
+ {KEY_M_ALT | 'e', ESC_STR "Ne", MCKEY_NOACTION}, /* Alt-e */
+ {KEY_M_ALT | 'f', ESC_STR "Nf", MCKEY_NOACTION}, /* Alt-f */
+ {KEY_M_ALT | 'g', ESC_STR "Ng", MCKEY_NOACTION}, /* Alt-g */
+ {KEY_M_ALT | 'h', ESC_STR "Nh", MCKEY_NOACTION}, /* Alt-h */
+ {KEY_M_ALT | 'i', ESC_STR "Ni", MCKEY_NOACTION}, /* Alt-i */
+ {KEY_M_ALT | 'j', ESC_STR "Nj", MCKEY_NOACTION}, /* Alt-j */
+ {KEY_M_ALT | 'k', ESC_STR "Nk", MCKEY_NOACTION}, /* Alt-k */
+ {KEY_M_ALT | 'l', ESC_STR "Nl", MCKEY_NOACTION}, /* Alt-l */
+ {KEY_M_ALT | 'm', ESC_STR "Nm", MCKEY_NOACTION}, /* Alt-m */
+ {KEY_M_ALT | 'n', ESC_STR "Nn", MCKEY_NOACTION}, /* Alt-n */
+ {KEY_M_ALT | 'o', ESC_STR "No", MCKEY_NOACTION}, /* Alt-o */
+ {KEY_M_ALT | 'p', ESC_STR "Np", MCKEY_NOACTION}, /* Alt-p */
+ {KEY_M_ALT | 'q', ESC_STR "Nq", MCKEY_NOACTION}, /* Alt-q */
+ {KEY_M_ALT | 'r', ESC_STR "Nr", MCKEY_NOACTION}, /* Alt-r */
+ {KEY_M_ALT | 's', ESC_STR "Ns", MCKEY_NOACTION}, /* Alt-s */
+ {KEY_M_ALT | 't', ESC_STR "Nt", MCKEY_NOACTION}, /* Alt-t */
+ {KEY_M_ALT | 'u', ESC_STR "Nu", MCKEY_NOACTION}, /* Alt-u */
+ {KEY_M_ALT | 'v', ESC_STR "Nv", MCKEY_NOACTION}, /* Alt-v */
+ {KEY_M_ALT | 'w', ESC_STR "Nw", MCKEY_NOACTION}, /* Alt-w */
+ {KEY_M_ALT | 'x', ESC_STR "Nx", MCKEY_NOACTION}, /* Alt-x */
+ {KEY_M_ALT | 'y', ESC_STR "Ny", MCKEY_NOACTION}, /* Alt-y */
+ {KEY_M_ALT | 'z', ESC_STR "Nz", MCKEY_NOACTION}, /* Alt-z */
+ {KEY_KP_SUBTRACT, ESC_STR "[S", MCKEY_NOACTION}, /* Gr-Minus */
+ {KEY_KP_ADD, ESC_STR "[T", MCKEY_NOACTION}, /* Gr-Plus */
+ {0, NULL, MCKEY_NOACTION},
+};
+
+/* This holds all the key definitions */
+static key_def *keys = NULL;
+
+static int input_fd;
+static int disabled_channels = 0; /* Disable channels checking */
+
+static GSList *select_list = NULL;
+
+static int seq_buffer[SEQ_BUFFER_LEN];
+static int *seq_append = NULL;
+
+static int *pending_keys = NULL;
+
+#ifdef __QNXNTO__
+ph_dv_f ph_attach;
+ph_ov_f ph_input_group;
+ph_pqc_f ph_query_cursor;
+#endif
+
+#ifdef HAVE_TEXTMODE_X11_SUPPORT
+static Display *x11_display;
+static Window x11_window;
+#endif /* HAVE_TEXTMODE_X11_SUPPORT */
+
+static KeySortType has_been_sorted = KEY_NOSORT;
+
+/* *INDENT-OFF* */
+static const size_t key_conv_tab_size = G_N_ELEMENTS (key_name_conv_tab) - 1;
+/* *INDENT-ON* */
+
+static const key_code_name_t *key_conv_tab_sorted[G_N_ELEMENTS (key_name_conv_tab) - 1];
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+select_cmp_by_fd_set (gconstpointer a, gconstpointer b)
+{
+ const select_t *s = (const select_t *) a;
+ const fd_set *f = (const fd_set *) b;
+
+ return (FD_ISSET (s->fd, f) ? 0 : 1);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+select_cmp_by_fd (gconstpointer a, gconstpointer b)
+{
+ const select_t *s = (const select_t *) a;
+ const int fd = GPOINTER_TO_INT (b);
+
+ return (s->fd == fd ? 0 : 1);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+add_selects (fd_set * select_set)
+{
+ int top_fd = 0;
+
+ if (disabled_channels == 0)
+ {
+ GSList *s;
+
+ for (s = select_list; s != NULL; s = g_slist_next (s))
+ {
+ select_t *p = (select_t *) s->data;
+
+ FD_SET (p->fd, select_set);
+ if (p->fd > top_fd)
+ top_fd = p->fd;
+ }
+ }
+
+ return top_fd;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+check_selects (fd_set * select_set)
+{
+ while (disabled_channels == 0)
+ {
+ GSList *s;
+ select_t *p;
+
+ s = g_slist_find_custom (select_list, select_set, select_cmp_by_fd_set);
+ if (s == NULL)
+ break;
+
+ p = (select_t *) s->data;
+ FD_CLR (p->fd, select_set);
+ p->callback (p->fd, p->info);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/* If set timeout is set, then we wait 0.1 seconds, else, we block */
+
+static void
+try_channels (gboolean set_timeout)
+{
+ struct timeval time_out;
+ static fd_set select_set;
+
+ while (TRUE)
+ {
+ struct timeval *timeptr = NULL;
+ int maxfdp, v;
+
+ FD_ZERO (&select_set);
+ FD_SET (input_fd, &select_set); /* Add stdin */
+ maxfdp = MAX (add_selects (&select_set), input_fd);
+
+ if (set_timeout)
+ {
+ time_out.tv_sec = 0;
+ time_out.tv_usec = 100 * MC_USEC_PER_MSEC;
+ timeptr = &time_out;
+ }
+
+ v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
+ if (v > 0)
+ {
+ check_selects (&select_set);
+ if (FD_ISSET (input_fd, &select_set))
+ break;
+ }
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static key_def *
+create_sequence (const char *seq, int code, int action)
+{
+ key_def *base, *p, *attach;
+
+ for (base = attach = NULL; *seq != '\0'; seq++)
+ {
+ p = g_new (key_def, 1);
+ if (base == NULL)
+ base = p;
+ if (attach != NULL)
+ attach->child = p;
+
+ p->ch = *seq;
+ p->code = code;
+ p->child = p->next = NULL;
+ if (seq[1] == '\0')
+ p->action = action;
+ else
+ p->action = MCKEY_NOACTION;
+ attach = p;
+ }
+ return base;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+define_sequences (const key_define_t * kd)
+{
+ int i;
+
+ for (i = 0; kd[i].code != 0; i++)
+ define_sequence (kd[i].code, kd[i].seq, kd[i].action);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+#ifdef HAVE_TEXTMODE_X11_SUPPORT
+static void
+init_key_x11 (void)
+{
+ if (getenv ("DISPLAY") != NULL && !mc_global.tty.disable_x11)
+ {
+ x11_display = mc_XOpenDisplay (0);
+
+ if (x11_display != NULL)
+ x11_window = DefaultRootWindow (x11_display);
+ }
+}
+#endif /* HAVE_TEXTMODE_X11_SUPPORT */
+
+/* --------------------------------------------------------------------------------------------- */
+/* Workaround for System V Curses vt100 bug */
+
+static int
+getch_with_delay (void)
+{
+ int c;
+
+ /* This routine could be used on systems without mouse support,
+ so we need to do the select check :-( */
+ while (TRUE)
+ {
+ if (pending_keys == NULL)
+ try_channels (FALSE);
+
+ /* Try to get a character */
+ c = get_key_code (0);
+ if (c != -1)
+ break;
+
+ /* Failed -> wait 0.1 secs and try again */
+ try_channels (TRUE);
+ }
+
+ /* Success -> return the character */
+ return c;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+xmouse_get_event (Gpm_Event * ev, gboolean extended)
+{
+ static gint64 tv1 = 0; /* Force first click as single */
+ static int clicks = 0;
+ static int last_btn = 0;
+ int btn;
+
+ /* Decode Xterm mouse information to a GPM style event */
+
+ if (!extended)
+ {
+ /* Variable btn has following meaning: */
+ /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
+ btn = tty_lowlevel_getch () - 32;
+ /* Coordinates are 33-based */
+ /* Transform them to 1-based */
+ ev->x = tty_lowlevel_getch () - 32;
+ ev->y = tty_lowlevel_getch () - 32;
+ }
+ else
+ {
+ /* SGR 1006 extension (e.g. "\e[<0;12;300M"):
+ - Numbers are encoded in decimal to make it ASCII-safe
+ and to overcome the limit of 223 columns/rows.
+ - Mouse release is encoded by trailing 'm' rather than 'M'
+ so that the released button can be reported.
+ - Numbers are no longer offset by 32. */
+ char c;
+
+ btn = ev->x = ev->y = 0;
+ ev->type = 0; /* In case we return on an invalid sequence */
+
+ while ((c = tty_lowlevel_getch ()) != ';')
+ {
+ if (c < '0' || c > '9')
+ return;
+ btn = 10 * btn + (c - '0');
+ }
+ while ((c = tty_lowlevel_getch ()) != ';')
+ {
+ if (c < '0' || c > '9')
+ return;
+ ev->x = 10 * ev->x + (c - '0');
+ }
+ while ((c = tty_lowlevel_getch ()) != 'M' && c != 'm')
+ {
+ if (c < '0' || c > '9')
+ return;
+ ev->y = 10 * ev->y + (c - '0');
+ }
+ /* Legacy mouse protocol doesn't tell which button was released,
+ conveniently all of mc's widgets are written not to rely on this
+ information. With the SGR extension the released button becomes
+ known, but for the sake of simplicity we just ignore it. */
+ if (c == 'm')
+ btn = 3;
+ }
+
+ /* There seems to be no way of knowing which button was released */
+ /* So we assume all the buttons were released */
+
+ if (btn == 3)
+ {
+ if (last_btn != 0)
+ {
+ if ((last_btn & (GPM_B_UP | GPM_B_DOWN)) != 0)
+ {
+ /* FIXME: DIRTY HACK */
+ /* don't generate GPM_UP after mouse wheel */
+ /* need for menu event handling */
+ ev->type = 0;
+ tv1 = 0;
+ }
+ else
+ {
+ ev->type = GPM_UP | (GPM_SINGLE << clicks);
+ tv1 = g_get_monotonic_time ();
+ }
+ ev->buttons = 0;
+ last_btn = 0;
+ clicks = 0;
+ }
+ else
+ {
+ /* Bogus event, maybe mouse wheel */
+ ev->type = 0;
+ }
+ }
+ else
+ {
+ gint64 tv2;
+
+ if (btn >= 32 && btn <= 34)
+ {
+ btn -= 32;
+ ev->type = GPM_DRAG;
+ }
+ else
+ ev->type = GPM_DOWN;
+
+ tv2 = g_get_monotonic_time ();
+ if (tv1 != 0 && tv2 - tv1 < (gint64) double_click_speed * MC_USEC_PER_MSEC)
+ {
+ clicks++;
+ clicks %= 3;
+ }
+ else
+ clicks = 0;
+
+ switch (btn)
+ {
+ case 0:
+ ev->buttons = GPM_B_LEFT;
+ break;
+ case 1:
+ ev->buttons = GPM_B_MIDDLE;
+ break;
+ case 2:
+ ev->buttons = GPM_B_RIGHT;
+ break;
+ case 64:
+ ev->buttons = GPM_B_UP;
+ clicks = 0;
+ break;
+ case 65:
+ ev->buttons = GPM_B_DOWN;
+ clicks = 0;
+ break;
+ default:
+ /* Nothing */
+ ev->type = 0;
+ ev->buttons = 0;
+ break;
+ }
+ last_btn = ev->buttons;
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/**
+ * Get modifier state (shift, alt, ctrl) for the last key pressed.
+ * We are assuming that the state didn't change since the key press.
+ * This is only correct if get_modifier() is called very fast after
+ * the input was received, so that the user didn't release the
+ * modifier keys yet.
+ */
+
+static int
+get_modifier (void)
+{
+ int result = 0;
+#ifdef __QNXNTO__
+ static int in_photon = 0;
+ static int ph_ig = 0;
+#endif /* __QNXNTO__ */
+
+#ifdef HAVE_TEXTMODE_X11_SUPPORT
+ if (x11_window != 0)
+ {
+ Window root, child;
+ int root_x, root_y;
+ int win_x, win_y;
+ unsigned int mask;
+
+ mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
+ &root_y, &win_x, &win_y, &mask);
+
+ if ((mask & ShiftMask) != 0)
+ result |= KEY_M_SHIFT;
+ if ((mask & ControlMask) != 0)
+ result |= KEY_M_CTRL;
+ return result;
+ }
+#endif /* HAVE_TEXTMODE_X11_SUPPORT */
+
+#ifdef __QNXNTO__
+ if (in_photon == 0)
+ {
+ /* First time here, let's load Photon library and attach to Photon */
+ in_photon = -1;
+
+ if (getenv ("PHOTON2_PATH") != NULL)
+ {
+ /* QNX 6.x has no support for RTLD_LAZY */
+ void *ph_handle;
+
+ ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW);
+ if (ph_handle != NULL)
+ {
+ ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
+ ph_input_group = (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
+ ph_query_cursor = (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
+ if ((ph_attach != NULL) && (ph_input_group != NULL) && (ph_query_cursor != NULL)
+ && (*ph_attach) (0, 0) != NULL)
+ {
+ /* Attached */
+ ph_ig = (*ph_input_group) (0);
+ in_photon = 1;
+ }
+ }
+ }
+ }
+ /* We do not have Photon running. Assume we are in text console or xterm */
+ if (in_photon == -1)
+ {
+ int mod_status;
+ int shift_ext_status;
+
+ if (devctl (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, sizeof (mod_status), NULL) ==
+ -1)
+ return 0;
+
+ shift_ext_status = mod_status & 0xffffff00UL;
+ mod_status &= 0x7f;
+ if ((mod_status & _LINESTATUS_CON_ALT) != 0)
+ result |= KEY_M_ALT;
+ if ((mod_status & _LINESTATUS_CON_CTRL) != 0)
+ result |= KEY_M_CTRL;
+ if ((mod_status & _LINESTATUS_CON_SHIFT) != 0 || (shift_ext_status & 0x00000800UL) != 0)
+ result |= KEY_M_SHIFT;
+ }
+ else
+ {
+ PhCursorInfo_t cursor_info;
+
+ (*ph_query_cursor) (ph_ig, &cursor_info);
+ if ((cursor_info.key_mods & 0x04) != 0)
+ result |= KEY_M_ALT;
+ if ((cursor_info.key_mods & 0x02) != 0)
+ result |= KEY_M_CTRL;
+ if ((cursor_info.key_mods & 0x01) != 0)
+ result |= KEY_M_SHIFT;
+ }
+#endif /* __QNXNTO__ */
+
+#if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
+ {
+ unsigned char modifiers = 6;
+
+ if (ioctl (0, TIOCLINUX, &modifiers) < 0)
+ return 0;
+
+ /* Translate Linux modifiers into mc modifiers */
+ if ((modifiers & SHIFT_PRESSED) != 0)
+ result |= KEY_M_SHIFT;
+ if ((modifiers & (ALTL_PRESSED | ALTR_PRESSED)) != 0)
+ result |= KEY_M_ALT;
+ if ((modifiers & CONTROL_PRESSED) != 0)
+ result |= KEY_M_CTRL;
+ }
+#endif /* !__linux__ */
+
+ return result;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static gboolean
+push_char (int c)
+{
+ gboolean ret = FALSE;
+
+ if (seq_append == NULL)
+ seq_append = seq_buffer;
+
+ if (seq_append != &(seq_buffer[SEQ_BUFFER_LEN - 2]))
+ {
+ *(seq_append++) = c;
+ *seq_append = '\0';
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/* Apply corrections for the keycode generated in get_key_code() */
+
+static int
+correct_key_code (int code)
+{
+ unsigned int c = code & ~KEY_M_MASK; /* code without modifier */
+ unsigned int mod = code & KEY_M_MASK; /* modifier */
+#ifdef __QNXNTO__
+ unsigned int qmod; /* bunch of the QNX console
+ modifiers needs unchanged */
+#endif /* __QNXNTO__ */
+
+ /*
+ * Add key modifiers directly from X11 or OS.
+ * Ordinary characters only get modifiers from sequences.
+ */
+ if (c < 32 || c >= 256)
+ mod |= get_modifier ();
+
+ /* This is needed if the newline is reported as carriage return */
+ if (c == '\r')
+ c = '\n';
+
+ /* This is reported to be useful on AIX */
+ if (c == KEY_SCANCEL)
+ c = '\t';
+
+ /* Convert Back Tab to Shift+Tab */
+ if (c == KEY_BTAB)
+ {
+ c = '\t';
+ mod = KEY_M_SHIFT;
+ }
+
+ /* F0 is the same as F10 for out purposes */
+ if (c == KEY_F (0))
+ c = KEY_F (10);
+
+ /*
+ * We are not interested if Ctrl was pressed when entering control
+ * characters, so assume that it was. When checking for such keys,
+ * XCTRL macro should be used. In some cases, we are interested,
+ * e.g. to distinguish Ctrl-Enter from Enter.
+ */
+ if (c == '\b')
+ {
+ /* Special case for backspase ('\b' < 32) */
+ c = KEY_BACKSPACE;
+ mod &= ~KEY_M_CTRL;
+ }
+ else if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n')
+ mod |= KEY_M_CTRL;
+
+#ifdef __QNXNTO__
+ qmod = get_modifier ();
+
+ if (c == 127 && mod == 0)
+ {
+ /* Add Ctrl/Alt/Shift-BackSpace */
+ mod |= get_modifier ();
+ c = KEY_BACKSPACE;
+ }
+
+ if (c == '0' && mod == 0 && (qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
+ {
+ /* Add Shift-Insert on key pad */
+ mod = KEY_M_SHIFT;
+ c = KEY_IC;
+ }
+
+ if (c == '.' && mod == 0 && (qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
+ {
+ /* Add Shift-Del on key pad */
+ mod = KEY_M_SHIFT;
+ c = KEY_DC;
+ }
+#endif /* __QNXNTO__ */
+
+ /* Unrecognized 0177 is delete (preserve Ctrl) */
+ if (c == 0177)
+ c = KEY_BACKSPACE;
+
+#if 0
+ /* Unrecognized Ctrl-d is delete */
+ if (c == 'd' & 31)
+ {
+ c = KEY_DC;
+ mod &= ~KEY_M_CTRL;
+ }
+
+ /* Unrecognized Ctrl-h is backspace */
+ if (c == 'h' & 31)
+ {
+ c = KEY_BACKSPACE;
+ mod &= ~KEY_M_CTRL;
+ }
+#endif
+
+ /* Shift+BackSpace is backspace */
+ if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT) != 0)
+ mod &= ~KEY_M_SHIFT;
+
+ /* Convert Shift+Fn to F(n+10) */
+ if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT) != 0)
+ c += 10;
+
+ /* Remove Shift information from function keys */
+ if (c >= KEY_F (1) && c <= KEY_F (20))
+ mod &= ~KEY_M_SHIFT;
+
+ if (!mc_global.tty.alternate_plus_minus)
+ switch (c)
+ {
+ case KEY_KP_ADD:
+ c = '+';
+ break;
+ case KEY_KP_SUBTRACT:
+ c = '-';
+ break;
+ case KEY_KP_MULTIPLY:
+ c = '*';
+ break;
+ default:
+ break;
+ }
+
+ return (mod | c);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+getch_with_timeout (unsigned int delay_us)
+{
+ fd_set Read_FD_Set;
+ int c;
+ struct timeval time_out;
+
+ time_out.tv_sec = delay_us / G_USEC_PER_SEC;
+ time_out.tv_usec = delay_us % G_USEC_PER_SEC;
+ tty_nodelay (TRUE);
+ FD_ZERO (&Read_FD_Set);
+ FD_SET (input_fd, &Read_FD_Set);
+ select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
+ c = tty_lowlevel_getch ();
+ tty_nodelay (FALSE);
+ return c;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+learn_store_key (char *buffer, char **p, int c)
+{
+ if (*p - buffer > 253)
+ return;
+
+ if (c == ESC_CHAR)
+ {
+ *(*p)++ = '\\';
+ *(*p)++ = 'e';
+ }
+ else if (c < ' ')
+ {
+ *(*p)++ = '^';
+ *(*p)++ = c + 'a' - 1;
+ }
+ else if (c == '^')
+ {
+ *(*p)++ = '^';
+ *(*p)++ = '^';
+ }
+ else
+ *(*p)++ = (char) c;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+k_dispose (key_def * k)
+{
+ if (k != NULL)
+ {
+ k_dispose (k->child);
+ k_dispose (k->next);
+ g_free (k);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+key_code_comparator_by_name (const void *p1, const void *p2)
+{
+ const key_code_name_t *n1 = *(const key_code_name_t * const *) p1;
+ const key_code_name_t *n2 = *(const key_code_name_t * const *) p2;
+
+ return g_ascii_strcasecmp (n1->name, n2->name);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+key_code_comparator_by_code (const void *p1, const void *p2)
+{
+ const key_code_name_t *n1 = *(const key_code_name_t * const *) p1;
+ const key_code_name_t *n2 = *(const key_code_name_t * const *) p2;
+
+ return n1->code - n2->code;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static inline void
+sort_key_conv_tab (enum KeySortType type_sort)
+{
+ if (has_been_sorted != type_sort)
+ {
+ size_t i;
+
+ for (i = 0; i < key_conv_tab_size; i++)
+ key_conv_tab_sorted[i] = &key_name_conv_tab[i];
+
+ if (type_sort == KEY_SORTBYNAME)
+ qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
+ &key_code_comparator_by_name);
+ else if (type_sort == KEY_SORTBYCODE)
+ qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
+ &key_code_comparator_by_code);
+
+ has_been_sorted = type_sort;
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+lookup_keyname (const char *name, int *idx)
+{
+ if (name[0] != '\0')
+ {
+ const key_code_name_t key = { 0, name, NULL, NULL };
+ const key_code_name_t *keyp = &key;
+ const key_code_name_t **res;
+
+ if (name[1] == '\0')
+ {
+ *idx = -1;
+ return (int) name[0];
+ }
+
+ sort_key_conv_tab (KEY_SORTBYNAME);
+
+ res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
+ sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
+
+ if (res != NULL)
+ {
+ *idx = (int) (res - key_conv_tab_sorted);
+ return (*res)->code;
+ }
+ }
+
+ *idx = -1;
+ return 0;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static gboolean
+lookup_keycode (const long code, int *idx)
+{
+ if (code != 0)
+ {
+ const key_code_name_t key = { code, NULL, NULL, NULL };
+ const key_code_name_t *keyp = &key;
+ const key_code_name_t **res;
+
+ sort_key_conv_tab (KEY_SORTBYCODE);
+
+ res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
+ sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
+
+ if (res != NULL)
+ {
+ *idx = (int) (res - key_conv_tab_sorted);
+ return TRUE;
+ }
+ }
+
+ *idx = -1;
+ return FALSE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+/* This has to be called before init_slang or whatever routine
+ calls any define_sequence */
+
+void
+init_key (void)
+{
+ const char *term;
+
+ term = getenv ("TERM");
+
+ /* This has to be the first define_sequence */
+ /* So, we can assume that the first keys member has ESC */
+ define_sequences (mc_default_keys);
+
+ /* Terminfo on irix does not have some keys */
+ if (mc_global.tty.xterm_flag
+ || (term != NULL
+ && (strncmp (term, "iris-ansi", 9) == 0
+ || strncmp (term, "xterm", 5) == 0
+ || strncmp (term, "rxvt", 4) == 0 || strncmp (term, "screen", 6) == 0)))
+ define_sequences (xterm_key_defines);
+
+ /* load some additional keys (e.g. direct Alt-? support) */
+ load_xtra_key_defines ();
+
+#ifdef __QNX__
+ if ((term != NULL) && (strncmp (term, "qnx", 3) == 0))
+ {
+ /* Modify the default value of use_8th_bit_as_meta: we would
+ * like to provide a working mc for a newbie who knows nothing
+ * about [Options|Display bits|Full 8 bits input]...
+ *
+ * Don't use 'meta'-bit, when we are dealing with a
+ * 'qnx*'-type terminal: clear the default value!
+ * These terminal types use 0xFF as an escape character,
+ * so use_8th_bit_as_meta==1 must not be enabled!
+ *
+ * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
+ * is not used now (doesn't even depend on use_8th_bit_as_meta
+ * as in mc-3.1.2)...GREAT!...no additional code is required!]
+ */
+ use_8th_bit_as_meta = FALSE;
+ }
+#endif /* __QNX__ */
+
+#ifdef HAVE_TEXTMODE_X11_SUPPORT
+ init_key_x11 ();
+#endif
+
+ /* Load the qansi-m key definitions
+ if we are running under the qansi-m terminal */
+ if (term != NULL && (strncmp (term, "qansi-m", 7) == 0))
+ define_sequences (qansi_key_defines);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/**
+ * This has to be called after SLang_init_tty/slint_init
+ */
+
+void
+init_key_input_fd (void)
+{
+#ifdef HAVE_SLANG
+ input_fd = SLang_TT_Read_FD;
+#endif
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+done_key (void)
+{
+ k_dispose (keys);
+ g_slist_free_full (select_list, g_free);
+
+#ifdef HAVE_TEXTMODE_X11_SUPPORT
+ if (x11_display)
+ mc_XCloseDisplay (x11_display);
+#endif
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+add_select_channel (int fd, select_fn callback, void *info)
+{
+ select_t *new;
+
+ new = g_new (select_t, 1);
+ new->fd = fd;
+ new->callback = callback;
+ new->info = info;
+
+ select_list = g_slist_prepend (select_list, new);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+delete_select_channel (int fd)
+{
+ GSList *p;
+
+ p = g_slist_find_custom (select_list, GINT_TO_POINTER (fd), select_cmp_by_fd);
+ if (p != NULL)
+ select_list = g_slist_delete_link (select_list, p);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+channels_up (void)
+{
+ if (disabled_channels == 0)
+ fputs ("Error: channels_up called with disabled_channels = 0\n", stderr);
+ disabled_channels--;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+channels_down (void)
+{
+ disabled_channels++;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/**
+ * Return the code associated with the symbolic name keyname
+ */
+
+long
+tty_keyname_to_keycode (const char *name, char **label)
+{
+ char **lc_keys, **p;
+ char *cname;
+ int k = -1;
+ int key = 0;
+ int lc_index = -1;
+
+ int use_meta = -1;
+ int use_ctrl = -1;
+ int use_shift = -1;
+
+ if (name == NULL)
+ return 0;
+
+ cname = g_strstrip (g_strdup (name));
+ lc_keys = g_strsplit_set (cname, "-+ ", -1);
+ g_free (cname);
+
+ for (p = lc_keys; p != NULL && *p != NULL; p++)
+ {
+ if ((*p)[0] != '\0')
+ {
+ int idx;
+
+ key = lookup_keyname (g_strstrip (*p), &idx);
+
+ if (key == KEY_M_ALT)
+ use_meta = idx;
+ else if (key == KEY_M_CTRL)
+ use_ctrl = idx;
+ else if (key == KEY_M_SHIFT)
+ use_shift = idx;
+ else
+ {
+ k = key;
+ lc_index = idx;
+ break;
+ }
+ }
+ }
+
+ g_strfreev (lc_keys);
+
+ /* output */
+ if (k <= 0)
+ return 0;
+
+ if (label != NULL)
+ {
+ GString *s;
+
+ s = g_string_new ("");
+
+ if (use_meta != -1)
+ {
+ g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
+ g_string_append_c (s, '-');
+ }
+ if (use_ctrl != -1)
+ {
+ g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
+ g_string_append_c (s, '-');
+ }
+ if (use_shift != -1)
+ {
+ if (k < 127)
+ g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
+ else
+ {
+ g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
+ g_string_append_c (s, '-');
+ g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
+ }
+ }
+ else if (k < 128)
+ {
+ if ((k >= 'A') || (lc_index < 0) || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
+ g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
+ else
+ g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
+ }
+ else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
+ g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
+ else
+ g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
+
+ *label = g_string_free (s, FALSE);
+ }
+
+ if (use_shift != -1)
+ {
+ if (k < 127 && k > 31)
+ k = g_ascii_toupper ((gchar) k);
+ else
+ k |= KEY_M_SHIFT;
+ }
+
+ if (use_ctrl != -1)
+ {
+ if (k < 256)
+ k = XCTRL (k);
+ else
+ k |= KEY_M_CTRL;
+ }
+
+ if (use_meta != -1)
+ k = ALT (k);
+
+ return (long) k;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+char *
+tty_keycode_to_keyname (const int keycode)
+{
+ /* code without modifier */
+ unsigned int k = keycode & ~KEY_M_MASK;
+ /* modifier */
+ unsigned int mod = keycode & KEY_M_MASK;
+
+ int key_idx = -1;
+
+ GString *s;
+ int idx;
+
+ s = g_string_sized_new (8);
+
+ if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
+ {
+ if ((mod & KEY_M_ALT) != 0 && lookup_keycode (KEY_M_ALT, &idx))
+ {
+ g_string_append (s, key_conv_tab_sorted[idx]->name);
+ g_string_append_c (s, '-');
+ }
+
+ if ((mod & KEY_M_CTRL) != 0)
+ {
+ /* non printeble chars like a CTRL-[A..Z] */
+ if (k < 32)
+ k += 64;
+
+ if (lookup_keycode (KEY_M_CTRL, &idx))
+ {
+ g_string_append (s, key_conv_tab_sorted[idx]->name);
+ g_string_append_c (s, '-');
+ }
+ }
+
+ if ((mod & KEY_M_SHIFT) != 0)
+ {
+ if (lookup_keycode (KEY_M_ALT, &idx))
+ {
+ if (k < 127)
+ g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
+ else
+ {
+ g_string_append (s, key_conv_tab_sorted[idx]->name);
+ g_string_append_c (s, '-');
+ g_string_append (s, key_conv_tab_sorted[key_idx]->name);
+ }
+ }
+ }
+ else if (k < 128)
+ {
+ if ((k >= 'A') || (key_idx < 0) || (key_conv_tab_sorted[key_idx]->name == NULL))
+ g_string_append_c (s, (gchar) k);
+ else
+ g_string_append (s, key_conv_tab_sorted[key_idx]->name);
+ }
+ else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
+ g_string_append (s, key_conv_tab_sorted[key_idx]->name);
+ else
+ g_string_append_c (s, (gchar) keycode);
+ }
+
+ return g_string_free (s, s->len == 0);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/**
+ * Return TRUE on success, FALSE on error.
+ * An error happens if SEQ is a beginning of an existing longer sequence.
+ */
+
+gboolean
+define_sequence (int code, const char *seq, int action)
+{
+ key_def *base;
+
+ if (strlen (seq) > SEQ_BUFFER_LEN - 1)
+ return FALSE;
+
+ for (base = keys; (base != NULL) && (*seq != '\0');)
+ if (*seq == base->ch)
+ {
+ if (base->child == NULL)
+ {
+ if (*(seq + 1) != '\0')
+ base->child = create_sequence (seq + 1, code, action);
+ else
+ {
+ /* The sequence matches an existing one. */
+ base->code = code;
+ base->action = action;
+ }
+ return TRUE;
+ }
+
+ base = base->child;
+ seq++;
+ }
+ else
+ {
+ if (base->next != NULL)
+ base = base->next;
+ else
+ {
+ base->next = create_sequence (seq, code, action);
+ return TRUE;
+ }
+ }
+
+ if (*seq == '\0')
+ {
+ /* Attempt to redefine a sequence with a shorter sequence. */
+ return FALSE;
+ }
+
+ keys = create_sequence (seq, code, action);
+ return TRUE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/**
+ * Check if we are idle, i.e. there are no pending keyboard or mouse
+ * events. Return 1 is idle, 0 is there are pending events.
+ */
+gboolean
+is_idle (void)
+{
+ int nfd;
+ fd_set select_set;
+ struct timeval time_out;
+
+ FD_ZERO (&select_set);
+ FD_SET (input_fd, &select_set);
+ nfd = MAX (0, input_fd) + 1;
+ time_out.tv_sec = 0;
+ time_out.tv_usec = 0;
+#ifdef HAVE_LIBGPM
+ if (mouse_enabled && use_mouse_p == MOUSE_GPM)
+ {
+ if (gpm_fd >= 0)
+ {
+ FD_SET (gpm_fd, &select_set);
+ nfd = MAX (nfd, gpm_fd + 1);
+ }
+ else
+ {
+ if (mouse_fd >= 0) /* error indicative */
+ {
+ if (FD_ISSET (mouse_fd, &select_set))
+ FD_CLR (mouse_fd, &select_set);
+ mouse_fd = gpm_fd;
+ }
+ /* gpm_fd == -2 means under some X terminal */
+ if (gpm_fd == -1)
+ {
+ mouse_enabled = FALSE;
+ use_mouse_p = MOUSE_NONE;
+ }
+ }
+ }
+#endif
+ return (select (nfd, &select_set, 0, 0, &time_out) <= 0);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+get_key_code (int no_delay)
+{
+ int c;
+ static key_def *this = NULL, *parent;
+ static gint64 esc_time = -1;
+ static int lastnodelay = -1;
+
+ if (no_delay != lastnodelay)
+ {
+ this = NULL;
+ lastnodelay = no_delay;
+ }
+
+ pend_send:
+ if (pending_keys != NULL)
+ {
+ gboolean bad_seq;
+
+ c = *pending_keys++;
+ while (c == ESC_CHAR)
+ c = ALT (*pending_keys++);
+
+ bad_seq = (*pending_keys != ESC_CHAR && *pending_keys != '\0');
+ if (*pending_keys == '\0' || bad_seq)
+ pending_keys = seq_append = NULL;
+
+ if (bad_seq)
+ {
+ /* This is an unknown ESC sequence.
+ * To prevent interpreting its tail as a random garbage,
+ * eat and discard all buffered and quickly following chars.
+ * Small, but non-zero timeout is needed to reconnect
+ * escape sequence split up by e.g. a serial line.
+ */
+ int paranoia = 20;
+
+ while (getch_with_timeout (old_esc_mode_timeout) >= 0 && --paranoia != 0)
+ ;
+ }
+ else
+ {
+ if (c > 127 && c < 256 && use_8th_bit_as_meta)
+ c = ALT (c & 0x7f);
+
+ goto done;
+ }
+ }
+
+ nodelay_try_again:
+ if (no_delay != 0)
+ tty_nodelay (TRUE);
+
+ c = tty_lowlevel_getch ();
+#if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
+ if (c == KEY_RESIZE)
+ goto nodelay_try_again;
+#endif
+
+ if (no_delay != 0)
+ {
+ tty_nodelay (FALSE);
+ if (c == -1)
+ {
+ if (this == NULL || parent == NULL || parent->action != MCKEY_ESCAPE || !old_esc_mode ||
+ esc_time == -1 || g_get_monotonic_time () < esc_time + old_esc_mode_timeout)
+ return -1;
+
+ this = NULL;
+ pending_keys = seq_append = NULL;
+ return ESC_CHAR;
+ }
+ }
+ else if (c == -1)
+ {
+ /* Maybe we got an incomplete match.
+ This we do only in delay mode, since otherwise
+ tty_lowlevel_getch can return -1 at any time. */
+ if (seq_append == NULL)
+ {
+ this = NULL;
+ return -1;
+ }
+
+ pending_keys = seq_buffer;
+ goto pend_send;
+ }
+
+ /* Search the key on the root */
+ if (no_delay == 0 || this == NULL)
+ {
+ this = keys;
+ parent = NULL;
+
+ if (c > 127 && c < 256 && use_8th_bit_as_meta)
+ {
+ c &= 0x7f;
+
+ /* The first sequence defined starts with esc */
+ parent = keys;
+ this = keys->child;
+ }
+ }
+
+ while (this != NULL)
+ {
+ if (c == this->ch)
+ {
+ if (this->child == NULL)
+ {
+ /* We got a complete match, return and reset search */
+ pending_keys = seq_append = NULL;
+ c = this->code;
+ goto done;
+ }
+
+ /* No match yet, but it may be a prefix for a valid seq */
+ if (!push_char (c))
+ {
+ pending_keys = seq_buffer;
+ goto pend_send;
+ }
+
+ parent = this;
+ this = this->child;
+ if (parent->action == MCKEY_ESCAPE && old_esc_mode)
+ {
+ if (no_delay != 0)
+ {
+ esc_time = g_get_monotonic_time ();
+ goto nodelay_try_again;
+ }
+
+ esc_time = -1;
+ c = getch_with_timeout (old_esc_mode_timeout);
+ if (c != -1)
+ continue;
+
+ pending_keys = seq_append = NULL;
+ this = NULL;
+ return ESC_CHAR;
+ }
+
+ if (no_delay != 0)
+ goto nodelay_try_again;
+ c = tty_lowlevel_getch ();
+ continue;
+ }
+
+ /* c != this->ch. Try other keys with this prefix */
+ if (this->next != NULL)
+ {
+ this = this->next;
+ continue;
+ }
+
+ /* No match found. Is it one of our ESC <key> specials? */
+ if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
+ {
+ /* Convert escape-digits to F-keys */
+ if (g_ascii_isdigit (c))
+ c = KEY_F (c - '0');
+ else if (c == ' ')
+ c = ESC_CHAR;
+ else
+ c = ALT (c);
+
+ pending_keys = seq_append = NULL;
+ goto done;
+ }
+
+ /* Unknown sequence. Maybe a prefix of a longer one. Save it. */
+ push_char (c);
+ pending_keys = seq_buffer;
+ goto pend_send;
+ } /* while (this != NULL) */
+
+ done:
+ this = NULL;
+ return correct_key_code (c);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/* Returns a character read from stdin with appropriate interpretation */
+/* Also takes care of generated mouse events */
+/* Returns EV_MOUSE if it is a mouse event */
+/* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
+
+int
+tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block)
+{
+ int c;
+ int flag = 0; /* Return value from select */
+#ifdef HAVE_LIBGPM
+ static struct Gpm_Event ev; /* Mouse event */
+#endif
+ struct timeval time_out;
+ struct timeval *time_addr = NULL;
+ static int dirty = 3;
+
+ if ((dirty == 3) || is_idle ())
+ {
+ mc_refresh ();
+ dirty = 1;
+ }
+ else
+ dirty++;
+
+ vfs_timeout_handler ();
+
+ /* Ok, we use (event->x < 0) to signal that the event does not contain
+ a suitable position for the mouse, so we can't use show_mouse_pointer
+ on it.
+ */
+ if (event->x > 0)
+ {
+ show_mouse_pointer (event->x, event->y);
+ if (!redo_event)
+ event->x = -1;
+ }
+
+ /* Repeat if using mouse */
+ while (pending_keys == NULL)
+ {
+ int nfd;
+ fd_set select_set;
+
+ FD_ZERO (&select_set);
+ FD_SET (input_fd, &select_set);
+ nfd = MAX (add_selects (&select_set), MAX (0, input_fd)) + 1;
+
+#ifdef HAVE_LIBGPM
+ if (mouse_enabled && (use_mouse_p == MOUSE_GPM))
+ {
+ if (gpm_fd >= 0)
+ {
+ FD_SET (gpm_fd, &select_set);
+ nfd = MAX (nfd, gpm_fd + 1);
+ }
+ else
+ {
+ if (mouse_fd >= 0) /* error indicative */
+ {
+ if (FD_ISSET (mouse_fd, &select_set))
+ FD_CLR (mouse_fd, &select_set);
+ mouse_fd = gpm_fd;
+ }
+ /* gpm_fd == -2 means under some X terminal */
+ if (gpm_fd == -1)
+ {
+ mouse_enabled = FALSE;
+ use_mouse_p = MOUSE_NONE;
+ }
+ break;
+ }
+ }
+#endif
+
+ if (redo_event)
+ {
+ time_out.tv_usec = mou_auto_repeat * MC_USEC_PER_MSEC;
+ time_out.tv_sec = 0;
+
+ time_addr = &time_out;
+ }
+ else
+ {
+ int seconds;
+
+ seconds = vfs_timeouts ();
+ time_addr = NULL;
+
+ if (seconds != 0)
+ {
+ /* the timeout could be improved and actually be
+ * the number of seconds until the next vfs entry
+ * timeouts in the stamp list.
+ */
+
+ time_out.tv_sec = seconds;
+ time_out.tv_usec = 0;
+ time_addr = &time_out;
+ }
+ }
+
+ if (!block || tty_got_winch ())
+ {
+ time_addr = &time_out;
+ time_out.tv_sec = 0;
+ time_out.tv_usec = 0;
+ }
+
+ tty_enable_interrupt_key ();
+ flag = select (nfd, &select_set, NULL, NULL, time_addr);
+ tty_disable_interrupt_key ();
+
+ /* select timed out: it could be for any of the following reasons:
+ * redo_event -> it was because of the MOU_REPEAT handler
+ * !block -> we did not block in the select call
+ * else -> 10 second timeout to check the vfs status.
+ */
+ if (flag == 0)
+ {
+ if (redo_event)
+ return EV_MOUSE;
+ if (!block || tty_got_winch ())
+ return EV_NONE;
+ vfs_timeout_handler ();
+ }
+ if (flag == -1 && errno == EINTR)
+ return EV_NONE;
+
+ check_selects (&select_set);
+
+ if (FD_ISSET (input_fd, &select_set))
+ break;
+
+#ifdef HAVE_LIBGPM
+ if (mouse_enabled && use_mouse_p == MOUSE_GPM)
+ {
+ if (gpm_fd >= 0)
+ {
+ if (FD_ISSET (gpm_fd, &select_set))
+ {
+ int status;
+
+ status = Gpm_GetEvent (&ev);
+ if (status == 1) /* success */
+ {
+ Gpm_FitEvent (&ev);
+ *event = ev;
+ return EV_MOUSE;
+ }
+ if (status <= 0) /* connection closed; -1 == error */
+ {
+ if (mouse_fd >= 0 && FD_ISSET (mouse_fd, &select_set))
+ FD_CLR (mouse_fd, &select_set);
+
+ disable_mouse ();
+ return EV_NONE;
+ }
+ }
+ }
+ else
+ {
+ if (mouse_fd >= 0) /* error indicative */
+ {
+ if (FD_ISSET (mouse_fd, &select_set))
+ FD_CLR (mouse_fd, &select_set);
+ mouse_fd = gpm_fd;
+ }
+ /* gpm_fd == -2 means under some X terminal */
+ if (gpm_fd == -1)
+ {
+ mouse_enabled = FALSE;
+ use_mouse_p = MOUSE_NONE;
+ }
+ break;
+ }
+ }
+#endif /* !HAVE_LIBGPM */
+ }
+
+#ifndef HAVE_SLANG
+ flag = is_wintouched (stdscr);
+ untouchwin (stdscr);
+#endif /* !HAVE_SLANG */
+ c = block ? getch_with_delay () : get_key_code (1);
+
+#ifndef HAVE_SLANG
+ if (flag > 0)
+ tty_touch_screen ();
+#endif /* !HAVE_SLANG */
+
+ if (mouse_enabled && (c == MCKEY_MOUSE
+#ifdef KEY_MOUSE
+ || c == KEY_MOUSE
+#endif /* KEY_MOUSE */
+ || c == MCKEY_EXTENDED_MOUSE))
+ {
+ /* Mouse event. See tickets 2956 and 3954 for extended mode detection. */
+ gboolean extended = c == MCKEY_EXTENDED_MOUSE;
+
+#ifdef KEY_MOUSE
+ extended = extended || (c == KEY_MOUSE && xmouse_seq == NULL
+ && xmouse_extended_seq != NULL);
+#endif /* KEY_MOUSE */
+
+ xmouse_get_event (event, extended);
+ c = (event->type != 0) ? EV_MOUSE : EV_NONE;
+ }
+ else if (c == MCKEY_BRACKETED_PASTING_START)
+ {
+ bracketed_pasting_in_progress = TRUE;
+ c = EV_NONE;
+ }
+ else if (c == MCKEY_BRACKETED_PASTING_END)
+ {
+ bracketed_pasting_in_progress = FALSE;
+ c = EV_NONE;
+ }
+
+ return c;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/* Returns a key press, mouse events are discarded */
+
+int
+tty_getch (void)
+{
+ Gpm_Event ev;
+ int key;
+
+ ev.x = -1;
+ while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE)
+ ;
+ return key;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+char *
+learn_key (void)
+{
+ /* LEARN_TIMEOUT in ms */
+#define LEARN_TIMEOUT 200
+
+ fd_set Read_FD_Set;
+ gint64 end_time;
+ int c;
+ char buffer[256];
+ char *p = buffer;
+
+ tty_keypad (FALSE); /* disable interpreting keys by ncurses */
+ c = tty_lowlevel_getch ();
+ while (c == -1)
+ c = tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
+ learn_store_key (buffer, &p, c);
+
+ end_time = g_get_monotonic_time () + LEARN_TIMEOUT * MC_USEC_PER_MSEC;
+
+ tty_nodelay (TRUE);
+ while (TRUE)
+ {
+ while ((c = tty_lowlevel_getch ()) == -1)
+ {
+ gint64 time_out;
+ struct timeval tv;
+
+ time_out = end_time - g_get_monotonic_time ();
+ if (time_out <= 0)
+ break;
+
+ tv.tv_sec = time_out / G_USEC_PER_SEC;
+ tv.tv_usec = time_out % G_USEC_PER_SEC;
+ FD_ZERO (&Read_FD_Set);
+ FD_SET (input_fd, &Read_FD_Set);
+ select (input_fd + 1, &Read_FD_Set, NULL, NULL, &tv);
+ }
+ if (c == -1)
+ break;
+ learn_store_key (buffer, &p, c);
+ }
+ tty_keypad (TRUE);
+ tty_nodelay (FALSE);
+ *p = '\0';
+ return (buffer[0] != '\0' ? g_strdup (buffer) : NULL);
+#undef LEARN_TIMEOUT
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/* xterm and linux console only: set keypad to numeric or application
+ mode. Only in application keypad mode it's possible to distinguish
+ the '+' key and the '+' on the keypad ('*' and '-' ditto) */
+
+void
+numeric_keypad_mode (void)
+{
+ if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
+ {
+ fputs (ESC_STR ">", stdout);
+ fflush (stdout);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+application_keypad_mode (void)
+{
+ if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
+ {
+ fputs (ESC_STR "=", stdout);
+ fflush (stdout);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+enable_bracketed_paste (void)
+{
+ printf (ESC_STR "[?2004h");
+ fflush (stdout);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+disable_bracketed_paste (void)
+{
+ printf (ESC_STR "[?2004l");
+ fflush (stdout);
+ bracketed_pasting_in_progress = FALSE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/key.h b/lib/tty/key.h
new file mode 100644
index 0000000..6dd2cee
--- /dev/null
+++ b/lib/tty/key.h
@@ -0,0 +1,121 @@
+/** \file key.h
+ * \brief Header: keyboard support routines
+ */
+
+#ifndef MC__KEY_H
+#define MC__KEY_H
+
+#include "lib/global.h" /* <glib.h> */
+#include "tty.h" /* KEY_F macro */
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+/* Possible return values from tty_get_event: */
+#define EV_MOUSE -2
+#define EV_NONE -1
+
+/*
+ * Internal representation of the key modifiers. It is used in the
+ * sequence tables and the keycodes in the mc sources.
+ */
+#define KEY_M_SHIFT 0x1000
+#define KEY_M_ALT 0x2000
+#define KEY_M_CTRL 0x4000
+#define KEY_M_MASK 0x7000
+
+#define XCTRL(x) (KEY_M_CTRL | ((x) & 0x1F))
+#define ALT(x) (KEY_M_ALT | (unsigned int)(x))
+
+/* To define sequences and return codes */
+#define MCKEY_NOACTION 0
+#define MCKEY_ESCAPE 1
+
+/* Return code for the mouse sequence */
+#define MCKEY_MOUSE -2
+
+/* Return code for the extended mouse sequence */
+#define MCKEY_EXTENDED_MOUSE -3
+
+/* Return code for brackets of bracketed paste mode */
+#define MCKEY_BRACKETED_PASTING_START -4
+#define MCKEY_BRACKETED_PASTING_END -5
+
+/*** enums ***************************************************************************************/
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+typedef struct
+{
+ int code;
+ const char *name;
+ const char *longname;
+ const char *shortcut;
+} key_code_name_t;
+
+struct Gpm_Event;
+
+/*** global variables defined in .c file *********************************************************/
+
+extern const key_code_name_t key_name_conv_tab[];
+
+extern int old_esc_mode_timeout;
+
+extern int double_click_speed;
+extern gboolean old_esc_mode;
+extern gboolean use_8th_bit_as_meta;
+extern int mou_auto_repeat;
+
+extern gboolean bracketed_pasting_in_progress;
+
+/*** declarations of public functions ************************************************************/
+
+gboolean define_sequence (int code, const char *seq, int action);
+
+void init_key (void);
+void init_key_input_fd (void);
+void done_key (void);
+
+long tty_keyname_to_keycode (const char *name, char **label);
+char *tty_keycode_to_keyname (const int keycode);
+/* mouse support */
+int tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block);
+gboolean is_idle (void);
+int tty_getch (void);
+
+/* While waiting for input, the program can select on more than one file */
+typedef int (*select_fn) (int fd, void *info);
+
+/* Channel manipulation */
+void add_select_channel (int fd, select_fn callback, void *info);
+void delete_select_channel (int fd);
+
+/* Activate/deactivate the channel checking */
+void channels_up (void);
+void channels_down (void);
+
+/* internally used in key.c, defined in keyxtra.c */
+void load_xtra_key_defines (void);
+
+/* Learn a single key */
+char *learn_key (void);
+
+/* Returns a key code (interpreted) */
+int get_key_code (int nodelay);
+
+/* Set keypad mode (xterm and linux console only) */
+void numeric_keypad_mode (void);
+void application_keypad_mode (void);
+
+/* Bracketed paste mode */
+void enable_bracketed_paste (void);
+void disable_bracketed_paste (void);
+
+/*** inline functions ****************************************************************************/
+
+static inline gboolean
+is_abort_char (int c)
+{
+ return ((c == (int) ESC_CHAR) || (c == (int) KEY_F (10)));
+}
+
+#endif /* MC_KEY_H */
diff --git a/lib/tty/keyxdef.c b/lib/tty/keyxdef.c
new file mode 100644
index 0000000..a496f67
--- /dev/null
+++ b/lib/tty/keyxdef.c
@@ -0,0 +1,455 @@
+/* {{{ Copyright */
+
+/*
+ Additional keyboard support routines.
+
+ Copyright (C) 1998-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Gyorgy Tamasi, 1998
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* }}} */
+
+/** \file keyxdef.c
+ * \brief Source: additional keyboard support routines
+ *
+ * PURPOSE:
+ * We would like to support the direct ALT-?/META-? and some other 'extra'
+ * keyboard functionality provided by some terminals under some OSes (and
+ * not supported by the 'learn keys...' facility of 'mc'.
+ * (First target platform: QNX.)
+ *
+ * REMARK:
+ *
+ * Implementation strategy: we don't want to rely on a specific terminal
+ * information database management API (termcap,terminfo,SLang,...), so we
+ * try to define a superset of the possible key identifiers here.
+ *
+ */
+
+#include <config.h>
+
+#include "lib/global.h"
+
+#include "tty.h"
+#include "mouse.h" /* required before key.h */
+#include "key.h"
+
+#if defined (__QNX__) && !defined (__QNXNTO__)
+#define HAVE_QNX_KEYS
+#endif
+
+#ifdef HAVE_QNX_KEYS
+
+/* select implementation: use QNX/term interface */
+#define __USE_QNX_TI
+
+/* implementation specific _TE() definition */
+#ifdef __USE_QNX_TI
+
+/* include QNX/term.h (not NCURSES/term.h!) */
+#if __WATCOMC__ > 1000
+#include <sys/term.h>
+#else
+#include <term.h>
+#endif
+#include <stdlib.h> /* getenv() */
+
+/* fieldname -> index conversion */
+#define __QTISX(_qtisn) \
+ (((int)(&((struct _strs*)0)->_qtisn))/sizeof(charoffset))
+
+/* define the OS/implementation-specific __TK() format */
+#define __TK(_tis,_tcs,_tisx,_qtisn) __QTISX(_qtisn)
+
+#endif /* __USE_QNX_TI */
+
+#endif /* HAVE_QNX_KEYS */
+
+
+/* {{{ */
+
+/* general key definitions:
+ *
+ * format:
+ *
+ * terminfo name,
+ * termcap name,
+ * index in the terminfo string table (ncurses),
+ * field name in the QNX terminfo strings struct
+ */
+
+/*** global variables ****************************************************************************/
+
+/*** file scope macro definitions ****************************************************************/
+
+
+#define Key_backspace __TK("kbs", "kb", 55, _ky_backspace )
+#define Key_catab __TK("ktbc", "ka", 56, _ky_catab )
+#define Key_clear __TK("kclr", "kC", 57, _ky_clear )
+#define Key_ctab __TK("kctab", "kt", 58, _ky_ctab )
+#define Key_dc __TK("kdch1", "kD", 59, _ky_dc )
+#define Key_dl __TK("kdl1", "kL", 60, _ky_dl )
+#define Key_down __TK("kcud1", "kd", 61, _ky_down )
+#define Key_eic __TK("krmir", "kM", 62, _ky_eic )
+#define Key_eol __TK("kel", "kE", 63, _ky_eol )
+#define Key_eos __TK("ked", "kS", 64, _ky_eos )
+#define Key_f0 __TK("kf0", "k0", 65, _ky_f0 )
+#define Key_f1 __TK("kf1", "k1", 66, _ky_f1 )
+#define Key_f10 __TK("kf10", "k;", 67, _ky_f10 )
+#define Key_f2 __TK("kf2", "k2", 68, _ky_f2 )
+#define Key_f3 __TK("kf3", "k3", 69, _ky_f3 )
+#define Key_f4 __TK("kf4", "k4", 70, _ky_f4 )
+#define Key_f5 __TK("kf5", "k5", 71, _ky_f5 )
+#define Key_f6 __TK("kf6", "k6", 72, _ky_f6 )
+#define Key_f7 __TK("kf7", "k7", 73, _ky_f7 )
+#define Key_f8 __TK("kf8", "k8", 74, _ky_f8 )
+#define Key_f9 __TK("kf9", "k9", 75, _ky_f9 )
+#define Key_home __TK("khome", "kh", 76, _ky_home )
+#define Key_ic __TK("kich1", "kI", 77, _ky_ic )
+#define Key_il __TK("kil1", "kA", 78, _ky_il )
+#define Key_left __TK("kcub1", "kl", 79, _ky_left )
+#define Key_ll __TK("kll", "kH", 80, _ky_ll )
+#define Key_npage __TK("knp", "kN", 81, _ky_npage )
+#define Key_ppage __TK("kpp", "kP", 82, _ky_ppage )
+#define Key_right __TK("kcuf1", "kr", 83, _ky_right )
+#define Key_sf __TK("kind", "kF", 84, _ky_sf )
+#define Key_sr __TK("kri", "kR", 85, _ky_sr )
+#define Key_stab __TK("khts", "kT", 86, _ky_stab )
+#define Key_up __TK("kcuu1", "ku", 87, _ky_up )
+#define Key_a1 __TK("ka1", "K1", 139, _ky_a1 )
+#define Key_a3 __TK("ka3", "K3", 140, _ky_a3 )
+#define Key_b2 __TK("kb2", "K2", 141, _ky_b2 )
+#define Key_c1 __TK("kc1", "K4", 142, _ky_c1 )
+#define Key_c3 __TK("kc3", "K5", 143, _ky_c3 )
+#define Key_btab __TK("kcbt", "kB", 148, _ky_btab )
+#define Key_beg __TK("kbeg", "@1", 158, _ky_beg )
+#define Key_cancel __TK("kcan", "@2", 159, _ky_cancel )
+#define Key_close __TK("kclo", "@3", 160, _ky_close )
+#define Key_command __TK("kcmd", "@4", 161, _ky_command )
+#define Key_copy __TK("kcpy", "@5", 162, _ky_copy )
+#define Key_create __TK("kcrt", "@6", 163, _ky_create )
+#define Key_end __TK("kend", "@7", 164, _ky_end )
+#define Key_enter __TK("kent", "@8", 165, _ky_enter )
+#define Key_exit __TK("kext", "@9", 166, _ky_exit )
+#define Key_find __TK("kfnd", "@0", 167, _ky_find )
+#define Key_help __TK("khlp", "%1", 168, _ky_help )
+#define Key_mark __TK("kmrk", "%2", 169, _ky_mark )
+#define Key_message __TK("kmsg", "%3", 170, _ky_message )
+#define Key_move __TK("kmov", "%4", 171, _ky_move )
+#define Key_next __TK("knxt", "%5", 172, _ky_next )
+#define Key_open __TK("kopn", "%6", 173, _ky_open )
+#define Key_options __TK("kopt", "%7", 174, _ky_options )
+#define Key_previous __TK("kprv", "%8", 175, _ky_previous )
+#define Key_print __TK("kprt", "%9", 176, _ky_print )
+#define Key_redo __TK("krdo", "%0", 177, _ky_redo )
+#define Key_reference __TK("kref", "&1", 178, _ky_reference )
+#define Key_refresh __TK("krfr", "&2", 179, _ky_refresh )
+#define Key_replace __TK("krpl", "&3", 180, _ky_replace )
+#define Key_restart __TK("krst", "&4", 181, _ky_restart )
+#define Key_resume __TK("kres", "&5", 182, _ky_resume )
+#define Key_save __TK("ksav", "&6", 183, _ky_save )
+#define Key_suspend __TK("kspd", "&7", 184, _ky_suspend )
+#define Key_undo __TK("kund", "&8", 185, _ky_undo )
+#define Key_sbeg __TK("kBEG", "&9", 186, _ky_sbeg )
+#define Key_scancel __TK("kCAN", "&0", 187, _ky_scancel )
+#define Key_scommand __TK("kCMD", "*1", 188, _ky_scommand )
+#define Key_scopy __TK("kCPY", "*2", 189, _ky_scopy )
+#define Key_screate __TK("kCRT", "*3", 190, _ky_screate )
+#define Key_sdc __TK("kDC", "*4", 191, _ky_sdc )
+#define Key_sdl __TK("kDL", "*5", 192, _ky_sdl )
+#define Key_select __TK("kslt", "*6", 193, _ky_select )
+#define Key_send __TK("kEND", "*7", 194, _ky_send )
+#define Key_seol __TK("kEOL", "*8", 195, _ky_seol )
+#define Key_sexit __TK("kEXT", "*9", 196, _ky_sexit )
+#define Key_sfind __TK("kFND", "*0", 197, _ky_sfind )
+#define Key_shelp __TK("kHLP", "#1", 198, _ky_shelp )
+#define Key_shome __TK("kHOM", "#2", 199, _ky_shome )
+#define Key_sic __TK("kIC", "#3", 200, _ky_sic )
+#define Key_sleft __TK("kLFT", "#4", 201, _ky_sleft )
+#define Key_smessage __TK("kMSG", "%a", 202, _ky_smessage )
+#define Key_smove __TK("kMOV", "%b", 203, _ky_smove )
+#define Key_snext __TK("kNXT", "%c", 204, _ky_snext )
+#define Key_soptions __TK("kOPT", "%d", 205, _ky_soptions )
+#define Key_sprevious __TK("kPRV", "%e", 206, _ky_sprevious )
+#define Key_sprint __TK("kPRT", "%f", 207, _ky_sprint )
+#define Key_sredo __TK("kRDO", "%g", 208, _ky_sredo )
+#define Key_sreplace __TK("kRPL", "%h", 209, _ky_sreplace )
+#define Key_sright __TK("kRIT", "%i", 210, _ky_sright )
+#define Key_srsume __TK("kRES", "%j", 211, _ky_srsume )
+#define Key_ssave __TK("kSAV", "!1", 212, _ky_ssave )
+#define Key_ssuspend __TK("kSPD", "!2", 213, _ky_ssuspend )
+#define Key_sundo __TK("kUND", "!3", 214, _ky_sundo )
+#define Key_f11 __TK("kf11", "F1", 216, _ky_f11 )
+#define Key_f12 __TK("kf12", "F2", 217, _ky_f12 )
+#define Key_f13 __TK("kf13", "F3", 218, _ky_f13 )
+#define Key_f14 __TK("kf14", "F4", 219, _ky_f14 )
+#define Key_f15 __TK("kf15", "F5", 220, _ky_f15 )
+#define Key_f16 __TK("kf16", "F6", 221, _ky_f16 )
+#define Key_f17 __TK("kf17", "F7", 222, _ky_f17 )
+#define Key_f18 __TK("kf18", "F8", 223, _ky_f18 )
+#define Key_f19 __TK("kf19", "F9", 224, _ky_f19 )
+#define Key_f20 __TK("kf20", "FA", 225, _ky_f20 )
+#define Key_f21 __TK("kf21", "FB", 226, _ky_f21 )
+#define Key_f22 __TK("kf22", "FC", 227, _ky_f22 )
+#define Key_f23 __TK("kf23", "FD", 228, _ky_f23 )
+#define Key_f24 __TK("kf24", "FE", 229, _ky_f24 )
+#define Key_f25 __TK("kf25", "FF", 230, _ky_f25 )
+#define Key_f26 __TK("kf26", "FG", 231, _ky_f26 )
+#define Key_f27 __TK("kf27", "FH", 232, _ky_f27 )
+#define Key_f28 __TK("kf28", "FI", 233, _ky_f28 )
+#define Key_f29 __TK("kf29", "FJ", 234, _ky_f29 )
+#define Key_f30 __TK("kf30", "FK", 235, _ky_f30 )
+#define Key_f31 __TK("kf31", "FL", 236, _ky_f31 )
+#define Key_f32 __TK("kf32", "FM", 237, _ky_f32 )
+#define Key_f33 __TK("kf33", "FN", 238, _ky_f33 )
+#define Key_f34 __TK("kf34", "FO", 239, _ky_f34 )
+#define Key_f35 __TK("kf35", "FP", 240, _ky_f35 )
+#define Key_f36 __TK("kf36", "FQ", 241, _ky_f36 )
+#define Key_f37 __TK("kf37", "FR", 242, _ky_f37 )
+#define Key_f38 __TK("kf38", "FS", 243, _ky_f38 )
+#define Key_f39 __TK("kf39", "FT", 244, _ky_f39 )
+#define Key_f40 __TK("kf40", "FU", 245, _ky_f40 )
+#define Key_f41 __TK("kf41", "FV", 246, _ky_f41 )
+#define Key_f42 __TK("kf42", "FW", 247, _ky_f42 )
+#define Key_f43 __TK("kf43", "FX", 248, _ky_f43 )
+#define Key_f44 __TK("kf44", "FY", 249, _ky_f44 )
+#define Key_f45 __TK("kf45", "FZ", 250, _ky_f45 )
+#define Key_f46 __TK("kf46", "Fa", 251, _ky_f46 )
+#define Key_f47 __TK("kf47", "Fb", 252, _ky_f47 )
+#define Key_f48 __TK("kf48", "Fc", 253, _ky_f48 )
+#define Key_f49 __TK("kf49", "Fd", 254, _ky_f49 )
+#define Key_f50 __TK("kf50", "Fe", 255, _ky_f50 )
+#define Key_f51 __TK("kf51", "Ff", 256, _ky_f51 )
+#define Key_f52 __TK("kf52", "Fg", 257, _ky_f52 )
+#define Key_f53 __TK("kf53", "Fh", 258, _ky_f53 )
+#define Key_f54 __TK("kf54", "Fi", 259, _ky_f54 )
+#define Key_f55 __TK("kf55", "Fj", 260, _ky_f55 )
+#define Key_f56 __TK("kf56", "Fk", 261, _ky_f56 )
+#define Key_f57 __TK("kf57", "Fl", 262, _ky_f57 )
+#define Key_f58 __TK("kf58", "Fm", 263, _ky_f58 )
+#define Key_f59 __TK("kf59", "Fn", 264, _ky_f59 )
+#define Key_f60 __TK("kf60", "Fo", 265, _ky_f60 )
+#define Key_f61 __TK("kf61", "Fp", 266, _ky_f61 )
+#define Key_f62 __TK("kf62", "Fq", 267, _ky_f62 )
+#define Key_f63 __TK("kf63", "Fr", 268, _ky_f63 )
+
+/* }}} */
+
+#ifdef HAVE_QNX_KEYS
+
+/* don't force pre-defining of base keys under QNX */
+#define FORCE_BASE_KEY_DEFS 0
+
+/* OS specific key aliases */
+#define Key_alt_a Key_clear
+#define Key_alt_b Key_stab
+#define Key_alt_c Key_close
+#define Key_alt_d Key_catab
+#define Key_alt_e Key_message
+#define Key_alt_f Key_find
+#define Key_alt_g Key_refresh
+#define Key_alt_h Key_help
+#define Key_alt_i Key_move
+#define Key_alt_j Key_restart
+#define Key_alt_k Key_options
+#define Key_alt_l Key_reference
+#define Key_alt_m Key_mark
+#define Key_alt_n Key_sbeg
+#define Key_alt_o Key_open
+#define Key_alt_p Key_resume
+#define Key_alt_q Key_save
+#define Key_alt_r Key_replace
+#define Key_alt_s Key_scopy
+#define Key_alt_t Key_screate
+#define Key_alt_u Key_undo
+#define Key_alt_v Key_sdl
+#define Key_alt_w Key_sexit
+#define Key_alt_x Key_sfind
+#define Key_alt_y Key_shelp
+#define Key_alt_z Key_soptions
+
+#define Key_ctl_enter Key_enter
+#define Key_ctl_tab Key_ctab
+
+#define Key_alt_tab Key_ctl_tab /* map ALT-TAB to CTRL-TAB */
+#define Key_alt_enter Key_ctl_enter /* map ALT-ENTER to CTRL-ENTER */
+
+#ifdef __USE_QNX_TI
+/* define current xtra_key_define_t (enable OS/implementation) */
+#define xtra_key_define_t qnx_key_define_t
+#endif /* __USE_QNX_TI */
+#endif /* HAVE_QNX_KEYS */
+
+
+#ifdef xtra_key_define_t
+#ifndef FORCE_BASE_KEY_DEFS
+#define FORCE_BASE_KEY_DEFS 0
+#endif
+#endif /* xtra_key_define_t */
+
+#ifdef HAVE_QNX_KEYS
+#ifdef __USE_QNX_TI
+#define __CT (__cur_term)
+#define __QTISOFFS(_qtisx) (((charoffset*)(&__CT->_strs))[_qtisx])
+#define __QTISSTR(_qtisx) (&__CT->_strtab[0]+__QTISOFFS(_qtisx))
+#endif /* __USE_QNX_TI */
+#endif /* HAVE_QNX_KEYS */
+
+/*** file scope type declarations ****************************************************************/
+
+#ifdef HAVE_QNX_KEYS
+#ifdef __USE_QNX_TI
+/* OS/implementation specific key-define struct */
+typedef const struct qnx_key_define_s
+{
+ int mc_code;
+ int str_idx;
+} qnx_key_define_t;
+#endif /* __USE_QNX_TI */
+#endif /* HAVE_QNX_KEYS */
+
+/*** file scope variables ************************************************************************/
+
+
+#ifdef xtra_key_define_t
+
+/* general key define table */
+xtra_key_define_t xtra_key_defines[] = {
+#if FORCE_BASE_KEY_DEFS
+ {KEY_BACKSPACE, Key_backspace},
+ {KEY_LEFT, Key_left},
+ {KEY_RIGHT, Key_right},
+ {KEY_UP, Key_up},
+ {KEY_DOWN, Key_down},
+ {KEY_NPAGE, Key_npage},
+ {KEY_PPAGE, Key_ppage},
+ {KEY_HOME, Key_home},
+ {KEY_END, Key_end},
+ {KEY_DC, Key_dc},
+ {KEY_IC, Key_ic},
+ {KEY_F (1), Key_f1},
+ {KEY_F (2), Key_f2},
+ {KEY_F (3), Key_f3},
+ {KEY_F (4), Key_f4},
+ {KEY_F (5), Key_f5},
+ {KEY_F (6), Key_f6},
+ {KEY_F (7), Key_f7},
+ {KEY_F (8), Key_f8},
+ {KEY_F (9), Key_f9},
+ {KEY_F (10), Key_f10},
+ {KEY_F (11), Key_f11},
+ {KEY_F (12), Key_f12},
+ {KEY_F (13), Key_f13},
+ {KEY_F (14), Key_f14},
+ {KEY_F (15), Key_f15},
+ {KEY_F (16), Key_f16},
+ {KEY_F (17), Key_f17},
+ {KEY_F (18), Key_f18},
+ {KEY_F (19), Key_f19},
+ {KEY_F (20), Key_f20},
+#endif
+ {ALT ('a'), Key_alt_a},
+ {ALT ('b'), Key_alt_b},
+ {ALT ('c'), Key_alt_c},
+ {ALT ('d'), Key_alt_d},
+ {ALT ('e'), Key_alt_e},
+ {ALT ('f'), Key_alt_f},
+ {ALT ('g'), Key_alt_g},
+ {ALT ('h'), Key_alt_h},
+ {ALT ('i'), Key_alt_i},
+ {ALT ('j'), Key_alt_j},
+ {ALT ('k'), Key_alt_k},
+ {ALT ('l'), Key_alt_l},
+ {ALT ('m'), Key_alt_m},
+ {ALT ('n'), Key_alt_n},
+ {ALT ('o'), Key_alt_o},
+ {ALT ('p'), Key_alt_p},
+ {ALT ('q'), Key_alt_q},
+ {ALT ('r'), Key_alt_r},
+ {ALT ('s'), Key_alt_s},
+ {ALT ('t'), Key_alt_t},
+ {ALT ('u'), Key_alt_u},
+ {ALT ('v'), Key_alt_v},
+ {ALT ('w'), Key_alt_w},
+ {ALT ('x'), Key_alt_x},
+ {ALT ('y'), Key_alt_y},
+ {ALT ('z'), Key_alt_z},
+
+ {ALT ('\n'), Key_alt_enter},
+ {ALT ('\t'), Key_alt_tab}
+};
+
+#endif /* xtra_key_define_t */
+
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+#ifdef HAVE_QNX_KEYS
+#ifdef __USE_QNX_TI
+void
+load_qnx_key_defines (void)
+{
+ static int _qnx_keys_defined = 0;
+
+ if (!_qnx_keys_defined)
+ {
+ int idx;
+ int term_setup_ok;
+
+ __setupterm (NULL, fileno (stdout), &term_setup_ok);
+ if (term_setup_ok != 1)
+ return;
+
+ for (idx = 0; idx < sizeof (xtra_key_defines) / sizeof (xtra_key_defines[0]); idx++)
+ {
+ int str_idx = xtra_key_defines[idx].str_idx;
+
+ if (__QTISOFFS (str_idx))
+ {
+ if (*__QTISSTR (str_idx))
+ {
+ define_sequence (xtra_key_defines[idx].mc_code,
+ __QTISSTR (str_idx), MCKEY_NOACTION);
+ }
+ }
+ }
+ _qnx_keys_defined = 1;
+ }
+}
+#endif /* __USE_QNX_TI */
+#endif /* HAVE_QNX_KEYS */
+
+/* --------------------------------------------------------------------------------------------- */
+/* called from key.c/init_key() */
+
+void
+load_xtra_key_defines (void)
+{
+#ifdef HAVE_QNX_KEYS
+ load_qnx_key_defines ();
+#endif
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/mouse.c b/lib/tty/mouse.c
new file mode 100644
index 0000000..cf42287
--- /dev/null
+++ b/lib/tty/mouse.c
@@ -0,0 +1,216 @@
+/*
+ Mouse managing
+
+ Copyright (C) 1994-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Andrew Borodin <aborodin@vmail.ru>, 2009.
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file mouse.c
+ * \brief Source: mouse managing
+ *
+ * Events received by clients of this library have their coordinates 0 based
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "lib/global.h"
+
+#include "tty.h"
+#include "tty-internal.h" /* mouse_enabled */
+#include "mouse.h"
+#include "key.h" /* define sequence */
+
+/*** global variables ****************************************************************************/
+
+Mouse_Type use_mouse_p = MOUSE_NONE;
+gboolean mouse_enabled = FALSE;
+int mouse_fd = -1; /* for when gpm_fd changes to < 0 and the old one must be cleared from select_set */
+const char *xmouse_seq;
+const char *xmouse_extended_seq;
+
+/*** file scope macro definitions ****************************************************************/
+
+/*** file scope type declarations ****************************************************************/
+
+/*** file scope variables ************************************************************************/
+
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+void
+show_mouse_pointer (int x, int y)
+{
+#ifdef HAVE_LIBGPM
+ if (use_mouse_p == MOUSE_GPM)
+ Gpm_DrawPointer (x, y, gpm_consolefd);
+#else
+ (void) x;
+ (void) y;
+#endif /* HAVE_LIBGPM */
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+init_mouse (void)
+{
+ switch (use_mouse_p)
+ {
+#ifdef HAVE_LIBGPM
+ case MOUSE_NONE:
+ use_mouse_p = MOUSE_GPM;
+ break;
+#endif /* HAVE_LIBGPM */
+
+ case MOUSE_XTERM_NORMAL_TRACKING:
+ case MOUSE_XTERM_BUTTON_EVENT_TRACKING:
+ if (xmouse_seq != NULL)
+ define_sequence (MCKEY_MOUSE, xmouse_seq, MCKEY_NOACTION);
+ if (xmouse_extended_seq != NULL)
+ define_sequence (MCKEY_EXTENDED_MOUSE, xmouse_extended_seq, MCKEY_NOACTION);
+ break;
+
+ default:
+ break;
+ }
+
+ enable_mouse ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+enable_mouse (void)
+{
+ if (mouse_enabled)
+ return;
+
+ switch (use_mouse_p)
+ {
+#ifdef HAVE_LIBGPM
+ case MOUSE_GPM:
+ {
+ Gpm_Connect conn;
+
+ conn.eventMask = ~GPM_MOVE;
+ conn.defaultMask = GPM_MOVE;
+ conn.minMod = 0;
+ conn.maxMod = 0;
+
+ mouse_fd = Gpm_Open (&conn, 0);
+ if (mouse_fd == -1)
+ {
+ use_mouse_p = MOUSE_NONE;
+ return;
+ }
+ mouse_enabled = TRUE;
+ }
+ break;
+#endif /* HAVE_LIBGPM */
+
+ case MOUSE_XTERM_NORMAL_TRACKING:
+ /* save old highlight mouse tracking */
+ printf (ESC_STR "[?1001s");
+
+ /* enable mouse tracking */
+ printf (ESC_STR "[?1000h");
+
+ /* enable SGR extended mouse reporting */
+ printf (ESC_STR "[?1006h");
+
+ fflush (stdout);
+ mouse_enabled = TRUE;
+ break;
+
+ case MOUSE_XTERM_BUTTON_EVENT_TRACKING:
+ /* save old highlight mouse tracking */
+ printf (ESC_STR "[?1001s");
+
+ /* enable mouse tracking */
+ printf (ESC_STR "[?1002h");
+
+ /* enable SGR extended mouse reporting */
+ printf (ESC_STR "[?1006h");
+
+ fflush (stdout);
+ mouse_enabled = TRUE;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+disable_mouse (void)
+{
+ if (!mouse_enabled)
+ return;
+
+ mouse_enabled = FALSE;
+
+ switch (use_mouse_p)
+ {
+#ifdef HAVE_LIBGPM
+ case MOUSE_GPM:
+ Gpm_Close ();
+ break;
+#endif
+ case MOUSE_XTERM_NORMAL_TRACKING:
+ /* disable SGR extended mouse reporting */
+ printf (ESC_STR "[?1006l");
+
+ /* disable mouse tracking */
+ printf (ESC_STR "[?1000l");
+
+ /* restore old highlight mouse tracking */
+ printf (ESC_STR "[?1001r");
+
+ fflush (stdout);
+ break;
+ case MOUSE_XTERM_BUTTON_EVENT_TRACKING:
+ /* disable SGR extended mouse reporting */
+ printf (ESC_STR "[?1006l");
+
+ /* disable mouse tracking */
+ printf (ESC_STR "[?1002l");
+
+ /* restore old highlight mouse tracking */
+ printf (ESC_STR "[?1001r");
+
+ fflush (stdout);
+ break;
+ default:
+ break;
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/mouse.h b/lib/tty/mouse.h
new file mode 100644
index 0000000..99d0a69
--- /dev/null
+++ b/lib/tty/mouse.h
@@ -0,0 +1,117 @@
+
+/** \file mouse.h
+ * \brief Header: mouse managing
+ *
+ * Events received by clients of this library have their coordinates 0 based
+ */
+
+#ifndef MC__MOUSE_H
+#define MC__MOUSE_H
+
+#ifdef HAVE_LIBGPM
+/* GPM mouse support include file */
+#include <gpm.h>
+#endif /* !HAVE_LIBGPM */
+
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+#ifndef HAVE_LIBGPM
+/* Equivalent definitions for non-GPM mouse support */
+/* These lines are modified version from the lines appearing in the */
+/* gpm.h include file of the Linux General Purpose Mouse server */
+
+#define GPM_B_LEFT (1 << 2)
+#define GPM_B_MIDDLE (1 << 1)
+#define GPM_B_RIGHT (1 << 0)
+
+#define GPM_BARE_EVENTS(ev) ((ev)&0xF)
+#endif /* !HAVE_LIBGPM */
+
+/* Mouse wheel events */
+#ifndef GPM_B_DOWN
+#define GPM_B_DOWN (1 << 5)
+#endif
+
+#ifndef GPM_B_UP
+#define GPM_B_UP (1 << 4)
+#endif
+
+/*** enums ***************************************************************************************/
+
+#ifndef HAVE_LIBGPM
+/* Xterm mouse support supports only GPM_DOWN and GPM_UP */
+/* If you use others make sure your code also works without them */
+enum Gpm_Etype
+{
+ GPM_MOVE = 1,
+ GPM_DRAG = 2, /* exactly one in four is active at a time */
+ GPM_DOWN = 4,
+ GPM_UP = 8,
+
+
+ GPM_SINGLE = 16, /* at most one in three is set */
+ GPM_DOUBLE = 32,
+ GPM_TRIPLE = 64,
+
+ GPM_MFLAG = 128, /* motion during click? */
+ GPM_HARD = 256 /* if set in the defaultMask, force an already
+ used event to pass over to another handler */
+};
+#endif /* !HAVE_LIBGPM */
+
+/* Constants returned from the mouse callback */
+enum
+{
+ MOU_UNHANDLED = 0,
+ MOU_NORMAL,
+ MOU_REPEAT
+};
+
+/* Type of mouse support */
+typedef enum
+{
+ MOUSE_NONE, /* Not detected yet */
+ MOUSE_DISABLED, /* Explicitly disabled by -d */
+ MOUSE_GPM, /* Support using GPM on Linux */
+ MOUSE_XTERM, /* Support using xterm-style mouse reporting */
+ MOUSE_XTERM_NORMAL_TRACKING = MOUSE_XTERM,
+ MOUSE_XTERM_BUTTON_EVENT_TRACKING
+} Mouse_Type;
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+#ifndef HAVE_LIBGPM
+typedef struct Gpm_Event
+{
+ int buttons, x, y;
+ enum Gpm_Etype type;
+} Gpm_Event;
+#endif /* !HAVE_LIBGPM */
+
+/*** global variables defined in .c file *********************************************************/
+
+/* Type of the currently used mouse */
+extern Mouse_Type use_mouse_p;
+
+/* To be used when gpm_fd were initially >= 0 */
+extern int mouse_fd;
+
+/* String indicating that a mouse event has occurred, usually "\E[M" */
+extern const char *xmouse_seq;
+
+/* String indicating that an SGR extended mouse event has occurred, namely "\E[<" */
+extern const char *xmouse_extended_seq;
+
+/*** declarations of public functions ************************************************************/
+
+/* General (i.e. both for xterm and gpm) mouse support definitions */
+
+void init_mouse (void);
+void enable_mouse (void);
+void disable_mouse (void);
+
+void show_mouse_pointer (int x, int y);
+
+/*** inline functions ****************************************************************************/
+#endif /* MC_MOUSE_H */
diff --git a/lib/tty/tty-internal.c b/lib/tty/tty-internal.c
new file mode 100644
index 0000000..c79301d
--- /dev/null
+++ b/lib/tty/tty-internal.c
@@ -0,0 +1,110 @@
+/*
+ Internal stuff of the terminal controlling library.
+
+ Copyright (C) 2019-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Andrew Borodin <aborodin@vmail.ru>, 2019.
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * \brief Source: internal stuff of the terminal controlling library.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "lib/global.h"
+
+#include <glib-unix.h>
+
+#include "tty-internal.h"
+
+/*** global variables ****************************************************************************/
+
+/* pipe to handle SIGWINCH */
+int sigwinch_pipe[2];
+
+/*** file scope macro definitions ****************************************************************/
+
+/*** global variables ****************************************************************************/
+
+/*** file scope type declarations ****************************************************************/
+
+/*** file scope variables ************************************************************************/
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_create_winch_pipe (void)
+{
+ GError *mcerror = NULL;
+
+ if (!g_unix_open_pipe (sigwinch_pipe, FD_CLOEXEC, &mcerror))
+ {
+ fprintf (stderr, _("\nCannot create pipe for SIGWINCH: %s (%d)\n"),
+ mcerror->message, mcerror->code);
+ g_error_free (mcerror);
+ exit (EXIT_FAILURE);
+ }
+
+ /* If we read from an empty pipe, then read(2) will block until data is available.
+ * If we write to a full pipe, then write(2) blocks until sufficient data has been read
+ * from the pipe to allow the write to complete..
+ * Therefore, use nonblocking I/O.
+ */
+ if (!g_unix_set_fd_nonblocking (sigwinch_pipe[0], TRUE, &mcerror))
+ {
+ fprintf (stderr, _("\nCannot configure write end of SIGWINCH pipe: %s (%d)\n"),
+ mcerror->message, mcerror->code);
+ g_error_free (mcerror);
+ tty_destroy_winch_pipe ();
+ exit (EXIT_FAILURE);
+ }
+
+ if (!g_unix_set_fd_nonblocking (sigwinch_pipe[1], TRUE, &mcerror))
+ {
+ fprintf (stderr, _("\nCannot configure read end of SIGWINCH pipe: %s (%d)\n"),
+ mcerror->message, mcerror->code);
+ g_error_free (mcerror);
+ tty_destroy_winch_pipe ();
+ exit (EXIT_FAILURE);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_destroy_winch_pipe (void)
+{
+ (void) close (sigwinch_pipe[0]);
+ (void) close (sigwinch_pipe[1]);
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/tty-internal.h b/lib/tty/tty-internal.h
new file mode 100644
index 0000000..a2cdfa7
--- /dev/null
+++ b/lib/tty/tty-internal.h
@@ -0,0 +1,49 @@
+
+/** \file tty-internal.h
+ * \brief Header: internal stuff of the terminal controlling library
+ */
+
+#ifndef MC__TTY_INTERNAL_H
+#define MC__TTY_INTERNAL_H
+
+#include "lib/global.h" /* include <glib.h> */
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+/* Taken from S-Lang's slutty.c */
+#ifdef _POSIX_VDISABLE
+#define NULL_VALUE _POSIX_VDISABLE
+#else
+#define NULL_VALUE 255
+#endif
+
+/*** enums ***************************************************************************************/
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+/*** global variables defined in .c file *********************************************************/
+
+/* The mouse is currently: TRUE - enabled, FALSE - disabled */
+extern gboolean mouse_enabled;
+
+/* terminal ca capabilities */
+extern char *smcup;
+extern char *rmcup;
+
+/* pipe to handle SIGWINCH */
+extern int sigwinch_pipe[2];
+
+/*** declarations of public functions ************************************************************/
+
+void tty_create_winch_pipe (void);
+void tty_destroy_winch_pipe (void);
+
+char *mc_tty_normalize_from_utf8 (const char *str);
+void tty_init_xterm_support (gboolean is_xterm);
+int tty_lowlevel_getch (void);
+
+void tty_colorize_area (int y, int x, int rows, int cols, int color);
+
+/*** inline functions ****************************************************************************/
+
+#endif /* MC_TTY_INTERNAL_H */
diff --git a/lib/tty/tty-ncurses.c b/lib/tty/tty-ncurses.c
new file mode 100644
index 0000000..08f663d
--- /dev/null
+++ b/lib/tty/tty-ncurses.c
@@ -0,0 +1,772 @@
+/*
+ Interface to the terminal controlling library.
+ Ncurses wrapper.
+
+ Copyright (C) 2005-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Andrew Borodin <aborodin@vmail.ru>, 2009.
+ Ilia Maslakov <il.smind@gmail.com>, 2009.
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * \brief Source: NCurses-based tty layer of Midnight-commander
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <termios.h>
+
+#include "lib/global.h"
+#include "lib/strutil.h" /* str_term_form */
+
+#ifndef WANT_TERM_H
+#define WANT_TERM_H
+#endif
+
+#include "tty-internal.h" /* mc_tty_normalize_from_utf8() */
+#include "tty.h"
+#include "color.h" /* tty_setcolor */
+#include "color-internal.h"
+#include "key.h"
+#include "mouse.h"
+#include "win.h"
+
+/* include at last !!! */
+#ifdef WANT_TERM_H
+#ifdef HAVE_NCURSES_TERM_H
+#include <ncurses/term.h>
+#else
+#include <term.h>
+#endif /* HAVE_NCURSES_TERM_H */
+#endif /* WANT_TERM_H */
+
+/*** global variables ****************************************************************************/
+
+/*** file scope macro definitions ****************************************************************/
+
+#if !defined(CTRL)
+#define CTRL(x) ((x) & 0x1f)
+#endif
+
+#define yx_in_screen(y, x) \
+ (y >= 0 && y < LINES && x >= 0 && x < COLS)
+
+/*** global variables ****************************************************************************/
+
+/*** file scope type declarations ****************************************************************/
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** file scope variables ************************************************************************/
+
+/* ncurses supports cursor positions only within window */
+/* We use our own cursor coordinates to support partially visible widgets */
+static int mc_curs_row, mc_curs_col;
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+tty_setup_sigwinch (void (*handler) (int))
+{
+#if (NCURSES_VERSION_MAJOR >= 4) && defined (SIGWINCH)
+ struct sigaction act, oact;
+
+ memset (&act, 0, sizeof (act));
+ act.sa_handler = handler;
+ sigemptyset (&act.sa_mask);
+#ifdef SA_RESTART
+ act.sa_flags = SA_RESTART;
+#endif /* SA_RESTART */
+ sigaction (SIGWINCH, &act, &oact);
+#endif /* SIGWINCH */
+
+ tty_create_winch_pipe ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+sigwinch_handler (int dummy)
+{
+ ssize_t n = 0;
+
+ (void) dummy;
+
+ n = write (sigwinch_pipe[1], "", 1);
+ (void) n;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+/**
+ * Get visible part of area.
+ *
+ * @returns TRUE if any part of area is in screen bounds, FALSE otherwise.
+ */
+static gboolean
+tty_clip (int *y, int *x, int *rows, int *cols)
+{
+ if (*y < 0)
+ {
+ *rows += *y;
+
+ if (*rows <= 0)
+ return FALSE;
+
+ *y = 0;
+ }
+
+ if (*x < 0)
+ {
+ *cols += *x;
+
+ if (*cols <= 0)
+ return FALSE;
+
+ *x = 0;
+ }
+
+ if (*y + *rows > LINES)
+ *rows = LINES - *y;
+
+ if (*rows <= 0)
+ return FALSE;
+
+ if (*x + *cols > COLS)
+ *cols = COLS - *x;
+
+ if (*cols <= 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+int
+mc_tty_normalize_lines_char (const char *ch)
+{
+ char *str2;
+ int res;
+
+ struct mc_tty_lines_struct
+ {
+ const char *line;
+ int line_code;
+ } const lines_codes[] = {
+ {"\342\224\230", ACS_LRCORNER}, /* ┌ */
+ {"\342\224\224", ACS_LLCORNER}, /* └ */
+ {"\342\224\220", ACS_URCORNER}, /* ┐ */
+ {"\342\224\214", ACS_ULCORNER}, /* ┘ */
+ {"\342\224\234", ACS_LTEE}, /* ├ */
+ {"\342\224\244", ACS_RTEE}, /* ┤ */
+ {"\342\224\254", ACS_TTEE}, /* ┬ */
+ {"\342\224\264", ACS_BTEE}, /* ┴ */
+ {"\342\224\200", ACS_HLINE}, /* ─ */
+ {"\342\224\202", ACS_VLINE}, /* │ */
+ {"\342\224\274", ACS_PLUS}, /* ┼ */
+
+ {"\342\225\235", ACS_LRCORNER | A_BOLD}, /* ╔ */
+ {"\342\225\232", ACS_LLCORNER | A_BOLD}, /* ╚ */
+ {"\342\225\227", ACS_URCORNER | A_BOLD}, /* ╗ */
+ {"\342\225\224", ACS_ULCORNER | A_BOLD}, /* ╝ */
+ {"\342\225\237", ACS_LTEE | A_BOLD}, /* ╟ */
+ {"\342\225\242", ACS_RTEE | A_BOLD}, /* ╢ */
+ {"\342\225\244", ACS_TTEE | A_BOLD}, /* ╤ */
+ {"\342\225\247", ACS_BTEE | A_BOLD}, /* ╧ */
+ {"\342\225\220", ACS_HLINE | A_BOLD}, /* ═ */
+ {"\342\225\221", ACS_VLINE | A_BOLD}, /* ║ */
+
+ {NULL, 0}
+ };
+
+ if (ch == NULL)
+ return (int) ' ';
+
+ for (res = 0; lines_codes[res].line; res++)
+ {
+ if (strcmp (ch, lines_codes[res].line) == 0)
+ return lines_codes[res].line_code;
+ }
+
+ str2 = mc_tty_normalize_from_utf8 (ch);
+ res = g_utf8_get_char_validated (str2, -1);
+
+ if (res < 0)
+ res = (unsigned char) str2[0];
+ g_free (str2);
+
+ return res;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_init (gboolean mouse_enable, gboolean is_xterm)
+{
+ struct termios mode;
+
+ initscr ();
+
+#ifdef HAVE_ESCDELAY
+ /*
+ * If ncurses exports the ESCDELAY variable, it should be set to
+ * a low value, or you'll experience a delay in processing escape
+ * sequences that are recognized by mc (e.g. Esc-Esc). On the other
+ * hand, making ESCDELAY too small can result in some sequences
+ * (e.g. cursor arrows) being reported as separate keys under heavy
+ * processor load, and this can be a problem if mc hasn't learned
+ * them in the "Learn Keys" dialog. The value is in milliseconds.
+ */
+ ESCDELAY = 200;
+#endif /* HAVE_ESCDELAY */
+
+ tcgetattr (STDIN_FILENO, &mode);
+ /* use Ctrl-g to generate SIGINT */
+ mode.c_cc[VINTR] = CTRL ('g'); /* ^g */
+ /* disable SIGQUIT to allow use Ctrl-\ key */
+ mode.c_cc[VQUIT] = NULL_VALUE;
+ tcsetattr (STDIN_FILENO, TCSANOW, &mode);
+
+ /* curses remembers the "in-program" modes after this call */
+ def_prog_mode ();
+
+ tty_start_interrupt_key ();
+
+ if (!mouse_enable)
+ use_mouse_p = MOUSE_DISABLED;
+ tty_init_xterm_support (is_xterm); /* do it before tty_enter_ca_mode() call */
+ tty_enter_ca_mode ();
+ tty_raw_mode ();
+ noecho ();
+ keypad (stdscr, TRUE);
+ nodelay (stdscr, FALSE);
+
+ tty_setup_sigwinch (sigwinch_handler);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_shutdown (void)
+{
+ tty_destroy_winch_pipe ();
+ tty_reset_shell_mode ();
+ tty_noraw_mode ();
+ tty_keypad (FALSE);
+ tty_reset_screen ();
+ tty_exit_ca_mode ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_enter_ca_mode (void)
+{
+ if (mc_global.tty.xterm_flag && smcup != NULL)
+ {
+ fprintf (stdout, /* ESC_STR ")0" */ ESC_STR "7" ESC_STR "[?47h");
+ fflush (stdout);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_exit_ca_mode (void)
+{
+ if (mc_global.tty.xterm_flag && rmcup != NULL)
+ {
+ fprintf (stdout, ESC_STR "[?47l" ESC_STR "8" ESC_STR "[m");
+ fflush (stdout);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_change_screen_size (void)
+{
+#if defined(TIOCGWINSZ) && NCURSES_VERSION_MAJOR >= 4
+ struct winsize winsz;
+
+ winsz.ws_col = winsz.ws_row = 0;
+
+#ifndef NCURSES_VERSION
+ tty_noraw_mode ();
+ tty_reset_screen ();
+#endif
+
+ /* Ioctl on the STDIN_FILENO */
+ ioctl (fileno (stdout), TIOCGWINSZ, &winsz);
+ if (winsz.ws_col != 0 && winsz.ws_row != 0)
+ {
+#if defined(NCURSES_VERSION) && defined(HAVE_RESIZETERM)
+ resizeterm (winsz.ws_row, winsz.ws_col);
+ clearok (stdscr, TRUE); /* sigwinch's should use a semaphore! */
+#else
+ COLS = winsz.ws_col;
+ LINES = winsz.ws_row;
+#endif
+ }
+#endif /* defined(TIOCGWINSZ) || NCURSES_VERSION_MAJOR >= 4 */
+
+#ifdef ENABLE_SUBSHELL
+ if (mc_global.tty.use_subshell)
+ tty_resize (mc_global.tty.subshell_pty);
+#endif
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_reset_prog_mode (void)
+{
+ reset_prog_mode ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_reset_shell_mode (void)
+{
+ reset_shell_mode ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_raw_mode (void)
+{
+ raw (); /* FIXME: unneeded? */
+ cbreak ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_noraw_mode (void)
+{
+ nocbreak (); /* FIXME: unneeded? */
+ noraw ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_noecho (void)
+{
+ noecho ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_flush_input (void)
+{
+ return flushinp ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_keypad (gboolean set)
+{
+ keypad (stdscr, (bool) set);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_nodelay (gboolean set)
+{
+ nodelay (stdscr, (bool) set);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_baudrate (void)
+{
+ return baudrate ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_lowlevel_getch (void)
+{
+ return getch ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_reset_screen (void)
+{
+ return endwin ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_touch_screen (void)
+{
+ touchwin (stdscr);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_gotoyx (int y, int x)
+{
+ mc_curs_row = y;
+ mc_curs_col = x;
+
+ if (y < 0)
+ y = 0;
+ if (y >= LINES)
+ y = LINES - 1;
+
+ if (x < 0)
+ x = 0;
+ if (x >= COLS)
+ x = COLS - 1;
+
+ move (y, x);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_getyx (int *py, int *px)
+{
+ *py = mc_curs_row;
+ *px = mc_curs_col;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_draw_hline (int y, int x, int ch, int len)
+{
+ int x1;
+
+ if (y < 0 || y >= LINES || x >= COLS)
+ return;
+
+ x1 = x;
+
+ if (x < 0)
+ {
+ len += x;
+ if (len <= 0)
+ return;
+ x = 0;
+ }
+
+ if ((chtype) ch == ACS_HLINE)
+ ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
+
+ move (y, x);
+ hline (ch, len);
+ move (y, x1);
+
+ mc_curs_row = y;
+ mc_curs_col = x1;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_draw_vline (int y, int x, int ch, int len)
+{
+ int y1;
+
+ if (x < 0 || x >= COLS || y >= LINES)
+ return;
+
+ y1 = y;
+
+ if (y < 0)
+ {
+ len += y;
+ if (len <= 0)
+ return;
+ y = 0;
+ }
+
+ if ((chtype) ch == ACS_VLINE)
+ ch = mc_tty_frm[MC_TTY_FRM_VERT];
+
+ move (y, x);
+ vline (ch, len);
+ move (y1, x);
+
+ mc_curs_row = y1;
+ mc_curs_col = x;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
+{
+ int i;
+
+ if (!tty_clip (&y, &x, &rows, &cols))
+ return;
+
+ for (i = 0; i < rows; i++)
+ {
+ move (y + i, x);
+ hline (ch, cols);
+ }
+
+ move (y, x);
+
+ mc_curs_row = y;
+ mc_curs_col = x;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_colorize_area (int y, int x, int rows, int cols, int color)
+{
+#ifdef ENABLE_SHADOWS
+ cchar_t *ctext;
+ wchar_t wch[10]; /* TODO not sure if the length is correct */
+ attr_t attrs;
+ short color_pair;
+
+ if (!use_colors || !tty_clip (&y, &x, &rows, &cols))
+ return;
+
+ tty_setcolor (color);
+ ctext = g_malloc (sizeof (cchar_t) * (cols + 1));
+
+ for (int row = 0; row < rows; row++)
+ {
+ mvin_wchnstr (y + row, x, ctext, cols);
+
+ for (int col = 0; col < cols; col++)
+ {
+ getcchar (&ctext[col], wch, &attrs, &color_pair, NULL);
+ setcchar (&ctext[col], wch, attrs, color, NULL);
+ }
+
+ mvadd_wchnstr (y + row, x, ctext, cols);
+ }
+
+ g_free (ctext);
+#else
+ (void) y;
+ (void) x;
+ (void) rows;
+ (void) cols;
+ (void) color;
+#endif /* ENABLE_SHADOWS */
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_set_alt_charset (gboolean alt_charset)
+{
+ (void) alt_charset;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_display_8bit (gboolean what)
+{
+ meta (stdscr, (int) what);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_print_char (int c)
+{
+ if (yx_in_screen (mc_curs_row, mc_curs_col))
+ addch (c);
+ mc_curs_col++;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_print_anychar (int c)
+{
+ if (mc_global.utf8_display || c > 255)
+ {
+ int res;
+ unsigned char str[UTF8_CHAR_LEN + 1];
+
+ res = g_unichar_to_utf8 (c, (char *) str);
+ if (res == 0)
+ {
+ if (yx_in_screen (mc_curs_row, mc_curs_col))
+ addch ('.');
+ mc_curs_col++;
+ }
+ else
+ {
+ const char *s;
+
+ str[res] = '\0';
+ s = str_term_form ((char *) str);
+
+ if (yx_in_screen (mc_curs_row, mc_curs_col))
+ addstr (s);
+
+ if (g_unichar_iswide (c))
+ mc_curs_col += 2;
+ else if (!g_unichar_iszerowidth (c))
+ mc_curs_col++;
+ }
+ }
+ else
+ {
+ if (yx_in_screen (mc_curs_row, mc_curs_col))
+ addch (c);
+ mc_curs_col++;
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_print_alt_char (int c, gboolean single)
+{
+ if (yx_in_screen (mc_curs_row, mc_curs_col))
+ {
+ if ((chtype) c == ACS_VLINE)
+ c = mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT];
+ else if ((chtype) c == ACS_HLINE)
+ c = mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ];
+ else if ((chtype) c == ACS_LTEE)
+ c = mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE];
+ else if ((chtype) c == ACS_RTEE)
+ c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE];
+ else if ((chtype) c == ACS_ULCORNER)
+ c = mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP];
+ else if ((chtype) c == ACS_LLCORNER)
+ c = mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM];
+ else if ((chtype) c == ACS_URCORNER)
+ c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP];
+ else if ((chtype) c == ACS_LRCORNER)
+ c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM];
+ else if ((chtype) c == ACS_PLUS)
+ c = mc_tty_frm[MC_TTY_FRM_CROSS];
+
+ addch (c);
+ }
+
+ mc_curs_col++;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_print_string (const char *s)
+{
+ int len;
+ int start = 0;
+
+ s = str_term_form (s);
+ len = str_term_width1 (s);
+
+ /* line is upper or below the screen or entire line is before or after screen */
+ if (mc_curs_row < 0 || mc_curs_row >= LINES || mc_curs_col + len <= 0 || mc_curs_col >= COLS)
+ {
+ mc_curs_col += len;
+ return;
+ }
+
+ /* skip invisible left part */
+ if (mc_curs_col < 0)
+ {
+ start = -mc_curs_col;
+ len += mc_curs_col;
+ mc_curs_col = 0;
+ }
+
+ mc_curs_col += len;
+ if (mc_curs_col >= COLS)
+ len = COLS - (mc_curs_col - len);
+
+ addstr (str_term_substring (s, start, len));
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_printf (const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUF_1K]; /* FIXME: is it enough? */
+
+ va_start (args, fmt);
+ g_vsnprintf (buf, sizeof (buf), fmt, args);
+ va_end (args);
+ tty_print_string (buf);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+char *
+tty_tgetstr (const char *cap)
+{
+ char *unused = NULL;
+
+ return tgetstr ((NCURSES_CONST char *) cap, &unused);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_refresh (void)
+{
+ refresh ();
+ doupdate ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_beep (void)
+{
+ beep ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/tty-ncurses.h b/lib/tty/tty-ncurses.h
new file mode 100644
index 0000000..8feb17c
--- /dev/null
+++ b/lib/tty/tty-ncurses.h
@@ -0,0 +1,50 @@
+
+#ifndef MC__TTY_NCURSES_H
+#define MC__TTY_NCURSES_H
+
+/* for cchar_t, getcchar(), setcchar() */
+#ifndef _XOPEN_SOURCE_EXTENDED
+#define _XOPEN_SOURCE_EXTENDED
+#endif
+
+#ifdef USE_NCURSES
+#ifdef HAVE_NCURSES_CURSES_H
+#include <ncurses/curses.h>
+#elif defined (HAVE_NCURSES_NCURSES_H)
+#include <ncurses/ncurses.h>
+#elif defined (HAVE_NCURSESW_CURSES_H)
+#include <ncursesw/curses.h>
+#elif defined (HAVE_NCURSES_HCURSES_H) || defined (HAVE_NCURSES_H)
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+#endif /* USE_NCURSES */
+
+#ifdef USE_NCURSESW
+#include <ncursesw/curses.h>
+#endif /* USE_NCURSESW */
+
+/* netbsd-libcurses doesn't define NCURSES_CONST */
+#ifndef NCURSES_CONST
+#define NCURSES_CONST const
+#endif
+
+/* do not draw shadows if NCurses is built with --disable-widec */
+#if defined(NCURSES_WIDECHAR) && NCURSES_WIDECHAR
+#define ENABLE_SHADOWS 1
+#endif
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+/*** enums ***************************************************************************************/
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+/*** global variables defined in .c file *********************************************************/
+
+/*** declarations of public functions ************************************************************/
+
+/*** inline functions ****************************************************************************/
+
+#endif /* MC_TTY_NCURSES_H */
diff --git a/lib/tty/tty-slang.c b/lib/tty/tty-slang.c
new file mode 100644
index 0000000..3aa74de
--- /dev/null
+++ b/lib/tty/tty-slang.c
@@ -0,0 +1,781 @@
+/*
+ Interface to the terminal controlling library.
+ Slang wrapper.
+
+ Copyright (C) 2005-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Andrew Borodin <aborodin@vmail.ru>, 2009
+ Egmont Koblinger <egmont@gmail.com>, 2010
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * \brief Source: S-Lang-based tty layer of Midnight Commander
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h> /* size_t */
+#include <unistd.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <termios.h>
+
+#include "lib/global.h"
+#include "lib/strutil.h" /* str_term_form */
+#include "lib/util.h" /* is_printable() */
+
+#include "tty-internal.h" /* mc_tty_normalize_from_utf8() */
+#include "tty.h"
+#include "color.h"
+#include "color-slang.h"
+#include "color-internal.h"
+#include "mouse.h" /* Gpm_Event is required in key.h */
+#include "key.h" /* define_sequence */
+#include "win.h"
+
+
+/*** global variables ****************************************************************************/
+
+/* If true program softkeys (HP terminals only) on startup and after every
+ command ran in the subshell to the description found in the termcap/terminfo
+ database */
+int reset_hp_softkeys = 0;
+
+/*** file scope macro definitions ****************************************************************/
+
+#ifndef SLTT_MAX_SCREEN_COLS
+#define SLTT_MAX_SCREEN_COLS 512
+#endif
+
+#ifndef SLTT_MAX_SCREEN_ROWS
+#define SLTT_MAX_SCREEN_ROWS 512
+#endif
+
+/*** file scope type declarations ****************************************************************/
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** file scope variables ************************************************************************/
+
+/* Various saved termios settings that we control here */
+static struct termios boot_mode;
+static struct termios new_mode;
+
+/* Controls whether we should wait for input in tty_lowlevel_getch */
+static gboolean no_slang_delay;
+
+static gboolean slsmg_active = FALSE;
+
+/* This table describes which capabilities we want and which values we
+ * assign to them.
+ */
+static const struct
+{
+ int key_code;
+ const char *key_name;
+} key_table[] =
+{
+ /* *INDENT-OFF* */
+ { KEY_F (0), "k0" },
+ { KEY_F (1), "k1" },
+ { KEY_F (2), "k2" },
+ { KEY_F (3), "k3" },
+ { KEY_F (4), "k4" },
+ { KEY_F (5), "k5" },
+ { KEY_F (6), "k6" },
+ { KEY_F (7), "k7" },
+ { KEY_F (8), "k8" },
+ { KEY_F (9), "k9" },
+ { KEY_F (10), "k;" },
+ { KEY_F (11), "F1" },
+ { KEY_F (12), "F2" },
+ { KEY_F (13), "F3" },
+ { KEY_F (14), "F4" },
+ { KEY_F (15), "F5" },
+ { KEY_F (16), "F6" },
+ { KEY_F (17), "F7" },
+ { KEY_F (18), "F8" },
+ { KEY_F (19), "F9" },
+ { KEY_F (20), "FA" },
+ { KEY_IC, "kI" },
+ { KEY_NPAGE, "kN" },
+ { KEY_PPAGE, "kP" },
+ { KEY_LEFT, "kl" },
+ { KEY_RIGHT, "kr" },
+ { KEY_UP, "ku" },
+ { KEY_DOWN, "kd" },
+ { KEY_DC, "kD" },
+ { KEY_BACKSPACE, "kb" },
+ { KEY_HOME, "kh" },
+ { KEY_END, "@7" },
+ { 0, NULL }
+ /* *INDENT-ON* */
+};
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+tty_setup_sigwinch (void (*handler) (int))
+{
+ (void) SLsignal (SIGWINCH, handler);
+ tty_create_winch_pipe ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+sigwinch_handler (int dummy)
+{
+ ssize_t n = 0;
+
+ (void) dummy;
+
+ n = write (sigwinch_pipe[1], "", 1);
+ (void) n;
+
+ (void) SLsignal (SIGWINCH, sigwinch_handler);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+/* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
+ elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
+ consequence is that function keys don't work in MC sometimes...
+ Unfortunately I don't now the one and only escape sequence to turn off.
+ softkeys (elm uses three different capabilities to turn on softkeys and two.
+ capabilities to turn them off)..
+ Among other things elm uses the pair we already use in slang_keypad. That's.
+ the reason why I call slang_reset_softkeys from slang_keypad. In lack of
+ something better the softkeys are programmed to their defaults from the
+ termcap/terminfo database.
+ The escape sequence to program the softkeys is taken from elm and it is.
+ hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
+ sequence. -- Norbert
+ */
+
+static void
+slang_reset_softkeys (void)
+{
+ int key;
+ static const char display[] = " ";
+ char tmp[BUF_SMALL];
+
+ for (key = 1; key < 9; key++)
+ {
+ char *send;
+
+ g_snprintf (tmp, sizeof (tmp), "k%d", key);
+ send = SLtt_tgetstr (tmp);
+ if (send != NULL)
+ {
+ g_snprintf (tmp, sizeof (tmp), ESC_STR "&f%dk%dd%dL%s%s", key,
+ (int) (sizeof (display) - 1), (int) strlen (send), display, send);
+ SLtt_write_string (tmp);
+ }
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+do_define_key (int code, const char *strcap)
+{
+ char *seq;
+
+ seq = SLtt_tgetstr ((SLFUTURE_CONST char *) strcap);
+ if (seq != NULL)
+ define_sequence (code, seq, MCKEY_NOACTION);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+load_terminfo_keys (void)
+{
+ int i;
+
+ for (i = 0; key_table[i].key_code; i++)
+ do_define_key (key_table[i].key_code, key_table[i].key_name);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+int
+mc_tty_normalize_lines_char (const char *str)
+{
+ char *str2;
+ int res;
+
+ struct mc_tty_lines_struct
+ {
+ const char *line;
+ int line_code;
+ } const lines_codes[] = {
+ {"\342\224\214", SLSMG_ULCORN_CHAR},
+ {"\342\224\220", SLSMG_URCORN_CHAR},
+ {"\342\224\224", SLSMG_LLCORN_CHAR},
+ {"\342\224\230", SLSMG_LRCORN_CHAR},
+ {"\342\224\234", SLSMG_LTEE_CHAR},
+ {"\342\224\244", SLSMG_RTEE_CHAR},
+ {"\342\224\254", SLSMG_UTEE_CHAR},
+ {"\342\224\264", SLSMG_DTEE_CHAR},
+ {"\342\224\200", SLSMG_HLINE_CHAR},
+ {"\342\224\202", SLSMG_VLINE_CHAR},
+ {"\342\224\274", SLSMG_PLUS_CHAR},
+
+ {NULL, 0}
+ };
+
+ if (!str)
+ return (int) ' ';
+
+ for (res = 0; lines_codes[res].line; res++)
+ {
+ if (strcmp (str, lines_codes[res].line) == 0)
+ return lines_codes[res].line_code;
+ }
+
+ str2 = mc_tty_normalize_from_utf8 (str);
+ res = g_utf8_get_char_validated (str2, -1);
+
+ if (res < 0)
+ res = (unsigned char) str2[0];
+ g_free (str2);
+
+ return res;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_init (gboolean mouse_enable, gboolean is_xterm)
+{
+ SLtt_Ignore_Beep = 1;
+
+ SLutf8_enable (-1); /* has to be called first before any of the other functions. */
+ SLtt_get_terminfo ();
+ /*
+ * If the terminal in not in terminfo but begins with a well-known
+ * string such as "linux" or "xterm" S-Lang will go on, but the
+ * terminal size and several other variables won't be initialized
+ * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
+ * small screen dimensions.
+ */
+ if ((COLS < 10) || (LINES < 5)
+#if SLANG_VERSION < 20303
+ /* Beginning from pre2.3.3-8 (55f58798c267d76a1b93d0d916027b71a10ac1ee),
+ these limitations were eliminated. */
+ || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS)
+#endif
+ )
+ {
+ fprintf (stderr,
+ _("Screen size %dx%d is not supported.\n"
+ "Check the TERM environment variable.\n"), COLS, LINES);
+ exit (EXIT_FAILURE);
+ }
+
+ tcgetattr (fileno (stdin), &boot_mode);
+ /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
+ SLang_init_tty (XCTRL ('g'), 1, 0);
+
+ if (mc_global.tty.ugly_line_drawing)
+ SLtt_Has_Alt_Charset = 0;
+
+ tcgetattr (SLang_TT_Read_FD, &new_mode);
+
+ tty_reset_prog_mode ();
+ load_terminfo_keys ();
+
+ SLtt_Blink_Mode = (tty_use_256colors (NULL) || tty_use_truecolors (NULL)) ? 1 : 0;
+
+ tty_start_interrupt_key ();
+
+ /* It's the small part from the previous init_key() */
+ init_key_input_fd ();
+
+ /* For 8-bit locales, NCurses handles 154 (0x9A) symbol properly, while S-Lang
+ * requires SLsmg_Display_Eight_Bit >= 154 (OR manual filtering if xterm display
+ * detected - but checking TERM would fail under screen, OR running xterm
+ * with allowC1Printable).
+ */
+ tty_display_8bit (FALSE);
+
+ SLsmg_init_smg ();
+ slsmg_active = TRUE;
+ if (!mouse_enable)
+ use_mouse_p = MOUSE_DISABLED;
+ tty_init_xterm_support (is_xterm); /* do it before tty_enter_ca_mode() call */
+ tty_enter_ca_mode ();
+ tty_keypad (TRUE);
+ tty_nodelay (FALSE);
+
+ tty_setup_sigwinch (sigwinch_handler);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_shutdown (void)
+{
+ char *op_cap;
+
+ tty_destroy_winch_pipe ();
+ tty_reset_shell_mode ();
+ tty_noraw_mode ();
+ tty_keypad (FALSE);
+ tty_reset_screen ();
+ tty_exit_ca_mode ();
+ SLang_reset_tty ();
+ slsmg_active = FALSE;
+
+ /* Load the op capability to reset the colors to those that were
+ * active when the program was started up
+ */
+ op_cap = SLtt_tgetstr ((SLFUTURE_CONST char *) "op");
+ if (op_cap != NULL)
+ {
+ fputs (op_cap, stdout);
+ fflush (stdout);
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_enter_ca_mode (void)
+{
+ /* S-Lang handles alternate screen switching and cursor position saving */
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_exit_ca_mode (void)
+{
+ /* S-Lang handles alternate screen switching and cursor position restoring */
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_change_screen_size (void)
+{
+ SLtt_get_screen_size ();
+ if (slsmg_active)
+ SLsmg_reinit_smg ();
+
+#ifdef ENABLE_SUBSHELL
+ if (mc_global.tty.use_subshell)
+ tty_resize (mc_global.tty.subshell_pty);
+#endif
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/* Done each time we come back from done mode */
+
+void
+tty_reset_prog_mode (void)
+{
+ tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
+ SLsmg_init_smg ();
+ slsmg_active = TRUE;
+ SLsmg_touch_lines (0, LINES);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/* Called each time we want to shutdown slang screen manager */
+
+void
+tty_reset_shell_mode (void)
+{
+ tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_raw_mode (void)
+{
+ tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_noraw_mode (void)
+{
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_noecho (void)
+{
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_flush_input (void)
+{
+ return 0; /* OK */
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_keypad (gboolean set)
+{
+ char *keypad_string;
+
+ keypad_string = SLtt_tgetstr ((SLFUTURE_CONST char *) (set ? "ks" : "ke"));
+ if (keypad_string != NULL)
+ SLtt_write_string (keypad_string);
+ if (set && reset_hp_softkeys)
+ slang_reset_softkeys ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_nodelay (gboolean set)
+{
+ no_slang_delay = set;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_baudrate (void)
+{
+ return SLang_TT_Baud_Rate;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_lowlevel_getch (void)
+{
+ int c;
+
+ if (no_slang_delay && (SLang_input_pending (0) == 0))
+ return -1;
+
+ c = SLang_getkey ();
+ if (c == SLANG_GETKEY_ERROR)
+ {
+ fprintf (stderr,
+ "SLang_getkey returned SLANG_GETKEY_ERROR\n"
+ "Assuming EOF on stdin and exiting\n");
+ exit (EXIT_FAILURE);
+ }
+
+ return c;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+tty_reset_screen (void)
+{
+ SLsmg_reset_smg ();
+ slsmg_active = FALSE;
+ return 0; /* OK */
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_touch_screen (void)
+{
+ SLsmg_touch_lines (0, LINES);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_gotoyx (int y, int x)
+{
+ SLsmg_gotorc (y, x);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_getyx (int *py, int *px)
+{
+ *py = SLsmg_get_row ();
+ *px = SLsmg_get_column ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_draw_hline (int y, int x, int ch, int len)
+{
+ int x1;
+
+ if (y < 0 || y >= LINES || x >= COLS)
+ return;
+
+ x1 = x;
+
+ if (x < 0)
+ {
+ len += x;
+ if (len <= 0)
+ return;
+ x = 0;
+ }
+
+ if (ch == ACS_HLINE)
+ ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
+ if (ch == 0)
+ ch = ACS_HLINE;
+
+ SLsmg_gotorc (y, x);
+
+ if (ch == ACS_HLINE)
+ SLsmg_draw_hline (len);
+ else
+ while (len-- != 0)
+ tty_print_char (ch);
+
+ SLsmg_gotorc (y, x1);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_draw_vline (int y, int x, int ch, int len)
+{
+ int y1;
+
+ if (x < 0 || x >= COLS || y >= LINES)
+ return;
+
+ y1 = y;
+
+ if (y < 0)
+ {
+ len += y;
+ if (len <= 0)
+ return;
+ y = 0;
+ }
+
+ if (ch == ACS_VLINE)
+ ch = mc_tty_frm[MC_TTY_FRM_VERT];
+ if (ch == 0)
+ ch = ACS_VLINE;
+
+ SLsmg_gotorc (y, x);
+
+ if (ch == ACS_VLINE)
+ SLsmg_draw_vline (len);
+ else
+ {
+ int pos = 0;
+
+ while (len-- != 0)
+ {
+ SLsmg_gotorc (y + pos, x);
+ tty_print_char (ch);
+ pos++;
+ }
+ }
+
+ SLsmg_gotorc (y1, x);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
+{
+ SLsmg_fill_region (y, x, rows, cols, ch);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_colorize_area (int y, int x, int rows, int cols, int color)
+{
+ if (use_colors)
+ SLsmg_set_color_in_region (color, y, x, rows, cols);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_set_alt_charset (gboolean alt_charset)
+{
+ SLsmg_set_char_set ((int) alt_charset);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_display_8bit (gboolean what)
+{
+ SLsmg_Display_Eight_Bit = what ? 128 : 160;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_print_char (int c)
+{
+ SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_print_alt_char (int c, gboolean single)
+{
+#define DRAW(x, y) (x == y) \
+ ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
+ : SLsmg_write_char ((unsigned int) y)
+ switch (c)
+ {
+ case ACS_VLINE:
+ DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
+ break;
+ case ACS_HLINE:
+ DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
+ break;
+ case ACS_LTEE:
+ DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
+ break;
+ case ACS_RTEE:
+ DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
+ break;
+ case ACS_TTEE:
+ DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_TOPMIDDLE : MC_TTY_FRM_DTOPMIDDLE]);
+ break;
+ case ACS_BTEE:
+ DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_BOTTOMMIDDLE : MC_TTY_FRM_DBOTTOMMIDDLE]);
+ break;
+ case ACS_ULCORNER:
+ DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
+ break;
+ case ACS_LLCORNER:
+ DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
+ break;
+ case ACS_URCORNER:
+ DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
+ break;
+ case ACS_LRCORNER:
+ DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
+ break;
+ case ACS_PLUS:
+ DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
+ break;
+ default:
+ SLsmg_write_char ((unsigned int) c);
+ }
+#undef DRAW
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_print_anychar (int c)
+{
+ if (c > 255)
+ {
+ char str[UTF8_CHAR_LEN + 1];
+ int res;
+
+ res = g_unichar_to_utf8 (c, str);
+ if (res == 0)
+ {
+ str[0] = '.';
+ str[1] = '\0';
+ }
+ else
+ {
+ str[res] = '\0';
+ }
+ SLsmg_write_string ((char *) str_term_form (str));
+ }
+ else
+ {
+ if (!is_printable (c))
+ c = '.';
+ SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_print_string (const char *s)
+{
+ SLsmg_write_string ((char *) str_term_form (s));
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_printf (const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ SLsmg_vprintf ((char *) fmt, args);
+ va_end (args);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+char *
+tty_tgetstr (const char *cap)
+{
+ return SLtt_tgetstr ((SLFUTURE_CONST char *) cap);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_refresh (void)
+{
+ SLsmg_refresh ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_beep (void)
+{
+ SLtt_beep ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/tty-slang.h b/lib/tty/tty-slang.h
new file mode 100644
index 0000000..eeaade3
--- /dev/null
+++ b/lib/tty/tty-slang.h
@@ -0,0 +1,48 @@
+
+#ifndef MC__TTY_SLANG_H
+#define MC__TTY_SLANG_H
+
+#include <slang.h>
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+#define KEY_F(x) (1000 + x)
+
+#define ACS_VLINE SLSMG_VLINE_CHAR
+#define ACS_HLINE SLSMG_HLINE_CHAR
+#define ACS_LTEE SLSMG_LTEE_CHAR
+#define ACS_RTEE SLSMG_RTEE_CHAR
+#define ACS_TTEE SLSMG_UTEE_CHAR
+#define ACS_BTEE SLSMG_DTEE_CHAR
+#define ACS_ULCORNER SLSMG_ULCORN_CHAR
+#define ACS_LLCORNER SLSMG_LLCORN_CHAR
+#define ACS_URCORNER SLSMG_URCORN_CHAR
+#define ACS_LRCORNER SLSMG_LRCORN_CHAR
+#define ACS_PLUS SLSMG_PLUS_CHAR
+
+#define COLS SLtt_Screen_Cols
+#define LINES SLtt_Screen_Rows
+
+#define ENABLE_SHADOWS 1
+
+/*** enums ***************************************************************************************/
+
+enum
+{
+ KEY_BACKSPACE = 400,
+ KEY_END, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT,
+ KEY_HOME, KEY_A1, KEY_C1, KEY_NPAGE, KEY_PPAGE, KEY_IC,
+ KEY_ENTER, KEY_DC, KEY_SCANCEL, KEY_BTAB
+};
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+/*** global variables defined in .c file *********************************************************/
+
+extern int reset_hp_softkeys;
+
+/*** declarations of public functions ************************************************************/
+
+/*** inline functions ****************************************************************************/
+
+#endif /* MC_TTY_SLANG_H */
diff --git a/lib/tty/tty.c b/lib/tty/tty.c
new file mode 100644
index 0000000..cae0a05
--- /dev/null
+++ b/lib/tty/tty.c
@@ -0,0 +1,416 @@
+/*
+ Interface to the terminal controlling library.
+
+ Copyright (C) 2005-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Roland Illig <roland.illig@gmx.de>, 2005.
+ Andrew Borodin <aborodin@vmail.ru>, 2009.
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file tty.c
+ * \brief Source: %interface to the terminal controlling library
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h> /* memset() */
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#else
+#include <sys/time.h>
+#include <sys/types.h>
+#endif
+#include <unistd.h> /* exit() */
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+/* In some systems (like Solaris 11.4 SPARC), TIOCSWINSZ is defined in termios.h */
+#include <termios.h>
+
+#include "lib/global.h"
+#include "lib/strutil.h"
+
+#include "tty.h"
+#include "tty-internal.h"
+#include "color.h" /* tty_set_normal_attrs() */
+#include "mouse.h" /* use_mouse_p */
+#include "win.h"
+
+/*** global variables ****************************************************************************/
+
+int mc_tty_frm[MC_TTY_FRM_MAX];
+
+/*** file scope macro definitions ****************************************************************/
+
+/*** file scope type declarations ****************************************************************/
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** file scope variables ************************************************************************/
+
+static SIG_ATOMIC_VOLATILE_T got_interrupt = 0;
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+sigintr_handler (int signo)
+{
+ (void) &signo;
+ got_interrupt = 1;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+/**
+ * Check terminal type. If $TERM is not set or value is empty, mc finishes with EXIT_FAILURE.
+ *
+ * @param force_xterm Set forced the XTerm type
+ *
+ * @return true if @param force_xterm is true or value of $TERM is one of following:
+ * term*
+ * konsole*
+ * rxvt*
+ * Eterm
+ * dtterm
+ * alacritty*
+ * foot*
+ * screen*
+ * tmux*
+ * contour*
+ */
+gboolean
+tty_check_term (gboolean force_xterm)
+{
+ const char *termvalue;
+
+ termvalue = getenv ("TERM");
+ if (termvalue == NULL || *termvalue == '\0')
+ {
+ fputs (_("The TERM environment variable is unset!\n"), stderr);
+ exit (EXIT_FAILURE);
+ }
+
+ /* *INDENT-OFF* */
+ return force_xterm
+ || strncmp (termvalue, "xterm", 5) == 0
+ || strncmp (termvalue, "konsole", 7) == 0
+ || strncmp (termvalue, "rxvt", 4) == 0
+ || strcmp (termvalue, "Eterm") == 0
+ || strcmp (termvalue, "dtterm") == 0
+ || strncmp (termvalue, "alacritty", 9) == 0
+ || strncmp (termvalue, "foot", 4) == 0
+ || strncmp (termvalue, "screen", 6) == 0
+ || strncmp (termvalue, "tmux", 4) == 0
+ || strncmp (termvalue, "contour", 7) == 0;
+ /* *INDENT-ON* */
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+extern void
+tty_start_interrupt_key (void)
+{
+ struct sigaction act;
+
+ memset (&act, 0, sizeof (act));
+ act.sa_handler = sigintr_handler;
+ sigemptyset (&act.sa_mask);
+#ifdef SA_RESTART
+ act.sa_flags = SA_RESTART;
+#endif /* SA_RESTART */
+ sigaction (SIGINT, &act, NULL);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+extern void
+tty_enable_interrupt_key (void)
+{
+ struct sigaction act;
+
+ memset (&act, 0, sizeof (act));
+ act.sa_handler = sigintr_handler;
+ sigemptyset (&act.sa_mask);
+ sigaction (SIGINT, &act, NULL);
+ got_interrupt = 0;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+extern void
+tty_disable_interrupt_key (void)
+{
+ struct sigaction act;
+
+ memset (&act, 0, sizeof (act));
+ act.sa_handler = SIG_IGN;
+ sigemptyset (&act.sa_mask);
+ sigaction (SIGINT, &act, NULL);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+extern gboolean
+tty_got_interrupt (void)
+{
+ gboolean rv;
+
+ rv = (got_interrupt != 0);
+ got_interrupt = 0;
+ return rv;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+gboolean
+tty_got_winch (void)
+{
+ fd_set fdset;
+ /* *INDENT-OFF* */
+ /* instant timeout */
+ struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
+ /* *INDENT-ON* */
+ int ok;
+
+ FD_ZERO (&fdset);
+ FD_SET (sigwinch_pipe[0], &fdset);
+
+ while ((ok = select (sigwinch_pipe[0] + 1, &fdset, NULL, NULL, &timeout)) < 0)
+ if (errno != EINTR)
+ {
+ perror (_("Cannot check SIGWINCH pipe"));
+ exit (EXIT_FAILURE);
+ }
+
+ return (ok != 0 && FD_ISSET (sigwinch_pipe[0], &fdset));
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_flush_winch (void)
+{
+ ssize_t n;
+
+ /* merge all SIGWINCH events raised to this moment */
+ do
+ {
+ char x[16];
+
+ /* read multiple events at a time */
+ n = read (sigwinch_pipe[0], &x, sizeof (x));
+ }
+ while (n > 0 || (n == -1 && errno == EINTR));
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_print_one_hline (gboolean single)
+{
+ tty_print_alt_char (ACS_HLINE, single);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_print_one_vline (gboolean single)
+{
+ tty_print_alt_char (ACS_VLINE, single);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_draw_box (int y, int x, int ys, int xs, gboolean single)
+{
+ int y2, x2;
+
+ if (ys <= 0 || xs <= 0)
+ return;
+
+ ys--;
+ xs--;
+
+ y2 = y + ys;
+ x2 = x + xs;
+
+ tty_draw_vline (y, x, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT], ys);
+ tty_draw_vline (y, x2, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT], ys);
+ tty_draw_hline (y, x, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ], xs);
+ tty_draw_hline (y2, x, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ], xs);
+ tty_gotoyx (y, x);
+ tty_print_alt_char (ACS_ULCORNER, single);
+ tty_gotoyx (y2, x);
+ tty_print_alt_char (ACS_LLCORNER, single);
+ tty_gotoyx (y, x2);
+ tty_print_alt_char (ACS_URCORNER, single);
+ tty_gotoyx (y2, x2);
+ tty_print_alt_char (ACS_LRCORNER, single);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_draw_box_shadow (int y, int x, int rows, int cols, int shadow_color)
+{
+ /* draw right shadow */
+ tty_colorize_area (y + 1, x + cols, rows - 1, 2, shadow_color);
+ /* draw bottom shadow */
+ tty_colorize_area (y + rows, x + 2, 1, cols, shadow_color);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+char *
+mc_tty_normalize_from_utf8 (const char *str)
+{
+ GIConv conv;
+ GString *buffer;
+ const char *_system_codepage = str_detect_termencoding ();
+
+ if (str_isutf8 (_system_codepage))
+ return g_strdup (str);
+
+ conv = g_iconv_open (_system_codepage, "UTF-8");
+ if (conv == INVALID_CONV)
+ return g_strdup (str);
+
+ buffer = g_string_new ("");
+
+ if (str_convert (conv, str, buffer) == ESTR_FAILURE)
+ {
+ g_string_free (buffer, TRUE);
+ str_close_conv (conv);
+ return g_strdup (str);
+ }
+ str_close_conv (conv);
+
+ return g_string_free (buffer, FALSE);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+/** Resize given terminal using TIOCSWINSZ, return ioctl() result */
+int
+tty_resize (int fd)
+{
+#if defined TIOCSWINSZ
+ struct winsize tty_size;
+
+ tty_size.ws_row = LINES;
+ tty_size.ws_col = COLS;
+ tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
+
+ return ioctl (fd, TIOCSWINSZ, &tty_size);
+#else
+ return 0;
+#endif
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+/** Clear screen */
+void
+tty_clear_screen (void)
+{
+ tty_set_normal_attrs ();
+ tty_fill_region (0, 0, LINES, COLS, ' ');
+ tty_refresh ();
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+tty_init_xterm_support (gboolean is_xterm)
+{
+ const char *termvalue;
+
+ termvalue = getenv ("TERM");
+
+ /* Check mouse and ca capabilities */
+ /* terminfo/termcap structures have been already initialized,
+ in slang_init() or/and init_curses() */
+ /* Check terminfo at first, then check termcap */
+ xmouse_seq = tty_tgetstr ("kmous");
+ if (xmouse_seq == NULL)
+ xmouse_seq = tty_tgetstr ("Km");
+ smcup = tty_tgetstr ("smcup");
+ if (smcup == NULL)
+ smcup = tty_tgetstr ("ti");
+ rmcup = tty_tgetstr ("rmcup");
+ if (rmcup == NULL)
+ rmcup = tty_tgetstr ("te");
+
+ if (strcmp (termvalue, "cygwin") == 0)
+ {
+ is_xterm = TRUE;
+ use_mouse_p = MOUSE_DISABLED;
+ }
+
+ if (is_xterm)
+ {
+ /* Default to the standard xterm sequence */
+ if (xmouse_seq == NULL)
+ xmouse_seq = ESC_STR "[M";
+
+ /* Enable mouse unless explicitly disabled by --nomouse */
+ if (use_mouse_p != MOUSE_DISABLED)
+ {
+ if (mc_global.tty.old_mouse)
+ use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
+ else
+ {
+ /* FIXME: this dirty hack to set supported type of tracking the mouse */
+ const char *color_term = getenv ("COLORTERM");
+ if (strncmp (termvalue, "rxvt", 4) == 0 ||
+ (color_term != NULL && strncmp (color_term, "rxvt", 4) == 0) ||
+ strcmp (termvalue, "Eterm") == 0)
+ use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
+ else
+ use_mouse_p = MOUSE_XTERM_BUTTON_EVENT_TRACKING;
+ }
+ }
+ }
+
+ /* There's only one termcap entry "kmous", typically containing "\E[M" or "\E[<".
+ * We need the former in xmouse_seq, the latter in xmouse_extended_seq.
+ * See tickets 2956, 3954, and 4063 for details. */
+ if (xmouse_seq != NULL)
+ {
+ if (strcmp (xmouse_seq, ESC_STR "[<") == 0)
+ xmouse_seq = ESC_STR "[M";
+
+ xmouse_extended_seq = ESC_STR "[<";
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/tty.h b/lib/tty/tty.h
new file mode 100644
index 0000000..90cbbc6
--- /dev/null
+++ b/lib/tty/tty.h
@@ -0,0 +1,146 @@
+
+/** \file tty.h
+ * \brief Header: %interface to the terminal controlling library
+ *
+ * This file is the %interface to the terminal controlling library:
+ * slang or ncurses. It provides an additional layer of abstraction
+ * above the "real" libraries to keep the number of ifdefs in the other
+ * files small.
+ */
+
+#ifndef MC__TTY_H
+#define MC__TTY_H
+
+#include "lib/global.h" /* include <glib.h> */
+
+#ifdef HAVE_SLANG
+#include "tty-slang.h"
+#else
+#include "tty-ncurses.h"
+#endif
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+#define KEY_KP_ADD 4001
+#define KEY_KP_SUBTRACT 4002
+#define KEY_KP_MULTIPLY 4003
+
+/*** enums ***************************************************************************************/
+
+typedef enum
+{
+ /* single lines */
+ MC_TTY_FRM_VERT,
+ MC_TTY_FRM_HORIZ,
+ MC_TTY_FRM_LEFTTOP,
+ MC_TTY_FRM_RIGHTTOP,
+ MC_TTY_FRM_LEFTBOTTOM,
+ MC_TTY_FRM_RIGHTBOTTOM,
+ MC_TTY_FRM_TOPMIDDLE,
+ MC_TTY_FRM_BOTTOMMIDDLE,
+ MC_TTY_FRM_LEFTMIDDLE,
+ MC_TTY_FRM_RIGHTMIDDLE,
+ MC_TTY_FRM_CROSS,
+
+ /* double lines */
+ MC_TTY_FRM_DVERT,
+ MC_TTY_FRM_DHORIZ,
+ MC_TTY_FRM_DLEFTTOP,
+ MC_TTY_FRM_DRIGHTTOP,
+ MC_TTY_FRM_DLEFTBOTTOM,
+ MC_TTY_FRM_DRIGHTBOTTOM,
+ MC_TTY_FRM_DTOPMIDDLE,
+ MC_TTY_FRM_DBOTTOMMIDDLE,
+ MC_TTY_FRM_DLEFTMIDDLE,
+ MC_TTY_FRM_DRIGHTMIDDLE,
+
+ MC_TTY_FRM_MAX
+} mc_tty_frm_t;
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+/*** global variables defined in .c file *********************************************************/
+
+extern int mc_tty_frm[];
+
+extern char *tty_tgetstr (const char *name);
+
+/*** declarations of public functions ************************************************************/
+
+extern void tty_beep (void);
+
+/* {{{ Input }}} */
+
+extern gboolean tty_check_term (gboolean force_xterm);
+extern void tty_init (gboolean mouse_enable, gboolean is_xterm);
+extern void tty_shutdown (void);
+
+extern void tty_start_interrupt_key (void);
+extern void tty_enable_interrupt_key (void);
+extern void tty_disable_interrupt_key (void);
+extern gboolean tty_got_interrupt (void);
+
+extern gboolean tty_got_winch (void);
+extern void tty_flush_winch (void);
+
+extern void tty_reset_prog_mode (void);
+extern void tty_reset_shell_mode (void);
+
+extern void tty_raw_mode (void);
+extern void tty_noraw_mode (void);
+
+extern void tty_noecho (void);
+extern int tty_flush_input (void);
+
+extern void tty_keypad (gboolean set);
+extern void tty_nodelay (gboolean set);
+extern int tty_baudrate (void);
+
+/* {{{ Output }}} */
+
+/*
+ The output functions do not check themselves for screen overflows,
+ so make sure that you never write more than what fits on the screen.
+ While SLang provides such a feature, ncurses does not.
+ */
+
+extern int tty_reset_screen (void);
+extern void tty_touch_screen (void);
+
+extern void tty_gotoyx (int y, int x);
+extern void tty_getyx (int *py, int *px);
+
+extern void tty_set_alt_charset (gboolean alt_charset);
+
+extern void tty_display_8bit (gboolean what);
+extern void tty_print_char (int c);
+extern void tty_print_alt_char (int c, gboolean single);
+extern void tty_print_anychar (int c);
+extern void tty_print_string (const char *s);
+/* *INDENT-OFF* */
+extern void tty_printf (const char *s, ...) G_GNUC_PRINTF (1, 2);
+/* *INDENT-ON* */
+
+extern void tty_print_one_vline (gboolean single);
+extern void tty_print_one_hline (gboolean single);
+extern void tty_draw_hline (int y, int x, int ch, int len);
+extern void tty_draw_vline (int y, int x, int ch, int len);
+extern void tty_draw_box (int y, int x, int rows, int cols, gboolean single);
+extern void tty_draw_box_shadow (int y, int x, int rows, int cols, int shadow_color);
+extern void tty_fill_region (int y, int x, int rows, int cols, unsigned char ch);
+
+extern int tty_resize (int fd);
+extern void tty_refresh (void);
+extern void tty_change_screen_size (void);
+
+/* Clear screen */
+extern void tty_clear_screen (void);
+
+extern int mc_tty_normalize_lines_char (const char *str);
+
+extern void tty_enter_ca_mode (void);
+extern void tty_exit_ca_mode (void);
+
+/*** inline functions ****************************************************************************/
+
+#endif /* MC__TTY_H */
diff --git a/lib/tty/win.c b/lib/tty/win.c
new file mode 100644
index 0000000..45451a4
--- /dev/null
+++ b/lib/tty/win.c
@@ -0,0 +1,168 @@
+/*
+ Terminal management xterm and rxvt support
+
+ Copyright (C) 1995-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Andrew Borodin <aborodin@vmail.ru>, 2009.
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file win.c
+ * \brief Source: Terminal management xterm and rxvt support
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#else
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include "lib/global.h"
+#include "lib/util.h" /* is_printable() */
+#include "tty-internal.h"
+#include "tty.h" /* tty_gotoyx, tty_print_char */
+#include "win.h"
+
+/*** global variables ****************************************************************************/
+
+char *smcup = NULL;
+char *rmcup = NULL;
+
+/*** file scope macro definitions ****************************************************************/
+
+/*** file scope type declarations ****************************************************************/
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** file scope variables ************************************************************************/
+
+static gboolean rxvt_extensions = FALSE;
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+/* my own weird protocol base 16 - paul */
+static int
+rxvt_getc (void)
+{
+ int r;
+ unsigned char c;
+
+ while (read (0, &c, 1) != 1);
+ if (c == '\n')
+ return -1;
+ r = (c - 'A') * 16;
+ while (read (0, &c, 1) != 1);
+ r += (c - 'A');
+ return r;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+anything_ready (void)
+{
+ fd_set fds;
+ struct timeval tv;
+
+ FD_ZERO (&fds);
+ FD_SET (0, &fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ return select (1, &fds, 0, 0, &tv);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+void
+show_rxvt_contents (int starty, unsigned char y1, unsigned char y2)
+{
+ unsigned char *k;
+ int bytes, i, j, cols = 0;
+
+ y1 += mc_global.keybar_visible != 0 ? 1 : 0; /* i don't know why we need this - paul */
+ y2 += mc_global.keybar_visible != 0 ? 1 : 0;
+ while (anything_ready ())
+ tty_lowlevel_getch ();
+
+ /* my own weird protocol base 26 - paul */
+ printf (ESC_STR "CL%c%c%c%c\n", (y1 / 26) + 'A', (y1 % 26) + 'A', (y2 / 26) + 'A',
+ (y2 % 26) + 'A');
+
+ bytes = (y2 - y1) * (COLS + 1) + 1; /* *should* be the number of bytes read */
+ j = 0;
+ k = g_malloc (bytes);
+ while (TRUE)
+ {
+ int c;
+
+ c = rxvt_getc ();
+ if (c < 0)
+ break;
+ if (j < bytes)
+ k[j++] = c;
+ for (cols = 1;; cols++)
+ {
+ c = rxvt_getc ();
+ if (c < 0)
+ break;
+ if (j < bytes)
+ k[j++] = c;
+ }
+ }
+ for (i = 0; i < j; i++)
+ {
+ if ((i % cols) == 0)
+ tty_gotoyx (starty + (i / cols), 0);
+ tty_print_char (is_printable (k[i]) ? k[i] : ' ');
+ }
+ g_free (k);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+gboolean
+look_for_rxvt_extensions (void)
+{
+ static gboolean been_called = FALSE;
+
+ if (!been_called)
+ {
+ const char *e = getenv ("RXVT_EXT");
+ rxvt_extensions = ((e != NULL) && (strcmp (e, "1.0") == 0));
+ been_called = TRUE;
+ }
+
+ if (rxvt_extensions)
+ mc_global.tty.console_flag = '\004';
+
+ return rxvt_extensions;
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/win.h b/lib/tty/win.h
new file mode 100644
index 0000000..4c31607
--- /dev/null
+++ b/lib/tty/win.h
@@ -0,0 +1,24 @@
+/** \file win.h
+ * \brief Header: X terminal management: xterm and rxvt
+ */
+
+#ifndef MC__WIN_H
+#define MC__WIN_H
+
+#include "lib/global.h" /* <glib.h> */
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+/*** enums ***************************************************************************************/
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+/*** global variables defined in .c file *********************************************************/
+
+/*** declarations of public functions ************************************************************/
+
+void show_rxvt_contents (int starty, unsigned char y1, unsigned char y2);
+gboolean look_for_rxvt_extensions (void);
+
+/*** inline functions ****************************************************************************/
+#endif /* MC_WIN_H */
diff --git a/lib/tty/x11conn.c b/lib/tty/x11conn.c
new file mode 100644
index 0000000..20e201b
--- /dev/null
+++ b/lib/tty/x11conn.c
@@ -0,0 +1,266 @@
+/*
+ X11 support for the Midnight Commander.
+
+ Copyright (C) 2005-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Roland Illig <roland.illig@gmx.de>, 2005.
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file x11conn.c
+ * \brief Source: X11 support
+ * \warning This code uses setjmp() and longjmp(). Before you modify _anything_ here,
+ * please read the relevant sections of the C standard.
+ */
+
+#include <config.h>
+
+#include <setjmp.h>
+#include <X11/Xlib.h>
+#ifdef HAVE_GMODULE
+#include <gmodule.h>
+#endif
+
+#include "lib/global.h"
+#include "x11conn.h"
+
+/*** global variables ****************************************************************************/
+
+/*** file scope macro definitions ****************************************************************/
+
+#ifndef HAVE_GMODULE
+#define func_XOpenDisplay XOpenDisplay
+#define func_XCloseDisplay XCloseDisplay
+#define func_XSetErrorHandler XSetErrorHandler
+#define func_XSetIOErrorHandler XSetIOErrorHandler
+#define func_XQueryPointer XQueryPointer
+#endif
+
+/*** file scope type declarations ****************************************************************/
+
+typedef int (*mc_XErrorHandler_callback) (Display *, XErrorEvent *);
+typedef int (*mc_XIOErrorHandler_callback) (Display *);
+
+/*** forward declarations (file scope functions) *************************************************/
+
+/*** file scope variables ************************************************************************/
+
+#ifdef HAVE_GMODULE
+static Display *(*func_XOpenDisplay) (_Xconst char *);
+static int (*func_XCloseDisplay) (Display *);
+static mc_XErrorHandler_callback (*func_XSetErrorHandler) (mc_XErrorHandler_callback);
+static mc_XIOErrorHandler_callback (*func_XSetIOErrorHandler) (mc_XIOErrorHandler_callback);
+static Bool (*func_XQueryPointer) (Display *, Window, Window *, Window *,
+ int *, int *, int *, int *, unsigned int *);
+
+static GModule *x11_module;
+#endif
+
+static gboolean handlers_installed = FALSE;
+
+/* This flag is set as soon as an X11 error is reported. Usually that
+ * means that the DISPLAY is not available anymore. We do not try to
+ * reconnect, as that would violate the X11 protocol. */
+static gboolean lost_connection = FALSE;
+
+static jmp_buf x11_exception; /* FIXME: get a better name */
+static gboolean longjmp_allowed = FALSE;
+
+/* --------------------------------------------------------------------------------------------- */
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+x_io_error_handler (Display * dpy)
+{
+ (void) dpy;
+
+ lost_connection = TRUE;
+ if (longjmp_allowed)
+ {
+ longjmp_allowed = FALSE;
+ longjmp (x11_exception, 1);
+ }
+ return 0;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+x_error_handler (Display * dpy, XErrorEvent * ee)
+{
+ (void) ee;
+ (void) func_XCloseDisplay (dpy);
+ return x_io_error_handler (dpy);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static void
+install_error_handlers (void)
+{
+ if (handlers_installed)
+ return;
+
+ (void) func_XSetErrorHandler (x_error_handler);
+ (void) func_XSetIOErrorHandler (x_io_error_handler);
+ handlers_installed = TRUE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static gboolean
+x11_available (void)
+{
+#ifdef HAVE_GMODULE
+ gchar *x11_module_fname;
+
+ if (lost_connection)
+ return FALSE;
+
+ if (x11_module != NULL)
+ return TRUE;
+
+ x11_module_fname = g_module_build_path (NULL, "X11");
+ x11_module = g_module_open (x11_module_fname, G_MODULE_BIND_LAZY);
+ if (x11_module == NULL)
+ x11_module = g_module_open ("libX11.so.6", G_MODULE_BIND_LAZY);
+
+ g_free (x11_module_fname);
+
+ if (x11_module == NULL)
+ return FALSE;
+
+ if (!g_module_symbol (x11_module, "XOpenDisplay", (void *) &func_XOpenDisplay))
+ goto cleanup;
+ if (!g_module_symbol (x11_module, "XCloseDisplay", (void *) &func_XCloseDisplay))
+ goto cleanup;
+ if (!g_module_symbol (x11_module, "XQueryPointer", (void *) &func_XQueryPointer))
+ goto cleanup;
+ if (!g_module_symbol (x11_module, "XSetErrorHandler", (void *) &func_XSetErrorHandler))
+ goto cleanup;
+ if (!g_module_symbol (x11_module, "XSetIOErrorHandler", (void *) &func_XSetIOErrorHandler))
+ goto cleanup;
+
+ install_error_handlers ();
+ return TRUE;
+
+ cleanup:
+ func_XOpenDisplay = 0;
+ func_XCloseDisplay = 0;
+ func_XQueryPointer = 0;
+ func_XSetErrorHandler = 0;
+ func_XSetIOErrorHandler = 0;
+ g_module_close (x11_module);
+ x11_module = NULL;
+ return FALSE;
+#else
+ install_error_handlers ();
+ return !(lost_connection);
+#endif
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+Display *
+mc_XOpenDisplay (const char *displayname)
+{
+ if (x11_available ())
+ {
+ if (setjmp (x11_exception) == 0)
+ {
+ Display *retval;
+
+ /* cppcheck-suppress redundantAssignment */
+ longjmp_allowed = TRUE;
+
+ retval = func_XOpenDisplay (displayname);
+
+ /* cppcheck-suppress redundantAssignment */
+ longjmp_allowed = FALSE;
+ return retval;
+ }
+ }
+ return NULL;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+mc_XCloseDisplay (Display * display)
+{
+ if (x11_available ())
+ {
+ if (setjmp (x11_exception) == 0)
+ {
+ int retval;
+
+ /* cppcheck-suppress redundantAssignment */
+ longjmp_allowed = TRUE;
+
+ retval = func_XCloseDisplay (display);
+
+ /* cppcheck-suppress redundantAssignment */
+ longjmp_allowed = FALSE;
+
+ return retval;
+ }
+ }
+ return 0;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+Bool
+mc_XQueryPointer (Display * display, Window win, Window * root_return,
+ Window * child_return, int *root_x_return, int *root_y_return,
+ int *win_x_return, int *win_y_return, unsigned int *mask_return)
+{
+ Bool retval;
+
+ if (x11_available ())
+ {
+ if (setjmp (x11_exception) == 0)
+ {
+ /* cppcheck-suppress redundantAssignment */
+ longjmp_allowed = TRUE;
+
+ retval = func_XQueryPointer (display, win, root_return,
+ child_return, root_x_return, root_y_return,
+ win_x_return, win_y_return, mask_return);
+
+ /* cppcheck-suppress redundantAssignment */
+ longjmp_allowed = FALSE;
+
+ return retval;
+ }
+ }
+ *root_return = None;
+ *child_return = None;
+ *root_x_return = 0;
+ *root_y_return = 0;
+ *win_x_return = 0;
+ *win_y_return = 0;
+ *mask_return = 0;
+ return False;
+}
+
+/* --------------------------------------------------------------------------------------------- */
diff --git a/lib/tty/x11conn.h b/lib/tty/x11conn.h
new file mode 100644
index 0000000..fbfe15a
--- /dev/null
+++ b/lib/tty/x11conn.h
@@ -0,0 +1,40 @@
+/** \file x11conn.h
+ * \brief Header: X11 support
+ * \warning This code uses setjmp() and longjmp(). Before you modify _anything_ here,
+ * please read the relevant sections of the C standard.
+ */
+
+#ifndef MC__X11CONN_H
+#define MC__X11CONN_H
+
+/*
+ This module provides support for some X11 functions. The functions
+ are loaded dynamically if GModule is available, and statically if
+ not. X11 session handling is somewhat robust. If there is an X11
+ error or a connection error, all further traffic to the X server
+ will be suppressed, and the functions will return reasonable default
+ values.
+ */
+
+#include <X11/Xlib.h>
+
+/*** typedefs(not structures) and defined constants **********************************************/
+
+/*** enums ***************************************************************************************/
+
+/*** structures declarations (and typedefs of structures)*****************************************/
+
+/*** global variables defined in .c file *********************************************************/
+
+/*** declarations of public functions ************************************************************/
+
+extern Display *mc_XOpenDisplay (const char *displayname);
+extern int mc_XCloseDisplay (Display * display);
+
+extern Bool mc_XQueryPointer (Display * display, Window win, Window * root_return,
+ Window * child_return, int *root_x_return, int *root_y_return,
+ int *win_x_return, int *win_y_return, unsigned int *mask_return);
+
+/*** inline functions ****************************************************************************/
+
+#endif /* MC__X11CONN_H */