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