1106356Smarcel/* 2106356Smarcel * Copyright (C) 1984-2021 Mark Nudelman 3106356Smarcel * 4106356Smarcel * You may distribute under the terms of either the GNU General Public 5106356Smarcel * License or the Less License, as specified in the README file. 6106356Smarcel * 7106356Smarcel * For more information, see the README file. 8106356Smarcel */ 9106356Smarcel 10106356Smarcel 11106356Smarcel/* 12106356Smarcel * Routines dealing with getting input from the keyboard (i.e. from the user). 13106356Smarcel */ 14106356Smarcel 15106356Smarcel#include "less.h" 16106356Smarcel#if OS2 17106356Smarcel#include "cmd.h" 18106356Smarcel#include "pckeys.h" 19106356Smarcel#endif 20106356Smarcel#if MSDOS_COMPILER==WIN32C 21106356Smarcel#define WIN32_LEAN_AND_MEAN 22106356Smarcel#ifndef _WIN32_WINNT 23106356Smarcel#define _WIN32_WINNT 0x400 24106356Smarcel#endif 25106356Smarcel#include <windows.h> 26106722Smarcelpublic DWORD console_mode; 27106356Smarcelpublic HANDLE tty; 28106356Smarcel#else 29106722Smarcelpublic int tty; 30106722Smarcel#endif 31106356Smarcel#if LESSTEST 32106722Smarcelpublic char *ttyin_name = NULL; 33106356Smarcelpublic int rstat_file = -1; 34106356Smarcel#endif /*LESSTEST*/ 35106356Smarcelextern int sigs; 36106722Smarcelextern int utf_mode; 37106722Smarcelextern int wheel_lines; 38106356Smarcel 39106356Smarcel/* 40251812Shrs * Get name of tty device. 41106722Smarcel */ 42106722Smarcel#if !MSDOS_COMPILER 43106722Smarcel public char * 44106722Smarceltty_device(VOID_PARAM) 45106356Smarcel{ 46106722Smarcel char *dev = NULL; 47118393Sru#if HAVE_TTYNAME 48106722Smarcel dev = ttyname(2); 49208622Smarcel#endif 50118180Sru if (dev == NULL) 51222726Smarcel dev = "/dev/tty"; 52222726Smarcel#if LESSTEST 53118180Sru if (ttyin_name != NULL) 54118393Sru dev = ttyin_name; 55118180Sru#endif /*LESSTEST*/ 56118180Sru return dev; 57118180Sru} 58222726Smarcel#endif /* MSDOS_COMPILER */ 59222726Smarcel 60222726Smarcel/* 61118180Sru * Open keyboard for input. 62118180Sru */ 63222726Smarcel public void 64222726Smarcelopen_getchr(VOID_PARAM) 65222726Smarcel{ 66254075Smarcel#if MSDOS_COMPILER==WIN32C 67118180Sru /* Need this to let child processes inherit our console handle */ 68228043Smarcel SECURITY_ATTRIBUTES sa; 69228043Smarcel memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); 70118180Sru sa.nLength = sizeof(SECURITY_ATTRIBUTES); 71254075Smarcel sa.bInheritHandle = TRUE; 72254075Smarcel tty = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, 73118180Sru FILE_SHARE_READ, &sa, 74118180Sru OPEN_EXISTING, 0L, NULL); 75222726Smarcel GetConsoleMode(tty, &console_mode); 76133426Smarcel /* Make sure we get Ctrl+C events. */ 77133426Smarcel SetConsoleMode(tty, ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT); 78106722Smarcel#else 79106722Smarcel#if MSDOS_COMPILER 80251812Shrs extern int fd0; 81222766Smarcel /* 82251812Shrs * Open a new handle to CON: in binary mode 83222766Smarcel * for unbuffered keyboard read. 84222726Smarcel */ 85106722Smarcel 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 118close_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 131pclose(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 146default_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 161rstat(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 175getchr(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