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