/* * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab * Copyright (C) 2008 - DIGITEO - Allan CORNET * * This file must be used under the terms of the CeCILL. * This source file is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt * */ /*--------------------------------------------------------------------------*/ #include #include #include #include "TermConsole.h" #include "MALLOC.h" #include "TermCommand.h" #include "FocusOnConsole.h" #include "strdup_Windows.h" #include "TermCompletion.h" #include "TermLine.h" #include "scilines.h" #include "HistoryManager.h" #include "storeCommand.h" /* ismenu */ #include "localization.h" /*--------------------------------------------------------------------------*/ #ifdef CR_1 #undef CR_1 #endif #define CR_1 '\n' #ifdef CR_2 #undef CR_2 #endif #define CR_2 '\r' /*--------------------------------------------------------------------------*/ static HANDLE Win32OutputStream = NULL, Win32InputStream = NULL; static DWORD OldWin32Mode; /*--------------------------------------------------------------------------*/ static BOOL InitTerm = TRUE; /*--------------------------------------------------------------------------*/ static unsigned char TerminalGetchar(void); static BOOL isCTRLPressed(DWORD StateKey); static BOOL isCTRL_VKEY(int VKEY); static BOOL isALTPressed(DWORD StateKey); static BOOL isALT_VKEY(int VKEY); static BOOL isExtendedPressed(DWORD StateKey); static void simulateCarriageReturn(void); static char actionControlKey(void); /*--------------------------------------------------------------------------*/ static BOOL CtrlHandler( DWORD fdwCtrlType ) { switch ( fdwCtrlType ) { case CTRL_C_EVENT: { ControlC_Command(); newLine(); simulateCarriageReturn(); } return TRUE; } return FALSE; } /*--------------------------------------------------------------------------*/ static void simulateCarriageReturn(void) { INPUT_RECORD rec; DWORD written; memset (&rec, 0, sizeof(rec)); rec.EventType = KEY_EVENT; rec.Event.KeyEvent.bKeyDown = TRUE; rec.Event.KeyEvent.wRepeatCount = 13; rec.Event.KeyEvent.uChar.AsciiChar = 13; if (!Win32InputStream) { Win32InputStream = GetStdHandle(STD_INPUT_HANDLE); } WriteConsoleInput(Win32InputStream, &rec, 1, &written); } /*--------------------------------------------------------------------------*/ void InitializeTerminal(void) { if (!Win32InputStream) { Win32InputStream = GetStdHandle(STD_INPUT_HANDLE); GetConsoleMode(Win32InputStream, &OldWin32Mode); SetConsoleMode(Win32InputStream, ENABLE_PROCESSED_INPUT); } if (!Win32OutputStream) { Win32OutputStream = GetStdHandle(STD_OUTPUT_HANDLE); } setFocusOnConsole(); SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ); } /*--------------------------------------------------------------------------*/ void TerminalBeep(void) { MessageBeep(MB_OK); } /*--------------------------------------------------------------------------*/ int TerminalPrintf(char *buffer) { if (buffer) { if (buffer[0] != 0) { int len = (int)strlen (buffer); /* flush all stream */ /* problem with fortran output */ fflush(NULL); len = fputs (buffer, stdout); /* flush all stream */ /* problem with fortran output */ fflush(NULL); return len; } return 0; } return -1; } /*--------------------------------------------------------------------------*/ int TerminalPutc(char ch) { return putc(ch, stdout); } /*--------------------------------------------------------------------------*/ static unsigned char TerminalGetchar(void) { INPUT_RECORD irBuffer; DWORD n = 0; unsigned char ch = 0; do { /* http://bugzilla.scilab.org/show_bug.cgi?id=1052 */ if ( ismenu() == 1 ) { return 0; } WaitForSingleObject(Win32InputStream, INFINITE); PeekConsoleInput (Win32InputStream, &irBuffer, 1, &n); switch (irBuffer.EventType) { case KEY_EVENT: { if (irBuffer.Event.KeyEvent.bKeyDown) { if (irBuffer.Event.KeyEvent.dwControlKeyState) { if (isCTRLPressed(irBuffer.Event.KeyEvent.dwControlKeyState)) { char c = actionControlKey(); if (c) { ReadConsoleInputW (Win32InputStream, &irBuffer, 1, &n); return c; } else { if (irBuffer.Event.KeyEvent.uChar.AsciiChar != '\0') { ReadConsoleInputW (Win32InputStream, &irBuffer, 1, &n); c = irBuffer.Event.KeyEvent.uChar.AsciiChar; if ( (c > 0) && !iscntrl(c) ) { return c; } } else { ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } } break; } if (isALTPressed(irBuffer.Event.KeyEvent.dwControlKeyState)) { if (irBuffer.Event.KeyEvent.uChar.AsciiChar != '\0') { ReadConsole (Win32InputStream, &ch, 1, &n, NULL); return ch; } else { DWORD stateKey = 0; WORD vk = 0; ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); stateKey = irBuffer.Event.KeyEvent.dwControlKeyState; vk = irBuffer.Event.KeyEvent.wVirtualKeyCode; switch (vk) { case VK_F4: ALTF4_Command(); break; default: break; } } break; } } if (irBuffer.Event.KeyEvent.uChar.AsciiChar != '\0') { ReadConsole (Win32InputStream, &ch, 1, &n, NULL); switch (ch) { case VK_TAB: TermCompletion(); break; case VK_BACK: deletePreviousChar(); break; default: { if ( !iscntrl(ch) || (ch == CR_1) || (ch == CR_2) ) { return ch; } } break; } } else { WORD vk = 0; ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); vk = irBuffer.Event.KeyEvent.wVirtualKeyCode; switch (vk) { case VK_F1: case VK_HELP: F1_Command(); break; case VK_F2: F2_Command(); break; case VK_LEFT: moveBackSingleChar(); break; case VK_RIGHT: moveForwardSingleChar(); break; case VK_UP: moveBackHistory(); break; case VK_DOWN: moveForwardHistory(); break; case VK_DELETE: deleteCurrentChar(); break; case VK_HOME: moveBeginningLine(); break; case VK_END: moveEndLine(); break; default: break; } } } else { ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } } break; case MOUSE_EVENT: { /* Read mouse Input but not used */ ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } break; case WINDOW_BUFFER_SIZE_EVENT: { /* Read resize event Input */ setColumnsSize(irBuffer.Event.WindowBufferSizeEvent.dwSize.X); setLinesSize(irBuffer.Event.WindowBufferSizeEvent.dwSize.Y); ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } break; case MENU_EVENT: { ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } break; case FOCUS_EVENT: { ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } break; default: { /* Read Input but not used */ ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } break; } } while (TRUE); } /*--------------------------------------------------------------------------*/ static char actionControlKey(void) { if ( isCTRL_VKEY('X') || isCTRL_VKEY('C') ) { ControlC_Command(); return '\n'; } else if (isCTRL_VKEY('A')) /* moves to the beginning of the line */ { moveBeginningLine(); } else if (isCTRL_VKEY('B')) /* moves back a single character */ { moveBackSingleChar(); } else if (isCTRL_VKEY('D')) /* deletes the current character */ { deleteCurrentChar(); } else if (isCTRL_VKEY('E')) /* moves to the end of the line */ { moveEndLine(); } else if (isCTRL_VKEY('F')) /* moves forward a single character */ { moveForwardSingleChar(); } else if (isCTRL_VKEY('H')) /* delete the previous character */ { deletePreviousChar(); } else if (isCTRL_VKEY('K')) /* kills from current position to the end of line */ { killCurrentPositionToEndLine(); } else if (isCTRL_VKEY('N')) /* moves forward through history */ { moveForwardHistory(); } else if (isCTRL_VKEY('P')) /* moves back through history */ { moveBackHistory(); } else if ( isCTRL_VKEY('R') || isCTRL_VKEY('L') ) /* redraw line in case it gets trashed */ { redrawLine(); } else if (isCTRL_VKEY('U')) /* kills the entire line */ { clearCurrentLine(); } else if (isCTRL_VKEY('V')) { pasteClipBoard(); } else if (isCTRL_VKEY('W')) /* kills last word */ { killLastWord(); } else if (isCTRL_VKEY(VK_TAB) || isCTRL_VKEY(VK_SPACE)) /* Completion */ { TermCompletion(); } else if (isCTRL_VKEY(VK_LEFT)) /* */ { moveBackSingleWord(); } else if (isCTRL_VKEY(VK_RIGHT)) /* */ { moveForwardSingleWord(); } return 0; } /*--------------------------------------------------------------------------*/ char *TerminalGetString(char *prompt) { if (InitTerm) { InitializeTerminal(); InitTerm = FALSE; } newLine(); setCurrentPrompt(prompt); /* print the prompt */ displayPrompt(); /* initialize history search */ setSearchedTokenInScilabHistory(NULL); for (;;) { unsigned char cur_char = TerminalGetchar(); if (cur_char <= 0) { return NULL; } /* http://bugzilla.scilab.org/show_bug.cgi?id=1052 */ if (ismenu () == 1) { /* Abort current line */ return NULL; } if ( (cur_char == CR_1) || (cur_char == CR_2) ) { if ( isHistorySearch() ) { putLineSearchedHistory(); } else { char *line = getCurrentLine(); TerminalPutc('\n'); appendLineToScilabHistory(line); return line; } } else { TerminalPutc(cur_char); addCharacterCurrentLine(cur_char); } } return NULL; } /*--------------------------------------------------------------------------*/ static BOOL isCTRLPressed(DWORD StateKey) { return ((StateKey & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) != 0); } /*--------------------------------------------------------------------------*/ static BOOL isALTPressed(DWORD StateKey) { return ((StateKey & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) != 0); } /*--------------------------------------------------------------------------*/ static BOOL isExtendedPressed(DWORD StateKey) { return ((StateKey & (ENHANCED_KEY)) != 0); } /*--------------------------------------------------------------------------*/ static BOOL isCTRL_VKEY(int VKEY) { return ( GetKeyState(VKEY) & 0x80 ); } /*--------------------------------------------------------------------------*/