void Display_Newline(int bCarriageReturn) { // Display_Flush(); // Going down! giCurrentLine ++; if( giCurrentLine == giDisplayLines ) giCurrentLine = 0; if( giCurrentLine == giFirstLine ) { giFirstLine ++; if(giFirstLine == giDisplayLines) giFirstLine = 0; } if( bCarriageReturn ) { giCurrentLinePos = 0; giCurrentCol = 0; } else { giCurrentLinePos = 0; int i = giCurrentCol; if( !gasDisplayLines[giCurrentLine] ) { giCurrentCol = 0; while(i--) Display_AddText(1, " "); } else { while( i -- ) { uint32_t cp; giCurrentLinePos += ReadUTF8(gasDisplayLines[giCurrentLine]+giCurrentLinePos, &cp); if( !Unicode_IsPrinting(cp) ) i ++; } } } }
// === CODE === int main(int argc, char *argv[], const char **envp) { AxWin3_Connect(NULL); // --- Build up window gMainWindow = AxWin3_RichText_CreateWindow(NULL, AXWIN3_RICHTEXT_READONLY); AxWin3_SetWindowTitle(gMainWindow, "Terminal"); // TODO: Update title with other info gMenuWindow = AxWin3_Menu_Create(gMainWindow); AxWin3_Menu_AddItem(gMenuWindow, "Copy\tWin+C", NULL, NULL, 0, NULL); AxWin3_Menu_AddItem(gMenuWindow, "Paste\tWin+V", NULL, NULL, 0, NULL); // TODO: Populate menu // TODO: Tabs? AxWin3_RichText_SetKeyHandler (gMainWindow, Term_KeyHandler); AxWin3_RichText_SetMouseHandler (gMainWindow, Term_MouseHandler); AxWin3_RichText_SetDefaultColour(gMainWindow, 0xFFFFFF); AxWin3_RichText_SetBackground (gMainWindow, 0x000000); AxWin3_RichText_SetFont (gMainWindow, "#monospace", 10); AxWin3_RichText_SetCursorPos (gMainWindow, 0, 0); AxWin3_RichText_SetCursorType (gMainWindow, AXWIN3_RICHTEXT_CURSOR_INV); AxWin3_RichText_SetCursorBlink (gMainWindow, 1); tTerminal *term = Display_Init(80, 25, 100); AxWin3_ResizeWindow(gMainWindow, 80*8, 25*16); AxWin3_MoveWindow(gMainWindow, 20, 50); AxWin3_ShowWindow(gMainWindow, 1); AxWin3_FocusWindow(gMainWindow); // Create PTY giPTYHandle = _SysOpen("/Devices/pts/ptmx", OPENFLAG_READ|OPENFLAG_WRITE); if( giPTYHandle < 0 ) { perror("Unable to create/open PTY"); _SysDebug("Unable to create/open PTY: %s", strerror(errno)); return -1; } // - Initialise { _SysIOCtl(giPTYHandle, PTY_IOCTL_SETID, "gui0"); struct ptymode mode = {.InputMode = PTYIMODE_CANON|PTYIMODE_ECHO, .OutputMode=0}; struct ptydims dims = {.W = 80, .H = 25}; _SysIOCtl(giPTYHandle, PTY_IOCTL_SETMODE, &mode); _SysIOCtl(giPTYHandle, PTY_IOCTL_SETDIMS, &dims); } // Spawn shell { int fd = _SysOpen("/Devices/pts/gui0", OPENFLAG_READ|OPENFLAG_WRITE); int fds[] = {fd, fd, fd}; const char *argv[] = {"CLIShell", NULL}; int pid = _SysSpawn("/Acess/Bin/CLIShell", argv, envp, 3, fds, NULL); if( pid < 0 ) _SysDebug("ERROR: Shell spawn failed: %s", strerror(errno)); _SysIOCtl(fd, PTY_IOCTL_SETPGRP, &pid); _SysClose(fd); } // Main loop for( ;; ) { fd_set fds; FD_ZERO(&fds); FD_SET(giPTYHandle, &fds); AxWin3_MessageSelect(giPTYHandle + 1, &fds); if( FD_ISSET(giPTYHandle, &fds) ) { _SysDebug("Activity on child stdout"); // Read and update screen char buf[512]; int len = _SysRead(giPTYHandle, buf, sizeof(buf)); if( len <= 0 ) break; Term_HandleOutput(term, len, buf); } } return 0; } int Term_KeyHandler(tHWND Window, int bPress, uint32_t KeySym, uint32_t Translated) { static int ctrl_state = 0; // Handle modifiers #define _bitset(var,bit,set) do{if(set)var|=1<<(bit);else var&=~(1<<(bit));}while(0) switch(KeySym) { case KEYSYM_LEFTCTRL: _bitset(ctrl_state, 0, bPress!=0); return 0; case KEYSYM_RIGHTCTRL: _bitset(ctrl_state, 1, bPress!=0); return 0; } #undef _bitset // Handle shortcuts // - Ctrl-A -- Ctrl-Z if( ctrl_state && KeySym >= KEYSYM_a && KeySym <= KEYSYM_z ) { Translated = KeySym - KEYSYM_a + 1; _SysDebug("Ctrl-%c: KS %x => Trans %x", 'A'+(KeySym-KEYSYM_a), KeySym, Translated); } // == 2 :: FIRE if( bPress == 2 ) { if( Translated ) { char buf[6]; int len; // Encode and send len = WriteUTF8(buf, Translated); _SysDebug("Keystroke %x:%x translated to '%.*s'", KeySym, Translated, len, buf); _SysWrite(giPTYHandle, buf, len); return 0; } // No translation, look for escape sequences to send const char *str = NULL; switch(KeySym) { case KEYSYM_LEFTARROW: str = "\x1b[D"; break; case KEYSYM_RIGHTARROW: str = "\x1b[C"; break; case KEYSYM_UPARROW: str = "\x1b[A"; break; case KEYSYM_DOWNARROW: str = "\x1b[B"; break; } if( str ) { _SysWrite(giPTYHandle, str, strlen(str)); } } return 0; } int Term_MouseHandler(tHWND Window, int bPress, int Button, int Row, int Col) { return 0; } void Term_HandleOutput(tTerminal *Term, int Len, const char *Buf) { // TODO: Handle graphical / accelerated modes //_SysDebug("Term_HandleOutput: %i \"%.*s\"", Len, Len, Buf); int ofs = 0; int esc_len = 0; while( ofs < Len ) { esc_len = Term_HandleVT100(Term, Len - ofs, Buf + ofs); if( esc_len < 0 ) { Display_AddText(Term, -esc_len, Buf + ofs); esc_len = -esc_len; } ofs += esc_len; //_SysDebug("Len = %i, ofs = %i", Len, ofs); } Display_Flush(Term); }