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> 26public DWORD console_mode; 27public HANDLE tty; 28#else 29public int tty; 30#endif 31#if LESSTEST 32public char *ttyin_name = NULL; 33#endif /*LESSTEST*/ 34extern int sigs; 35extern int utf_mode; 36extern int wheel_lines; 37 38#if !MSDOS_COMPILER 39static 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 */ 55public 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 */ 81public 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 */ 121public 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 */ 133public 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 */ 146public 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 */ 162public 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