0f9cc1aa393689ff7630d92b01230663d9b188b1
[scilab.git] / scilab / modules / console / src / c / windows / TermConsole.c
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2008 - DIGITEO - Allan CORNET
4 *
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution.  The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10 *
11 */
12 /*--------------------------------------------------------------------------*/
13 #include <Windows.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include "TermConsole.h"
17 #include "sci_malloc.h"
18 #include "TermCommand.h"
19 #include "FocusOnConsole.h"
20 #include "os_string.h"
21 #include "TermCompletion.h"
22 #include "TermLine.h"
23 #include "scilines.h"
24 #include "HistoryManager.h"
25 #include "storeCommand.h" /* ismenu */
26 #include "localization.h"
27 /*--------------------------------------------------------------------------*/
28 #ifdef CR_1
29 #undef CR_1
30 #endif
31 #define CR_1 '\n'
32
33 #ifdef CR_2
34 #undef CR_2
35 #endif
36 #define CR_2 '\r'
37 /*--------------------------------------------------------------------------*/
38 static HANDLE Win32OutputStream = NULL, Win32InputStream = NULL;
39 static DWORD OldWin32Mode;
40 /*--------------------------------------------------------------------------*/
41 static BOOL InitTerm = TRUE;
42 /*--------------------------------------------------------------------------*/
43 static unsigned char TerminalGetchar(void);
44 static BOOL isCTRLPressed(DWORD StateKey);
45 static BOOL isCTRL_VKEY(int VKEY);
46 static BOOL isALTPressed(DWORD StateKey);
47 static BOOL isALT_VKEY(int VKEY);
48 static BOOL isExtendedPressed(DWORD StateKey);
49 static void simulateCarriageReturn(void);
50 static char actionControlKey(void);
51 /*--------------------------------------------------------------------------*/
52 static BOOL CtrlHandler( DWORD fdwCtrlType )
53 {
54     switch ( fdwCtrlType )
55     {
56         case CTRL_C_EVENT:
57         {
58             ControlC_Command();
59             newLine();
60             simulateCarriageReturn();
61         }
62         return TRUE;
63     }
64     return FALSE;
65 }
66 /*--------------------------------------------------------------------------*/
67 static void simulateCarriageReturn(void)
68 {
69     INPUT_RECORD rec;
70     DWORD written;
71
72     memset (&rec, 0, sizeof(rec));
73     rec.EventType = KEY_EVENT;
74     rec.Event.KeyEvent.bKeyDown = TRUE;
75     rec.Event.KeyEvent.wRepeatCount = 13;
76     rec.Event.KeyEvent.uChar.AsciiChar = 13;
77
78     if (!Win32InputStream)
79     {
80         Win32InputStream = GetStdHandle(STD_INPUT_HANDLE);
81     }
82     WriteConsoleInput(Win32InputStream, &rec, 1, &written);
83 }
84 /*--------------------------------------------------------------------------*/
85 void InitializeTerminal(void)
86 {
87     if (!Win32InputStream)
88     {
89         Win32InputStream = GetStdHandle(STD_INPUT_HANDLE);
90         GetConsoleMode(Win32InputStream, &OldWin32Mode);
91         SetConsoleMode(Win32InputStream, ENABLE_PROCESSED_INPUT);
92     }
93
94     if (!Win32OutputStream)
95     {
96         Win32OutputStream = GetStdHandle(STD_OUTPUT_HANDLE);
97     }
98
99     setFocusOnConsole();
100
101     SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE );
102
103 }
104 /*--------------------------------------------------------------------------*/
105 void TerminalBeep(void)
106 {
107     MessageBeep(MB_OK);
108 }
109 /*--------------------------------------------------------------------------*/
110 int TerminalPrintf(char *buffer)
111 {
112     if (buffer)
113     {
114         if (buffer[0] != 0)
115         {
116             int len = (int)strlen (buffer);
117             /* flush all stream */
118             /* problem with fortran output */
119             fflush(NULL);
120
121             len = fputs (buffer, stdout);
122
123             /* flush all stream */
124             /* problem with fortran output */
125             fflush(NULL);
126
127             return len;
128         }
129         return 0;
130     }
131     return -1;
132 }
133 /*--------------------------------------------------------------------------*/
134 int TerminalPutc(char ch)
135 {
136     return putc(ch, stdout);
137 }
138 /*--------------------------------------------------------------------------*/
139 static unsigned char TerminalGetchar(void)
140 {
141     INPUT_RECORD irBuffer;
142     DWORD n = 0;
143     unsigned char ch = 0;
144     do
145     {
146         /* http://bugzilla.scilab.org/show_bug.cgi?id=1052 */
147         if ( ismenu() == 1 )
148         {
149             return 0;
150         }
151
152         WaitForSingleObject(Win32InputStream, INFINITE);
153         PeekConsoleInput (Win32InputStream, &irBuffer, 1, &n);
154
155         switch (irBuffer.EventType)
156         {
157             case KEY_EVENT:
158             {
159                 if (irBuffer.Event.KeyEvent.bKeyDown)
160                 {
161                     if (irBuffer.Event.KeyEvent.dwControlKeyState)
162                     {
163                         if (isCTRLPressed(irBuffer.Event.KeyEvent.dwControlKeyState))
164                         {
165                             char c = actionControlKey();
166                             if (c)
167                             {
168                                 ReadConsoleInputW (Win32InputStream, &irBuffer, 1, &n);
169                                 return c;
170                             }
171                             else
172                             {
173                                 if (irBuffer.Event.KeyEvent.uChar.AsciiChar != '\0')
174                                 {
175                                     ReadConsoleInputW (Win32InputStream, &irBuffer, 1, &n);
176                                     c = irBuffer.Event.KeyEvent.uChar.AsciiChar;
177                                     if ( (c > 0) && !iscntrl(c) )
178                                     {
179                                         return c;
180                                     }
181                                 }
182                                 else
183                                 {
184                                     ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n);
185                                 }
186                             }
187                             break;
188                         }
189
190                         if (isALTPressed(irBuffer.Event.KeyEvent.dwControlKeyState))
191                         {
192                             if (irBuffer.Event.KeyEvent.uChar.AsciiChar != '\0')
193                             {
194                                 ReadConsole (Win32InputStream, &ch, 1, &n, NULL);
195                                 return ch;
196                             }
197                             else
198                             {
199                                 DWORD stateKey = 0;
200                                 WORD vk = 0;
201
202                                 ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n);
203
204                                 stateKey = irBuffer.Event.KeyEvent.dwControlKeyState;
205                                 vk = irBuffer.Event.KeyEvent.wVirtualKeyCode;
206
207                                 switch (vk)
208                                 {
209                                     case VK_F4:
210                                         ALTF4_Command();
211                                         break;
212
213                                     default:
214                                         break;
215                                 }
216                             }
217                             break;
218                         }
219                     }
220
221                     if (irBuffer.Event.KeyEvent.uChar.AsciiChar != '\0')
222                     {
223                         ReadConsole (Win32InputStream, &ch, 1, &n, NULL);
224
225                         switch (ch)
226                         {
227                             case VK_TAB:
228                                 TermCompletion();
229                                 break;
230                             case VK_BACK:
231                                 deletePreviousChar();
232                                 break;
233                             default:
234                             {
235                                 if ( !iscntrl(ch) || (ch == CR_1) || (ch == CR_2) )
236                                 {
237                                     return ch;
238                                 }
239                             }
240                             break;
241                         }
242                     }
243                     else
244                     {
245                         WORD vk = 0;
246                         ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n);
247                         vk = irBuffer.Event.KeyEvent.wVirtualKeyCode;
248
249                         switch (vk)
250                         {
251                             case VK_F1:
252                             case VK_HELP:
253                                 F1_Command();
254                                 break;
255                             case VK_F2:
256                                 F2_Command();
257                                 break;
258                             case VK_LEFT:
259                                 moveBackSingleChar();
260                                 break;
261                             case VK_RIGHT:
262                                 moveForwardSingleChar();
263                                 break;
264                             case VK_UP:
265                                 moveBackHistory();
266                                 break;
267                             case VK_DOWN:
268                                 moveForwardHistory();
269                                 break;
270                             case VK_DELETE:
271                                 deleteCurrentChar();
272                                 break;
273                             case VK_HOME:
274                                 moveBeginningLine();
275                                 break;
276                             case VK_END:
277                                 moveEndLine();
278                                 break;
279                             default:
280                                 break;
281                         }
282                     }
283                 }
284                 else
285                 {
286                     ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n);
287                 }
288             }
289             break;
290             case MOUSE_EVENT:
291             {
292                 /* Read mouse Input but not used */
293                 ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n);
294             }
295             break;
296             case WINDOW_BUFFER_SIZE_EVENT:
297             {
298                 /* Read resize event Input */
299                 setColumnsSize(irBuffer.Event.WindowBufferSizeEvent.dwSize.X);
300                 setLinesSize(irBuffer.Event.WindowBufferSizeEvent.dwSize.Y);
301
302                 ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n);
303             }
304             break;
305             case MENU_EVENT:
306             {
307                 ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n);
308             }
309             break;
310             case FOCUS_EVENT:
311             {
312                 ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n);
313             }
314             break;
315             default:
316             {
317                 /* Read Input but not used */
318                 ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n);
319             }
320             break;
321         }
322     }
323     while (TRUE);
324 }
325 /*--------------------------------------------------------------------------*/
326 static char actionControlKey(void)
327 {
328     if ( isCTRL_VKEY('X') || isCTRL_VKEY('C') )
329     {
330         ControlC_Command();
331         return '\n';
332     }
333     else if (isCTRL_VKEY('A')) /* moves to the beginning of the line */
334     {
335         moveBeginningLine();
336     }
337     else if (isCTRL_VKEY('B')) /* moves back a single character */
338     {
339         moveBackSingleChar();
340     }
341     else if (isCTRL_VKEY('D')) /* deletes the current character */
342     {
343         deleteCurrentChar();
344     }
345     else if (isCTRL_VKEY('E')) /* moves to the end of the line */
346     {
347         moveEndLine();
348     }
349     else if (isCTRL_VKEY('F')) /* moves forward a single character */
350     {
351         moveForwardSingleChar();
352     }
353     else if (isCTRL_VKEY('H')) /* delete the previous character */
354     {
355         deletePreviousChar();
356     }
357     else if (isCTRL_VKEY('K')) /* kills from current position to the end of line */
358     {
359         killCurrentPositionToEndLine();
360     }
361     else if (isCTRL_VKEY('N')) /* moves forward through history */
362     {
363         moveForwardHistory();
364     }
365     else if (isCTRL_VKEY('P')) /* moves back through history */
366     {
367         moveBackHistory();
368     }
369     else if ( isCTRL_VKEY('R') || isCTRL_VKEY('L') ) /* redraw line in case it gets trashed */
370     {
371         redrawLine();
372     }
373     else if (isCTRL_VKEY('U')) /* kills the entire line */
374     {
375         clearCurrentLine();
376     }
377     else if (isCTRL_VKEY('V'))
378     {
379         pasteClipBoard();
380     }
381     else if (isCTRL_VKEY('W')) /* kills last word */
382     {
383         killLastWord();
384     }
385     else if (isCTRL_VKEY(VK_TAB) || isCTRL_VKEY(VK_SPACE)) /* Completion */
386     {
387         TermCompletion();
388     }
389     else if (isCTRL_VKEY(VK_LEFT)) /* */
390     {
391         moveBackSingleWord();
392     }
393     else if (isCTRL_VKEY(VK_RIGHT)) /* */
394     {
395         moveForwardSingleWord();
396     }
397     return 0;
398 }
399 /*--------------------------------------------------------------------------*/
400 char *TerminalGetString(char *prompt)
401 {
402     if (InitTerm)
403     {
404         InitializeTerminal();
405         InitTerm = FALSE;
406     }
407
408     newLine();
409
410     setCurrentPrompt(prompt);
411
412     /* print the prompt */
413     displayPrompt();
414
415     /* initialize history search */
416     setSearchedTokenInScilabHistory(NULL);
417
418     for (;;)
419     {
420         unsigned char cur_char = TerminalGetchar();
421
422         if (cur_char <= 0)
423         {
424             return NULL;
425         }
426
427         /* http://bugzilla.scilab.org/show_bug.cgi?id=1052 */
428         if (ismenu () == 1)
429         {
430             /* Abort current line */
431             return NULL;
432         }
433
434         if ( (cur_char == CR_1) || (cur_char == CR_2) )
435         {
436             if ( isHistorySearch() )
437             {
438                 putLineSearchedHistory();
439             }
440             else
441             {
442                 char *line = getCurrentLine();
443                 TerminalPutc('\n');
444                 appendLineToScilabHistory(line);
445                 return line;
446             }
447         }
448         else
449         {
450             TerminalPutc(cur_char);
451             addCharacterCurrentLine(cur_char);
452         }
453     }
454     return NULL;
455 }
456 /*--------------------------------------------------------------------------*/
457 static BOOL isCTRLPressed(DWORD StateKey)
458 {
459     return ((StateKey & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) != 0);
460 }
461 /*--------------------------------------------------------------------------*/
462 static BOOL isALTPressed(DWORD StateKey)
463 {
464     return ((StateKey & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) != 0);
465 }
466 /*--------------------------------------------------------------------------*/
467 static BOOL isExtendedPressed(DWORD StateKey)
468 {
469     return ((StateKey & (ENHANCED_KEY)) != 0);
470 }
471 /*--------------------------------------------------------------------------*/
472 static BOOL isCTRL_VKEY(int VKEY)
473 {
474     return ( GetKeyState(VKEY) & 0x80 );
475 }
476 /*--------------------------------------------------------------------------*/