xref: /freebsd/contrib/less/ttyin.c (revision 6829dae12bb055451fa467da4589c43bd03b1e64)
1 /*
2  * Copyright (C) 1984-2017  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 #include "windows.h"
22 extern char WIN32getch();
23 static DWORD console_mode;
24 #endif
25 
26 public int tty;
27 extern int sigs;
28 extern int utf_mode;
29 
30 /*
31  * Open keyboard for input.
32  */
33 	public void
34 open_getchr()
35 {
36 #if MSDOS_COMPILER==WIN32C
37 	/* Need this to let child processes inherit our console handle */
38 	SECURITY_ATTRIBUTES sa;
39 	memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
40 	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
41 	sa.bInheritHandle = TRUE;
42 	tty = (int) CreateFile("CONIN$", GENERIC_READ,
43 			FILE_SHARE_READ, &sa,
44 			OPEN_EXISTING, 0L, NULL);
45 	GetConsoleMode((HANDLE)tty, &console_mode);
46 	/* Make sure we get Ctrl+C events. */
47 	SetConsoleMode((HANDLE)tty, ENABLE_PROCESSED_INPUT);
48 #else
49 #if MSDOS_COMPILER
50 	extern int fd0;
51 	/*
52 	 * Open a new handle to CON: in binary mode
53 	 * for unbuffered keyboard read.
54 	 */
55 	 fd0 = dup(0);
56 	 close(0);
57 	 tty = open("CON", OPEN_READ);
58 #if MSDOS_COMPILER==DJGPPC
59 	/*
60 	 * Setting stdin to binary causes Ctrl-C to not
61 	 * raise SIGINT.  We must undo that side-effect.
62 	 */
63 	(void) __djgpp_set_ctrl_c(1);
64 #endif
65 #else
66 	/*
67 	 * Try /dev/tty.
68 	 * If that doesn't work, use file descriptor 2,
69 	 * which in Unix is usually attached to the screen,
70 	 * but also usually lets you read from the keyboard.
71 	 */
72 #if OS2
73 	/* The __open() system call translates "/dev/tty" to "con". */
74 	tty = __open("/dev/tty", OPEN_READ);
75 #else
76 	tty = open("/dev/tty", OPEN_READ);
77 #endif
78 	if (tty < 0)
79 		tty = 2;
80 #endif
81 #endif
82 }
83 
84 /*
85  * Close the keyboard.
86  */
87 	public void
88 close_getchr()
89 {
90 #if MSDOS_COMPILER==WIN32C
91 	SetConsoleMode((HANDLE)tty, console_mode);
92 	CloseHandle((HANDLE)tty);
93 #endif
94 }
95 
96 /*
97  * Get a character from the keyboard.
98  */
99 	public int
100 getchr()
101 {
102 	char c;
103 	int result;
104 
105 	do
106 	{
107 #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
108 		/*
109 		 * In raw read, we don't see ^C so look here for it.
110 		 */
111 		flush();
112 #if MSDOS_COMPILER==WIN32C
113 		if (ABORT_SIGS())
114 			return (READ_INTR);
115 		c = WIN32getch(tty);
116 #else
117 		c = getch();
118 #endif
119 		result = 1;
120 		if (c == '\003')
121 			return (READ_INTR);
122 #else
123 		{
124 			unsigned char uc;
125 			result = iread(tty, &uc, sizeof(char));
126 			c = (char) uc;
127 		}
128 		if (result == READ_INTR)
129 			return (READ_INTR);
130 		if (result < 0)
131 		{
132 			/*
133 			 * Don't call error() here,
134 			 * because error calls getchr!
135 			 */
136 			quit(QUIT_ERROR);
137 		}
138 #endif
139 #if 0 /* allow entering arbitrary hex chars for testing */
140 		/* ctrl-A followed by two hex chars makes a byte */
141 	{
142 		static int hex_in = 0;
143 		static int hex_value = 0;
144 		if (c == CONTROL('A'))
145 		{
146 			hex_in = 2;
147 			result = 0;
148 			continue;
149 		}
150 		if (hex_in > 0)
151 		{
152 			int v;
153 			if (c >= '0' && c <= '9')
154 				v = c - '0';
155 			else if (c >= 'a' && c <= 'f')
156 				v = c - 'a' + 10;
157 			else if (c >= 'A' && c <= 'F')
158 				v = c - 'A' + 10;
159 			else
160 				hex_in = 0;
161 			hex_value = (hex_value << 4) | v;
162 			if (--hex_in > 0)
163 			{
164 				result = 0;
165 				continue;
166 			}
167 			c = hex_value;
168 		}
169 	}
170 #endif
171 		/*
172 		 * Various parts of the program cannot handle
173 		 * an input character of '\0'.
174 		 * If a '\0' was actually typed, convert it to '\340' here.
175 		 */
176 		if (c == '\0')
177 			c = '\340';
178 	} while (result != 1);
179 
180 	return (c & 0xFF);
181 }
182