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 *
tty_device(VOID_PARAM)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
open_getchr(VOID_PARAM)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
close_getchr(VOID_PARAM)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
pclose(f)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
default_wheel_lines(VOID_PARAM)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
rstat(st)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
getchr(VOID_PARAM)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