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