* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT license.
*
* Author:
* François Revol, revol@free.fr.
*/
#include <SupportDefs.h>
#include <string.h>
#include "rom_calls.h"
#include <util/kernel_cpp.h>
#include "Handle.h"
#include "console.h"
#include "keyboard.h"
class ConsoleHandle : public CharHandle {
public:
ConsoleHandle();
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
size_t bufferSize);
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer,
size_t bufferSize);
void Clear();
void MoveTo(int16 x, int16 y);
void SetColor(int32 foreground, int32 background);
int Columns();
int Rows();
private:
static int16 fX;
static int16 fY;
uint16 fPen;
};
class ConsoleDevice : public ExecDevice {
public:
ConsoleDevice(const char *title);
virtual ~ConsoleDevice();
status_t Open();
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
void Clear();
void MoveTo(int16 x, int16 y);
void SetColor(int32 foreground, int32 background);
int Columns();
int Rows();
int WaitForKey();
protected:
const char *fTitle;
struct Window *fWindow;
int fRows, fCols;
};
class KeyboardDevice : public ExecDevice {
public:
KeyboardDevice();
virtual ~KeyboardDevice();
status_t Open();
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
int WaitForKey();
status_t ReadEvent(struct InputEvent *event);
protected:
};
class LLKeyboardDevice : public CharHandle {
public:
LLKeyboardDevice();
virtual ~LLKeyboardDevice();
status_t Open();
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
int WaitForKey();
protected:
};
static const uint16 kPalette[] = {
0x000,
0x00a,
0x0a0,
0x0aa,
0xa00,
0xa0a,
0xa50,
0xaaa,
0x555,
0x55f,
0x5f5,
0x5ff,
0xf55,
0xf5f,
0xff5,
0xfff
};
struct Screen *gScreen;
static int16 sFontWidth, sFontHeight;
static int sScreenTopOffset = 16;
int16 ConsoleHandle::fX = 0;
int16 ConsoleHandle::fY = 0;
FILE *stdin, *stdout, *stderr, *dbgerr;
ConsoleHandle::ConsoleHandle()
: CharHandle()
{
}
ssize_t
ConsoleHandle::ReadAt(void *, off_t , void *buffer,
size_t bufferSize)
{
return B_ERROR;
}
ssize_t
ConsoleHandle::WriteAt(void *, off_t , const void *buffer,
size_t bufferSize)
{
const char *string = (const char *)buffer;
size_t i, len;
for (i = 0, len = 0; i < bufferSize; i++, len++) {
if (string[i] == '\0')
break;
if (string[i] == '\n') {
fX = 0;
fY++;
if (fY >= console_height())
fY = 0;
len = 0;
console_set_cursor(fX, fY);
continue;
}
Text(&gScreen->RastPort, &string[i], 1);
}
return bufferSize;
}
void
ConsoleHandle::Clear()
{
Move(&gScreen->RastPort, 0, sScreenTopOffset);
ClearScreen(&gScreen->RastPort);
}
void
ConsoleHandle::MoveTo(int16 x, int16 y)
{
fX = x;
fY = y;
Move(&gScreen->RastPort, sFontWidth * x,
sFontHeight * y + sScreenTopOffset);
}
void
ConsoleHandle::SetColor(int32 foreground, int32 background)
{
SetAPen(&gScreen->RastPort, foreground);
SetBPen(&gScreen->RastPort, background);
}
int
ConsoleHandle::Columns()
{
int columnCount = gScreen->Width / sFontWidth;
return columnCount;
}
int
ConsoleHandle::Rows()
{
int lineCount = (gScreen->Height - sScreenTopOffset) / sFontHeight;
return lineCount;
}
ConsoleDevice::ConsoleDevice(const char *title)
: ExecDevice(),
fTitle(title),
fWindow(NULL)
{
}
ConsoleDevice::~ConsoleDevice()
{
}
status_t
ConsoleDevice::Open()
{
status_t err;
if (fWindow)
return B_ERROR;
err = AllocRequest(sizeof(struct IOStdReq));
if (err < B_OK)
panic("AllocRequest");;
if (err < B_OK)
return err;
int16 topEdge = gScreen->Height - 60;
int height = 60;
if (fTitle == NULL) {
topEdge = 10;
height = gScreen->Height - 40;
fTitle = "Console";
}
struct NewWindow newWindow = {
0, topEdge,
gScreen->Width, height,
BLACK, WHITE,
IDCMP_CLOSEWINDOW,
WFLG_SIZEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_SIMPLE_REFRESH
| WFLG_ACTIVATE,
NULL,
NULL,
fTitle,
gScreen,
NULL,
100, 45,
gScreen->Width, gScreen->Height,
CUSTOMSCREEN
};
fWindow = OpenWindow(&newWindow);
if (fWindow == NULL)
panic("OpenWindow");;
if (fWindow == NULL)
return B_ERROR;
fIOStdReq->io_Data = fWindow;
fIOStdReq->io_Length = sizeof(struct Window);
err = ExecDevice::Open(CONSOLENAME, CONU_STANDARD, 0);
if (err < B_OK)
return err;
MoveTo(0, 0);
SetColor(WHITE, BLACK);
Clear();
}
ssize_t
ConsoleDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
{
return ExecDevice::ReadAt(cookie, pos, buffer, bufferSize);
}
int
ConsoleDevice::WaitForKey()
{
char ascii;
if (Read(&ascii, 1) < 1)
return TEXT_CONSOLE_NO_KEY;
if (ascii == (char)0x9b) {
if (Read(&ascii, 1) < 1)
return TEXT_CONSOLE_NO_KEY;
switch (ascii) {
case 'A':
return TEXT_CONSOLE_KEY_UP;
case 'B':
return TEXT_CONSOLE_KEY_DOWN;
case 'D':
return TEXT_CONSOLE_KEY_LEFT;
case 'C':
return TEXT_CONSOLE_KEY_RIGHT;
case '4':
{
if (Read(&ascii, 1) < 1)
return TEXT_CONSOLE_NO_KEY;
if (ascii == '~')
return TEXT_CONSOLE_NO_KEY;
switch (ascii) {
case '1':
Read(&ascii, 1);
return TEXT_CONSOLE_KEY_PAGE_UP;
case '2':
Read(&ascii, 1);
return TEXT_CONSOLE_KEY_PAGE_UP;
default:
return TEXT_CONSOLE_NO_KEY;
}
return TEXT_CONSOLE_NO_KEY;
}
default:
break;
}
}
return ascii;
}
ssize_t
ConsoleDevice::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
{
return ExecDevice::WriteAt(cookie, pos, buffer, bufferSize);
}
void
ConsoleDevice::Clear()
{
char buff[] = "\x0c";
WriteAt(NULL, 0LL, buff, sizeof(buff) - 1);
}
void
ConsoleDevice::MoveTo(int16 x, int16 y)
{
char buff[32];
x = MIN(79,MAX(0,x));
y = MIN(24,MAX(0,y));
sprintf(buff, "\x9b%02d;%02d\x48", y + 1, x + 1);
WriteAt(NULL, 0LL, buff, strlen(buff));
}
void
ConsoleDevice::SetColor(int32 foreground, int32 background)
{
char buff[] = "\2330;30;40m";
if (foreground >= 8) {
foreground -= 8;
}
if (foreground == background) {
foreground = 7 - background;
}
if (foreground < 8)
buff[4] += foreground;
if (background < 8)
buff[7] += background;
WriteAt(NULL, 0LL, buff, sizeof(buff) - 1);
}
int
ConsoleDevice::Columns()
{
struct ConUnit *unit = (struct ConUnit *)fIOStdReq->io_Unit;
return unit->cu_XMax;
}
int
ConsoleDevice::Rows()
{
struct ConUnit *unit = (struct ConUnit *)fIOStdReq->io_Unit;
return unit->cu_YMax - 1;
}
KeyboardDevice::KeyboardDevice()
: ExecDevice()
{
}
KeyboardDevice::~KeyboardDevice()
{
}
status_t
KeyboardDevice::Open()
{
return ExecDevice::Open("keyboard.device");
}
status_t
KeyboardDevice::ReadEvent(struct InputEvent *event)
{
fIOStdReq->io_Command = KBD_READEVENT;
fIOStdReq->io_Flags = IOF_QUICK;
fIOStdReq->io_Length = sizeof(struct InputEvent);
fIOStdReq->io_Data = event;
status_t err = Do();
if (err < B_OK)
return err;
dprintf("key: class %d sclass %d code %d 0x%02x qual 0x%04x\n",
event->ie_Class, event->ie_SubClass,
event->ie_Code, event->ie_Code, event->ie_Qualifier);
*/
return B_OK;
}
ssize_t
KeyboardDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
{
struct InputEvent event;
ssize_t actual;
status_t err;
do {
err = ReadEvent(&event);
if (err < B_OK)
return err;
} while (event.ie_Code > IECODE_UP_PREFIX);
actual = MapRawKey(&event, (char *)buffer, bufferSize, NULL);
if (actual > 0) {
return actual;
}
return B_ERROR;
}
int
KeyboardDevice::WaitForKey()
{
struct InputEvent event;
char ascii;
ssize_t actual;
status_t err;
do {
err = ReadEvent(&event);
if (err < B_OK)
return err;
} while (event.ie_Code < IECODE_UP_PREFIX);
event.ie_Code &= ~IECODE_UP_PREFIX;
switch (event.ie_Code) {
case IECODE_KEY_UP:
return TEXT_CONSOLE_KEY_UP;
case IECODE_KEY_DOWN:
return TEXT_CONSOLE_KEY_DOWN;
case IECODE_KEY_LEFT:
return TEXT_CONSOLE_KEY_LEFT;
case IECODE_KEY_RIGHT:
return TEXT_CONSOLE_KEY_RIGHT;
case IECODE_KEY_PAGE_UP:
return TEXT_CONSOLE_KEY_PAGE_UP;
case IECODE_KEY_PAGE_DOWN:
return TEXT_CONSOLE_KEY_PAGE_DOWN;
default:
break;
}
actual = MapRawKey(&event, &ascii, 1, NULL);
if (actual > 0)
return ascii;
return TEXT_CONSOLE_NO_KEY;
}
ssize_t
KeyboardDevice::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
{
return B_ERROR;
}
LLKeyboardDevice::LLKeyboardDevice()
: CharHandle()
{
}
LLKeyboardDevice::~LLKeyboardDevice()
{
}
status_t
LLKeyboardDevice::Open()
{
if (LowLevelBase == NULL)
LowLevelBase = (Library *)OldOpenLibrary(LOWLEVELNAME);
return (LowLevelBase == NULL) ? B_ERROR : B_OK;
}
ssize_t
LLKeyboardDevice::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
{
struct InputEvent event;
ssize_t actual;
status_t err;
uint32 key;
key = GetKey();
if (key & 0x0000ffff == 0x0ff)
return B_ERROR;
event.ie_Class = IECLASS_RAWKEY;
event.ie_SubClass = IESUBCLASS_RAWKEY;
event.ie_Code = (uint16)(key & 0x0000ffff);
event.ie_Qualifier = (key & 0xffff0000) >> 16;
actual = MapRawKey(&event, (char *)buffer, bufferSize, NULL);
if (actual > 0) {
return actual;
}
return B_ERROR;
}
int
LLKeyboardDevice::WaitForKey()
{
struct InputEvent event;
uint32 key;
char ascii;
ssize_t actual;
status_t err;
do {
key = GetKey();
} while (key & 0x0000ffff == 0x0ff);
event.ie_Class = IECLASS_RAWKEY;
event.ie_SubClass = IESUBCLASS_RAWKEY;
event.ie_Code = (uint16)(key & 0x0000ffff);
event.ie_Qualifier = (key & 0xffff0000) >> 16;
switch (event.ie_Code) {
case IECODE_KEY_UP:
return TEXT_CONSOLE_KEY_UP;
case IECODE_KEY_DOWN:
return TEXT_CONSOLE_KEY_DOWN;
case IECODE_KEY_LEFT:
return TEXT_CONSOLE_KEY_LEFT;
case IECODE_KEY_RIGHT:
return TEXT_CONSOLE_KEY_RIGHT;
case IECODE_KEY_PAGE_UP:
return TEXT_CONSOLE_KEY_PAGE_UP;
case IECODE_KEY_PAGE_DOWN:
return TEXT_CONSOLE_KEY_PAGE_DOWN;
default:
break;
}
actual = MapRawKey(&event, &ascii, 1, NULL);
if (actual > 0)
return ascii;
return TEXT_CONSOLE_NO_KEY;
}
ssize_t
LLKeyboardDevice::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
{
return B_ERROR;
}
static ConsoleDevice sOutput(NULL);
static ConsoleDevice sDebugOutput("Debug");
static ConsoleDevice &sInput = sOutput;
status_t
console_init(void)
{
status_t err;
GRAPHICS_BASE_NAME = (GfxBase *)OldOpenLibrary(GRAPHICSNAME);
if (GRAPHICS_BASE_NAME == NULL)
panic("Cannot open %s", GRAPHICSNAME);
static NewScreen newScreen = {
0, 0,
640, -1,
4,
BLACK, WHITE,
0x8000,
0x11,
NULL,
"Haiku Loader",
NULL,
NULL
};
gScreen = OpenScreen(&newScreen);
if (gScreen == NULL)
panic("OpenScreen()\n");
LoadRGB4(&gScreen->ViewPort, kPalette, 16);
SetDrMd(&gScreen->RastPort, JAM2);
TextAttr attrs = { "Topaz", 8, 0, 0};
TextFont *font = OpenFont(&attrs);
*/
TextFont *font = OpenFont(gScreen->Font);
if (font == NULL)
panic("OpenFont()\n");
sFontHeight = gScreen->Font->ta_YSize;
sFontWidth = font->tf_XSize;
sScreenTopOffset = gScreen->BarHeight * 2;
err = sDebugOutput.Open();
if (err < B_OK)
panic("sDebugOutput.Open() 0x%08lx\n", err);
dbgerr = stderr = (FILE *)&sDebugOutput;
err = sOutput.Open();
if (err < B_OK)
panic("sOutput.Open() 0x%08lx\n", err);
stdout = (FILE *)&sOutput;
console_set_cursor(0, 0);
dprintf("LeftEdge %d\n", gScreen->LeftEdge);
dprintf("TopEdge %d\n", gScreen->TopEdge);
dprintf("Width %d\n", gScreen->Width);
dprintf("Height %d\n", gScreen->Height);
dprintf("MouseX %d\n", gScreen->MouseX);
dprintf("MouseY %d\n", gScreen->MouseY);
dprintf("Flags 0x%08x\n", gScreen->Flags);
dprintf("BarHeight %d\n", gScreen->BarHeight);
dprintf("BarVBorder %d\n", gScreen->BarVBorder);
dprintf("BarHBorder %d\n", gScreen->BarHBorder);
dprintf("MenuVBorder %d\n", gScreen->MenuVBorder);
dprintf("MenuHBorder %d\n", gScreen->MenuHBorder);
dprintf("WBorTop %d\n", gScreen->WBorTop);
dprintf("WBorLeft %d\n", gScreen->WBorLeft);
dprintf("WBorRight %d\n", gScreen->WBorRight);
dprintf("WBorBottom %d\n", gScreen->WBorBottom);
*/
KEYMAP_BASE_NAME = (Library *)OldOpenLibrary(KEYMAPNAME);
if (KEYMAP_BASE_NAME == NULL)
panic("Cannot open %s", KEYMAPNAME);
err = sInput.Open();
if (err < B_OK)
panic("sInput.Open() 0x%08lx\n", err);
*/
stdin = (FILE *)&sInput;
return B_OK;
}
void
console_clear_screen(void)
{
sOutput.Clear();
}
int32
console_width(void)
{
return sOutput.Columns();
}
int32
console_height(void)
{
return sOutput.Rows();
}
void
console_set_cursor(int32 x, int32 y)
{
sOutput.MoveTo(x, y);
}
void
console_set_color(int32 foreground, int32 background)
{
sOutput.SetColor(foreground, background);
}
void
console_show_cursor(void)
{
}
void
console_hide_cursor(void)
{
}
int
console_wait_for_key(void)
{
int key = sInput.WaitForKey();
return key;
}