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; 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 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 */ 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 */ 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 */ 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 */ 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 */ 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