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