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