1/*
2 * Copyright 2007-2023, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT license.
4 *
5 * Author:
6 *		Fran��ois Revol, revol@free.fr.
7 */
8
9#include <SupportDefs.h>
10#include <string.h>
11#include "toscalls.h"
12#include <util/kernel_cpp.h>
13
14#include "console.h"
15#include "keyboard.h"
16
17
18static bool sForceBW = false;	// force black & white for Milan
19
20
21// TOS emulates a VT52
22
23class Console : public ConsoleNode {
24	public:
25		Console();
26
27		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
28			size_t bufferSize);
29		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer,
30			size_t bufferSize);
31
32		void ClearScreen();
33		int32 Width();
34		int32 Height();
35		void SetCursor(int32 x, int32 y);
36		void SetCursorVisible(bool visible);
37		void SetColors(int32 foreground, int32 background);
38	private:
39		int16 fHandle;
40};
41
42
43extern ConsoleNode* gConsoleNode;
44static Console sConsole;
45FILE *stdin, *stdout, *stderr;
46
47
48Console::Console()
49	: ConsoleNode(), fHandle(DEV_CONSOLE)
50{
51}
52
53
54ssize_t
55Console::ReadAt(void */*cookie*/, off_t /*pos*/, void *buffer,
56	size_t bufferSize)
57{
58	// don't seek in character devices
59	// not implemented (and not yet? needed)
60	return B_ERROR;
61}
62
63
64ssize_t
65Console::WriteAt(void */*cookie*/, off_t /*pos*/, const void *buffer,
66	size_t bufferSize)
67{
68	const char *string = (const char *)buffer;
69	size_t i;
70
71	// be nice to our audience and replace single "\n" with "\r\n"
72
73	for (i = 0; i < bufferSize; i++) {
74		if (string[i] == '\0')
75			break;
76		if (string[i] == '\n')
77			Bconout(fHandle, '\r');
78		Bconout(fHandle, string[i]);
79	}
80
81	return bufferSize;
82}
83
84
85void
86Console::ClearScreen()
87{
88	Write("\033E", 2);
89}
90
91
92int32
93Console::Width()
94{
95	return 80;
96}
97
98
99int32
100Console::Height()
101{
102	return 25;
103}
104
105
106void
107Console::SetCursor(int32 x, int32 y)
108{
109	char buff[] = "\033Y  ";
110	x = MIN(79,MAX(0,x));
111	y = MIN(24,MAX(0,y));
112	buff[3] += (char)x;
113	buff[2] += (char)y;
114	Write(buff, 4);
115}
116
117
118void
119Console::SetCursorVisible(bool visible)
120{
121	// TODO
122}
123
124static int
125translate_color(int32 color)
126{
127	/*
128			r	g	b
129		0:	0	0	0		// black
130		1:	0	0	aa		// dark blue
131		2:	0	aa	0		// dark green
132		3:	0	aa	aa		// cyan
133		4:	aa	0	0		// dark red
134		5:	aa	0	aa		// purple
135		6:	aa	55	0		// brown
136		7:	aa	aa	aa		// light gray
137		8:	55	55	55		// dark gray
138		9:	55	55	ff		// light blue
139		a:	55	ff	55		// light green
140		b:	55	ff	ff		// light cyan
141		c:	ff	55	55		// light red
142		d:	ff	55	ff		// magenta
143		e:	ff	ff	55		// yellow
144		f:	ff	ff	ff		// white
145	*/
146	// cf. http://www.fortunecity.com/skyscraper/apple/308/html/chap4.htm
147	static const char cmap[] = {
148		15, 4, 2, 6, 1, 5, 3, 7,
149		8, 12, 10, 14, 9, 13, 11, 0 };
150
151	if (color < 0 || color >= 16)
152		return 0;
153	return cmap[color];
154}
155
156
157void
158Console::SetColors(int32 foreground, int32 background)
159{
160	char buff[] = "\033b \033c ";
161	if (sForceBW) {
162		if (background == 0)
163			foreground = 15;
164		else {
165			background = 15;
166			foreground = 0;
167		}
168
169	}
170	buff[2] += (char)translate_color(foreground);
171	buff[5] += (char)translate_color(background);
172	Write(buff, 6);
173}
174
175
176//	#pragma mark -
177
178
179constexpr bool kDumpColors = false;
180constexpr bool kDumpMilanModes = false;
181
182static void
183dump_colors()
184{
185	int bg, fg;
186	dprintf("colors:\n");
187	for (bg = 0; bg < 16; bg++) {
188		for (fg = 0; fg < 16; fg++) {
189			console_set_color(fg, bg);
190			dprintf("#");
191		}
192		console_set_color(0, 15);
193		dprintf("\n");
194	}
195}
196
197
198static int32
199dump_milan_modes(SCREENINFO *info, uint32 flags)
200{
201	dprintf("mode: %d '%s':\n flags %08" B_PRIx32 " @%08" B_PRIx32 " %dx%d (%dx%d)\n%d planes %d colors fmt %08" B_PRIx32 "\n",
202		info->devID, info->name, info->scrFlags, info->frameadr,
203		info->scrWidth, info->scrHeight,
204		info->virtWidth, info->virtHeight,
205		info->scrPlanes, info->scrColors, info->scrFormat);
206	return ENUMMODE_CONT;
207}
208
209status_t
210console_init(void)
211{
212	gConsoleNode = &sConsole;
213
214	console_clear_screen();
215
216	// enable stdio functionality
217	stdin = (FILE *)&sConsole;
218	stdout = stderr = (FILE *)&sConsole;
219
220	if (tos_find_cookie('_MIL')) {
221		dprintf("Milan detected... forcing black & white\n");
222		if (kDumpMilanModes) {
223			dprintf("Getrez() = %d\n", Getrez());
224			Setscreen(-1, &dump_milan_modes, MI_MAGIC, CMD_ENUMMODES);
225			Setscreen((void*)-1, (void*)-1, 0, 0);
226		}
227		sForceBW = true;
228	}
229
230	if (kDumpColors)
231		dump_colors();
232
233	return B_OK;
234}
235
236
237// #pragma mark -
238
239
240int
241console_wait_for_key(void)
242{
243#if 0
244	// XXX: do this way and remove keyboard.cpp ?
245	// wait for a key
246	char buffer[3];
247	ssize_t bytesRead;
248	do {
249		bytesRead = sInput.ReadAt(NULL, 0, buffer, 3);
250		if (bytesRead < 0)
251			return 0;
252	} while (bytesRead == 0);
253#endif
254	union key key = wait_for_key();
255
256	if (key.code.ascii == 0) {
257		switch (key.code.bios) {
258			case BIOS_KEY_UP:
259				return TEXT_CONSOLE_KEY_UP;
260			case BIOS_KEY_DOWN:
261				return TEXT_CONSOLE_KEY_DOWN;
262			case BIOS_KEY_PAGE_UP:
263				return TEXT_CONSOLE_KEY_PAGE_UP;
264			case BIOS_KEY_PAGE_DOWN:
265				return TEXT_CONSOLE_KEY_PAGE_DOWN;
266			case BIOS_KEY_HOME:
267				return TEXT_CONSOLE_KEY_HOME;
268			case BIOS_KEY_END:
269				return TEXT_CONSOLE_KEY_END;
270			default:
271				return 0;
272		}
273	} else
274		return key.code.ascii;
275}
276
277