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