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