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
);
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 /*********************************************************************
68 int CDECL
_cputs(const char* str
)
73 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return -1;
77 if (WriteConsoleA(MSVCRT_console_out
, str
, len
, &count
, NULL
)
84 /*********************************************************************
87 int CDECL
_cputws(const wchar_t* str
)
92 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return -1;
93 len
= MSVCRT_wcslen(str
);
96 if (WriteConsoleW(MSVCRT_console_out
, str
, len
, &count
, NULL
)
103 #define NORMAL_CHAR 0
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
)
125 for (i
= 0; i
< ARRAY_SIZE(enh_map
); i
++)
127 if (ir
->Event
.KeyEvent
.wVirtualScanCode
== enh_map
[i
].vk
)
131 if (ir
->Event
.KeyEvent
.dwControlKeyState
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
))
133 else if (ir
->Event
.KeyEvent
.dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
) )
135 else if (ir
->Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
)
140 *ch1
= enh_map
[i
].ch
[idx
][0];
141 *ch2
= enh_map
[i
].ch
[idx
][1];
146 WARN("Unmapped char keyState=%x vk=%x\n",
147 ir
->Event
.KeyEvent
.dwControlKeyState
, ir
->Event
.KeyEvent
.wVirtualScanCode
);
151 /*********************************************************************
152 * _getch_nolock (MSVCR80.@)
154 int CDECL
_getch_nolock(void)
158 if (__MSVCRT_console_buffer
!= EOF
)
160 retval
= __MSVCRT_console_buffer
;
161 __MSVCRT_console_buffer
= EOF
;
169 GetConsoleMode(MSVCRT_console_in
, &mode
);
171 SetConsoleMode(MSVCRT_console_in
, 0);
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
;
188 if (handle_enhanced_keys(&ir
, &ch1
, &ch2
))
191 __MSVCRT_console_buffer
= ch2
;
200 SetConsoleMode(MSVCRT_console_in
, mode
);
205 /*********************************************************************
208 int CDECL
_getch(void)
213 ret
= _getch_nolock();
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
;
236 GetConsoleMode(MSVCRT_console_in
, &mode
);
238 SetConsoleMode(MSVCRT_console_in
, 0);
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
;
255 if (handle_enhanced_keys(&ir
, &ch1
, &ch2
))
258 __MSVCRT_console_buffer_w
= ch2
;
267 SetConsoleMode(MSVCRT_console_in
, mode
);
272 /*********************************************************************
275 wchar_t CDECL
_getwch(void)
280 ret
= _getwch_nolock();
285 /*********************************************************************
286 * _putch_nolock (MSVCR80.@)
288 int CDECL
_putch_nolock(int c
)
291 if (WriteConsoleA(MSVCRT_console_out
, &c
, 1, &count
, NULL
) && count
== 1)
296 /*********************************************************************
299 int CDECL
_putch(int c
)
302 c
= _putch_nolock(c
);
307 /*********************************************************************
308 * _putwch_nolock (MSVCR80.@)
310 wchar_t CDECL
_putwch_nolock(wchar_t c
)
313 if (WriteConsoleW(MSVCRT_console_out
, &c
, 1, &count
, NULL
) && count
==1)
318 /*********************************************************************
321 wchar_t CDECL
_putwch(wchar_t c
)
324 c
= _putwch_nolock(c
);
329 /*********************************************************************
330 * _getche_nolock (MSVCR80.@)
332 int CDECL
_getche_nolock(void)
335 retval
= _getch_nolock();
337 retval
= _putch_nolock(retval
);
341 /*********************************************************************
344 int CDECL
_getche(void)
349 ret
= _getche_nolock();
354 /*********************************************************************
355 * _getwche_nolock (MSVCR80.@)
357 wchar_t CDECL
_getwche_nolock(void)
360 wch
= _getch_nolock();
363 return _putwch_nolock(wch
);
366 /*********************************************************************
367 * _getwche (MSVCRT.@)
369 wchar_t CDECL
_getwche(void)
374 ret
= _getwche_nolock();
379 /*********************************************************************
382 char* CDECL
_cgets(char* str
)
388 TRACE("(%p)\n", str
);
389 str
[1] = 0; /* Length */
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') {
399 else if(got
== 1 && buf
[got
-1] == '\n') {
403 else if(got
== str
[0] && buf
[got
-1] == '\r') {
412 SetConsoleMode(MSVCRT_console_in
, conmode
);
417 /*********************************************************************
418 * _ungetch_nolock (MSVCRT.@)
420 int CDECL
_ungetch_nolock(int c
)
423 if (c
!= EOF
&& __MSVCRT_console_buffer
== EOF
)
424 retval
= __MSVCRT_console_buffer
= c
;
428 /*********************************************************************
429 * _ungetch (MSVCRT.@)
431 int CDECL
_ungetch(int c
)
434 c
= _ungetch_nolock(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
;
450 /*********************************************************************
451 * _ungetwch (MSVCRT.@)
453 wchar_t CDECL
_ungetwch(wchar_t c
)
456 c
= _ungetwch_nolock(c
);
461 /*********************************************************************
464 int CDECL
_kbhit(void)
469 if (__MSVCRT_console_buffer
!= EOF
)
473 /* FIXME: There has to be a faster way than this in Win32.. */
474 INPUT_RECORD
*ir
= NULL
;
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
)
497 static int puts_clbk_console_a(void *ctx
, int len
, const char *str
)
500 if(!WriteConsoleA(MSVCRT_console_out
, str
, len
, NULL
, NULL
))
506 static int puts_clbk_console_w(void *ctx
, int len
, const wchar_t *str
)
509 if(!WriteConsoleW(MSVCRT_console_out
, str
, len
, NULL
, NULL
))
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
, ...)
531 __ms_va_start( valist
, format
);
532 retval
= _vcprintf(format
, valist
);
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
, ...)
555 __ms_va_start( valist
, format
);
556 retval
= _vcwprintf(format
, valist
);
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 */