17784Swpaul/*
27784Swpaul * Copyright (C) 1984-2012  Mark Nudelman
37784Swpaul *
47784Swpaul * You may distribute under the terms of either the GNU General Public
57784Swpaul * License or the Less License, as specified in the README file.
67784Swpaul *
77784Swpaul * For more information, see the README file.
87784Swpaul */
97784Swpaul
107784Swpaul
117784Swpaul/*
127784Swpaul * Routines dealing with getting input from the keyboard (i.e. from the user).
137784Swpaul */
147784Swpaul
157784Swpaul#include "less.h"
167784Swpaul#if OS2
177784Swpaul#include "cmd.h"
187784Swpaul#include "pckeys.h"
197784Swpaul#endif
207784Swpaul#if MSDOS_COMPILER==WIN32C
217784Swpaul#include "windows.h"
227784Swpaulextern char WIN32getch();
237784Swpaulstatic DWORD console_mode;
247784Swpaul#endif
257784Swpaul
267784Swpaulpublic int tty;
277784Swpaulextern int sigs;
287784Swpaulextern int utf_mode;
297784Swpaul
307784Swpaul/*
3150476Speter * Open keyboard for input.
327784Swpaul */
337784Swpaul	public void
347784Swpaulopen_getchr()
3579538Sru{
367784Swpaul#if MSDOS_COMPILER==WIN32C
377784Swpaul	/* Need this to let child processes inherit our console handle */
387784Swpaul	SECURITY_ATTRIBUTES sa;
397784Swpaul	memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
407784Swpaul	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
4168962Sru	sa.bInheritHandle = TRUE;
427784Swpaul	tty = (int) CreateFile("CONIN$", GENERIC_READ,
4357731Ssheldonh			FILE_SHARE_READ, &sa,
4457731Ssheldonh			OPEN_EXISTING, 0L, NULL);
457784Swpaul	GetConsoleMode((HANDLE)tty, &console_mode);
467784Swpaul	/* Make sure we get Ctrl+C events. */
477784Swpaul	SetConsoleMode((HANDLE)tty, ENABLE_PROCESSED_INPUT);
48140293Sru#else
49140293Sru#if MSDOS_COMPILER
507784Swpaul	extern int fd0;
5157731Ssheldonh	/*
5257731Ssheldonh	 * Open a new handle to CON: in binary mode
5357731Ssheldonh	 * for unbuffered keyboard read.
5457731Ssheldonh	 */
557784Swpaul	 fd0 = dup(0);
567784Swpaul	 close(0);
5732302Ssteve	 tty = open("CON", OPEN_READ);
58140567Sru#if MSDOS_COMPILER==DJGPPC
597784Swpaul	/*
607784Swpaul	 * Setting stdin to binary causes Ctrl-C to not
617784Swpaul	 * raise SIGINT.  We must undo that side-effect.
627784Swpaul	 */
637784Swpaul	(void) __djgpp_set_ctrl_c(1);
647784Swpaul#endif
657784Swpaul#else
667784Swpaul	/*
677784Swpaul	 * Try /dev/tty.
687784Swpaul	 * If that doesn't work, use file descriptor 2,
697784Swpaul	 * which in Unix is usually attached to the screen,
7057731Ssheldonh	 * but also usually lets you read from the keyboard.
7157731Ssheldonh	 */
7257731Ssheldonh#if OS2
7357731Ssheldonh	/* The __open() system call translates "/dev/tty" to "con". */
747784Swpaul	tty = __open("/dev/tty", OPEN_READ);
757784Swpaul#else
767784Swpaul	tty = open("/dev/tty", OPEN_READ);
777784Swpaul#endif
787784Swpaul	if (tty < 0)
797784Swpaul		tty = 2;
807784Swpaul#endif
8113744Smpp#endif
827784Swpaul}
837784Swpaul
8413744Smpp/*
857784Swpaul * Close the keyboard.
867784Swpaul */
877784Swpaul	public void
887784Swpaulclose_getchr()
897784Swpaul{
907784Swpaul#if MSDOS_COMPILER==WIN32C
917784Swpaul	SetConsoleMode((HANDLE)tty, console_mode);
9268962Sru	CloseHandle((HANDLE)tty);
937784Swpaul#endif
947784Swpaul}
957784Swpaul
967784Swpaul/*
9732302Ssteve * Get a character from the keyboard.
9889362Sru */
997784Swpaul	public int
1007784Swpaulgetchr()
10168962Sru{
1027784Swpaul	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		result = iread(tty, &c, sizeof(char));
124		if (result == READ_INTR)
125			return (READ_INTR);
126		if (result < 0)
127		{
128			/*
129			 * Don't call error() here,
130			 * because error calls getchr!
131			 */
132			quit(QUIT_ERROR);
133		}
134#endif
135#if 0 /* allow entering arbitrary hex chars for testing */
136		/* ctrl-A followed by two hex chars makes a byte */
137	{
138		int hex_in = 0;
139		int hex_value = 0;
140		if (c == CONTROL('A'))
141		{
142			hex_in = 2;
143			result = 0;
144			continue;
145		}
146		if (hex_in > 0)
147		{
148			int v;
149			if (c >= '0' && c <= '9')
150				v = c - '0';
151			else if (c >= 'a' && c <= 'f')
152				v = c - 'a' + 10;
153			else if (c >= 'A' && c <= 'F')
154				v = c - 'A' + 10;
155			else
156				hex_in = 0;
157			hex_value = (hex_value << 4) | v;
158			if (--hex_in > 0)
159			{
160				result = 0;
161				continue;
162			}
163			c = hex_value;
164		}
165	}
166#endif
167		/*
168		 * Various parts of the program cannot handle
169		 * an input character of '\0'.
170		 * If a '\0' was actually typed, convert it to '\340' here.
171		 */
172		if (c == '\0')
173			c = '\340';
174	} while (result != 1);
175
176	return (c & 0xFF);
177}
178