xref: /netbsd-src/external/bsd/less/dist/ttyin.c (revision 838f5788460f0f133b15d706e644d692a9d4d6ec)
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
open_tty_device(constant char * dev)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  */
open_tty(void)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  */
open_getchr(void)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  */
close_getchr(void)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  */
pclose(FILE * f)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  */
default_wheel_lines(void)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  */
getchr(void)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