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
18 static bool sForceBW = false; // force black & white for Milan
19
20
21 // TOS emulates a VT52
22
23 class 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
43 extern ConsoleNode* gConsoleNode;
44 static Console sConsole;
45 FILE *stdin, *stdout, *stderr;
46
47
Console()48 Console::Console()
49 : ConsoleNode(), fHandle(DEV_CONSOLE)
50 {
51 }
52
53
54 ssize_t
ReadAt(void *,off_t,void * buffer,size_t bufferSize)55 Console::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
64 ssize_t
WriteAt(void *,off_t,const void * buffer,size_t bufferSize)65 Console::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
85 void
ClearScreen()86 Console::ClearScreen()
87 {
88 Write("\033E", 2);
89 }
90
91
92 int32
Width()93 Console::Width()
94 {
95 return 80;
96 }
97
98
99 int32
Height()100 Console::Height()
101 {
102 return 25;
103 }
104
105
106 void
SetCursor(int32 x,int32 y)107 Console::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
118 void
SetCursorVisible(bool visible)119 Console::SetCursorVisible(bool visible)
120 {
121 // TODO
122 }
123
124 static int
translate_color(int32 color)125 translate_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
157 void
SetColors(int32 foreground,int32 background)158 Console::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
179 constexpr bool kDumpColors = false;
180 constexpr bool kDumpMilanModes = false;
181
182 static void
dump_colors()183 dump_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
198 static int32
dump_milan_modes(SCREENINFO * info,uint32 flags)199 dump_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
209 status_t
console_init(void)210 console_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
240 int
console_wait_for_key(void)241 console_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