#include <acess.h>
#include <fs_devfs.h>
#include <modules.h>
-#include <tpl_drv_video.h>
-#include <tpl_drv_keyboard.h>
-#include <tpl_drv_terminal.h>
+#include <api_drv_video.h>
+#include <api_drv_keyboard.h>
+#include <api_drv_terminal.h>
#include <errno.h>
#include <semaphore.h>
-#define USE_CTRL_ALT 1
-
// === CONSTANTS ===
#define VERSION ((0<<8)|(50))
#define MAX_INPUT_CHARS8 (MAX_INPUT_CHARS32*4)
//#define DEFAULT_OUTPUT "BochsGA"
#define DEFAULT_OUTPUT "Vesa"
+#define FALLBACK_OUTPUT "x86_VGAText"
#define DEFAULT_INPUT "PS2Keyboard"
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
#define DEFAULT_SCROLLBACK 2 // 2 Screens of text + current screen
+//#define DEFAULT_SCROLLBACK 0
#define DEFAULT_COLOUR (VT_COL_BLACK|(0xAAA<<16))
#define VT_FLAG_HIDECSR 0x01
#define VT_FLAG_ALTBUF 0x02 //!< Alternate screen buffer
+#define VT_FLAG_RAWIN 0x04 //!< Don't handle ^Z/^C/^V
#define VT_FLAG_HASFB 0x10 //!< Set if the VTerm has requested the Framebuffer
enum eVT_InModes {
};
// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, DEFAULT_OUTPUT, DEFAULT_INPUT, NULL);
+MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, DEFAULT_INPUT, FALLBACK_OUTPUT, NULL);
tDevFS_Driver gVT_DrvInfo = {
NULL, "VTerm",
{
Log_Debug("VTerm", "Argument '%s'", arg);
if( strcmp(opt, "Video") == 0 ) {
- if( !gsVT_OutputDevice && Modules_InitialiseBuiltin( val ) == 0 )
+ if( !gsVT_OutputDevice )
gsVT_OutputDevice = strdup(val);
}
else if( strcmp(opt, "Input") == 0 ) {
- if( !gsVT_InputDevice && Modules_InitialiseBuiltin( val ) == 0 )
+ if( !gsVT_InputDevice )
gsVT_InputDevice = strdup(val);
}
else if( strcmp(opt, "Width") == 0 ) {
}
// Apply Defaults
- if(!gsVT_OutputDevice) gsVT_OutputDevice = strdup(DEFAULT_OUTPUT);
- if(!gsVT_InputDevice) gsVT_InputDevice = strdup(DEFAULT_INPUT);
+ if(!gsVT_OutputDevice) gsVT_OutputDevice = (char*)DEFAULT_OUTPUT;
+ else if( Module_EnsureLoaded( gsVT_OutputDevice ) ) gsVT_OutputDevice = (char*)DEFAULT_OUTPUT;
+ if( Module_EnsureLoaded( gsVT_OutputDevice ) ) gsVT_OutputDevice = (char*)FALLBACK_OUTPUT;
+
+ if(!gsVT_InputDevice) gsVT_InputDevice = (char*)DEFAULT_INPUT;
+ else if( Module_EnsureLoaded( gsVT_InputDevice ) ) gsVT_InputDevice = (char*)DEFAULT_INPUT;
- // Create paths
+ // Create device paths
{
char *tmp;
tmp = malloc( 9 + strlen(gsVT_OutputDevice) + 1 );
strcpy(tmp, "/Devices/");
strcpy(&tmp[9], gsVT_OutputDevice);
gsVT_OutputDevice = tmp;
+
tmp = malloc( 9 + strlen(gsVT_InputDevice) + 1 );
strcpy(tmp, "/Devices/");
strcpy(&tmp[9], gsVT_InputDevice);
// Set kernel output to VT0
Debug_SetKTerminal("/Devices/VTerm/0");
- Log_Log("VTerm", "Returning %i", MODULE_ERR_OK);
return MODULE_ERR_OK;
}
// Resize the text terminals
giVT_RealWidth = mode.width;
giVT_RealHeight = mode.height;
+ Log_Debug("VTerm", "Resizing terminals to %ix%i",
+ giVT_RealWidth/giVT_CharWidth, giVT_RealHeight/giVT_CharHeight);
for( i = 0; i < NUM_VTS; i ++ )
{
if( gVT_Terminals[i].Mode != TERM_MODE_TEXT ) continue;
gVT_Terminals[i].TextWidth = giVT_RealWidth/giVT_CharWidth;
gVT_Terminals[i].TextHeight = giVT_RealHeight/giVT_CharHeight;
+ gVT_Terminals[i].ScrollHeight = gVT_Terminals[i].TextHeight;
gVT_Terminals[i].Text = realloc(
gVT_Terminals[i].Text,
}
/**
- * \fn Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
* \brief Read from a virtual terminal
*/
Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
// Other - UCS-4
default:
VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UCS-4)");
-
+
avail = term->InputWrite - term->InputRead;
if(avail < 0)
avail += MAX_INPUT_CHARS32;
Codepoint &= 0x7FFFFFFF;
switch(Codepoint)
{
- #if !USE_CTRL_ALT
- case KEY_RSHIFT: gbVT_CtrlDown = 0; break;
- case KEY_LSHIFT: gbVT_AltDown = 0; break;
- #else
case KEY_LALT: gbVT_AltDown &= ~1; break;
case KEY_RALT: gbVT_AltDown &= ~2; break;
case KEY_LCTRL: gbVT_CtrlDown &= ~1; break;
case KEY_RCTRL: gbVT_CtrlDown &= ~2; break;
- #endif
}
return;
}
switch(Codepoint)
{
- #if !USE_CTRL_ALT // HACK: Use both shifts instead of Ctrl-Alt
- case KEY_RSHIFT: gbVT_CtrlDown = 1; break;
- case KEY_LSHIFT: gbVT_AltDown = 1; break;
- #else
case KEY_LALT: gbVT_AltDown |= 1; break;
case KEY_RALT: gbVT_AltDown |= 2; break;
case KEY_LCTRL: gbVT_CtrlDown |= 1; break;
case KEY_RCTRL: gbVT_CtrlDown |= 2; break;
- #endif
default:
if(!gbVT_AltDown || !gbVT_CtrlDown)
case KEY_PGDOWN:
if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF )
return ;
- if( gpVT_CurTerm->ViewPos < gpVT_CurTerm->Width*gpVT_CurTerm->Height*(giVT_Scrollback-1) )
+ if( gpVT_CurTerm->ViewPos < gpVT_CurTerm->Width*gpVT_CurTerm->Height*(giVT_Scrollback) )
gpVT_CurTerm->ViewPos += gpVT_CurTerm->Width;
else
- gpVT_CurTerm->ViewPos = gpVT_CurTerm->Width*gpVT_CurTerm->Height*(giVT_Scrollback-1);
+ gpVT_CurTerm->ViewPos = gpVT_CurTerm->Width*gpVT_CurTerm->Height*(giVT_Scrollback);
return;
}
}
// Unprintable / Don't Pass
return;
}
+
+#if 0
+ // Handle meta characters
+ if( !(term->Flags & VT_FLAG_RAWIN) )
+ {
+ switch(buf[0])
+ {
+ case '\3': // ^C
+
+ break;
+ }
+ }
+#endif
// Write
if( MAX_INPUT_CHARS8 - term->InputWrite >= len )
}
VFS_MarkAvaliable(&term->Node, 1);
-
- // Wake up the thread waiting on us
- //if( term->ReadingThread >= 0 ) {
- // Threads_WakeTID(term->ReadingThread);
- //}
}
/**
}
// Get Command
- if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+ if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
{
if( bQuestionMark )
{
break;
}
break;
+ default:
+ Log_Warning("VTerm", "Unknown control sequence '\\x1B[?%c'", c);
+ break;
}
}
else
break;
}
break;
+
+ // Erase in line
+ case 'K':
+ switch(args[0])
+ {
+ case 0: // Erase to right
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ {
+ int i, max;
+ max = Term->Width - Term->AltWritePos % Term->Width;
+ for( i = 0; i < max; i ++ )
+ Term->AltBuf[Term->AltWritePos+i].Ch = 0;
+ }
+ else
+ {
+ int i, max;
+ max = Term->Width - Term->WritePos % Term->Width;
+ for( i = 0; i < max; i ++ )
+ Term->Text[Term->WritePos+i].Ch = 0;
+ }
+ VT_int_UpdateScreen(Term, 0);
+ break;
+ case 1: // Erase to left
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ {
+ int i = Term->AltWritePos % Term->Width;
+ while( i -- )
+ Term->AltBuf[Term->AltWritePos++].Ch = 0;
+ }
+ else
+ {
+ int i = Term->WritePos % Term->Width;
+ while( i -- )
+ Term->Text[Term->WritePos++].Ch = 0;
+ }
+ VT_int_UpdateScreen(Term, 0);
+ break;
+ case 2: // Erase all
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ {
+ VT_int_ClearLine(Term, Term->AltWritePos / Term->Width);
+ }
+ else
+ {
+ VT_int_ClearLine(Term, Term->WritePos / Term->Width);
+ }
+ VT_int_UpdateScreen(Term, 0);
+ break;
+ }
+ break;
+
// Set cursor position
case 'H':
if( Term->Flags & VT_FLAG_ALTBUF )
Term->AltWritePos = args[0] + args[1]*Term->TextWidth;
else
Term->WritePos = args[0] + args[1]*Term->TextWidth;
- Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]);
+ //Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]);
break;
// Scroll up `n` lines
case 'S':
tmp = -1;
// Scroll down `n` lines
- case 'P':
+ case 'T':
if(argc == 1) tmp *= args[0];
-
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ VT_int_ScrollText(Term, tmp);
+ else
+ {
+ if(Term->ViewPos/Term->TextWidth + tmp < 0)
+ break;
+ if(Term->ViewPos/Term->TextWidth + tmp > Term->TextHeight * (giVT_Scrollback + 1))
+ break;
+
+ Term->ViewPos += Term->TextWidth*tmp;
+ }
break;
// Set Font flags
break;
default:
- Log_Warning("VTerm", "Unknown control sequence");
+ Log_Warning("VTerm", "Unknown control sequence '\\x1B[%c'", c);
break;
}
}
write_pos -= write_pos % Term->TextWidth;
break;
- case '\t':
+ case '\t': { int tmp = write_pos / Term->TextWidth;
+ write_pos %= Term->TextWidth;
do {
buffer[ write_pos ].Ch = '\0';
buffer[ write_pos ].Colour = Term->CurColour;
write_pos ++;
} while(write_pos & 7);
- break;
+ write_pos += tmp * Term->TextWidth;
+ break; }
case '\b':
// Backspace is invalid at Offset 0
// Update the last line
Term->WritePos -= Term->TextWidth;
VT_int_UpdateScreen( Term, 0 );
+ Term->WritePos += Term->TextWidth;
VT_int_ScrollText(Term, 1);
+
+ Term->ViewPos += Term->TextWidth;
}
}
{
tVT_Char *buf;
int height, init_write_pos;
- int base, len, i;
-
+ int len, i;
+ int scroll_top, scroll_height;
+
+ // Get buffer pointer and attributes
if( Term->Flags & VT_FLAG_ALTBUF )
{
buf = Term->AltBuf;
height = Term->TextHeight;
init_write_pos = Term->AltWritePos;
+ scroll_top = Term->ScrollTop;
+ scroll_height = Term->ScrollHeight;
}
else
{
buf = Term->Text;
- height = Term->TextHeight*giVT_Scrollback;
+ height = Term->TextHeight*(giVT_Scrollback+1);
init_write_pos = Term->WritePos;
+ scroll_top = 0;
+ scroll_height = height;
}
-
+
+ // Scroll text downwards
if( Count > 0 )
{
- if(Count > Term->ScrollHeight) Count = Term->ScrollHeight;
- base = Term->TextWidth*(Term->ScrollTop + Term->ScrollHeight - Count);
- len = Term->TextWidth*(height - Term->ScrollHeight - Count - Term->ScrollTop);
+ int base;
+
+ // Set up
+ if(Count > scroll_height) Count = scroll_height;
+ base = Term->TextWidth*(scroll_top + scroll_height - Count);
+ len = Term->TextWidth*(scroll_height - Count);
// Scroll terminal cache
- memcpy(
- &buf[Term->TextWidth*Term->ScrollTop],
- &buf[Term->TextWidth*(Term->ScrollTop+Count)],
+ memmove(
+ &buf[Term->TextWidth*scroll_top],
+ &buf[Term->TextWidth*(scroll_top+Count)],
len*sizeof(tVT_Char)
);
// Clear last rows
for( i = 0; i < Term->TextWidth*Count; i ++ )
{
- Term->AltBuf[ base + i ].Ch = 0;
- Term->AltBuf[ base + i ].Colour = Term->CurColour;
+ buf[ base + i ].Ch = 0;
+ buf[ base + i ].Colour = Term->CurColour;
}
// Update Screen
VT_int_ScrollFramebuffer( Term, Count );
- Term->WritePos = Term->ViewPos + Term->ScrollTop + (Term->ScrollHeight - Count);
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ Term->AltWritePos = base;
+ else
+ Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
for( i = 0; i < Count; i ++ )
{
VT_int_UpdateScreen( Term, 0 );
else
{
Count = -Count;
- if(Count > Term->ScrollHeight) Count = Term->ScrollHeight;
+ if(Count > scroll_height) Count = scroll_height;
- len = Term->TextWidth*(height - Term->ScrollHeight - Count - Term->ScrollTop);
+ len = Term->TextWidth*(scroll_height - Count);
// Scroll terminal cache
- memcpy(
- &buf[Term->TextWidth*(Term->ScrollTop+Count)],
- &buf[Term->TextWidth*Term->ScrollTop],
+ memmove(
+ &buf[Term->TextWidth*(scroll_top+Count)],
+ &buf[Term->TextWidth*scroll_top],
len*sizeof(tVT_Char)
);
// Clear preceding rows
for( i = 0; i < Term->TextWidth*Count; i ++ )
{
- Term->AltBuf[ i ].Ch = 0;
- Term->AltBuf[ i ].Colour = Term->CurColour;
+ buf[ i ].Ch = 0;
+ buf[ i ].Colour = Term->CurColour;
}
VT_int_ScrollFramebuffer( Term, -Count );
- Term->WritePos = Term->ViewPos + Term->ScrollTop;
+ if( Term->Flags & VT_FLAG_ALTBUF )
+ Term->AltWritePos = Term->TextWidth*scroll_top;
+ else
+ Term->WritePos = Term->ViewPos;
for( i = 0; i < Count; i ++ )
{
VT_int_UpdateScreen( Term, 0 );
// BLIT to 0,0 from 0,giVT_CharHeight
buf.Op = VIDEO_2DOP_BLIT;
buf.SrcX = 0; buf.DstX = 0;
+ // TODO: Don't assume character dimensions
buf.W = Term->TextWidth * giVT_CharWidth;
if( Count > 0 )
{
buf.SrcY = (Term->ScrollTop+Count) * giVT_CharHeight;
buf.DstY = Term->ScrollTop * giVT_CharHeight;
- buf.H = (Term->ScrollHeight-Count) * giVT_CharHeight;
}
else // Scroll up, move text down
{
+ Count = -Count;
buf.SrcY = Term->ScrollTop * giVT_CharHeight;
buf.DstY = (Term->ScrollTop+Count) * giVT_CharHeight;
- buf.H = (Term->ScrollHeight+Count) * giVT_CharHeight;
}
+ buf.H = (Term->ScrollHeight-Count) * giVT_CharHeight;
VFS_WriteAt(giVT_OutputDevHandle, 0, sizeof(buf), &buf);
// Restore old mode (this function is only called during text mode)
Term->Flags |= VT_FLAG_ALTBUF;
else
Term->Flags &= ~VT_FLAG_ALTBUF;
+ VT_int_UpdateScreen(Term, 1);
}
// ---