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