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
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
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 /*********************************************************************
70 int CDECL
_cputs(const char* str
)
75 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return -1;
79 if (WriteConsoleA(MSVCRT_console_out
, str
, len
, &count
, NULL
)
86 /*********************************************************************
89 int CDECL
_cputws(const MSVCRT_wchar_t
* str
)
94 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return -1;
98 if (WriteConsoleW(MSVCRT_console_out
, str
, len
, &count
, NULL
)
105 #define NORMAL_CHAR 0
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
)
127 for (i
= 0; i
< sizeof(enh_map
) / sizeof(enh_map
[0]); i
++)
129 if (ir
->Event
.KeyEvent
.wVirtualScanCode
== enh_map
[i
].vk
)
133 if (ir
->Event
.KeyEvent
.dwControlKeyState
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
))
135 else if (ir
->Event
.KeyEvent
.dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
) )
137 else if (ir
->Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
)
142 *ch1
= enh_map
[i
].ch
[idx
][0];
143 *ch2
= enh_map
[i
].ch
[idx
][1];
148 WARN("Unmapped char keyState=%x vk=%x\n",
149 ir
->Event
.KeyEvent
.dwControlKeyState
, ir
->Event
.KeyEvent
.wVirtualScanCode
);
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
;
171 GetConsoleMode(MSVCRT_console_in
, &mode
);
173 SetConsoleMode(MSVCRT_console_in
, 0);
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
;
190 if (handle_enhanced_keys(&ir
, &ch1
, &ch2
))
193 __MSVCRT_console_buffer
= ch2
;
202 SetConsoleMode(MSVCRT_console_in
, mode
);
207 /*********************************************************************
210 int CDECL
_getch(void)
215 ret
= _getch_nolock();
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
;
238 GetConsoleMode(MSVCRT_console_in
, &mode
);
240 SetConsoleMode(MSVCRT_console_in
, 0);
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
;
257 if (handle_enhanced_keys(&ir
, &ch1
, &ch2
))
260 __MSVCRT_console_buffer_w
= ch2
;
269 SetConsoleMode(MSVCRT_console_in
, mode
);
274 /*********************************************************************
277 MSVCRT_wchar_t CDECL
_getwch(void)
282 ret
= _getwch_nolock();
287 /*********************************************************************
288 * _putch_nolock (MSVCR80.@)
290 int CDECL
_putch_nolock(int c
)
293 if (WriteConsoleA(MSVCRT_console_out
, &c
, 1, &count
, NULL
) && count
== 1)
298 /*********************************************************************
301 int CDECL
_putch(int c
)
304 c
= _putch_nolock(c
);
309 /*********************************************************************
310 * _putwch_nolock (MSVCR80.@)
312 MSVCRT_wchar_t CDECL
_putwch_nolock(MSVCRT_wchar_t c
)
315 if (WriteConsoleW(MSVCRT_console_out
, &c
, 1, &count
, NULL
) && count
==1)
320 /*********************************************************************
323 MSVCRT_wchar_t CDECL
_putwch(MSVCRT_wchar_t c
)
326 c
= _putwch_nolock(c
);
331 /*********************************************************************
332 * _getche_nolock (MSVCR80.@)
334 int CDECL
_getche_nolock(void)
337 retval
= _getch_nolock();
338 if (retval
!= MSVCRT_EOF
)
339 retval
= _putch_nolock(retval
);
343 /*********************************************************************
346 int CDECL
_getche(void)
351 ret
= _getche_nolock();
356 /*********************************************************************
357 * _getwche_nolock (MSVCR80.@)
359 MSVCRT_wchar_t CDECL
_getwche_nolock(void)
362 wch
= _getch_nolock();
363 if (wch
== MSVCRT_WEOF
)
365 return _putwch_nolock(wch
);
368 /*********************************************************************
369 * _getwche (MSVCRT.@)
371 MSVCRT_wchar_t CDECL
_getwche(void)
376 ret
= _getwche_nolock();
381 /*********************************************************************
384 char* CDECL
_cgets(char* str
)
390 TRACE("(%p)\n", str
);
391 str
[1] = 0; /* Length */
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') {
401 else if(got
== 1 && buf
[got
-1] == '\n') {
405 else if(got
== str
[0] && buf
[got
-1] == '\r') {
414 SetConsoleMode(MSVCRT_console_in
, conmode
);
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
;
430 /*********************************************************************
431 * _ungetch (MSVCRT.@)
433 int CDECL
_ungetch(int c
)
436 c
= _ungetch_nolock(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
;
452 /*********************************************************************
453 * _ungetwch (MSVCRT.@)
455 MSVCRT_wchar_t CDECL
_ungetwch(MSVCRT_wchar_t c
)
458 c
= _ungetwch_nolock(c
);
463 /*********************************************************************
466 int CDECL
_kbhit(void)
471 if (__MSVCRT_console_buffer
!= MSVCRT_EOF
)
475 /* FIXME: There has to be a faster way than this in Win32.. */
476 INPUT_RECORD
*ir
= NULL
;
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
)
499 static int puts_clbk_console_a(void *ctx
, int len
, const char *str
)
502 if(!WriteConsoleA(MSVCRT_console_out
, str
, len
, NULL
, NULL
))
508 static int puts_clbk_console_w(void *ctx
, int len
, const MSVCRT_wchar_t
*str
)
511 if(!WriteConsoleW(MSVCRT_console_out
, str
, len
, NULL
, NULL
))
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
, ...)
533 __ms_va_start( valist
, format
);
534 retval
= _vcprintf(format
, valist
);
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
, ...)
557 __ms_va_start( valist
, format
);
558 retval
= _vcwprintf(format
, valist
);
564 /*********************************************************************
565 * __conio_common_vcprintf (MSVCRT.@)
567 int CDECL
MSVCRT__conio_common_vcprintf(unsigned __int64 options
, const char* format
,
568 MSVCRT__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 (MSVCRT.@)
579 int CDECL
MSVCRT__conio_common_vcwprintf(unsigned __int64 options
, const MSVCRT_wchar_t
* format
,
580 MSVCRT__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
);