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