xref: /freebsd/contrib/less/ttyin.c (revision c77c488926555ca344ae3a417544cf7a720e1de1)
1a5f0fb15SPaul Saab /*
2*c77c4889SXin LI  * Copyright (C) 1984-2024  Mark Nudelman
3a5f0fb15SPaul Saab  *
4a5f0fb15SPaul Saab  * You may distribute under the terms of either the GNU General Public
5a5f0fb15SPaul Saab  * License or the Less License, as specified in the README file.
6a5f0fb15SPaul Saab  *
796e55cc7SXin LI  * For more information, see the README file.
8a5f0fb15SPaul Saab  */
9a5f0fb15SPaul Saab 
10a5f0fb15SPaul Saab 
11a5f0fb15SPaul Saab /*
12a5f0fb15SPaul Saab  * Routines dealing with getting input from the keyboard (i.e. from the user).
13a5f0fb15SPaul Saab  */
14a5f0fb15SPaul Saab 
15a5f0fb15SPaul Saab #include "less.h"
16c9346414SPaul Saab #if OS2
17c9346414SPaul Saab #include "cmd.h"
18c9346414SPaul Saab #include "pckeys.h"
19c9346414SPaul Saab #endif
20a5f0fb15SPaul Saab #if MSDOS_COMPILER==WIN32C
21b7780dbeSXin LI #define WIN32_LEAN_AND_MEAN
22b7780dbeSXin LI #ifndef _WIN32_WINNT
23b7780dbeSXin LI #define _WIN32_WINNT 0x400
24a5f0fb15SPaul Saab #endif
25b7780dbeSXin LI #include <windows.h>
26*c77c4889SXin LI #ifndef ENABLE_EXTENDED_FLAGS
27*c77c4889SXin LI #define ENABLE_EXTENDED_FLAGS 0x80
28*c77c4889SXin LI #define ENABLE_QUICK_EDIT_MODE 0x40
29*c77c4889SXin LI #endif
30*c77c4889SXin LI #ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
31*c77c4889SXin LI #define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
32*c77c4889SXin LI #endif
33b7780dbeSXin LI public HANDLE tty;
34*c77c4889SXin LI public DWORD init_console_input_mode;
35*c77c4889SXin LI public DWORD curr_console_input_mode;
36*c77c4889SXin LI public DWORD base_console_input_mode;
37*c77c4889SXin LI public DWORD mouse_console_input_mode;
38b7780dbeSXin LI #else
39000ba3e8STim J. Robbins public int tty;
40b7780dbeSXin LI #endif
41*c77c4889SXin LI extern int sigs;
422235c7feSXin LI #if LESSTEST
432235c7feSXin LI public char *ttyin_name = NULL;
44*c77c4889SXin LI public lbool is_lesstest(void)
45*c77c4889SXin LI {
46*c77c4889SXin LI 	return ttyin_name != NULL;
47*c77c4889SXin LI }
482235c7feSXin LI #endif /*LESSTEST*/
49a5f0fb15SPaul Saab 
502235c7feSXin LI #if !MSDOS_COMPILER
51d713e089SXin LI static int open_tty_device(constant char* dev)
522235c7feSXin LI {
5395270f73SXin LI #if OS2
5495270f73SXin LI 	/* The __open() system call translates "/dev/tty" to "con". */
5595270f73SXin LI 	return __open(dev, OPEN_READ);
5695270f73SXin LI #else
5795270f73SXin LI 	return open(dev, OPEN_READ);
582235c7feSXin LI #endif
5995270f73SXin LI }
6095270f73SXin LI 
6195270f73SXin LI /*
6295270f73SXin LI  * Open the tty device.
6395270f73SXin LI  * Try ttyname(), then try /dev/tty, then use file descriptor 2.
6495270f73SXin LI  * In Unix, file descriptor 2 is usually attached to the screen,
6595270f73SXin LI  * but also usually lets you read from the keyboard.
6695270f73SXin LI  */
67d713e089SXin LI public int open_tty(void)
6895270f73SXin LI {
6995270f73SXin LI 	int fd = -1;
702235c7feSXin LI #if LESSTEST
71*c77c4889SXin LI 	if (is_lesstest())
7295270f73SXin LI 		fd = open_tty_device(ttyin_name);
732235c7feSXin LI #endif /*LESSTEST*/
7495270f73SXin LI #if HAVE_TTYNAME
7595270f73SXin LI 	if (fd < 0)
7695270f73SXin LI 	{
7795270f73SXin LI 		constant char *dev = ttyname(2);
7895270f73SXin LI 		if (dev != NULL)
7995270f73SXin LI 			fd = open_tty_device(dev);
8095270f73SXin LI 	}
8195270f73SXin LI #endif
8295270f73SXin LI 	if (fd < 0)
8395270f73SXin LI 		fd = open_tty_device("/dev/tty");
8495270f73SXin LI 	if (fd < 0)
8595270f73SXin LI 		fd = 2;
86*c77c4889SXin LI #ifdef __MVS__
87*c77c4889SXin LI 	struct f_cnvrt cvtreq = {SETCVTON, 0, 1047};
88*c77c4889SXin LI 	fcntl(fd, F_CONTROL_CVT, &cvtreq);
89*c77c4889SXin LI #endif
9095270f73SXin LI 	return fd;
912235c7feSXin LI }
922235c7feSXin LI #endif /* MSDOS_COMPILER */
932235c7feSXin LI 
942235c7feSXin LI /*
95a5f0fb15SPaul Saab  * Open keyboard for input.
96a5f0fb15SPaul Saab  */
97d713e089SXin LI public void open_getchr(void)
98a5f0fb15SPaul Saab {
99a5f0fb15SPaul Saab #if MSDOS_COMPILER==WIN32C
100a5f0fb15SPaul Saab 	/* Need this to let child processes inherit our console handle */
101a5f0fb15SPaul Saab 	SECURITY_ATTRIBUTES sa;
102a5f0fb15SPaul Saab 	memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
103a5f0fb15SPaul Saab 	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
104a5f0fb15SPaul Saab 	sa.bInheritHandle = TRUE;
105b7780dbeSXin LI 	tty = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
106a5f0fb15SPaul Saab 			FILE_SHARE_READ, &sa,
107a5f0fb15SPaul Saab 			OPEN_EXISTING, 0L, NULL);
108*c77c4889SXin LI 	GetConsoleMode(tty, &init_console_input_mode);
109*c77c4889SXin LI 	/* base mode: ensure we get ctrl-C events, and don't get VT input. */
110*c77c4889SXin LI 	base_console_input_mode = (init_console_input_mode | ENABLE_PROCESSED_INPUT) & ~ENABLE_VIRTUAL_TERMINAL_INPUT;
111*c77c4889SXin LI 	/* mouse mode: enable mouse and disable quick edit. */
112*c77c4889SXin LI 	mouse_console_input_mode = (base_console_input_mode | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS) & ~ENABLE_QUICK_EDIT_MODE;
113*c77c4889SXin LI 	/* Start with base mode. If --mouse is given, switch to mouse mode in init_mouse. */
114*c77c4889SXin LI 	curr_console_input_mode = base_console_input_mode;
115*c77c4889SXin LI 	SetConsoleMode(tty, curr_console_input_mode);
116a5f0fb15SPaul Saab #else
117c9346414SPaul Saab #if MSDOS_COMPILER
118a5f0fb15SPaul Saab 	extern int fd0;
119a5f0fb15SPaul Saab 	/*
120a5f0fb15SPaul Saab 	 * Open a new handle to CON: in binary mode
121a5f0fb15SPaul Saab 	 * for unbuffered keyboard read.
122a5f0fb15SPaul Saab 	 */
123a5f0fb15SPaul Saab 	 fd0 = dup(0);
124a5f0fb15SPaul Saab 	 close(0);
125a5f0fb15SPaul Saab 	 tty = open("CON", OPEN_READ);
126a5f0fb15SPaul Saab #if MSDOS_COMPILER==DJGPPC
127a5f0fb15SPaul Saab 	/*
128a5f0fb15SPaul Saab 	 * Setting stdin to binary causes Ctrl-C to not
129a5f0fb15SPaul Saab 	 * raise SIGINT.  We must undo that side-effect.
130a5f0fb15SPaul Saab 	 */
131a5f0fb15SPaul Saab 	(void) __djgpp_set_ctrl_c(1);
132a5f0fb15SPaul Saab #endif
133a5f0fb15SPaul Saab #else
13495270f73SXin LI 	tty = open_tty();
135a5f0fb15SPaul Saab #endif
136a5f0fb15SPaul Saab #endif
137a5f0fb15SPaul Saab }
138a5f0fb15SPaul Saab 
139a5f0fb15SPaul Saab /*
140a5f0fb15SPaul Saab  * Close the keyboard.
141a5f0fb15SPaul Saab  */
142d713e089SXin LI public void close_getchr(void)
143a5f0fb15SPaul Saab {
144a5f0fb15SPaul Saab #if MSDOS_COMPILER==WIN32C
145*c77c4889SXin LI 	SetConsoleMode(tty, init_console_input_mode);
146b7780dbeSXin LI 	CloseHandle(tty);
147a5f0fb15SPaul Saab #endif
148a5f0fb15SPaul Saab }
149a5f0fb15SPaul Saab 
150b7780dbeSXin LI #if MSDOS_COMPILER==WIN32C
151b7780dbeSXin LI /*
152*c77c4889SXin LI  * Close the pipe, restoring the console mode (CMD resets it, losing the mouse).
153b7780dbeSXin LI  */
154d713e089SXin LI public int pclose(FILE *f)
155b7780dbeSXin LI {
156b7780dbeSXin LI 	int result;
157b7780dbeSXin LI 
158b7780dbeSXin LI 	result = _pclose(f);
159*c77c4889SXin LI 	SetConsoleMode(tty, curr_console_input_mode);
160b7780dbeSXin LI 	return result;
161b7780dbeSXin LI }
162b7780dbeSXin LI #endif
163b7780dbeSXin LI 
164b7780dbeSXin LI /*
165b7780dbeSXin LI  * Get the number of lines to scroll when mouse wheel is moved.
166b7780dbeSXin LI  */
167d713e089SXin LI public int default_wheel_lines(void)
168b7780dbeSXin LI {
169b7780dbeSXin LI 	int lines = 1;
170b7780dbeSXin LI #if MSDOS_COMPILER==WIN32C
171b7780dbeSXin LI 	if (SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &lines, 0))
172b7780dbeSXin LI 	{
173b7780dbeSXin LI 		if (lines == WHEEL_PAGESCROLL)
174b7780dbeSXin LI 			lines = 3;
175b7780dbeSXin LI 	}
176b7780dbeSXin LI #endif
177b7780dbeSXin LI 	return lines;
178b7780dbeSXin LI }
179b7780dbeSXin LI 
180a5f0fb15SPaul Saab /*
181a5f0fb15SPaul Saab  * Get a character from the keyboard.
182a5f0fb15SPaul Saab  */
183d713e089SXin LI public int getchr(void)
184a5f0fb15SPaul Saab {
185a5f0fb15SPaul Saab 	char c;
186*c77c4889SXin LI 	ssize_t result;
187a5f0fb15SPaul Saab 
188a5f0fb15SPaul Saab 	do
189a5f0fb15SPaul Saab 	{
1902235c7feSXin LI 		flush();
191a5f0fb15SPaul Saab #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
192a5f0fb15SPaul Saab 		/*
193a5f0fb15SPaul Saab 		 * In raw read, we don't see ^C so look here for it.
194a5f0fb15SPaul Saab 		 */
195a5f0fb15SPaul Saab #if MSDOS_COMPILER==WIN32C
196a5f0fb15SPaul Saab 		if (ABORT_SIGS())
197a5f0fb15SPaul Saab 			return (READ_INTR);
198b7780dbeSXin LI 		c = WIN32getch();
199a5f0fb15SPaul Saab #else
200a5f0fb15SPaul Saab 		c = getch();
201a5f0fb15SPaul Saab #endif
202a5f0fb15SPaul Saab 		result = 1;
203a5f0fb15SPaul Saab 		if (c == '\003')
204a5f0fb15SPaul Saab 			return (READ_INTR);
205a5f0fb15SPaul Saab #else
206f6b74a7dSXin LI 		{
207f6b74a7dSXin LI 			unsigned char uc;
208f6b74a7dSXin LI 			result = iread(tty, &uc, sizeof(char));
209f6b74a7dSXin LI 			c = (char) uc;
210f6b74a7dSXin LI 		}
211a5f0fb15SPaul Saab 		if (result == READ_INTR)
212a5f0fb15SPaul Saab 			return (READ_INTR);
213a5f0fb15SPaul Saab 		if (result < 0)
214a5f0fb15SPaul Saab 		{
215a5f0fb15SPaul Saab 			/*
216a5f0fb15SPaul Saab 			 * Don't call error() here,
217a5f0fb15SPaul Saab 			 * because error calls getchr!
218a5f0fb15SPaul Saab 			 */
219a5f0fb15SPaul Saab 			quit(QUIT_ERROR);
220a5f0fb15SPaul Saab 		}
221a5f0fb15SPaul Saab #endif
222d713e089SXin LI #if LESSTEST
223d713e089SXin LI 		if (c == LESS_DUMP_CHAR)
224d713e089SXin LI 		{
225d713e089SXin LI 			dump_screen();
226d713e089SXin LI 			result = 0;
227d713e089SXin LI 			continue;
228d713e089SXin LI 		}
229d713e089SXin LI #endif
2306dcb072bSXin LI #if 0 /* allow entering arbitrary hex chars for testing */
2316dcb072bSXin LI 		/* ctrl-A followed by two hex chars makes a byte */
2327f074f9cSXin LI 	{
233f6b74a7dSXin LI 		static int hex_in = 0;
234f6b74a7dSXin LI 		static int hex_value = 0;
2356dcb072bSXin LI 		if (c == CONTROL('A'))
2366dcb072bSXin LI 		{
2376dcb072bSXin LI 			hex_in = 2;
2386dcb072bSXin LI 			result = 0;
2396dcb072bSXin LI 			continue;
2406dcb072bSXin LI 		}
2416dcb072bSXin LI 		if (hex_in > 0)
2426dcb072bSXin LI 		{
2436dcb072bSXin LI 			int v;
2446dcb072bSXin LI 			if (c >= '0' && c <= '9')
2456dcb072bSXin LI 				v = c - '0';
2466dcb072bSXin LI 			else if (c >= 'a' && c <= 'f')
2476dcb072bSXin LI 				v = c - 'a' + 10;
2486dcb072bSXin LI 			else if (c >= 'A' && c <= 'F')
2496dcb072bSXin LI 				v = c - 'A' + 10;
2506dcb072bSXin LI 			else
251b7780dbeSXin LI 				v = 0;
2526dcb072bSXin LI 			hex_value = (hex_value << 4) | v;
2536dcb072bSXin LI 			if (--hex_in > 0)
2546dcb072bSXin LI 			{
2556dcb072bSXin LI 				result = 0;
2566dcb072bSXin LI 				continue;
2576dcb072bSXin LI 			}
2586dcb072bSXin LI 			c = hex_value;
2596dcb072bSXin LI 		}
2607f074f9cSXin LI 	}
2616dcb072bSXin LI #endif
262a5f0fb15SPaul Saab 		/*
263a5f0fb15SPaul Saab 		 * Various parts of the program cannot handle
264a5f0fb15SPaul Saab 		 * an input character of '\0'.
265a5f0fb15SPaul Saab 		 * If a '\0' was actually typed, convert it to '\340' here.
266a5f0fb15SPaul Saab 		 */
267a5f0fb15SPaul Saab 		if (c == '\0')
268a5f0fb15SPaul Saab 			c = '\340';
269a5f0fb15SPaul Saab 	} while (result != 1);
270a5f0fb15SPaul Saab 
2716dcb072bSXin LI 	return (c & 0xFF);
272a5f0fb15SPaul Saab }
273