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