ttyin.c revision 355504
1256381Smarkm/*
2256381Smarkm * Copyright (C) 1984-2019  Mark Nudelman
3256381Smarkm *
4256381Smarkm * You may distribute under the terms of either the GNU General Public
5256381Smarkm * License or the Less License, as specified in the README file.
6256381Smarkm *
7256381Smarkm * For more information, see the README file.
8256381Smarkm */
9256381Smarkm
10256381Smarkm
11256381Smarkm/*
12256381Smarkm * Routines dealing with getting input from the keyboard (i.e. from the user).
13256381Smarkm */
14256381Smarkm
15256381Smarkm#include "less.h"
16256381Smarkm#if OS2
17256381Smarkm#include "cmd.h"
18256381Smarkm#include "pckeys.h"
19256381Smarkm#endif
20256381Smarkm#if MSDOS_COMPILER==WIN32C
21256381Smarkm#define WIN32_LEAN_AND_MEAN
22256381Smarkm#ifndef _WIN32_WINNT
23256381Smarkm#define _WIN32_WINNT 0x400
24256381Smarkm#endif
25256381Smarkm#include <windows.h>
26256381Smarkmstatic DWORD console_mode;
27256381Smarkmpublic HANDLE tty;
28256381Smarkm#else
29256381Smarkmpublic int tty;
30256381Smarkm#endif
31256381Smarkmextern int sigs;
32256381Smarkmextern int utf_mode;
33256381Smarkmextern int wheel_lines;
34256381Smarkm
35256381Smarkm/*
36256381Smarkm * Open keyboard for input.
37256381Smarkm */
38256381Smarkm	public void
39256381Smarkmopen_getchr(VOID_PARAM)
40{
41#if MSDOS_COMPILER==WIN32C
42	/* Need this to let child processes inherit our console handle */
43	SECURITY_ATTRIBUTES sa;
44	memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
45	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
46	sa.bInheritHandle = TRUE;
47	tty = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
48			FILE_SHARE_READ, &sa,
49			OPEN_EXISTING, 0L, NULL);
50	GetConsoleMode(tty, &console_mode);
51	/* Make sure we get Ctrl+C events. */
52	SetConsoleMode(tty, ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT);
53#else
54#if MSDOS_COMPILER
55	extern int fd0;
56	/*
57	 * Open a new handle to CON: in binary mode
58	 * for unbuffered keyboard read.
59	 */
60	 fd0 = dup(0);
61	 close(0);
62	 tty = open("CON", OPEN_READ);
63#if MSDOS_COMPILER==DJGPPC
64	/*
65	 * Setting stdin to binary causes Ctrl-C to not
66	 * raise SIGINT.  We must undo that side-effect.
67	 */
68	(void) __djgpp_set_ctrl_c(1);
69#endif
70#else
71	/*
72	 * Try /dev/tty.
73	 * If that doesn't work, use file descriptor 2,
74	 * which in Unix is usually attached to the screen,
75	 * but also usually lets you read from the keyboard.
76	 */
77#if OS2
78	/* The __open() system call translates "/dev/tty" to "con". */
79	tty = __open("/dev/tty", OPEN_READ);
80#else
81	tty = open("/dev/tty", OPEN_READ);
82#endif
83	if (tty < 0)
84		tty = 2;
85#endif
86#endif
87}
88
89/*
90 * Close the keyboard.
91 */
92	public void
93close_getchr(VOID_PARAM)
94{
95#if MSDOS_COMPILER==WIN32C
96	SetConsoleMode(tty, console_mode);
97	CloseHandle(tty);
98#endif
99}
100
101#if MSDOS_COMPILER==WIN32C
102/*
103 * Close the pipe, restoring the keyboard (CMD resets it, losing the mouse).
104 */
105	int
106pclose(f)
107	FILE *f;
108{
109	int result;
110
111	result = _pclose(f);
112	SetConsoleMode(tty, ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT);
113	return result;
114}
115#endif
116
117/*
118 * Get the number of lines to scroll when mouse wheel is moved.
119 */
120	public int
121default_wheel_lines(VOID_PARAM)
122{
123	int lines = 1;
124#if MSDOS_COMPILER==WIN32C
125	if (SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &lines, 0))
126	{
127		if (lines == WHEEL_PAGESCROLL)
128			lines = 3;
129	}
130#endif
131	return lines;
132}
133
134/*
135 * Get a character from the keyboard.
136 */
137	public int
138getchr(VOID_PARAM)
139{
140	char c;
141	int result;
142
143	do
144	{
145#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
146		/*
147		 * In raw read, we don't see ^C so look here for it.
148		 */
149		flush();
150#if MSDOS_COMPILER==WIN32C
151		if (ABORT_SIGS())
152			return (READ_INTR);
153		c = WIN32getch();
154#else
155		c = getch();
156#endif
157		result = 1;
158		if (c == '\003')
159			return (READ_INTR);
160#else
161		{
162			unsigned char uc;
163			result = iread(tty, &uc, sizeof(char));
164			c = (char) uc;
165		}
166		if (result == READ_INTR)
167			return (READ_INTR);
168		if (result < 0)
169		{
170			/*
171			 * Don't call error() here,
172			 * because error calls getchr!
173			 */
174			quit(QUIT_ERROR);
175		}
176#endif
177#if 0 /* allow entering arbitrary hex chars for testing */
178		/* ctrl-A followed by two hex chars makes a byte */
179	{
180		static int hex_in = 0;
181		static int hex_value = 0;
182		if (c == CONTROL('A'))
183		{
184			hex_in = 2;
185			result = 0;
186			continue;
187		}
188		if (hex_in > 0)
189		{
190			int v;
191			if (c >= '0' && c <= '9')
192				v = c - '0';
193			else if (c >= 'a' && c <= 'f')
194				v = c - 'a' + 10;
195			else if (c >= 'A' && c <= 'F')
196				v = c - 'A' + 10;
197			else
198				v = 0;
199			hex_value = (hex_value << 4) | v;
200			if (--hex_in > 0)
201			{
202				result = 0;
203				continue;
204			}
205			c = hex_value;
206		}
207	}
208#endif
209		/*
210		 * Various parts of the program cannot handle
211		 * an input character of '\0'.
212		 * If a '\0' was actually typed, convert it to '\340' here.
213		 */
214		if (c == '\0')
215			c = '\340';
216	} while (result != 1);
217
218	return (c & 0xFF);
219}
220