ttyin.c revision 221715
190075Sobrien/*
290075Sobrien * Copyright (C) 1984-2011  Mark Nudelman
390075Sobrien *
490075Sobrien * You may distribute under the terms of either the GNU General Public
590075Sobrien * License or the Less License, as specified in the README file.
690075Sobrien *
790075Sobrien * For more information about less, or for information on how to
890075Sobrien * contact the author, see the README file.
990075Sobrien */
1090075Sobrien
1190075Sobrien
1290075Sobrien/*
1390075Sobrien * Routines dealing with getting input from the keyboard (i.e. from the user).
1490075Sobrien */
1590075Sobrien
1690075Sobrien#include "less.h"
1790075Sobrien#if OS2
1890075Sobrien#include "cmd.h"
1990075Sobrien#include "pckeys.h"
2090075Sobrien#endif
2190075Sobrien#if MSDOS_COMPILER==WIN32C
2290075Sobrien#include "windows.h"
2390075Sobrienextern char WIN32getch();
2490075Sobrienstatic DWORD console_mode;
2590075Sobrien#endif
2690075Sobrien
2790075Sobrienpublic int tty;
2890075Sobrienextern int sigs;
2990075Sobrienextern int utf_mode;
3090075Sobrien
3190075Sobrien/*
3290075Sobrien * Open keyboard for input.
3390075Sobrien */
3490075Sobrien	public void
3590075Sobrienopen_getchr()
3690075Sobrien{
3790075Sobrien#if MSDOS_COMPILER==WIN32C
3890075Sobrien	/* Need this to let child processes inherit our console handle */
3990075Sobrien	SECURITY_ATTRIBUTES sa;
4090075Sobrien	memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
4190075Sobrien	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
4290075Sobrien	sa.bInheritHandle = TRUE;
4390075Sobrien	tty = (int) CreateFile("CONIN$", GENERIC_READ,
4490075Sobrien			FILE_SHARE_READ, &sa,
4590075Sobrien			OPEN_EXISTING, 0L, NULL);
4690075Sobrien	GetConsoleMode((HANDLE)tty, &console_mode);
4790075Sobrien	/* Make sure we get Ctrl+C events. */
4890075Sobrien	SetConsoleMode((HANDLE)tty, ENABLE_PROCESSED_INPUT);
4990075Sobrien#else
5090075Sobrien#if MSDOS_COMPILER
5190075Sobrien	extern int fd0;
5290075Sobrien	/*
5390075Sobrien	 * Open a new handle to CON: in binary mode
5490075Sobrien	 * for unbuffered keyboard read.
5590075Sobrien	 */
5690075Sobrien	 fd0 = dup(0);
5790075Sobrien	 close(0);
5890075Sobrien	 tty = open("CON", OPEN_READ);
5990075Sobrien#if MSDOS_COMPILER==DJGPPC
6090075Sobrien	/*
6190075Sobrien	 * Setting stdin to binary causes Ctrl-C to not
6290075Sobrien	 * raise SIGINT.  We must undo that side-effect.
6390075Sobrien	 */
6490075Sobrien	(void) __djgpp_set_ctrl_c(1);
6590075Sobrien#endif
6690075Sobrien#else
6790075Sobrien	/*
6890075Sobrien	 * Try /dev/tty.
6990075Sobrien	 * If that doesn't work, use file descriptor 2,
7090075Sobrien	 * which in Unix is usually attached to the screen,
7190075Sobrien	 * but also usually lets you read from the keyboard.
7290075Sobrien	 */
7390075Sobrien#if OS2
7490075Sobrien	/* The __open() system call translates "/dev/tty" to "con". */
7590075Sobrien	tty = __open("/dev/tty", OPEN_READ);
7690075Sobrien#else
7790075Sobrien	tty = open("/dev/tty", OPEN_READ);
7890075Sobrien#endif
7990075Sobrien	if (tty < 0)
8090075Sobrien		tty = 2;
8190075Sobrien#endif
8290075Sobrien#endif
8390075Sobrien}
8490075Sobrien
8590075Sobrien/*
8690075Sobrien * Close the keyboard.
8790075Sobrien */
8890075Sobrien	public void
8990075Sobrienclose_getchr()
9090075Sobrien{
9190075Sobrien#if MSDOS_COMPILER==WIN32C
9290075Sobrien	SetConsoleMode((HANDLE)tty, console_mode);
9390075Sobrien	CloseHandle((HANDLE)tty);
9490075Sobrien#endif
9590075Sobrien}
9690075Sobrien
9790075Sobrien/*
9890075Sobrien * Get a character from the keyboard.
9990075Sobrien */
10090075Sobrien	public int
10190075Sobriengetchr()
10290075Sobrien{
10390075Sobrien	char c;
10490075Sobrien	int result;
10590075Sobrien
10690075Sobrien	do
10790075Sobrien	{
10890075Sobrien#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
10990075Sobrien		/*
11090075Sobrien		 * In raw read, we don't see ^C so look here for it.
11190075Sobrien		 */
11290075Sobrien		flush();
11390075Sobrien#if MSDOS_COMPILER==WIN32C
11490075Sobrien		if (ABORT_SIGS())
11590075Sobrien			return (READ_INTR);
11690075Sobrien		c = WIN32getch(tty);
11790075Sobrien#else
11890075Sobrien		c = getch();
11990075Sobrien#endif
12090075Sobrien		result = 1;
12190075Sobrien		if (c == '\003')
12290075Sobrien			return (READ_INTR);
12390075Sobrien#else
12490075Sobrien		result = iread(tty, &c, sizeof(char));
12590075Sobrien		if (result == READ_INTR)
12690075Sobrien			return (READ_INTR);
12790075Sobrien		if (result < 0)
12890075Sobrien		{
12990075Sobrien			/*
13090075Sobrien			 * Don't call error() here,
13190075Sobrien			 * because error calls getchr!
13290075Sobrien			 */
13390075Sobrien			quit(QUIT_ERROR);
13490075Sobrien		}
13590075Sobrien#endif
13690075Sobrien#if 0 /* allow entering arbitrary hex chars for testing */
13790075Sobrien		/* ctrl-A followed by two hex chars makes a byte */
13890075Sobrien	{
13990075Sobrien		int hex_in = 0;
14090075Sobrien		int hex_value = 0;
14190075Sobrien		if (c == CONTROL('A'))
14290075Sobrien		{
14390075Sobrien			hex_in = 2;
14490075Sobrien			result = 0;
14590075Sobrien			continue;
14690075Sobrien		}
14790075Sobrien		if (hex_in > 0)
14890075Sobrien		{
14990075Sobrien			int v;
15090075Sobrien			if (c >= '0' && c <= '9')
15190075Sobrien				v = c - '0';
15290075Sobrien			else if (c >= 'a' && c <= 'f')
15390075Sobrien				v = c - 'a' + 10;
154			else if (c >= 'A' && c <= 'F')
155				v = c - 'A' + 10;
156			else
157				hex_in = 0;
158			hex_value = (hex_value << 4) | v;
159			if (--hex_in > 0)
160			{
161				result = 0;
162				continue;
163			}
164			c = hex_value;
165		}
166	}
167#endif
168		/*
169		 * Various parts of the program cannot handle
170		 * an input character of '\0'.
171		 * If a '\0' was actually typed, convert it to '\340' here.
172		 */
173		if (c == '\0')
174			c = '\340';
175	} while (result != 1);
176
177	return (c & 0xFF);
178}
179