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