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