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