include: Fix __dmb declaration.
[wine.git] / dlls / msvcrt / console.c
blob26f7b554636a8bc84d1733a13725a3aa25365487
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);
32 /* MT */
33 #define LOCK_CONSOLE _lock(_CONIO_LOCK)
34 #define UNLOCK_CONSOLE _unlock(_CONIO_LOCK)
36 static HANDLE MSVCRT_console_in = INVALID_HANDLE_VALUE;
37 static HANDLE MSVCRT_console_out= INVALID_HANDLE_VALUE;
38 static int __MSVCRT_console_buffer = EOF;
39 static wchar_t __MSVCRT_console_buffer_w = WEOF;
41 /* INTERNAL: Initialise console handles */
42 void msvcrt_init_console(void)
44 TRACE(":Opening console handles\n");
46 MSVCRT_console_in = CreateFileA("CONIN$", GENERIC_WRITE|GENERIC_READ,
47 FILE_SHARE_WRITE|FILE_SHARE_READ,
48 NULL, OPEN_EXISTING, 0, NULL);
49 MSVCRT_console_out= CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
50 NULL, OPEN_EXISTING, 0, NULL);
52 if ((MSVCRT_console_in == INVALID_HANDLE_VALUE) ||
53 (MSVCRT_console_out== INVALID_HANDLE_VALUE))
54 WARN(":Console handle Initialisation FAILED!\n");
57 /* INTERNAL: Free console handles */
58 void msvcrt_free_console(void)
60 TRACE(":Closing console handles\n");
61 CloseHandle(MSVCRT_console_in);
62 CloseHandle(MSVCRT_console_out);
65 /*********************************************************************
66 * _cputs (MSVCRT.@)
68 int CDECL _cputs(const char* str)
70 DWORD count;
71 int len, retval = -1;
73 if (!MSVCRT_CHECK_PMT(str != NULL)) return -1;
74 len = strlen(str);
76 LOCK_CONSOLE;
77 if (WriteConsoleA(MSVCRT_console_out, str, len, &count, NULL)
78 && count == len)
79 retval = 0;
80 UNLOCK_CONSOLE;
81 return retval;
84 /*********************************************************************
85 * _cputws (MSVCRT.@)
87 int CDECL _cputws(const wchar_t* str)
89 DWORD count;
90 int len, retval = -1;
92 if (!MSVCRT_CHECK_PMT(str != NULL)) return -1;
93 len = wcslen(str);
95 LOCK_CONSOLE;
96 if (WriteConsoleW(MSVCRT_console_out, str, len, &count, NULL)
97 && count == len)
98 retval = 0;
99 UNLOCK_CONSOLE;
100 return retval;
103 #define NORMAL_CHAR 0
104 #define ALT_CHAR 1
105 #define CTRL_CHAR 2
106 #define SHIFT_CHAR 3
108 static const struct {unsigned short vk; unsigned char ch[4][2];} enh_map[] = {
109 {0x47, {{0xE0, 0x47}, {0x00, 0x97}, {0xE0, 0x77}, {0xE0, 0x47}}},
110 {0x48, {{0xE0, 0x48}, {0x00, 0x98}, {0xE0, 0x8D}, {0xE0, 0x48}}},
111 {0x49, {{0xE0, 0x49}, {0x00, 0x99}, {0xE0, 0x86}, {0xE0, 0x49}}},
112 {0x4B, {{0xE0, 0x4B}, {0x00, 0x9B}, {0xE0, 0x73}, {0xE0, 0x4B}}},
113 {0x4D, {{0xE0, 0x4D}, {0x00, 0x9D}, {0xE0, 0x74}, {0xE0, 0x4D}}},
114 {0x4F, {{0xE0, 0x4F}, {0x00, 0x9F}, {0xE0, 0x75}, {0xE0, 0x4F}}},
115 {0x50, {{0xE0, 0x50}, {0x00, 0xA0}, {0xE0, 0x91}, {0xE0, 0x50}}},
116 {0x51, {{0xE0, 0x51}, {0x00, 0xA1}, {0xE0, 0x76}, {0xE0, 0x51}}},
117 {0x52, {{0xE0, 0x52}, {0x00, 0xA2}, {0xE0, 0x92}, {0xE0, 0x52}}},
118 {0x53, {{0xE0, 0x53}, {0x00, 0xA3}, {0xE0, 0x93}, {0xE0, 0x53}}},
121 static BOOL handle_enhanced_keys(INPUT_RECORD *ir, unsigned char *ch1, unsigned char *ch2)
123 int i;
125 for (i = 0; i < ARRAY_SIZE(enh_map); i++)
127 if (ir->Event.KeyEvent.wVirtualScanCode == enh_map[i].vk)
129 unsigned idx;
131 if (ir->Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
132 idx = ALT_CHAR;
133 else if (ir->Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) )
134 idx = CTRL_CHAR;
135 else if (ir->Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
136 idx = SHIFT_CHAR;
137 else
138 idx = NORMAL_CHAR;
140 *ch1 = enh_map[i].ch[idx][0];
141 *ch2 = enh_map[i].ch[idx][1];
142 return TRUE;
146 WARN("Unmapped char keyState=%x vk=%x\n",
147 ir->Event.KeyEvent.dwControlKeyState, ir->Event.KeyEvent.wVirtualScanCode);
148 return FALSE;
151 /*********************************************************************
152 * _getch_nolock (MSVCR80.@)
154 int CDECL _getch_nolock(void)
156 int retval = EOF;
158 if (__MSVCRT_console_buffer != EOF)
160 retval = __MSVCRT_console_buffer;
161 __MSVCRT_console_buffer = EOF;
163 else
165 INPUT_RECORD ir;
166 DWORD count;
167 DWORD mode = 0;
169 GetConsoleMode(MSVCRT_console_in, &mode);
170 if(mode)
171 SetConsoleMode(MSVCRT_console_in, 0);
173 do {
174 if (ReadConsoleInputA(MSVCRT_console_in, &ir, 1, &count))
176 /* Only interested in ASCII chars */
177 if (ir.EventType == KEY_EVENT &&
178 ir.Event.KeyEvent.bKeyDown)
180 unsigned char ch1, ch2;
182 if (ir.Event.KeyEvent.uChar.AsciiChar)
184 retval = ir.Event.KeyEvent.uChar.AsciiChar;
185 break;
188 if (handle_enhanced_keys(&ir, &ch1, &ch2))
190 retval = ch1;
191 __MSVCRT_console_buffer = ch2;
192 break;
196 else
197 break;
198 } while(1);
199 if (mode)
200 SetConsoleMode(MSVCRT_console_in, mode);
202 return retval;
205 /*********************************************************************
206 * _getch (MSVCRT.@)
208 int CDECL _getch(void)
210 int ret;
212 LOCK_CONSOLE;
213 ret = _getch_nolock();
214 UNLOCK_CONSOLE;
215 return ret;
218 /*********************************************************************
219 * _getwch_nolock (MSVCR80.@)
221 wchar_t CDECL _getwch_nolock(void)
223 wchar_t retval = WEOF;
225 if (__MSVCRT_console_buffer_w != WEOF)
227 retval = __MSVCRT_console_buffer_w;
228 __MSVCRT_console_buffer_w = WEOF;
230 else
232 INPUT_RECORD ir;
233 DWORD count;
234 DWORD mode = 0;
236 GetConsoleMode(MSVCRT_console_in, &mode);
237 if(mode)
238 SetConsoleMode(MSVCRT_console_in, 0);
240 do {
241 if (ReadConsoleInputW(MSVCRT_console_in, &ir, 1, &count))
243 /* Only interested in ASCII chars */
244 if (ir.EventType == KEY_EVENT &&
245 ir.Event.KeyEvent.bKeyDown)
247 unsigned char ch1, ch2;
249 if (ir.Event.KeyEvent.uChar.UnicodeChar)
251 retval = ir.Event.KeyEvent.uChar.UnicodeChar;
252 break;
255 if (handle_enhanced_keys(&ir, &ch1, &ch2))
257 retval = ch1;
258 __MSVCRT_console_buffer_w = ch2;
259 break;
263 else
264 break;
265 } while(1);
266 if (mode)
267 SetConsoleMode(MSVCRT_console_in, mode);
269 return retval;
272 /*********************************************************************
273 * _getwch (MSVCRT.@)
275 wchar_t CDECL _getwch(void)
277 wchar_t ret;
279 LOCK_CONSOLE;
280 ret = _getwch_nolock();
281 UNLOCK_CONSOLE;
282 return ret;
285 /*********************************************************************
286 * _putch_nolock (MSVCR80.@)
288 int CDECL _putch_nolock(int c)
290 DWORD count;
291 if (WriteConsoleA(MSVCRT_console_out, &c, 1, &count, NULL) && count == 1)
292 return c;
293 return EOF;
296 /*********************************************************************
297 * _putch (MSVCRT.@)
299 int CDECL _putch(int c)
301 LOCK_CONSOLE;
302 c = _putch_nolock(c);
303 UNLOCK_CONSOLE;
304 return c;
307 /*********************************************************************
308 * _putwch_nolock (MSVCR80.@)
310 wchar_t CDECL _putwch_nolock(wchar_t c)
312 DWORD count;
313 if (WriteConsoleW(MSVCRT_console_out, &c, 1, &count, NULL) && count==1)
314 return c;
315 return WEOF;
318 /*********************************************************************
319 * _putwch (MSVCRT.@)
321 wchar_t CDECL _putwch(wchar_t c)
323 LOCK_CONSOLE;
324 c = _putwch_nolock(c);
325 UNLOCK_CONSOLE;
326 return c;
329 /*********************************************************************
330 * _getche_nolock (MSVCR80.@)
332 int CDECL _getche_nolock(void)
334 int retval;
335 retval = _getch_nolock();
336 if (retval != EOF)
337 retval = _putch_nolock(retval);
338 return retval;
341 /*********************************************************************
342 * _getche (MSVCRT.@)
344 int CDECL _getche(void)
346 int ret;
348 LOCK_CONSOLE;
349 ret = _getche_nolock();
350 UNLOCK_CONSOLE;
351 return ret;
354 /*********************************************************************
355 * _getwche_nolock (MSVCR80.@)
357 wchar_t CDECL _getwche_nolock(void)
359 wchar_t wch;
360 wch = _getch_nolock();
361 if (wch == WEOF)
362 return wch;
363 return _putwch_nolock(wch);
366 /*********************************************************************
367 * _getwche (MSVCRT.@)
369 wchar_t CDECL _getwche(void)
371 wchar_t ret;
373 LOCK_CONSOLE;
374 ret = _getwche_nolock();
375 UNLOCK_CONSOLE;
376 return ret;
379 /*********************************************************************
380 * _cgets (MSVCRT.@)
382 char* CDECL _cgets(char* str)
384 char *buf = str + 2;
385 DWORD got;
386 DWORD conmode = 0;
388 TRACE("(%p)\n", str);
389 str[1] = 0; /* Length */
390 LOCK_CONSOLE;
391 GetConsoleMode(MSVCRT_console_in, &conmode);
392 SetConsoleMode(MSVCRT_console_in, ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT);
394 if(ReadConsoleA(MSVCRT_console_in, buf, str[0], &got, NULL)) {
395 if(buf[got-2] == '\r') {
396 buf[got-2] = 0;
397 str[1] = got-2;
399 else if(got == 1 && buf[got-1] == '\n') {
400 buf[0] = 0;
401 str[1] = 0;
403 else if(got == str[0] && buf[got-1] == '\r') {
404 buf[got-1] = 0;
405 str[1] = got-1;
407 else
408 str[1] = got;
410 else
411 buf = NULL;
412 SetConsoleMode(MSVCRT_console_in, conmode);
413 UNLOCK_CONSOLE;
414 return buf;
417 /*********************************************************************
418 * _ungetch_nolock (MSVCRT.@)
420 int CDECL _ungetch_nolock(int c)
422 int retval = EOF;
423 if (c != EOF && __MSVCRT_console_buffer == EOF)
424 retval = __MSVCRT_console_buffer = c;
425 return retval;
428 /*********************************************************************
429 * _ungetch (MSVCRT.@)
431 int CDECL _ungetch(int c)
433 LOCK_CONSOLE;
434 c = _ungetch_nolock(c);
435 UNLOCK_CONSOLE;
436 return c;
439 /*********************************************************************
440 * _ungetwch_nolock (MSVCR80.@)
442 wchar_t CDECL _ungetwch_nolock(wchar_t c)
444 wchar_t retval = WEOF;
445 if (c != WEOF && __MSVCRT_console_buffer_w == WEOF)
446 retval = __MSVCRT_console_buffer_w = c;
447 return retval;
450 /*********************************************************************
451 * _ungetwch (MSVCRT.@)
453 wchar_t CDECL _ungetwch(wchar_t c)
455 LOCK_CONSOLE;
456 c = _ungetwch_nolock(c);
457 UNLOCK_CONSOLE;
458 return c;
461 /*********************************************************************
462 * _kbhit (MSVCRT.@)
464 int CDECL _kbhit(void)
466 int retval = 0;
468 LOCK_CONSOLE;
469 if (__MSVCRT_console_buffer != EOF)
470 retval = 1;
471 else
473 /* FIXME: There has to be a faster way than this in Win32.. */
474 INPUT_RECORD *ir = NULL;
475 DWORD count = 0, i;
477 GetNumberOfConsoleInputEvents(MSVCRT_console_in, &count);
479 if (count && (ir = malloc(count * sizeof(INPUT_RECORD))) &&
480 PeekConsoleInputA(MSVCRT_console_in, ir, count, &count))
481 for(i = 0; i < count - 1; i++)
483 if (ir[i].EventType == KEY_EVENT &&
484 ir[i].Event.KeyEvent.bKeyDown &&
485 ir[i].Event.KeyEvent.uChar.AsciiChar)
487 retval = 1;
488 break;
491 free(ir);
493 UNLOCK_CONSOLE;
494 return retval;
497 static int puts_clbk_console_a(void *ctx, int len, const char *str)
499 LOCK_CONSOLE;
500 if(!WriteConsoleA(MSVCRT_console_out, str, len, NULL, NULL))
501 len = -1;
502 UNLOCK_CONSOLE;
503 return len;
506 static int puts_clbk_console_w(void *ctx, int len, const wchar_t *str)
508 LOCK_CONSOLE;
509 if(!WriteConsoleW(MSVCRT_console_out, str, len, NULL, NULL))
510 len = -1;
511 UNLOCK_CONSOLE;
512 return len;
515 /*********************************************************************
516 * _vcprintf (MSVCRT.@)
518 int CDECL _vcprintf(const char* format, __ms_va_list valist)
520 return pf_printf_a(puts_clbk_console_a, NULL, format, NULL, 0, arg_clbk_valist, NULL, &valist);
523 /*********************************************************************
524 * _cprintf (MSVCRT.@)
526 int WINAPIV _cprintf(const char* format, ...)
528 int retval;
529 __ms_va_list valist;
531 __ms_va_start( valist, format );
532 retval = _vcprintf(format, valist);
533 __ms_va_end(valist);
535 return retval;
539 /*********************************************************************
540 * _vcwprintf (MSVCRT.@)
542 int CDECL _vcwprintf(const wchar_t* format, __ms_va_list valist)
544 return pf_printf_w(puts_clbk_console_w, NULL, format, NULL, 0, arg_clbk_valist, NULL, &valist);
547 /*********************************************************************
548 * _cwprintf (MSVCRT.@)
550 int WINAPIV _cwprintf(const wchar_t* format, ...)
552 int retval;
553 __ms_va_list valist;
555 __ms_va_start( valist, format );
556 retval = _vcwprintf(format, valist);
557 __ms_va_end(valist);
559 return retval;
562 #if _MSVCR_VER>=140
564 /*********************************************************************
565 * __conio_common_vcprintf (UCRTBASE.@)
567 int CDECL __conio_common_vcprintf(unsigned __int64 options, const char* format,
568 _locale_t locale, __ms_va_list valist)
570 if (options & ~UCRTBASE_PRINTF_MASK)
571 FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
572 return pf_printf_a(puts_clbk_console_a, NULL, format, locale,
573 options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
576 /*********************************************************************
577 * __conio_common_vcwprintf (UCRTBASE.@)
579 int CDECL __conio_common_vcwprintf(unsigned __int64 options, const wchar_t* format,
580 _locale_t locale, __ms_va_list valist)
582 if (options & ~UCRTBASE_PRINTF_MASK)
583 FIXME("options %s not handled\n", wine_dbgstr_longlong(options));
584 return pf_printf_w(puts_clbk_console_w, NULL, format, locale,
585 options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
588 #endif /* _MSVCR_VER>=140 */