File: msgetch.c

package info (click to toggle)
jove 4.16-5
  • links: PTS
  • area: main
  • in suites: potato, slink
  • size: 1,804 kB
  • ctags: 2,866
  • sloc: ansic: 27,140; makefile: 401
file content (253 lines) | stat: -rw-r--r-- 7,159 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/************************************************************************
 * This program is Copyright (C) 1986-1996 by Jonathan Payne.  JOVE is  *
 * provided to you without charge, and with no warranty.  You may give  *
 * away copies of JOVE, including sources, provided that this notice is *
 * included in all the files.                                           *
 ************************************************************************/

/* MSDOS keyboard routines */

#include "jove.h"

#ifdef MSDOS	/* the body is the rest of this file */

#include "chars.h"
#include "disp.h"	/* for redisplay() */

#include <bios.h>
#include <dos.h>


private void rawkey_wait proto((void));

#ifdef IBMPCDOS
private ZXchar	last = EOF;

bool enhanced_keybrd;	/* VAR: exploit "enhanced" keyboard? */

/* Unlike the other _NKEYBRD services, the _NKEYBRD_READY service
 * *requires* specific support within _bios_keybrd.  In particular
 * the key information is returned in the ZF flag, which is not
 * captured otherwise.  If _NKEYBRD_READY is defined in the headers,
 * we presume that _bios_keybrd supports it.
 */
# ifdef _NKEYBRD_READY
#  define jkbready() \
	(_bios_keybrd(enhanced_keybrd? _NKEYBRD_READY : _KEYBRD_READY) != 0)
# else /* !_NKEYBRD_READY */
#  ifdef ZTCDOS
    /* Workaround for Zortech 3.0: use Zortech's asm() capability.
     *
     * Interrupt 16h, service 1h (get keyboard status) and
     * interrupt 16h, service 11h (get enhanced keyboard status)
     * return with ZF cleared iff there is a character.
     * The zkbready macro returns YES iff there is a character.
     *
     * Note that the nature of the Zortech asm facility demands
     * that the "service" argument be a constant expression.
     */
#   define zkbready(service)	(0 == (int) asm( \
	0xB4, service,	/* mov ah,service */ \
	0xCD, 0x16,	/* int 16h */ \
	0x9F,		/* lahf */ \
	0x25, 0x00, 0x40,	/* and ax,04000h */ \
	0x99		/* cwd [needed due to a Zortech bug] */ \
	))
#   define _NKEYBRD_READY	0x11
#   define jkbready()	\
	(enhanced_keybrd? zkbready(_NKEYBRD_READY) : zkbready(_KEYBRD_READY))
#  endif/* ZTCDOS */
# endif /* !_NKEYBRD_READY */

# ifdef jkbready	/* we can support enhanced keyboard */
#  ifndef _NKEYBRD_READ
#   define _NKEYBRD_READ		0x10
#  endif
#  define jkbread()	_bios_keybrd(enhanced_keybrd? _NKEYBRD_READ : _KEYBRD_READ)

#  ifndef _NKEYBRD_SHIFTSTATUS
#   define _NKEYBRD_SHIFTSTATUS	0x12
#  endif
#  define jkbshift()	_bios_keybrd(enhanced_keybrd? _NKEYBRD_SHIFTSTATUS : _KEYBRD_SHIFTSTATUS)
# else /* !kebready */
   /* We don't know how to support the enhanced keyboard, so we won't */
#  define jkbready()	_bios_keybrd(_KEYBRD_READY)
#  define jkbread()	_bios_keybrd(_KEYBRD_READ)
#  define jkbshift()	_bios_keybrd(_KEYBRD_SHIFTSTATUS)
# endif /* !kebready */

/* This table returns an Ascii character corresponding to a Scan Code index.
 * If a key has no ASCII equivalent, the table contains 0.
 */
static const char scanToAsciiLower[] = {
	/* 00 */ 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\\', '\b',
	/* 10 */ '-', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0, 0, 'a',
	/* 20 */ 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 0, '\r', 0, 'z', 'x',
	/* 30 */ 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, 0, 0, ' ', 0, 0 };

static const char scanToAsciiUpper[] = {
	/* 00 */ 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '|', '\177',
	/* 10 */ '_', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0, 0, 'A',
	/* 20 */ 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '\"', 0, '\r', 0, 'Z', 'X',
	/* 30 */ 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 0, 0, 0, 0, ' ', 0, 0 };

#endif /* IBMPCDOS */

ZXchar
getrawinchar()
{
#ifdef IBMPCDOS
	unsigned scan;

	if (last != EOF) {
		scan = last;
		last = EOF;
		return scan;
	}

	rawkey_wait();
	scan = jkbread();

	/* check for Ctrl-spacebar and magically turn it into a Ctrl-@
	 * (scan == 0x03, char == 0x00).  Because keystrokes are queued
	 * but shift state is real-time, we add a (heuristic!) check
	 * requiring that no further characters are in the queue.
	 * Warning: the heuristic is not perfect.  The control could be
	 * recognized even if the it was pressed after the spacebar was
	 * released!
	 */
	if ((scan&0xff) == ' ' && (jkbshift() & 0x04) && !jkbready())
		scan = 0x0300;

	if ((scan&0xff) == 0 || (scan&0xff) == 0xe0) {
		ZXchar	next = ZXRC(scan >> 8);
		ZXchar  asciiChar;

		if (MetaKey && next < sizeof(scanToAsciiUpper)
		&& 0 != (asciiChar = ((jkbshift() & 0x03) && !jkbready()
			? scanToAsciiUpper : scanToAsciiLower)[next]))
		{
			last = asciiChar;
			scan = ESC;
		} else {
			/* Re-map shifted arrow keys and shifted Insert, Delete, Home, End,
			 * PgUp, and PgDn from 71-83 to 171-183.  This hack depends on
			 * the same heuristic as the ctrl-spacebar hack.
			 */
			if (71 <= next && next <= 83 && (jkbshift() & 0x03) && !jkbready())
				next += 100;
			/* Re-map keys that should have been ASCII */
			switch (next) {
			case 0x03:	/* ^@ and ^Space key */
				scan = '\0';	/* ASCII NUL */
				break;
			case 0x53:	/* Delete key */
				scan = DEL;	/* ASCII DEL */
				break;
			default:
				last = next;	/* not ASCII: more to come next time */
				scan = PCNONASCII;
				break;
			}
		}
	}
	return scan&0xff;

#else /* !IBMPCDOS */
# ifdef RAINBOW

	union REGS regs;

	rawkey_wait();

	for (;;) {
		regs.x.di = 2;
		int86(0x18, &regs, &regs);
		if (regs.h.al != 0)	/* should never happen, but who knows */
			return regs.h.al;
	}
# else /* !RAINBOW */
	rawkey_wait();
	return bdos(0x06, 0x00ff, 0xff) & 0xff;
# endif /* !RAINBOW */
#endif /* !IBMPCDOS */
}

private bool	waiting = NO;

bool
rawkey_ready()
{
#ifdef IBMPCDOS
	return !waiting && (last != EOF || jkbready());
#else /* !IBMPCDOS */
	union REGS regs;

	if (waiting)
		return NO;
# ifdef RAINBOW
	regs.x.di = 4;
	int86(0x18, &regs, &regs);
	return regs.h.cl != 0;
# else /* !RAINBOW */
	regs.h.ah = 0x44;		/* ioctl call */
	regs.x.bx = 0;			/* stdin file handle */
	regs.h.al = 0x06;		/* get input status */
	intdos(&regs, &regs);
	return regs.h.al & 1;
# endif /* !RAINBOW */
#endif /* !IBMPCDOS */
}

/* Wait for next character, updating the modeline if it displays the time.
 * NOTE: this is a busy wait.
 */
private void
rawkey_wait()
{
	while (!rawkey_ready()) {
		if (UpdModLine) {
			waiting = YES;
			redisplay();
			waiting = NO;
		} else if (TimeDisplayed) {
			struct dostime_t tc;
			static char lastmin = 0;

			_dos_gettime(&tc);
			if (tc.minute != lastmin) {
				UpdModLine = YES;
				lastmin = tc.minute;
			}
		} else {
			/* No reason to busy wait: return to do a blocking read.
			 * This might improve performance in multitasking systems.
			 */
			break;
		}
	}
}

void
ttysetattr(n)
bool	n;	/* also used as subscript! */
{
	static char break_state;

	if (n) {
		/* set the break state to off */
		union REGS regs;

		regs.h.ah = 0x33;		/* break status */
		regs.h.al = 0x00;		/* request current state */
		intdos(&regs, &regs);
		break_state = regs.h.dl;

		bdos(0x33, 0, 1);	/* turn off break */
	} else {
		/* restore the break state */
		bdos(0x33, break_state, 1);
	}
}

#endif /* MSDOS */