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
;
37 static HANDLE MSVCRT_console_out
;
38 static int __MSVCRT_console_buffer
= EOF
;
39 static wchar_t __MSVCRT_console_buffer_w
= WEOF
;
41 /* INTERNAL: Initialise console handles, _CONIO_LOCK must be held */
42 static HANDLE
msvcrt_input_console(void)
44 if (!MSVCRT_console_in
)
46 MSVCRT_console_in
= CreateFileA("CONIN$", GENERIC_WRITE
|GENERIC_READ
,
47 FILE_SHARE_WRITE
|FILE_SHARE_READ
,
48 NULL
, OPEN_EXISTING
, 0, NULL
);
49 if (MSVCRT_console_in
== INVALID_HANDLE_VALUE
)
50 WARN("Input console handle initialization failed!\n");
52 return MSVCRT_console_in
;
55 static HANDLE
msvcrt_output_console(void)
57 if (!MSVCRT_console_out
)
59 MSVCRT_console_out
= CreateFileA("CONOUT$", GENERIC_WRITE
, FILE_SHARE_WRITE
,
60 NULL
, OPEN_EXISTING
, 0, NULL
);
61 if (MSVCRT_console_out
== INVALID_HANDLE_VALUE
)
62 WARN("Output console handle initialization failed!\n");
64 return MSVCRT_console_out
;
67 /* INTERNAL: Free console handles */
68 void msvcrt_free_console(void)
70 TRACE(":Closing console handles\n");
71 CloseHandle(MSVCRT_console_in
);
72 CloseHandle(MSVCRT_console_out
);
75 /*********************************************************************
78 int CDECL
_cputs(const char* str
)
83 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return -1;
87 if (WriteConsoleA(msvcrt_output_console(), str
, len
, &count
, NULL
)
94 /*********************************************************************
97 int CDECL
_cputws(const wchar_t* str
)
100 int len
, retval
= -1;
102 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return -1;
106 if (WriteConsoleW(msvcrt_output_console(), str
, len
, &count
, NULL
)
113 #define NORMAL_CHAR 0
118 static const struct {unsigned short vk
; unsigned char ch
[4][2];} enh_map
[] = {
119 {0x47, {{0xE0, 0x47}, {0x00, 0x97}, {0xE0, 0x77}, {0xE0, 0x47}}},
120 {0x48, {{0xE0, 0x48}, {0x00, 0x98}, {0xE0, 0x8D}, {0xE0, 0x48}}},
121 {0x49, {{0xE0, 0x49}, {0x00, 0x99}, {0xE0, 0x86}, {0xE0, 0x49}}},
122 {0x4B, {{0xE0, 0x4B}, {0x00, 0x9B}, {0xE0, 0x73}, {0xE0, 0x4B}}},
123 {0x4D, {{0xE0, 0x4D}, {0x00, 0x9D}, {0xE0, 0x74}, {0xE0, 0x4D}}},
124 {0x4F, {{0xE0, 0x4F}, {0x00, 0x9F}, {0xE0, 0x75}, {0xE0, 0x4F}}},
125 {0x50, {{0xE0, 0x50}, {0x00, 0xA0}, {0xE0, 0x91}, {0xE0, 0x50}}},
126 {0x51, {{0xE0, 0x51}, {0x00, 0xA1}, {0xE0, 0x76}, {0xE0, 0x51}}},
127 {0x52, {{0xE0, 0x52}, {0x00, 0xA2}, {0xE0, 0x92}, {0xE0, 0x52}}},
128 {0x53, {{0xE0, 0x53}, {0x00, 0xA3}, {0xE0, 0x93}, {0xE0, 0x53}}},
131 static BOOL
handle_enhanced_keys(INPUT_RECORD
*ir
, unsigned char *ch1
, unsigned char *ch2
)
135 for (i
= 0; i
< ARRAY_SIZE(enh_map
); i
++)
137 if (ir
->Event
.KeyEvent
.wVirtualScanCode
== enh_map
[i
].vk
)
141 if (ir
->Event
.KeyEvent
.dwControlKeyState
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
))
143 else if (ir
->Event
.KeyEvent
.dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
) )
145 else if (ir
->Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
)
150 *ch1
= enh_map
[i
].ch
[idx
][0];
151 *ch2
= enh_map
[i
].ch
[idx
][1];
156 WARN("Unmapped char keyState=%x vk=%x\n",
157 ir
->Event
.KeyEvent
.dwControlKeyState
, ir
->Event
.KeyEvent
.wVirtualScanCode
);
161 /*********************************************************************
162 * _getch_nolock (MSVCR80.@)
164 int CDECL
_getch_nolock(void)
168 if (__MSVCRT_console_buffer
!= EOF
)
170 retval
= __MSVCRT_console_buffer
;
171 __MSVCRT_console_buffer
= EOF
;
179 GetConsoleMode(msvcrt_input_console(), &mode
);
181 SetConsoleMode(msvcrt_input_console(), 0);
184 if (ReadConsoleInputA(msvcrt_input_console(), &ir
, 1, &count
))
186 /* Only interested in ASCII chars */
187 if (ir
.EventType
== KEY_EVENT
&&
188 ir
.Event
.KeyEvent
.bKeyDown
)
190 unsigned char ch1
, ch2
;
192 if (ir
.Event
.KeyEvent
.uChar
.AsciiChar
)
194 retval
= ir
.Event
.KeyEvent
.uChar
.AsciiChar
;
198 if (handle_enhanced_keys(&ir
, &ch1
, &ch2
))
201 __MSVCRT_console_buffer
= ch2
;
210 SetConsoleMode(msvcrt_input_console(), mode
);
215 /*********************************************************************
218 int CDECL
_getch(void)
223 ret
= _getch_nolock();
228 /*********************************************************************
229 * _getwch_nolock (MSVCR80.@)
231 wchar_t CDECL
_getwch_nolock(void)
233 wchar_t retval
= WEOF
;
235 if (__MSVCRT_console_buffer_w
!= WEOF
)
237 retval
= __MSVCRT_console_buffer_w
;
238 __MSVCRT_console_buffer_w
= WEOF
;
246 GetConsoleMode(msvcrt_input_console(), &mode
);
248 SetConsoleMode(msvcrt_input_console(), 0);
251 if (ReadConsoleInputW(msvcrt_input_console(), &ir
, 1, &count
))
253 /* Only interested in ASCII chars */
254 if (ir
.EventType
== KEY_EVENT
&&
255 ir
.Event
.KeyEvent
.bKeyDown
)
257 unsigned char ch1
, ch2
;
259 if (ir
.Event
.KeyEvent
.uChar
.UnicodeChar
)
261 retval
= ir
.Event
.KeyEvent
.uChar
.UnicodeChar
;
265 if (handle_enhanced_keys(&ir
, &ch1
, &ch2
))
268 __MSVCRT_console_buffer_w
= ch2
;
277 SetConsoleMode(msvcrt_input_console(), mode
);
282 /*********************************************************************
285 wchar_t CDECL
_getwch(void)
290 ret
= _getwch_nolock();
295 /*********************************************************************
296 * _putch_nolock (MSVCR80.@)
298 int CDECL
_putch_nolock(int c
)
301 if (WriteConsoleA(msvcrt_output_console(), &c
, 1, &count
, NULL
) && count
== 1)
306 /*********************************************************************
309 int CDECL
_putch(int c
)
312 c
= _putch_nolock(c
);
317 /*********************************************************************
318 * _putwch_nolock (MSVCR80.@)
320 wchar_t CDECL
_putwch_nolock(wchar_t c
)
323 if (WriteConsoleW(msvcrt_output_console(), &c
, 1, &count
, NULL
) && count
==1)
328 /*********************************************************************
331 wchar_t CDECL
_putwch(wchar_t c
)
334 c
= _putwch_nolock(c
);
339 /*********************************************************************
340 * _getche_nolock (MSVCR80.@)
342 int CDECL
_getche_nolock(void)
345 retval
= _getch_nolock();
347 retval
= _putch_nolock(retval
);
351 /*********************************************************************
354 int CDECL
_getche(void)
359 ret
= _getche_nolock();
364 /*********************************************************************
365 * _getwche_nolock (MSVCR80.@)
367 wchar_t CDECL
_getwche_nolock(void)
370 wch
= _getch_nolock();
373 return _putwch_nolock(wch
);
376 /*********************************************************************
377 * _getwche (MSVCRT.@)
379 wchar_t CDECL
_getwche(void)
384 ret
= _getwche_nolock();
389 /*********************************************************************
392 char* CDECL
_cgets(char* str
)
398 TRACE("(%p)\n", str
);
399 str
[1] = 0; /* Length */
401 GetConsoleMode(msvcrt_input_console(), &conmode
);
402 SetConsoleMode(msvcrt_input_console(), ENABLE_LINE_INPUT
|ENABLE_ECHO_INPUT
|ENABLE_PROCESSED_INPUT
);
404 if(ReadConsoleA(msvcrt_input_console(), buf
, str
[0], &got
, NULL
)) {
405 if(buf
[got
-2] == '\r') {
409 else if(got
== 1 && buf
[got
-1] == '\n') {
413 else if(got
== str
[0] && buf
[got
-1] == '\r') {
422 SetConsoleMode(msvcrt_input_console(), conmode
);
427 /*********************************************************************
428 * _ungetch_nolock (MSVCRT.@)
430 int CDECL
_ungetch_nolock(int c
)
433 if (c
!= EOF
&& __MSVCRT_console_buffer
== EOF
)
434 retval
= __MSVCRT_console_buffer
= c
;
438 /*********************************************************************
439 * _ungetch (MSVCRT.@)
441 int CDECL
_ungetch(int c
)
444 c
= _ungetch_nolock(c
);
449 /*********************************************************************
450 * _ungetwch_nolock (MSVCR80.@)
452 wchar_t CDECL
_ungetwch_nolock(wchar_t c
)
454 wchar_t retval
= WEOF
;
455 if (c
!= WEOF
&& __MSVCRT_console_buffer_w
== WEOF
)
456 retval
= __MSVCRT_console_buffer_w
= c
;
460 /*********************************************************************
461 * _ungetwch (MSVCRT.@)
463 wchar_t CDECL
_ungetwch(wchar_t c
)
466 c
= _ungetwch_nolock(c
);
471 /*********************************************************************
474 int CDECL
_kbhit(void)
479 if (__MSVCRT_console_buffer
!= EOF
)
483 /* FIXME: There has to be a faster way than this in Win32.. */
484 INPUT_RECORD
*ir
= NULL
;
487 GetNumberOfConsoleInputEvents(msvcrt_input_console(), &count
);
489 if (count
&& (ir
= malloc(count
* sizeof(INPUT_RECORD
))) &&
490 PeekConsoleInputA(msvcrt_input_console(), ir
, count
, &count
))
491 for(i
= 0; i
< count
- 1; i
++)
493 if (ir
[i
].EventType
== KEY_EVENT
&&
494 ir
[i
].Event
.KeyEvent
.bKeyDown
&&
495 ir
[i
].Event
.KeyEvent
.uChar
.AsciiChar
)
507 static int puts_clbk_console_a(void *ctx
, int len
, const char *str
)
510 if(!WriteConsoleA(msvcrt_output_console(), str
, len
, NULL
, NULL
))
516 static int puts_clbk_console_w(void *ctx
, int len
, const wchar_t *str
)
519 if(!WriteConsoleW(msvcrt_output_console(), str
, len
, NULL
, NULL
))
525 /*********************************************************************
526 * _vcprintf (MSVCRT.@)
528 int CDECL
_vcprintf(const char* format
, __ms_va_list valist
)
530 return pf_printf_a(puts_clbk_console_a
, NULL
, format
, NULL
, 0, arg_clbk_valist
, NULL
, &valist
);
533 /*********************************************************************
534 * _cprintf (MSVCRT.@)
536 int WINAPIV
_cprintf(const char* format
, ...)
541 __ms_va_start( valist
, format
);
542 retval
= _vcprintf(format
, valist
);
549 /*********************************************************************
550 * _vcwprintf (MSVCRT.@)
552 int CDECL
_vcwprintf(const wchar_t* format
, __ms_va_list valist
)
554 return pf_printf_w(puts_clbk_console_w
, NULL
, format
, NULL
, 0, arg_clbk_valist
, NULL
, &valist
);
557 /*********************************************************************
558 * _cwprintf (MSVCRT.@)
560 int WINAPIV
_cwprintf(const wchar_t* format
, ...)
565 __ms_va_start( valist
, format
);
566 retval
= _vcwprintf(format
, valist
);
574 /*********************************************************************
575 * __conio_common_vcprintf (UCRTBASE.@)
577 int CDECL
__conio_common_vcprintf(unsigned __int64 options
, const char* format
,
578 _locale_t locale
, __ms_va_list valist
)
580 if (options
& ~UCRTBASE_PRINTF_MASK
)
581 FIXME("options %s not handled\n", wine_dbgstr_longlong(options
));
582 return pf_printf_a(puts_clbk_console_a
, NULL
, format
, locale
,
583 options
& UCRTBASE_PRINTF_MASK
, arg_clbk_valist
, NULL
, &valist
);
586 /*********************************************************************
587 * __conio_common_vcwprintf (UCRTBASE.@)
589 int CDECL
__conio_common_vcwprintf(unsigned __int64 options
, const wchar_t* format
,
590 _locale_t locale
, __ms_va_list valist
)
592 if (options
& ~UCRTBASE_PRINTF_MASK
)
593 FIXME("options %s not handled\n", wine_dbgstr_longlong(options
));
594 return pf_printf_w(puts_clbk_console_w
, NULL
, format
, locale
,
595 options
& UCRTBASE_PRINTF_MASK
, arg_clbk_valist
, NULL
, &valist
);
598 #endif /* _MSVCR_VER>=140 */