ucrtbase: Add support for natural string widths.
[wine.git] / dlls / msvcrt / console.c
blob8293b1d64884c2f388daea0411549ce929aba643
1 /*
2 * msvcrt.dll console functions
4 * Copyright 2000 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Note: init and free don't need MT locking since they are called at DLL
21 * (de)attachment time, which is synchronised for us
24 #include "msvcrt.h"
25 #include "winnls.h"
26 #include "wincon.h"
27 #include "mtdll.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
34 /* MT */
35 #define LOCK_CONSOLE _mlock(_CONIO_LOCK)
36 #define UNLOCK_CONSOLE _munlock(_CONIO_LOCK)
38 static HANDLE MSVCRT_console_in = INVALID_HANDLE_VALUE;
39 static HANDLE MSVCRT_console_out= INVALID_HANDLE_VALUE;
40 static int __MSVCRT_console_buffer = MSVCRT_EOF;
41 static MSVCRT_wchar_t __MSVCRT_console_buffer_w = MSVCRT_WEOF;
43 /* INTERNAL: Initialise console handles */
44 void msvcrt_init_console(void)
46 TRACE(":Opening console handles\n");
48 MSVCRT_console_in = CreateFileA("CONIN$", GENERIC_WRITE|GENERIC_READ,
49 FILE_SHARE_WRITE|FILE_SHARE_READ,
50 NULL, OPEN_EXISTING, 0, NULL);
51 MSVCRT_console_out= CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
52 NULL, OPEN_EXISTING, 0, NULL);
54 if ((MSVCRT_console_in == INVALID_HANDLE_VALUE) ||
55 (MSVCRT_console_out== INVALID_HANDLE_VALUE))
56 WARN(":Console handle Initialisation FAILED!\n");
59 /* INTERNAL: Free console handles */
60 void msvcrt_free_console(void)
62 TRACE(":Closing console handles\n");
63 CloseHandle(MSVCRT_console_in);
64 CloseHandle(MSVCRT_console_out);
67 /*********************************************************************
68 * _cputs (MSVCRT.@)
70 int CDECL _cputs(const char* str)
72 DWORD count;
73 int len, retval = -1;
75 if (!MSVCRT_CHECK_PMT(str != NULL)) return -1;
76 len = strlen(str);
78 LOCK_CONSOLE;
79 if (WriteConsoleA(MSVCRT_console_out, str, len, &count, NULL)
80 && count == len)
81 retval = 0;
82 UNLOCK_CONSOLE;
83 return retval;
86 /*********************************************************************
87 * _cputws (MSVCRT.@)
89 int CDECL _cputws(const MSVCRT_wchar_t* str)
91 DWORD count;
92 int len, retval = -1;
94 if (!MSVCRT_CHECK_PMT(str != NULL)) return -1;
95 len = lstrlenW(str);
97 LOCK_CONSOLE;
98 if (WriteConsoleW(MSVCRT_console_out, str, len, &count, NULL)
99 && count == len)
100 retval = 0;
101 UNLOCK_CONSOLE;
102 return retval;
105 #define NORMAL_CHAR 0
106 #define ALT_CHAR 1
107 #define CTRL_CHAR 2
108 #define SHIFT_CHAR 3
110 static const struct {unsigned short vk; unsigned char ch[4][2];} enh_map[] = {
111 {0x47, {{0xE0, 0x47}, {0x00, 0x97}, {0xE0, 0x77}, {0xE0, 0x47}}},
112 {0x48, {{0xE0, 0x48}, {0x00, 0x98}, {0xE0, 0x8D}, {0xE0, 0x48}}},
113 {0x49, {{0xE0, 0x49}, {0x00, 0x99}, {0xE0, 0x86}, {0xE0, 0x49}}},
114 {0x4B, {{0xE0, 0x4B}, {0x00, 0x9B}, {0xE0, 0x73}, {0xE0, 0x4B}}},
115 {0x4D, {{0xE0, 0x4D}, {0x00, 0x9D}, {0xE0, 0x74}, {0xE0, 0x4D}}},
116 {0x4F, {{0xE0, 0x4F}, {0x00, 0x9F}, {0xE0, 0x75}, {0xE0, 0x4F}}},
117 {0x50, {{0xE0, 0x50}, {0x00, 0xA0}, {0xE0, 0x91}, {0xE0, 0x50}}},
118 {0x51, {{0xE0, 0x51}, {0x00, 0xA1}, {0xE0, 0x76}, {0xE0, 0x51}}},
119 {0x52, {{0xE0, 0x52}, {0x00, 0xA2}, {0xE0, 0x92}, {0xE0, 0x52}}},
120 {0x53, {{0xE0, 0x53}, {0x00, 0xA3}, {0xE0, 0x93}, {0xE0, 0x53}}},
123 static BOOL handle_enhanced_keys(INPUT_RECORD *ir, unsigned char *ch1, unsigned char *ch2)
125 int i;
127 for (i = 0; i < sizeof(enh_map) / sizeof(enh_map[0]); i++)
129 if (ir->Event.KeyEvent.wVirtualScanCode == enh_map[i].vk)
131 unsigned idx;
133 if (ir->Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
134 idx = ALT_CHAR;
135 else if (ir->Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) )
136 idx = CTRL_CHAR;
137 else if (ir->Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
138 idx = SHIFT_CHAR;
139 else
140 idx = NORMAL_CHAR;
142 *ch1 = enh_map[i].ch[idx][0];
143 *ch2 = enh_map[i].ch[idx][1];
144 return TRUE;
148 WARN("Unmapped char keyState=%x vk=%x\n",
149 ir->Event.KeyEvent.dwControlKeyState, ir->Event.KeyEvent.wVirtualScanCode);
150 return FALSE;
153 /*********************************************************************
154 * _getch_nolock (MSVCR80.@)
156 int CDECL _getch_nolock(void)
158 int retval = MSVCRT_EOF;
160 if (__MSVCRT_console_buffer != MSVCRT_EOF)
162 retval = __MSVCRT_console_buffer;
163 __MSVCRT_console_buffer = MSVCRT_EOF;
165 else
167 INPUT_RECORD ir;
168 DWORD count;
169 DWORD mode = 0;
171 GetConsoleMode(MSVCRT_console_in, &mode);
172 if(mode)
173 SetConsoleMode(MSVCRT_console_in, 0);
175 do {
176 if (ReadConsoleInputA(MSVCRT_console_in, &ir, 1, &count))
178 /* Only interested in ASCII chars */
179 if (ir.EventType == KEY_EVENT &&
180 ir.Event.KeyEvent.bKeyDown)
182 unsigned char ch1, ch2;
184 if (ir.Event.KeyEvent.uChar.AsciiChar)
186 retval = ir.Event.KeyEvent.uChar.AsciiChar;
187 break;
190 if (handle_enhanced_keys(&ir, &ch1, &ch2))
192 retval = ch1;
193 __MSVCRT_console_buffer = ch2;
194 break;
198 else
199 break;
200 } while(1);
201 if (mode)
202 SetConsoleMode(MSVCRT_console_in, mode);
204 return retval;
207 /*********************************************************************
208 * _getch (MSVCRT.@)
210 int CDECL _getch(void)
212 int ret;
214 LOCK_CONSOLE;
215 ret = _getch_nolock();
216 UNLOCK_CONSOLE;
217 return ret;
220 /*********************************************************************
221 * _getwch_nolock (MSVCR80.@)
223 MSVCRT_wchar_t CDECL _getwch_nolock(void)
225 MSVCRT_wchar_t retval = MSVCRT_WEOF;
227 if (__MSVCRT_console_buffer_w != MSVCRT_WEOF)
229 retval = __MSVCRT_console_buffer_w;
230 __MSVCRT_console_buffer_w = MSVCRT_WEOF;
232 else
234 INPUT_RECORD ir;
235 DWORD count;
236 DWORD mode = 0;
238 GetConsoleMode(MSVCRT_console_in, &mode);
239 if(mode)
240 SetConsoleMode(MSVCRT_console_in, 0);
242 do {
243 if (ReadConsoleInputW(MSVCRT_console_in, &ir, 1, &count))
245 /* Only interested in ASCII chars */
246 if (ir.EventType == KEY_EVENT &&
247 ir.Event.KeyEvent.bKeyDown)
249 unsigned char ch1, ch2;
251 if (ir.Event.KeyEvent.uChar.UnicodeChar)
253 retval = ir.Event.KeyEvent.uChar.UnicodeChar;
254 break;
257 if (handle_enhanced_keys(&ir, &ch1, &ch2))
259 retval = ch1;
260 __MSVCRT_console_buffer_w = ch2;
261 break;
265 else
266 break;
267 } while(1);
268 if (mode)
269 SetConsoleMode(MSVCRT_console_in, mode);
271 return retval;
274 /*********************************************************************
275 * _getwch (MSVCRT.@)
277 MSVCRT_wchar_t CDECL _getwch(void)
279 MSVCRT_wchar_t ret;
281 LOCK_CONSOLE;
282 ret = _getwch_nolock();
283 UNLOCK_CONSOLE;
284 return ret;
287 /*********************************************************************
288 * _putch_nolock (MSVCR80.@)
290 int CDECL _putch_nolock(int c)
292 DWORD count;
293 if (WriteConsoleA(MSVCRT_console_out, &c, 1, &count, NULL) && count == 1)
294 return c;
295 return MSVCRT_EOF;
298 /*********************************************************************
299 * _putch (MSVCRT.@)
301 int CDECL _putch(int c)
303 LOCK_CONSOLE;
304 c = _putch_nolock(c);
305 UNLOCK_CONSOLE;
306 return c;
309 /*********************************************************************
310 * _putwch_nolock (MSVCR80.@)
312 MSVCRT_wchar_t CDECL _putwch_nolock(MSVCRT_wchar_t c)
314 DWORD count;
315 if (WriteConsoleW(MSVCRT_console_out, &c, 1, &count, NULL) && count==1)
316 return c;
317 return MSVCRT_WEOF;
320 /*********************************************************************
321 * _putwch (MSVCRT.@)
323 MSVCRT_wchar_t CDECL _putwch(MSVCRT_wchar_t c)
325 LOCK_CONSOLE;
326 c = _putwch_nolock(c);
327 UNLOCK_CONSOLE;
328 return c;
331 /*********************************************************************
332 * _getche_nolock (MSVCR80.@)
334 int CDECL _getche_nolock(void)
336 int retval;
337 retval = _getch_nolock();
338 if (retval != MSVCRT_EOF)
339 retval = _putch_nolock(retval);
340 return retval;
343 /*********************************************************************
344 * _getche (MSVCRT.@)
346 int CDECL _getche(void)
348 int ret;
350 LOCK_CONSOLE;
351 ret = _getche_nolock();
352 UNLOCK_CONSOLE;
353 return ret;
356 /*********************************************************************
357 * _getwche_nolock (MSVCR80.@)
359 MSVCRT_wchar_t CDECL _getwche_nolock(void)
361 MSVCRT_wchar_t wch;
362 wch = _getch_nolock();
363 if (wch == MSVCRT_WEOF)
364 return wch;
365 return _putwch_nolock(wch);
368 /*********************************************************************
369 * _getwche (MSVCRT.@)
371 MSVCRT_wchar_t CDECL _getwche(void)
373 MSVCRT_wchar_t ret;
375 LOCK_CONSOLE;
376 ret = _getwche_nolock();
377 UNLOCK_CONSOLE;
378 return ret;
381 /*********************************************************************
382 * _cgets (MSVCRT.@)
384 char* CDECL _cgets(char* str)
386 char *buf = str + 2;
387 DWORD got;
388 DWORD conmode = 0;
390 TRACE("(%p)\n", str);
391 str[1] = 0; /* Length */
392 LOCK_CONSOLE;
393 GetConsoleMode(MSVCRT_console_in, &conmode);
394 SetConsoleMode(MSVCRT_console_in, ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT);
396 if(ReadConsoleA(MSVCRT_console_in, buf, str[0], &got, NULL)) {
397 if(buf[got-2] == '\r') {
398 buf[got-2] = 0;
399 str[1] = got-2;
401 else if(got == 1 && buf[got-1] == '\n') {
402 buf[0] = 0;
403 str[1] = 0;
405 else if(got == str[0] && buf[got-1] == '\r') {
406 buf[got-1] = 0;
407 str[1] = got-1;
409 else
410 str[1] = got;
412 else
413 buf = NULL;
414 SetConsoleMode(MSVCRT_console_in, conmode);
415 UNLOCK_CONSOLE;
416 return buf;
419 /*********************************************************************
420 * _ungetch_nolock (MSVCRT.@)
422 int CDECL _ungetch_nolock(int c)
424 int retval = MSVCRT_EOF;
425 if (c != MSVCRT_EOF && __MSVCRT_console_buffer == MSVCRT_EOF)
426 retval = __MSVCRT_console_buffer = c;
427 return retval;
430 /*********************************************************************
431 * _ungetch (MSVCRT.@)
433 int CDECL _ungetch(int c)
435 LOCK_CONSOLE;
436 c = _ungetch_nolock(c);
437 UNLOCK_CONSOLE;
438 return c;
441 /*********************************************************************
442 * _ungetwch_nolock (MSVCR80.@)
444 MSVCRT_wchar_t CDECL _ungetwch_nolock(MSVCRT_wchar_t c)
446 MSVCRT_wchar_t retval = MSVCRT_WEOF;
447 if (c != MSVCRT_WEOF && __MSVCRT_console_buffer_w == MSVCRT_WEOF)
448 retval = __MSVCRT_console_buffer_w = c;
449 return retval;
452 /*********************************************************************
453 * _ungetwch (MSVCRT.@)
455 MSVCRT_wchar_t CDECL _ungetwch(MSVCRT_wchar_t c)
457 LOCK_CONSOLE;
458 c = _ungetwch_nolock(c);
459 UNLOCK_CONSOLE;
460 return c;
463 /*********************************************************************
464 * _kbhit (MSVCRT.@)
466 int CDECL _kbhit(void)
468 int retval = 0;
470 LOCK_CONSOLE;
471 if (__MSVCRT_console_buffer != MSVCRT_EOF)
472 retval = 1;
473 else
475 /* FIXME: There has to be a faster way than this in Win32.. */
476 INPUT_RECORD *ir = NULL;
477 DWORD count = 0, i;
479 GetNumberOfConsoleInputEvents(MSVCRT_console_in, &count);
481 if (count && (ir = MSVCRT_malloc(count * sizeof(INPUT_RECORD))) &&
482 PeekConsoleInputA(MSVCRT_console_in, ir, count, &count))
483 for(i = 0; i < count - 1; i++)
485 if (ir[i].EventType == KEY_EVENT &&
486 ir[i].Event.KeyEvent.bKeyDown &&
487 ir[i].Event.KeyEvent.uChar.AsciiChar)
489 retval = 1;
490 break;
493 MSVCRT_free(ir);
495 UNLOCK_CONSOLE;
496 return retval;
499 static int puts_clbk_console_a(void *ctx, int len, const char *str)
501 LOCK_CONSOLE;
502 if(!WriteConsoleA(MSVCRT_console_out, str, len, NULL, NULL))
503 len = -1;
504 UNLOCK_CONSOLE;
505 return len;
508 static int puts_clbk_console_w(void *ctx, int len, const MSVCRT_wchar_t *str)
510 LOCK_CONSOLE;
511 if(!WriteConsoleW(MSVCRT_console_out, str, len, NULL, NULL))
512 len = -1;
513 UNLOCK_CONSOLE;
514 return len;
517 /*********************************************************************
518 * _vcprintf (MSVCRT.@)
520 int CDECL _vcprintf(const char* format, __ms_va_list valist)
522 return pf_printf_a(puts_clbk_console_a, NULL, format, NULL, 0, arg_clbk_valist, NULL, &valist);
525 /*********************************************************************
526 * _cprintf (MSVCRT.@)
528 int CDECL _cprintf(const char* format, ...)
530 int retval;
531 __ms_va_list valist;
533 __ms_va_start( valist, format );
534 retval = _vcprintf(format, valist);
535 __ms_va_end(valist);
537 return retval;
541 /*********************************************************************
542 * _vcwprintf (MSVCRT.@)
544 int CDECL _vcwprintf(const MSVCRT_wchar_t* format, __ms_va_list valist)
546 return pf_printf_w(puts_clbk_console_w, NULL, format, NULL, 0, arg_clbk_valist, NULL, &valist);
549 /*********************************************************************
550 * _cwprintf (MSVCRT.@)
552 int CDECL _cwprintf(const MSVCRT_wchar_t* format, ...)
554 int retval;
555 __ms_va_list valist;
557 __ms_va_start( valist, format );
558 retval = _vcwprintf(format, valist);
559 __ms_va_end(valist);
561 return retval;