Home | History | Annotate | Line # | Download | only in dist
      1 /*	$NetBSD: ttyin.c,v 1.4 2023/10/06 05:49:49 simonb Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1984-2023  Mark Nudelman
      5  *
      6  * You may distribute under the terms of either the GNU General Public
      7  * License or the Less License, as specified in the README file.
      8  *
      9  * For more information, see the README file.
     10  */
     11 
     12 
     13 /*
     14  * Routines dealing with getting input from the keyboard (i.e. from the user).
     15  */
     16 
     17 #include "less.h"
     18 #if OS2
     19 #include "cmd.h"
     20 #include "pckeys.h"
     21 #endif
     22 #if MSDOS_COMPILER==WIN32C
     23 #define WIN32_LEAN_AND_MEAN
     24 #ifndef _WIN32_WINNT
     25 #define _WIN32_WINNT 0x400
     26 #endif
     27 #include <windows.h>
     28 public DWORD console_mode;
     29 public HANDLE tty;
     30 #else
     31 public int tty;
     32 #endif
     33 #if LESSTEST
     34 public char *ttyin_name = NULL;
     35 #endif /*LESSTEST*/
     36 extern int sigs;
     37 extern int utf_mode;
     38 extern int wheel_lines;
     39 
     40 #if !MSDOS_COMPILER
     41 static int open_tty_device(constant char* dev)
     42 {
     43 #if OS2
     44 	/* The __open() system call translates "/dev/tty" to "con". */
     45 	return __open(dev, OPEN_READ);
     46 #else
     47 	return open(dev, OPEN_READ);
     48 #endif
     49 }
     50 
     51 /*
     52  * Open the tty device.
     53  * Try ttyname(), then try /dev/tty, then use file descriptor 2.
     54  * In Unix, file descriptor 2 is usually attached to the screen,
     55  * but also usually lets you read from the keyboard.
     56  */
     57 public int open_tty(void)
     58 {
     59 	int fd = -1;
     60 #if LESSTEST
     61 	if (ttyin_name != NULL)
     62 		fd = open_tty_device(ttyin_name);
     63 #endif /*LESSTEST*/
     64 #if HAVE_TTYNAME
     65 	if (fd < 0)
     66 	{
     67 		constant char *dev = ttyname(2);
     68 		if (dev != NULL)
     69 			fd = open_tty_device(dev);
     70 	}
     71 #endif
     72 	if (fd < 0)
     73 		fd = open_tty_device("/dev/tty");
     74 	if (fd < 0)
     75 		fd = 2;
     76 	return fd;
     77 }
     78 #endif /* MSDOS_COMPILER */
     79 
     80 /*
     81  * Open keyboard for input.
     82  */
     83 public void open_getchr(void)
     84 {
     85 #if MSDOS_COMPILER==WIN32C
     86 	/* Need this to let child processes inherit our console handle */
     87 	SECURITY_ATTRIBUTES sa;
     88 	memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
     89 	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
     90 	sa.bInheritHandle = TRUE;
     91 	tty = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
     92 			FILE_SHARE_READ, &sa,
     93 			OPEN_EXISTING, 0L, NULL);
     94 	GetConsoleMode(tty, &console_mode);
     95 	/* Make sure we get Ctrl+C events. */
     96 	SetConsoleMode(tty, ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT);
     97 #else
     98 #if MSDOS_COMPILER
     99 	extern int fd0;
    100 	/*
    101 	 * Open a new handle to CON: in binary mode
    102 	 * for unbuffered keyboard read.
    103 	 */
    104 	 fd0 = dup(0);
    105 	 close(0);
    106 	 tty = open("CON", OPEN_READ);
    107 #if MSDOS_COMPILER==DJGPPC
    108 	/*
    109 	 * Setting stdin to binary causes Ctrl-C to not
    110 	 * raise SIGINT.  We must undo that side-effect.
    111 	 */
    112 	(void) __djgpp_set_ctrl_c(1);
    113 #endif
    114 #else
    115 	tty = open_tty();
    116 #endif
    117 #endif
    118 }
    119 
    120 /*
    121  * Close the keyboard.
    122  */
    123 public void close_getchr(void)
    124 {
    125 #if MSDOS_COMPILER==WIN32C
    126 	SetConsoleMode(tty, console_mode);
    127 	CloseHandle(tty);
    128 #endif
    129 }
    130 
    131 #if MSDOS_COMPILER==WIN32C
    132 /*
    133  * Close the pipe, restoring the keyboard (CMD resets it, losing the mouse).
    134  */
    135 public int pclose(FILE *f)
    136 {
    137 	int result;
    138 
    139 	result = _pclose(f);
    140 	SetConsoleMode(tty, ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT);
    141 	return result;
    142 }
    143 #endif
    144 
    145 /*
    146  * Get the number of lines to scroll when mouse wheel is moved.
    147  */
    148 public int default_wheel_lines(void)
    149 {
    150 	int lines = 1;
    151 #if MSDOS_COMPILER==WIN32C
    152 	if (SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &lines, 0))
    153 	{
    154 		if (lines == WHEEL_PAGESCROLL)
    155 			lines = 3;
    156 	}
    157 #endif
    158 	return lines;
    159 }
    160 
    161 /*
    162  * Get a character from the keyboard.
    163  */
    164 public int getchr(void)
    165 {
    166 	char c;
    167 	int result;
    168 
    169 	do
    170 	{
    171 		flush();
    172 #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
    173 		/*
    174 		 * In raw read, we don't see ^C so look here for it.
    175 		 */
    176 #if MSDOS_COMPILER==WIN32C
    177 		if (ABORT_SIGS())
    178 			return (READ_INTR);
    179 		c = WIN32getch();
    180 #else
    181 		c = getch();
    182 #endif
    183 		result = 1;
    184 		if (c == '\003')
    185 			return (READ_INTR);
    186 #else
    187 		{
    188 			unsigned char uc;
    189 			result = iread(tty, &uc, sizeof(char));
    190 			c = (char) uc;
    191 		}
    192 		if (result == READ_INTR)
    193 			return (READ_INTR);
    194 		if (result < 0)
    195 		{
    196 			/*
    197 			 * Don't call error() here,
    198 			 * because error calls getchr!
    199 			 */
    200 			quit(QUIT_ERROR);
    201 		}
    202 #endif
    203 #if LESSTEST
    204 		if (c == LESS_DUMP_CHAR)
    205 		{
    206 			dump_screen();
    207 			result = 0;
    208 			continue;
    209 		}
    210 #endif
    211 #if 0 /* allow entering arbitrary hex chars for testing */
    212 		/* ctrl-A followed by two hex chars makes a byte */
    213 	{
    214 		static int hex_in = 0;
    215 		static int hex_value = 0;
    216 		if (c == CONTROL('A'))
    217 		{
    218 			hex_in = 2;
    219 			result = 0;
    220 			continue;
    221 		}
    222 		if (hex_in > 0)
    223 		{
    224 			int v;
    225 			if (c >= '0' && c <= '9')
    226 				v = c - '0';
    227 			else if (c >= 'a' && c <= 'f')
    228 				v = c - 'a' + 10;
    229 			else if (c >= 'A' && c <= 'F')
    230 				v = c - 'A' + 10;
    231 			else
    232 				v = 0;
    233 			hex_value = (hex_value << 4) | v;
    234 			if (--hex_in > 0)
    235 			{
    236 				result = 0;
    237 				continue;
    238 			}
    239 			c = hex_value;
    240 		}
    241 	}
    242 #endif
    243 		/*
    244 		 * Various parts of the program cannot handle
    245 		 * an input character of '\0'.
    246 		 * If a '\0' was actually typed, convert it to '\340' here.
    247 		 */
    248 		if (c == '\0')
    249 			c = '\340';
    250 	} while (result != 1);
    251 
    252 	return (c & 0xFF);
    253 }
    254