160786Sps/*
2240121Sdelphij * Copyright (C) 1984-2012  Mark Nudelman
360786Sps *
460786Sps * You may distribute under the terms of either the GNU General Public
560786Sps * License or the Less License, as specified in the README file.
660786Sps *
7240121Sdelphij * For more information, see the README file.
860786Sps */
960786Sps
1060786Sps
1160786Sps/*
1260786Sps * Routines dealing with getting input from the keyboard (i.e. from the user).
1360786Sps */
1460786Sps
1560786Sps#include "less.h"
1689019Sps#if OS2
1789019Sps#include "cmd.h"
1889019Sps#include "pckeys.h"
1989019Sps#endif
2060786Sps#if MSDOS_COMPILER==WIN32C
2160786Sps#include "windows.h"
2260786Spsextern char WIN32getch();
2360786Spsstatic DWORD console_mode;
2460786Sps#endif
2560786Sps
26128345Stjrpublic int tty;
2760786Spsextern int sigs;
28161475Sdelphijextern int utf_mode;
2960786Sps
3060786Sps/*
3160786Sps * Open keyboard for input.
3260786Sps */
3360786Sps	public void
3460786Spsopen_getchr()
3560786Sps{
3660786Sps#if MSDOS_COMPILER==WIN32C
3760786Sps	/* Need this to let child processes inherit our console handle */
3860786Sps	SECURITY_ATTRIBUTES sa;
3960786Sps	memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
4060786Sps	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
4160786Sps	sa.bInheritHandle = TRUE;
4260786Sps	tty = (int) CreateFile("CONIN$", GENERIC_READ,
4360786Sps			FILE_SHARE_READ, &sa,
4460786Sps			OPEN_EXISTING, 0L, NULL);
4560786Sps	GetConsoleMode((HANDLE)tty, &console_mode);
4660786Sps	/* Make sure we get Ctrl+C events. */
4760786Sps	SetConsoleMode((HANDLE)tty, ENABLE_PROCESSED_INPUT);
4860786Sps#else
4989019Sps#if MSDOS_COMPILER
5060786Sps	extern int fd0;
5160786Sps	/*
5260786Sps	 * Open a new handle to CON: in binary mode
5360786Sps	 * for unbuffered keyboard read.
5460786Sps	 */
5560786Sps	 fd0 = dup(0);
5660786Sps	 close(0);
5760786Sps	 tty = open("CON", OPEN_READ);
5860786Sps#if MSDOS_COMPILER==DJGPPC
5960786Sps	/*
6060786Sps	 * Setting stdin to binary causes Ctrl-C to not
6160786Sps	 * raise SIGINT.  We must undo that side-effect.
6260786Sps	 */
6360786Sps	(void) __djgpp_set_ctrl_c(1);
6460786Sps#endif
6560786Sps#else
6660786Sps	/*
6760786Sps	 * Try /dev/tty.
6860786Sps	 * If that doesn't work, use file descriptor 2,
6960786Sps	 * which in Unix is usually attached to the screen,
7060786Sps	 * but also usually lets you read from the keyboard.
7160786Sps	 */
7289019Sps#if OS2
7389019Sps	/* The __open() system call translates "/dev/tty" to "con". */
7489019Sps	tty = __open("/dev/tty", OPEN_READ);
7589019Sps#else
7660786Sps	tty = open("/dev/tty", OPEN_READ);
7789019Sps#endif
7860786Sps	if (tty < 0)
7960786Sps		tty = 2;
8060786Sps#endif
8160786Sps#endif
8260786Sps}
8360786Sps
8460786Sps/*
8560786Sps * Close the keyboard.
8660786Sps */
8760786Sps	public void
8860786Spsclose_getchr()
8960786Sps{
9060786Sps#if MSDOS_COMPILER==WIN32C
9160786Sps	SetConsoleMode((HANDLE)tty, console_mode);
9260786Sps	CloseHandle((HANDLE)tty);
9360786Sps#endif
9460786Sps}
9560786Sps
9660786Sps/*
9760786Sps * Get a character from the keyboard.
9860786Sps */
9960786Sps	public int
10060786Spsgetchr()
10160786Sps{
10260786Sps	char c;
10360786Sps	int result;
10460786Sps
10560786Sps	do
10660786Sps	{
10760786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
10860786Sps		/*
10960786Sps		 * In raw read, we don't see ^C so look here for it.
11060786Sps		 */
11160786Sps		flush();
11260786Sps#if MSDOS_COMPILER==WIN32C
11360786Sps		if (ABORT_SIGS())
11460786Sps			return (READ_INTR);
11560786Sps		c = WIN32getch(tty);
11660786Sps#else
11760786Sps		c = getch();
11860786Sps#endif
11960786Sps		result = 1;
12060786Sps		if (c == '\003')
12160786Sps			return (READ_INTR);
12260786Sps#else
12360786Sps		result = iread(tty, &c, sizeof(char));
12460786Sps		if (result == READ_INTR)
12560786Sps			return (READ_INTR);
12660786Sps		if (result < 0)
12760786Sps		{
12860786Sps			/*
12960786Sps			 * Don't call error() here,
13060786Sps			 * because error calls getchr!
13160786Sps			 */
13260786Sps			quit(QUIT_ERROR);
13360786Sps		}
13460786Sps#endif
135161475Sdelphij#if 0 /* allow entering arbitrary hex chars for testing */
136161475Sdelphij		/* ctrl-A followed by two hex chars makes a byte */
137170256Sdelphij	{
138170256Sdelphij		int hex_in = 0;
139170256Sdelphij		int hex_value = 0;
140161475Sdelphij		if (c == CONTROL('A'))
141161475Sdelphij		{
142161475Sdelphij			hex_in = 2;
143161475Sdelphij			result = 0;
144161475Sdelphij			continue;
145161475Sdelphij		}
146161475Sdelphij		if (hex_in > 0)
147161475Sdelphij		{
148161475Sdelphij			int v;
149161475Sdelphij			if (c >= '0' && c <= '9')
150161475Sdelphij				v = c - '0';
151161475Sdelphij			else if (c >= 'a' && c <= 'f')
152161475Sdelphij				v = c - 'a' + 10;
153161475Sdelphij			else if (c >= 'A' && c <= 'F')
154161475Sdelphij				v = c - 'A' + 10;
155161475Sdelphij			else
156161475Sdelphij				hex_in = 0;
157161475Sdelphij			hex_value = (hex_value << 4) | v;
158161475Sdelphij			if (--hex_in > 0)
159161475Sdelphij			{
160161475Sdelphij				result = 0;
161161475Sdelphij				continue;
162161475Sdelphij			}
163161475Sdelphij			c = hex_value;
164161475Sdelphij		}
165170256Sdelphij	}
166161475Sdelphij#endif
16760786Sps		/*
16860786Sps		 * Various parts of the program cannot handle
16960786Sps		 * an input character of '\0'.
17060786Sps		 * If a '\0' was actually typed, convert it to '\340' here.
17160786Sps		 */
17260786Sps		if (c == '\0')
17360786Sps			c = '\340';
17460786Sps	} while (result != 1);
17560786Sps
176161475Sdelphij	return (c & 0xFF);
17760786Sps}
178