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