1 /********************************************************************/
2 /* */
3 /* con_win.c Driver for windows console access. */
4 /* Copyright (C) 1989 - 2005 Thomas Mertes */
5 /* */
6 /* This file is part of the Seed7 Runtime Library. */
7 /* */
8 /* The Seed7 Runtime Library is free software; you can */
9 /* redistribute it and/or modify it under the terms of the GNU */
10 /* Lesser General Public License as published by the Free Software */
11 /* Foundation; either version 2.1 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* The Seed7 Runtime Library is distributed in the hope that it */
15 /* will be useful, but WITHOUT ANY WARRANTY; without even the */
16 /* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /* PURPOSE. See the GNU Lesser General Public License for more */
18 /* details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General */
21 /* Public License along with this program; if not, write to the */
22 /* Free Software Foundation, Inc., 51 Franklin Street, */
23 /* Fifth Floor, Boston, MA 02110-1301, USA. */
24 /* */
25 /* Module: Seed7 Runtime Library */
26 /* File: seed7/src/con_win.c */
27 /* Changes: 2005 Thomas Mertes */
28 /* Content: Driver for windows console access. */
29 /* */
30 /********************************************************************/
31
32 #define LOG_FUNCTIONS 0
33 #define VERBOSE_EXCEPTIONS 0
34
35 #include "version.h"
36
37 #include "stdlib.h"
38 #include "stdio.h"
39 #include "string.h"
40 #include "windows.h"
41 #include "wchar.h"
42
43 #include "common.h"
44 #include "heaputl.h"
45 #include "striutl.h"
46 #include "fil_rtl.h"
47 #include "ut8_rtl.h"
48 #include "rtl_err.h"
49 #include "con_drv.h"
50 #include "kbd_drv.h"
51
52
53 #define SCRHEIGHT 25
54 #define SCRWIDTH 80
55 #define WRITE_STRI_BLOCK_SIZE 256
56
57 static boolType keybd_initialized = FALSE;
58 static DWORD savedKeybdMode;
59 static HANDLE hKeyboard = INVALID_HANDLE_VALUE;
60
61 static char currentattribute;
62 static boolType console_initialized = FALSE;
63
64 static const charType map_1252_to_unicode[] = {
65 /* 128 */ 0x20AC, '?', 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
66 /* 136 */ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, '?', 0x017D, '?',
67 /* 144 */ '?', 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
68 /* 152 */ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, '?', 0x017E, 0x0178};
69
70
71
kbdShut(void)72 void kbdShut (void)
73
74 { /* kbdShut */
75 if (keybd_initialized) {
76 if (hKeyboard != INVALID_HANDLE_VALUE) {
77 SetConsoleMode(hKeyboard, savedKeybdMode);
78 } /* if */
79 } /* if */
80 } /* kbdShut */
81
82
83
kbd_init(void)84 static void kbd_init (void)
85
86 { /* kbd_init */
87 logFunction(printf("kbd_init\n"););
88 hKeyboard = GetStdHandle(STD_INPUT_HANDLE);
89 if (hKeyboard != INVALID_HANDLE_VALUE) {
90 if (unlikely(GetConsoleMode(hKeyboard, &savedKeybdMode) == 0)) {
91 logError(printf("kbd_init: GetConsoleMode(hKeyboard, *) failed:\n"
92 "Error=" FMT_U32 "\n", (uint32Type) GetLastError());
93 fflush(stdout););
94 } else {
95 #ifdef OUT_OF_ORDER
96 if (savedKeybdMode & ENABLE_ECHO_INPUT) { printf("ECHO_INPUT\n"); }
97 if (savedKeybdMode & ENABLE_EXTENDED_FLAGS) { printf("EXTENDED_FLAGS\n"); }
98 if (savedKeybdMode & ENABLE_INSERT_MODE) { printf("INSERT_MODE\n"); }
99 if (savedKeybdMode & ENABLE_LINE_INPUT) { printf("LINE_INPUT\n"); }
100 if (savedKeybdMode & ENABLE_MOUSE_INPUT) { printf("MOUSE_INPUT\n"); }
101 if (savedKeybdMode & ENABLE_PROCESSED_INPUT) { printf("PROCESSED_INPUT\n"); }
102 if (savedKeybdMode & ENABLE_QUICK_EDIT_MODE) { printf("QUICK_EDIT_MODE\n"); }
103 if (savedKeybdMode & ENABLE_WINDOW_INPUT) { printf("WINDOW_INPUT\n"); }
104 /* if (savedKeybdMode & ENABLE_VIRTUAL_TERMINAL_INPUT) { printf("VIRTUAL_TERMINAL_INPUT\n"); } */
105 #endif
106 /* ENABLE_LINE_INPUT enables CTRL-S processing. */
107 /* ENABLE_PROCESSED_INPUT enables CTRL-C processing. */
108 SetConsoleMode(hKeyboard, savedKeybdMode &
109 (DWORD) ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT));
110 keybd_initialized = TRUE;
111 atexit(kbdShut);
112 } /* if */
113 } /* if */
114 logFunction(printf("kbd_init -->\n"););
115 } /* kbd_init */
116
117
118
kbdKeyPressed(void)119 boolType kbdKeyPressed (void)
120
121 {
122 INPUT_RECORD event;
123 DWORD count = 0;
124 boolType ignoreEvent;
125 boolType result;
126
127 /* kbdKeyPressed */
128 logFunction(printf("kbdKeyPressed\n"););
129 if (!keybd_initialized) {
130 kbd_init();
131 } /* if */
132 do {
133 ignoreEvent = FALSE;
134 result = PeekConsoleInputW(hKeyboard, &event, 1, &count) != 0 &&
135 count != 0;
136 if (result) {
137 if (event.EventType == KEY_EVENT) {
138 if (event.Event.KeyEvent.bKeyDown) {
139 switch (event.Event.KeyEvent.wVirtualKeyCode){
140 case VK_SHIFT:
141 case VK_CONTROL:
142 case VK_MENU:
143 case VK_CAPITAL:
144 case VK_NUMLOCK:
145 case VK_SCROLL:
146 ignoreEvent = TRUE;
147 break;
148 } /* switch */
149 } else {
150 ignoreEvent = TRUE;
151 } /* if */
152 } else if (event.EventType == FOCUS_EVENT ||
153 event.EventType == MENU_EVENT ||
154 event.EventType == MOUSE_EVENT) {
155 /* Ignore focus and menu events. */
156 /* They are used internally by windows. */
157 /* Ignore mouse movement and button press events. */
158 ignoreEvent = TRUE;
159 } else {
160 printf("kbdKeyPressed: EventType = %d\n", event.EventType);
161 } /* if */
162 if (ignoreEvent) {
163 /* Skip the event to be ignored. */
164 ignoreEvent = ReadConsoleInputW(hKeyboard, &event, 1, &count) != 0;
165 /* If reading the event, that already has been */
166 /* peeked, fails the loop is terminated. */
167 } /* if */
168 } /* if */
169 } while (ignoreEvent);
170 logFunction(printf("kbdKeyPressed --> %d\n", result););
171 return result;
172 } /* kbdKeyPressed */
173
174
175
kbdGetc(void)176 charType kbdGetc (void)
177
178 {
179 INPUT_RECORD event;
180 DWORD count;
181 charType result = K_NONE;
182
183 /* kbdGetc */
184 logFunction(printf("kbdGetc\n"););
185 if (!keybd_initialized) {
186 kbd_init();
187 } /* if */
188 while (result == K_NONE &&
189 ReadConsoleInputW(hKeyboard, &event, 1, &count) != 0) {
190 if (event.EventType == KEY_EVENT) {
191 if (event.Event.KeyEvent.bKeyDown) {
192 if (event.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
193 switch (event.Event.KeyEvent.wVirtualKeyCode){
194 case VK_LBUTTON: result = K_MOUSE1; break;
195 case VK_MBUTTON: result = K_MOUSE2; break;
196 case VK_RBUTTON: result = K_MOUSE3; break;
197 case VK_RETURN: result = K_NL; break;
198 case VK_F1: result = K_SFT_F1; break;
199 case VK_F2: result = K_SFT_F2; break;
200 case VK_F3: result = K_SFT_F3; break;
201 case VK_F4: result = K_SFT_F4; break;
202 case VK_F5: result = K_SFT_F5; break;
203 case VK_F6: result = K_SFT_F6; break;
204 case VK_F7: result = K_SFT_F7; break;
205 case VK_F8: result = K_SFT_F8; break;
206 case VK_F9: result = K_SFT_F9; break;
207 case VK_F10: result = K_SFT_F10; break;
208 case VK_F11: result = K_SFT_F11; break;
209 case VK_F12: result = K_SFT_F12; break;
210 case VK_LEFT: result = K_LEFT; break;
211 case VK_RIGHT: result = K_RIGHT; break;
212 case VK_UP: result = K_UP; break;
213 case VK_DOWN: result = K_DOWN; break;
214 case VK_HOME: result = K_HOME; break;
215 case VK_END: result = K_END; break;
216 case VK_PRIOR: result = K_PGUP; break;
217 case VK_NEXT: result = K_PGDN; break;
218 case VK_INSERT: result = K_INS; break;
219 case VK_DELETE: result = K_DEL; break;
220 case VK_CLEAR: result = K_PAD_CENTER; break;
221 case VK_APPS: result = K_UNDEF; break;
222 case VK_TAB: result = K_BACKTAB; break;
223 case VK_SHIFT:
224 case VK_CONTROL:
225 case VK_MENU:
226 case VK_CAPITAL:
227 case VK_NUMLOCK:
228 case VK_SCROLL: result = K_NONE; break;
229 default: result = K_UNDEF; break;
230 } /* switch */
231 } else if (event.Event.KeyEvent.dwControlKeyState &
232 (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
233 switch (event.Event.KeyEvent.wVirtualKeyCode){
234 case VK_LBUTTON: result = K_MOUSE1; break;
235 case VK_MBUTTON: result = K_MOUSE2; break;
236 case VK_RBUTTON: result = K_MOUSE3; break;
237 case VK_RETURN: result = K_NL; break;
238 case VK_F1: result = K_ALT_F1; break;
239 case VK_F2: result = K_ALT_F2; break;
240 case VK_F3: result = K_ALT_F3; break;
241 case VK_F4: result = K_ALT_F4; break;
242 case VK_F5: result = K_ALT_F5; break;
243 case VK_F6: result = K_ALT_F6; break;
244 case VK_F7: result = K_ALT_F7; break;
245 case VK_F8: result = K_ALT_F8; break;
246 case VK_F9: result = K_ALT_F9; break;
247 case VK_F10: result = K_ALT_F10; break;
248 case VK_F11: result = K_ALT_F11; break;
249 case VK_F12: result = K_ALT_F12; break;
250 case VK_LEFT: result = K_LEFT; break;
251 case VK_RIGHT: result = K_RIGHT; break;
252 case VK_UP: result = K_UP; break;
253 case VK_DOWN: result = K_DOWN; break;
254 case VK_HOME: result = K_HOME; break;
255 case VK_END: result = K_END; break;
256 case VK_PRIOR: result = K_PGUP; break;
257 case VK_NEXT: result = K_PGDN; break;
258 case VK_INSERT: result = K_INS; break;
259 case VK_DELETE: result = K_DEL; break;
260 case VK_CLEAR: result = K_PAD_CENTER; break;
261 case VK_APPS: result = K_UNDEF; break;
262 case VK_SHIFT:
263 case VK_CONTROL:
264 case VK_MENU:
265 case VK_CAPITAL:
266 case VK_NUMLOCK:
267 case VK_SCROLL: result = K_NONE; break;
268 default: result = K_UNDEF; break;
269 } /* switch */
270 } else if (event.Event.KeyEvent.dwControlKeyState &
271 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
272 switch (event.Event.KeyEvent.wVirtualKeyCode){
273 case VK_LBUTTON: result = K_MOUSE1; break;
274 case VK_MBUTTON: result = K_MOUSE2; break;
275 case VK_RBUTTON: result = K_MOUSE3; break;
276 case VK_RETURN: result = K_NL; break;
277 case VK_F1: result = K_CTL_F1; break;
278 case VK_F2: result = K_CTL_F2; break;
279 case VK_F3: result = K_CTL_F3; break;
280 case VK_F4: result = K_CTL_F4; break;
281 case VK_F5: result = K_CTL_F5; break;
282 case VK_F6: result = K_CTL_F6; break;
283 case VK_F7: result = K_CTL_F7; break;
284 case VK_F8: result = K_CTL_F8; break;
285 case VK_F9: result = K_CTL_F9; break;
286 case VK_F10: result = K_CTL_F10; break;
287 case VK_F11: result = K_CTL_F11; break;
288 case VK_F12: result = K_CTL_F12; break;
289 case VK_LEFT: result = K_CTL_LEFT; break;
290 case VK_RIGHT: result = K_CTL_RIGHT; break;
291 case VK_UP: result = K_CTL_UP; break;
292 case VK_DOWN: result = K_CTL_DOWN; break;
293 case VK_HOME: result = K_CTL_HOME; break;
294 case VK_END: result = K_CTL_END; break;
295 case VK_PRIOR: result = K_CTL_PGUP; break;
296 case VK_NEXT: result = K_CTL_PGDN; break;
297 case VK_INSERT: result = K_CTL_INS; break;
298 case VK_DELETE: result = K_CTL_DEL; break;
299 case VK_CLEAR: result = K_PAD_CENTER; break;
300 case VK_APPS: result = K_UNDEF; break;
301 case VK_SHIFT:
302 case VK_CONTROL:
303 case VK_MENU:
304 case VK_CAPITAL:
305 case VK_NUMLOCK:
306 case VK_SCROLL: result = K_NONE; break;
307 default: result = K_UNDEF; break;
308 } /* switch */
309 } else {
310 switch (event.Event.KeyEvent.wVirtualKeyCode){
311 case VK_LBUTTON: result = K_MOUSE1; break;
312 case VK_MBUTTON: result = K_MOUSE2; break;
313 case VK_RBUTTON: result = K_MOUSE3; break;
314 case VK_RETURN: result = K_NL; break;
315 case VK_F1: result = K_F1; break;
316 case VK_F2: result = K_F2; break;
317 case VK_F3: result = K_F3; break;
318 case VK_F4: result = K_F4; break;
319 case VK_F5: result = K_F5; break;
320 case VK_F6: result = K_F6; break;
321 case VK_F7: result = K_F7; break;
322 case VK_F8: result = K_F8; break;
323 case VK_F9: result = K_F9; break;
324 case VK_F10: result = K_F10; break;
325 case VK_F11: result = K_F11; break;
326 case VK_F12: result = K_F12; break;
327 case VK_LEFT: result = K_LEFT; break;
328 case VK_RIGHT: result = K_RIGHT; break;
329 case VK_UP: result = K_UP; break;
330 case VK_DOWN: result = K_DOWN; break;
331 case VK_HOME: result = K_HOME; break;
332 case VK_END: result = K_END; break;
333 case VK_PRIOR: result = K_PGUP; break;
334 case VK_NEXT: result = K_PGDN; break;
335 case VK_INSERT: result = K_INS; break;
336 case VK_DELETE: result = K_DEL; break;
337 case VK_CLEAR: result = K_PAD_CENTER; break;
338 case VK_APPS: result = K_UNDEF; break;
339 case VK_SHIFT:
340 case VK_CONTROL:
341 case VK_MENU:
342 case VK_CAPITAL:
343 case VK_NUMLOCK:
344 case VK_SCROLL: result = K_NONE; break;
345 default: result = K_UNDEF; break;
346 } /* switch */
347 } /* if */
348 if (result == K_UNDEF) {
349 if (event.Event.KeyEvent.uChar.UnicodeChar != 0) {
350 if (event.Event.KeyEvent.dwControlKeyState &
351 (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
352 switch (event.Event.KeyEvent.uChar.UnicodeChar) {
353 case 'A': case 'a': result = K_ALT_A; break;
354 case 'B': case 'b': result = K_ALT_B; break;
355 case 'C': case 'c': result = K_ALT_C; break;
356 case 'D': case 'd': result = K_ALT_D; break;
357 case 'E': case 'e': result = K_ALT_E; break;
358 case 'F': case 'f': result = K_ALT_F; break;
359 case 'G': case 'g': result = K_ALT_G; break;
360 case 'H': case 'h': result = K_ALT_H; break;
361 case 'I': case 'i': result = K_ALT_I; break;
362 case 'J': case 'j': result = K_ALT_J; break;
363 case 'K': case 'k': result = K_ALT_K; break;
364 case 'L': case 'l': result = K_ALT_L; break;
365 case 'M': case 'm': result = K_ALT_M; break;
366 case 'N': case 'n': result = K_ALT_N; break;
367 case 'O': case 'o': result = K_ALT_O; break;
368 case 'P': case 'p': result = K_ALT_P; break;
369 case 'Q': case 'q': result = K_ALT_Q; break;
370 case 'R': case 'r': result = K_ALT_R; break;
371 case 'S': case 's': result = K_ALT_S; break;
372 case 'T': case 't': result = K_ALT_T; break;
373 case 'U': case 'u': result = K_ALT_U; break;
374 case 'V': case 'v': result = K_ALT_V; break;
375 case 'W': case 'w': result = K_ALT_W; break;
376 case 'X': case 'x': result = K_ALT_X; break;
377 case 'Y': case 'y': result = K_ALT_Y; break;
378 case 'Z': case 'z': result = K_ALT_Z; break;
379 case '0': result = K_ALT_0; break;
380 case '1': result = K_ALT_1; break;
381 case '2': result = K_ALT_2; break;
382 case '3': result = K_ALT_3; break;
383 case '4': result = K_ALT_4; break;
384 case '5': result = K_ALT_5; break;
385 case '6': result = K_ALT_6; break;
386 case '7': result = K_ALT_7; break;
387 case '8': result = K_ALT_8; break;
388 case '9': result = K_ALT_9; break;
389 } /* switch */
390 } /* if */
391 if (result == K_UNDEF) {
392 result = event.Event.KeyEvent.uChar.UnicodeChar;
393 if (result >= 128 && result <= 159) {
394 result = map_1252_to_unicode[result - 128];
395 } /* if */
396 } /* if */
397 } else {
398 /*
399 printf("VK: %lu\n",
400 (unsigned long) event.Event.KeyEvent.wVirtualKeyCode);
401 printf("Char: %lu\n",
402 (unsigned long) event.Event.KeyEvent.uChar.UnicodeChar);
403 printf("CKey: %lx\n",
404 (unsigned long) event.Event.KeyEvent.dwControlKeyState);
405 */
406 } /* if */
407 } /* if */
408 } /* if */
409 } else if (event.EventType == FOCUS_EVENT ||
410 event.EventType == MENU_EVENT ||
411 event.EventType == MOUSE_EVENT) {
412 /* Ignore focus and menu events. */
413 /* They are used internally by windows. */
414 /* Ignore mouse movement and button press events. */
415 } else {
416 printf("kbdGetc: EventType = %d\n", event.EventType);
417 } /* if */
418 } /* while */
419 logFunction(printf("kbdGetc --> %d\n", result););
420 return result;
421 } /* kbdGetc */
422
423
424
kbdRawGetc(void)425 charType kbdRawGetc (void)
426
427 { /* kbdRawGetc */
428 return kbdGetc();
429 } /* kbdRawGetc */
430
431
432
con_setcolor(intType foreground,intType background)433 static void con_setcolor (intType foreground, intType background)
434
435 { /* con_setcolor */
436 currentattribute = (char) (foreground + 16 * (background % 8));
437 } /* con_setcolor */
438
439
440
con_standardcolour(void)441 static void con_standardcolour (void)
442
443 { /* con_standardcolour */
444 con_setcolor(lightgray, black);
445 } /* con_standardcolour */
446
447
448
con_normalcolour(void)449 static void con_normalcolour (void)
450
451 { /* con_normalcolour */
452 con_setcolor(lightgray, black);
453 } /* con_normalcolour */
454
455
456
textheight(void)457 intType textheight (void)
458
459 { /* textheight */
460 return 1;
461 } /* textheight */
462
463
464
textwidth(striType stri,intType startcol,intType stopcol)465 intType textwidth (striType stri,
466 intType startcol, intType stopcol)
467
468 { /* textwidth */
469 return stopcol + 1 - startcol;
470 } /* textwidth */
471
472
473
textcolumns(striType stri,intType striwidth,intType * cols,intType * rest)474 void textcolumns (striType stri, intType striwidth,
475 intType *cols, intType *rest)
476
477 { /* textcolumns */
478 *cols = striwidth;
479 *rest = 0;
480 } /* textcolumns */
481
482
483
conHeight(void)484 int conHeight (void)
485
486 {
487 HANDLE hConsole;
488 CONSOLE_SCREEN_BUFFER_INFO con_info;
489
490 /* conHeight */
491 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
492 if (hConsole != INVALID_HANDLE_VALUE) {
493 if (GetConsoleScreenBufferInfo(hConsole, &con_info)) {
494 return con_info.dwSize.Y;
495 } else {
496 /* printf("GetConsoleScreenBufferInfo(%d, & ) --> Error " FMT_U32 "\n",
497 hConsole, (uint32Type) GetLastError()); */
498 return SCRHEIGHT;
499 } /* if */
500 } else {
501 /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
502 hConsole, (uint32Type) GetLastError()); */
503 return SCRHEIGHT;
504 } /* if */
505 } /* conHeight */
506
507
508
conWidth(void)509 int conWidth (void)
510
511 {
512 HANDLE hConsole;
513 CONSOLE_SCREEN_BUFFER_INFO con_info;
514
515 /* conWidth */
516 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
517 if (hConsole != INVALID_HANDLE_VALUE) {
518 if (GetConsoleScreenBufferInfo(hConsole, &con_info)) {
519 return con_info.dwSize.X;
520 } else {
521 /* printf("GetConsoleScreenBufferInfo(%d, & ) --> Error " FMT_U32 "\n",
522 hConsole, (uint32Type) GetLastError()); */
523 return SCRWIDTH;
524 } /* if */
525 } else {
526 /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
527 hConsole, (uint32Type) GetLastError()); */
528 return SCRWIDTH;
529 } /* if */
530 } /* conWidth */
531
532
533
conFlush(void)534 void conFlush (void)
535
536 { /* conFlush */
537 } /* conFlush */
538
539
540
conCursor(boolType on)541 void conCursor (boolType on)
542
543 {
544 HANDLE hConsole;
545 CONSOLE_CURSOR_INFO info;
546
547 /* conCursor */
548 if (console_initialized) {
549 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
550 if (hConsole != INVALID_HANDLE_VALUE) {
551 if (likely(GetConsoleCursorInfo(hConsole, &info) != 0)) {
552 info.bVisible = on;
553 if (unlikely(SetConsoleCursorInfo(hConsole, &info) == 0)) {
554 /* printf("SetConsoleCursorInfo(%d, (visible=%d)) --> Error " FMT_U32 "\n",
555 hConsole, on, (uint32Type) GetLastError()); */
556 } /* if */
557 } else {
558 /* printf("GetConsoleCursorInfo(%d, *) --> Error " FMT_U32 "\n",
559 hConsole, (uint32Type) GetLastError()); */
560 } /* if */
561 } else {
562 /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
563 hConsole, (uint32Type) GetLastError()); */
564 } /* if */
565 } /* if */
566 } /* conCursor */
567
568
569
570 /**
571 * Moves the system cursor to the given place of the console.
572 * If no system cursor exists this procedure can be replaced by
573 * a dummy procedure.
574 */
conSetCursor(intType line,intType column)575 void conSetCursor (intType line, intType column)
576
577 {
578 HANDLE hConsole;
579 COORD position;
580
581 /* conSetCursor */
582 if (unlikely(line <= 0 || column <= 0)) {
583 raise_error(RANGE_ERROR);
584 } else if (line <= INT16TYPE_MAX && column <= INT16TYPE_MAX) {
585 if (console_initialized) {
586 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
587 if (hConsole != INVALID_HANDLE_VALUE) {
588 position.X = (int16Type) (column - 1);
589 position.Y = (int16Type) (line - 1);
590 if (SetConsoleCursorPosition(hConsole, position) == 0) {
591 /* printf("SetConsoleCursorPosition(%d, (%d, %d)) --> Error " FMT_U32 "\n",
592 hConsole, column - 1, line - 1, (uint32Type) GetLastError()); */
593 } /* if */
594 } else {
595 /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
596 hConsole, (uint32Type) GetLastError()); */
597 } /* if */
598 } /* if */
599 } /* if */
600 } /* conSetCursor */
601
602
603
conColumn(void)604 intType conColumn (void)
605
606 {
607 HANDLE hConsole;
608 CONSOLE_SCREEN_BUFFER_INFO con_info;
609
610 /* conColumn */
611 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
612 if (hConsole != INVALID_HANDLE_VALUE) {
613 if (GetConsoleScreenBufferInfo(hConsole, &con_info)) {
614 return (intType) con_info.dwCursorPosition.X + 1;
615 } else {
616 /* printf("GetConsoleScreenBufferInfo(%d, & ) --> Error " FMT_U32 "\n",
617 hConsole, (uint32Type) GetLastError()); */
618 return 1;
619 } /* if */
620 } else {
621 /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
622 hConsole, (uint32Type) GetLastError()); */
623 return 1;
624 } /* if */
625 } /* conColumn */
626
627
628
conLine(void)629 intType conLine (void)
630
631 {
632 HANDLE hConsole;
633 CONSOLE_SCREEN_BUFFER_INFO con_info;
634
635 /* conLine */
636 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
637 if (hConsole != INVALID_HANDLE_VALUE) {
638 if (GetConsoleScreenBufferInfo(hConsole, &con_info)) {
639 return (intType) con_info.dwCursorPosition.Y + 1;
640 } else {
641 /* printf("GetConsoleScreenBufferInfo(%d, & ) --> Error " FMT_U32 "\n",
642 hConsole, (uint32Type) GetLastError()); */
643 return 1;
644 } /* if */
645 } else {
646 /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
647 hConsole, (uint32Type) GetLastError()); */
648 return 1;
649 } /* if */
650 } /* conLine */
651
652
653
doWriteConsole(HANDLE hConsole,const const_striType stri)654 static void doWriteConsole (HANDLE hConsole, const const_striType stri)
655
656 {
657 wcharType wstri_buffer[WRITE_STRI_BLOCK_SIZE * SURROGATE_PAIR_FACTOR];
658 wstriType wstri;
659 wstriType wstri_part;
660 memSizeType wstri_size;
661 errInfoType err_info = OKAY_NO_ERROR;
662 DWORD numchars;
663
664 /* doWriteConsole */
665 /* fprintf(stderr, "doWriteConsole(%lx, ...)", (unsigned long) hConsole); */
666 if (stri->size <= WRITE_STRI_BLOCK_SIZE) {
667 wstri_size = stri_to_utf16(wstri_buffer, stri->mem, stri->size, &err_info);
668 if (unlikely(err_info != OKAY_NO_ERROR)) {
669 raise_error(err_info);
670 } else {
671 WriteConsoleW(hConsole, wstri_buffer, (DWORD) wstri_size, &numchars, NULL);
672 } /* if */
673 } else {
674 /* ALLOC_WSTRI adds space for a NULL termination, which is not needed here. */
675 if (unlikely(stri->size >
676 (MAX_WSTRI_LEN + NULL_TERMINATION_LEN) / SURROGATE_PAIR_FACTOR ||
677 !ALLOC_WSTRI(wstri, stri->size * SURROGATE_PAIR_FACTOR -
678 NULL_TERMINATION_LEN))) {
679 raise_error(MEMORY_ERROR);
680 } else {
681 wstri_size = stri_to_utf16(wstri, stri->mem, stri->size, &err_info);
682 if (unlikely(err_info != OKAY_NO_ERROR)) {
683 raise_error(err_info);
684 } else {
685 wstri_part = wstri;
686 /* Writing may fail for lengths above 26000 to 32000 */
687 while (wstri_size > 25000) {
688 WriteConsoleW(hConsole, wstri_part, 25000, &numchars, NULL);
689 wstri_part = &wstri_part[25000];
690 wstri_size -= 25000;
691 } /* while */
692 WriteConsoleW(hConsole, wstri_part, (DWORD) wstri_size, &numchars, NULL);
693 } /* if */
694 UNALLOC_WSTRI(wstri, stri->size * SURROGATE_PAIR_FACTOR - NULL_TERMINATION_LEN);
695 } /* if */
696 } /* if */
697 } /* doWriteConsole */
698
699
700
701 /**
702 * Write a string to the current position of the console.
703 * Unicode characters are written with the encoding of the
704 * operating system. The cursor position is changed, if
705 * one of the characters '\n', '\r' and '\b' is written.
706 * If the standard output file of the operating system has
707 * been redirected UTF-8 encoded characters are written to
708 * the redirected file.
709 */
conWrite(const const_striType stri)710 void conWrite (const const_striType stri)
711
712 {
713 HANDLE hConsole;
714 DWORD mode;
715
716 /* conWrite */
717 logFunction(printf("conWrite(\"%s\")\n", striAsUnquotedCStri(stri)););
718 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
719 if (hConsole != INVALID_HANDLE_VALUE &&
720 GetFileType(hConsole) == FILE_TYPE_CHAR &&
721 GetConsoleMode(hConsole, &mode) != 0) {
722 /* hConsole refers to a real console */
723 doWriteConsole(hConsole, stri);
724 } else {
725 /* The output has been redirected */
726 ut8Write(&stdoutFileRecord, stri);
727 } /* if */
728 logFunction(printf("conWrite -->\n"););
729 } /* conWrite */
730
731
732
733 /**
734 * Clears the area described by startlin, stoplin, startcol and stopcol.
735 */
conClear(intType startlin,intType startcol,intType stoplin,intType stopcol)736 void conClear (intType startlin, intType startcol,
737 intType stoplin, intType stopcol)
738
739 {
740 HANDLE hConsole;
741 COORD position;
742 DWORD numchars;
743
744 /* conClear */
745 if (unlikely(startlin <= 0 || startcol <= 0 ||
746 stoplin < startlin || stopcol < startcol)) {
747 raise_error(RANGE_ERROR);
748 } else if (startlin <= INT16TYPE_MAX && startcol <= INT16TYPE_MAX) {
749 if (stoplin > INT16TYPE_MAX) {
750 stoplin = INT16TYPE_MAX;
751 } /* if */
752 if (stopcol > INT16TYPE_MAX) {
753 stopcol = INT16TYPE_MAX;
754 } /* if */
755 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
756 if (hConsole != INVALID_HANDLE_VALUE) {
757 position.X = (int16Type) (startcol - 1);
758 position.Y = (int16Type) (startlin - 1);
759 while (position.Y < (int16Type) stoplin) {
760 FillConsoleOutputCharacter(hConsole, (TCHAR) ' ',
761 (unsigned int) (stopcol - startcol + 1), position, &numchars);
762 position.Y++;
763 } /* while */
764 } /* if */
765 } /* if */
766 } /* conClear */
767
768
769
770 /**
771 * Scrolls the area inside startlin, startcol, stoplin and
772 * stopcol upward by count lines. The upper count lines of the
773 * area are overwritten. At the lower end of the area blank lines
774 * are inserted. Nothing is changed outside the area.
775 * The calling function assures that count is greater or equal 1.
776 */
conUpScroll(intType startlin,intType startcol,intType stoplin,intType stopcol,intType count)777 void conUpScroll (intType startlin, intType startcol,
778 intType stoplin, intType stopcol, intType count)
779
780 {
781 HANDLE hConsole;
782 SMALL_RECT scrollRect;
783 COORD destOrigin;
784 CHAR_INFO fillChar;
785
786 /* conUpScroll */
787 if (unlikely(startlin <= 0 || startcol <= 0 ||
788 stoplin < startlin || stopcol < startcol)) {
789 raise_error(RANGE_ERROR);
790 } else if (startlin <= INT16TYPE_MAX && startcol <= INT16TYPE_MAX) {
791 if (count > stoplin - startlin + 1) {
792 conClear(startlin, startcol, stoplin, stopcol);
793 } else {
794 if (stoplin > INT16TYPE_MAX) {
795 stoplin = INT16TYPE_MAX;
796 } /* if */
797 if (stopcol > INT16TYPE_MAX) {
798 stopcol = INT16TYPE_MAX;
799 } /* if */
800 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
801 if (hConsole != INVALID_HANDLE_VALUE) {
802 scrollRect.Left = (int16Type) (startcol - 1);
803 scrollRect.Top = (int16Type) (startlin + count - 1);
804 scrollRect.Right = (int16Type) (stopcol - 1);
805 scrollRect.Bottom = (int16Type) (stoplin - 1);
806 destOrigin.X = (int16Type) (startcol - 1);
807 destOrigin.Y = (int16Type) (startlin - 1);
808 memset(&fillChar, 0, sizeof(CHAR_INFO));
809 fillChar.Char.AsciiChar = ' ';
810 ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, destOrigin, &fillChar);
811 } else {
812 /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
813 hConsole, (uint32Type) GetLastError()); */
814 } /* if */
815 } /* if */
816 } /* if */
817 } /* conUpScroll */
818
819
820
821 /**
822 * Scrolls the area inside startlin, startcol, stoplin and
823 * stopcol downward by count lines. The lower count lines of the
824 * area are overwritten. At the upper end of the area blank lines
825 * are inserted. Nothing is changed outside the area.
826 * The calling function assures that count is greater or equal 1.
827 */
conDownScroll(intType startlin,intType startcol,intType stoplin,intType stopcol,intType count)828 void conDownScroll (intType startlin, intType startcol,
829 intType stoplin, intType stopcol, intType count)
830
831 {
832 HANDLE hConsole;
833 SMALL_RECT scrollRect;
834 COORD destOrigin;
835 CHAR_INFO fillChar;
836
837 /* conDownScroll */
838 if (unlikely(startlin <= 0 || startcol <= 0 ||
839 stoplin < startlin || stopcol < startcol)) {
840 raise_error(RANGE_ERROR);
841 } else if (startlin <= INT16TYPE_MAX && startcol <= INT16TYPE_MAX) {
842 if (count > stoplin - startlin + 1) {
843 conClear(startlin, startcol, stoplin, stopcol);
844 } else {
845 if (stoplin > INT16TYPE_MAX) {
846 stoplin = INT16TYPE_MAX;
847 } /* if */
848 if (stopcol > INT16TYPE_MAX) {
849 stopcol = INT16TYPE_MAX;
850 } /* if */
851 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
852 if (hConsole != INVALID_HANDLE_VALUE) {
853 scrollRect.Left = (int16Type) (startcol - 1);
854 scrollRect.Top = (int16Type) (startlin - 1);
855 scrollRect.Right = (int16Type) (stopcol - 1);
856 scrollRect.Bottom = (int16Type) (stoplin - count - 1);
857 destOrigin.X = (int16Type) (startcol - 1);
858 destOrigin.Y = (int16Type) (startlin + count - 1);
859 memset(&fillChar, 0, sizeof(CHAR_INFO));
860 fillChar.Char.AsciiChar = ' ';
861 ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, destOrigin, &fillChar);
862 } else {
863 /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
864 hConsole, (uint32Type) GetLastError()); */
865 } /* if */
866 } /* if */
867 } /* if */
868 } /* conDownScroll */
869
870
871
872 /**
873 * Scrolls the area inside startlin, startcol, stoplin and
874 * stopcol leftward by count columns. The left count columns of the
875 * area are overwritten. At the right end of the area blank columns
876 * are inserted. Nothing is changed outside the area.
877 * The calling function assures that count is greater or equal 1.
878 */
conLeftScroll(intType startlin,intType startcol,intType stoplin,intType stopcol,intType count)879 void conLeftScroll (intType startlin, intType startcol,
880 intType stoplin, intType stopcol, intType count)
881
882 {
883 HANDLE hConsole;
884 SMALL_RECT scrollRect;
885 COORD destOrigin;
886 CHAR_INFO fillChar;
887
888 /* conLeftScroll */
889 if (unlikely(startlin <= 0 || startcol <= 0 ||
890 stoplin < startlin || stopcol < startcol)) {
891 raise_error(RANGE_ERROR);
892 } else if (startlin <= INT16TYPE_MAX && startcol <= INT16TYPE_MAX) {
893 if (count > stopcol - startcol + 1) {
894 conClear(startlin, startcol, stoplin, stopcol);
895 } else {
896 if (stoplin > INT16TYPE_MAX) {
897 stoplin = INT16TYPE_MAX;
898 } /* if */
899 if (stopcol > INT16TYPE_MAX) {
900 stopcol = INT16TYPE_MAX;
901 } /* if */
902 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
903 if (hConsole != INVALID_HANDLE_VALUE) {
904 scrollRect.Left = (int16Type) (startcol + count - 1);
905 scrollRect.Top = (int16Type) (startlin - 1);
906 scrollRect.Right = (int16Type) (stopcol - 1);
907 scrollRect.Bottom = (int16Type) (stoplin - 1);
908 destOrigin.X = (int16Type) (startcol - 1);
909 destOrigin.Y = (int16Type) (startlin - 1);
910 memset(&fillChar, 0, sizeof(CHAR_INFO));
911 fillChar.Char.AsciiChar = ' ';
912 ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, destOrigin, &fillChar);
913 } else {
914 /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
915 hConsole, (uint32Type) GetLastError()); */
916 } /* if */
917 } /* if */
918 } /* if */
919 } /* conLeftScroll */
920
921
922
923 /**
924 * Scrolls the area inside startlin, startcol, stoplin and
925 * stopcol rightward by count columns. The right count columns of the
926 * area are overwritten. At the left end of the area blank columns
927 * are inserted. Nothing is changed outside the area.
928 * The calling function assures that count is greater or equal 1.
929 */
conRightScroll(intType startlin,intType startcol,intType stoplin,intType stopcol,intType count)930 void conRightScroll (intType startlin, intType startcol,
931 intType stoplin, intType stopcol, intType count)
932
933 {
934 HANDLE hConsole;
935 SMALL_RECT scrollRect;
936 COORD destOrigin;
937 CHAR_INFO fillChar;
938
939 /* conRightScroll */
940 if (unlikely(startlin <= 0 || startcol <= 0 ||
941 stoplin < startlin || stopcol < startcol)) {
942 raise_error(RANGE_ERROR);
943 } else if (startlin <= INT16TYPE_MAX && startcol <= INT16TYPE_MAX) {
944 if (count > stopcol - startcol + 1) {
945 conClear(startlin, startcol, stoplin, stopcol);
946 } else {
947 if (stoplin > INT16TYPE_MAX) {
948 stoplin = INT16TYPE_MAX;
949 } /* if */
950 if (stopcol > INT16TYPE_MAX) {
951 stopcol = INT16TYPE_MAX;
952 } /* if */
953 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
954 if (hConsole != INVALID_HANDLE_VALUE) {
955 scrollRect.Left = (int16Type) (startcol - 1);
956 scrollRect.Top = (int16Type) (startlin - 1);
957 scrollRect.Right = (int16Type) (stopcol - count - 1);
958 scrollRect.Bottom = (int16Type) (stoplin - 1);
959 destOrigin.X = (int16Type) (startcol + count - 1);
960 destOrigin.Y = (int16Type) (startlin - 1);
961 memset(&fillChar, 0, sizeof(CHAR_INFO));
962 fillChar.Char.AsciiChar = ' ';
963 ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, destOrigin, &fillChar);
964 } else {
965 /* printf("GetStdHandle(STD_OUTPUT_HANDLE) --> %d / Error " FMT_U32 "\n",
966 hConsole, (uint32Type) GetLastError()); */
967 } /* if */
968 } /* if */
969 } /* if */
970 } /* conRightScroll */
971
972
973
conShut(void)974 void conShut (void)
975
976 { /* conShut */
977 logFunction(printf("conShut\n"););
978 if (console_initialized) {
979 con_standardcolour();
980 conCursor(TRUE);
981 conClear(1, 1, conHeight(), conWidth());
982 conSetCursor(1, 24);
983 console_initialized = FALSE;
984 } /* if */
985 logFunction(printf("conShut -->\n"););
986 } /* conShut */
987
988
989
990 /**
991 * Initializes and clears the console.
992 */
conOpen(void)993 int conOpen (void)
994
995 { /* conOpen */
996 logFunction(printf("conOpen\n"););
997 con_normalcolour();
998 conClear(1, 1, conHeight(), conWidth());
999 console_initialized = TRUE;
1000 conCursor(FALSE);
1001 conSetCursor(1, 1);
1002 atexit(conShut);
1003 logFunction(printf("conOpen -->\n"););
1004 return 1;
1005 } /* conOpen */
1006