Added FIXME comment for entry point parameter.
[wine] / win32 / console.c
1 /*
2  * Win32 kernel functions
3  *
4  * Copyright 1995 Martin von Loewis and Cameron Heide
5  * Copyright 1997 Karl Garrison
6  * Copyright 1998 John Richardson
7  * Copyright 1998 Marcus Meissner
8  */
9
10 /* FIXME:
11  * - Completely lacks SCREENBUFFER interface.
12  * - No abstraction for something other than xterm.
13  * - Key input translation shouldn't use VkKeyScan and MapVirtualKey, since
14  *   they are window (USER) driver dependend.
15  * - Output sometimes is buffered (We switched off buffering by ~ICANON ?)
16  */
17 /* Reference applications:
18  * -  IDA (interactive disassembler) full version 3.75. Works.
19  * -  LYNX/W32. Works mostly, some keys crash it.
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <termios.h>
28 #include <string.h>
29 #include <sys/ioctl.h>
30 #include <sys/types.h>
31 #include <sys/time.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #ifdef HAVE_SYS_ERRNO_H
35 #include <sys/errno.h>
36 #endif
37 #include <signal.h>
38 #include <assert.h>
39
40 #include "winbase.h"
41 #include "windef.h"
42 #include "wingdi.h"
43 #include "wine/winuser16.h"
44 #include "wine/keyboard16.h"
45 #include "thread.h"
46 #include "file.h"
47 #include "process.h"
48 #include "winerror.h"
49 #include "wincon.h"
50 #include "heap.h"
51 #include "server.h"
52 #include "debugtools.h"
53
54 DEFAULT_DEBUG_CHANNEL(console)
55
56
57 /* FIXME:  Should be in an internal header file.  OK, so which one?
58    Used by CONSOLE_makecomplex. */
59 int wine_openpty(int *master, int *slave, char *name,
60                  struct termios *term, struct winsize *winsize);
61
62 /****************************************************************************
63  *              CONSOLE_GetPid
64  */
65 static int CONSOLE_GetPid( HANDLE handle )
66 {
67     struct get_console_info_request *req = get_req_buffer();
68     req->handle = handle;
69     if (server_call( REQ_GET_CONSOLE_INFO )) return 0;
70     return req->pid;
71 }
72
73 /****************************************************************************
74  *              XTERM_string_to_IR                      [internal]
75  *
76  * Transfers a string read from XTERM to INPUT_RECORDs and adds them to the
77  * queue. Does translation of vt100 style function keys and xterm-mouse clicks.
78  */
79 static void
80 CONSOLE_string_to_IR( HANDLE hConsoleInput,unsigned char *buf,int len) {
81     int                 j,k;
82     INPUT_RECORD        ir;
83     DWORD               junk;
84
85     for (j=0;j<len;j++) {
86         unsigned char inchar = buf[j];
87
88         if (inchar!=27) { /* no escape -> 'normal' keyboard event */
89             ir.EventType = 1; /* Key_event */
90
91             ir.Event.KeyEvent.bKeyDown          = 1;
92             ir.Event.KeyEvent.wRepeatCount      = 0;
93
94             ir.Event.KeyEvent.dwControlKeyState = 0;
95             if (inchar & 0x80) {
96                 ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
97                 inchar &= ~0x80;
98             }
99             ir.Event.KeyEvent.wVirtualKeyCode = VkKeyScan16(inchar);
100             if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0100)
101                 ir.Event.KeyEvent.dwControlKeyState|=SHIFT_PRESSED;
102             if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0200)
103                 ir.Event.KeyEvent.dwControlKeyState|=LEFT_CTRL_PRESSED;
104             if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0400)
105                 ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
106             ir.Event.KeyEvent.wVirtualScanCode = MapVirtualKey16(
107                 ir.Event.KeyEvent.wVirtualKeyCode & 0x00ff,
108                 0 /* VirtualKeyCodes to ScanCode */
109             );
110             ir.Event.KeyEvent.uChar.AsciiChar = inchar;
111
112             if ((inchar==127)||(inchar=='\b')) { /* backspace */
113                 ir.Event.KeyEvent.uChar.AsciiChar = '\b'; /* FIXME: hmm */
114                 ir.Event.KeyEvent.wVirtualScanCode = 0x0e;
115                 ir.Event.KeyEvent.wVirtualKeyCode = VK_BACK;
116             } else {
117                 if ((inchar=='\n')||(inchar=='\r')) {
118                     ir.Event.KeyEvent.uChar.AsciiChar   = '\r';
119                     ir.Event.KeyEvent.wVirtualKeyCode   = VK_RETURN;
120                     ir.Event.KeyEvent.wVirtualScanCode  = 0x1c;
121                     ir.Event.KeyEvent.dwControlKeyState = 0;
122                 } else {
123                     if (inchar<' ') {
124                         /* FIXME: find good values for ^X */
125                         ir.Event.KeyEvent.wVirtualKeyCode = 0xdead;
126                         ir.Event.KeyEvent.wVirtualScanCode = 0xbeef;
127                     } 
128                 }
129             }
130
131             assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
132             ir.Event.KeyEvent.bKeyDown = 0;
133             assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
134             continue;
135         }
136         /* inchar is ESC */
137         if ((j==len-1) || (buf[j+1]!='[')) {/* add ESCape on its own */
138             ir.EventType = 1; /* Key_event */
139             ir.Event.KeyEvent.bKeyDown          = 1;
140             ir.Event.KeyEvent.wRepeatCount      = 0;
141
142             ir.Event.KeyEvent.wVirtualKeyCode   = VkKeyScan16(27);
143             ir.Event.KeyEvent.wVirtualScanCode  = MapVirtualKey16(
144                 ir.Event.KeyEvent.wVirtualKeyCode,0
145             );
146             ir.Event.KeyEvent.dwControlKeyState = 0;
147             ir.Event.KeyEvent.uChar.AsciiChar   = 27;
148             assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
149             ir.Event.KeyEvent.bKeyDown = 0;
150             assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
151             continue;
152         }
153         for (k=j;k<len;k++) {
154             if (((buf[k]>='A') && (buf[k]<='Z')) ||
155                 ((buf[k]>='a') && (buf[k]<='z')) ||
156                  (buf[k]=='~')
157             )
158                 break;
159         }
160         if (k<len) {
161             int subid,scancode=0;
162
163             ir.EventType                        = 1; /* Key_event */
164             ir.Event.KeyEvent.bKeyDown          = 1;
165             ir.Event.KeyEvent.wRepeatCount      = 0;
166             ir.Event.KeyEvent.dwControlKeyState = 0;
167
168             ir.Event.KeyEvent.wVirtualKeyCode   = 0xad; /* FIXME */
169             ir.Event.KeyEvent.wVirtualScanCode  = 0xad; /* FIXME */
170             ir.Event.KeyEvent.uChar.AsciiChar   = 0;
171
172             switch (buf[k]) {
173             case '~':
174                 sscanf(&buf[j+2],"%d",&subid);
175                 switch (subid) {
176                 case  2:/*INS */scancode = 0xe052;break;
177                 case  3:/*DEL */scancode = 0xe053;break;
178                 case  6:/*PGDW*/scancode = 0xe051;break;
179                 case  5:/*PGUP*/scancode = 0xe049;break;
180                 case 11:/*F1  */scancode = 0x003b;break;
181                 case 12:/*F2  */scancode = 0x003c;break;
182                 case 13:/*F3  */scancode = 0x003d;break;
183                 case 14:/*F4  */scancode = 0x003e;break;
184                 case 15:/*F5  */scancode = 0x003f;break;
185                 case 17:/*F6  */scancode = 0x0040;break;
186                 case 18:/*F7  */scancode = 0x0041;break;
187                 case 19:/*F8  */scancode = 0x0042;break;
188                 case 20:/*F9  */scancode = 0x0043;break;
189                 case 21:/*F10 */scancode = 0x0044;break;
190                 case 23:/*F11 */scancode = 0x00d9;break;
191                 case 24:/*F12 */scancode = 0x00da;break;
192                 /* FIXME: Shift-Fx */
193                 default:
194                         FIXME("parse ESC[%d~\n",subid);
195                         break;
196                 }
197                 break;
198             case 'A': /* Cursor Up    */scancode = 0xe048;break;
199             case 'B': /* Cursor Down  */scancode = 0xe050;break;
200             case 'D': /* Cursor Left  */scancode = 0xe04b;break;
201             case 'C': /* Cursor Right */scancode = 0xe04d;break;
202             case 'F': /* End          */scancode = 0xe04f;break;
203             case 'H': /* Home         */scancode = 0xe047;break;
204             case 'M':
205                 /* Mouse Button Press  (ESCM<button+'!'><x+'!'><y+'!'>) or
206                  *              Release (ESCM#<x+'!'><y+'!'>
207                  */
208                 if (k<len-3) {
209                     ir.EventType                        = MOUSE_EVENT;
210                     ir.Event.MouseEvent.dwMousePosition.x = buf[k+2]-'!';
211                     ir.Event.MouseEvent.dwMousePosition.y = buf[k+3]-'!';
212                     if (buf[k+1]=='#')
213                         ir.Event.MouseEvent.dwButtonState = 0;
214                     else
215                         ir.Event.MouseEvent.dwButtonState = 1<<(buf[k+1]-' ');
216                     ir.Event.MouseEvent.dwEventFlags      = 0; /* FIXME */
217                     assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk));
218                     j=k+3;
219                 }
220                 break;
221             case 'c':
222                 j=k;
223                 break;
224             }
225             if (scancode) {
226                 ir.Event.KeyEvent.wVirtualScanCode = scancode;
227                 ir.Event.KeyEvent.wVirtualKeyCode = MapVirtualKey16(scancode,1);
228                 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
229                 ir.Event.KeyEvent.bKeyDown              = 0;
230                 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
231                 j=k;
232                 continue;
233             }
234         }
235     }
236 }
237
238 /****************************************************************************
239  *              CONSOLE_get_input               (internal)
240  *
241  * Reads (nonblocking) as much input events as possible and stores them
242  * in an internal queue.
243  */
244 static void
245 CONSOLE_get_input( HANDLE handle, BOOL blockwait )
246 {
247     char        *buf = HeapAlloc(GetProcessHeap(),0,1);
248     int         len = 0, escape_seen = 0;
249
250     while (1)
251     {
252         DWORD res;
253         char inchar;
254
255         /* If we have at one time seen escape in this loop, we are 
256          * within an Escape sequence, so wait for a bit more input for the
257          * rest of the loop.
258          */
259         if (WaitForSingleObject( handle, escape_seen*10 )) break;
260         if (!ReadFile( handle, &inchar, 1, &res, NULL )) break;
261         if (!res) /* res 0 but readable means EOF? Hmm. */
262                 break;
263         buf = HeapReAlloc(GetProcessHeap(),0,buf,len+1);
264         buf[len++]=inchar;
265         if (inchar == 27) {
266                 if (len>1) {
267                         /* If we spot an ESC, we flush all up to it
268                          * since we can be sure that we have a complete
269                          * sequence.
270                          */
271                         CONSOLE_string_to_IR(handle,buf,len-1);
272                         buf = HeapReAlloc(GetProcessHeap(),0,buf,1);
273                         buf[0] = 27;
274                         len = 1;
275                 }
276                 escape_seen = 1;
277         }
278     }
279     CONSOLE_string_to_IR(handle,buf,len);
280     HeapFree(GetProcessHeap(),0,buf);
281 }
282
283 /******************************************************************************
284  * SetConsoleCtrlHandler [KERNEL32.459]  Adds function to calling process list
285  *
286  * PARAMS
287  *    func [I] Address of handler function
288  *    add  [I] Handler to add or remove
289  *
290  * RETURNS
291  *    Success: TRUE
292  *    Failure: FALSE
293  *
294  * CHANGED
295  * James Sutherland (JamesSutherland@gmx.de)
296  * Added global variables console_ignore_ctrl_c and handlers[]
297  * Does not yet do any error checking, or set LastError if failed.
298  * This doesn't yet matter, since these handlers are not yet called...!
299  */
300 static unsigned int console_ignore_ctrl_c = 0;
301 static HANDLER_ROUTINE *handlers[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
302 BOOL WINAPI SetConsoleCtrlHandler( HANDLER_ROUTINE *func, BOOL add )
303 {
304   unsigned int alloc_loop = sizeof(handlers)/sizeof(HANDLER_ROUTINE *);
305   unsigned int done = 0;
306   FIXME("(%p,%i) - no error checking or testing yet\n", func, add);
307   if (!func)
308     {
309       console_ignore_ctrl_c = add;
310       return TRUE;
311     }
312   if (add)
313       {
314         for (;alloc_loop--;)
315           if (!handlers[alloc_loop] && !done)
316             {
317               handlers[alloc_loop] = func;
318               done++;
319             }
320         if (!done)
321            FIXME("Out of space on CtrlHandler table\n");
322         return(done);
323       }
324     else
325       {
326         for (;alloc_loop--;)
327           if (handlers[alloc_loop] == func && !done)
328             {
329               handlers[alloc_loop] = 0;
330               done++;
331             }
332         if (!done)
333            WARN("Attempt to remove non-installed CtrlHandler %p\n",
334                 func);
335         return (done);
336       }
337     return (done);
338 }
339
340
341 /******************************************************************************
342  * GenerateConsoleCtrlEvent [KERNEL32.275] Simulate a CTRL-C or CTRL-BREAK
343  *
344  * PARAMS
345  *    dwCtrlEvent        [I] Type of event
346  *    dwProcessGroupID   [I] Process group ID to send event to
347  *
348  * NOTES
349  *    Doesn't yet work...!
350  *
351  * RETURNS
352  *    Success: True
353  *    Failure: False (and *should* [but doesn't] set LastError)
354  */
355 BOOL WINAPI GenerateConsoleCtrlEvent( DWORD dwCtrlEvent,
356                                         DWORD dwProcessGroupID )
357 {
358   if (dwCtrlEvent != CTRL_C_EVENT && dwCtrlEvent != CTRL_BREAK_EVENT)
359     {
360       ERR("invalid event %d for PGID %ld\n", 
361            (unsigned short)dwCtrlEvent, dwProcessGroupID );
362       return FALSE;
363     }
364   if (dwProcessGroupID == GetCurrentProcessId() )
365     {
366       FIXME("Attempt to send event %d to self - stub\n",
367              (unsigned short)dwCtrlEvent );
368       return FALSE;
369     }
370   FIXME("event %d to external PGID %ld - not implemented yet\n",
371          (unsigned short)dwCtrlEvent, dwProcessGroupID );
372   return FALSE;
373 }
374
375
376 /******************************************************************************
377  * CreateConsoleScreenBuffer [KERNEL32.151]  Creates a console screen buffer
378  *
379  * PARAMS
380  *    dwDesiredAccess    [I] Access flag
381  *    dwShareMode        [I] Buffer share mode
382  *    sa                 [I] Security attributes
383  *    dwFlags            [I] Type of buffer to create
384  *    lpScreenBufferData [I] Reserved
385  *
386  * NOTES
387  *    Should call SetLastError
388  *
389  * RETURNS
390  *    Success: Handle to new console screen buffer
391  *    Failure: INVALID_HANDLE_VALUE
392  */
393 HANDLE WINAPI CreateConsoleScreenBuffer( DWORD dwDesiredAccess,
394                 DWORD dwShareMode, LPSECURITY_ATTRIBUTES sa,
395                 DWORD dwFlags, LPVOID lpScreenBufferData )
396 {
397     FIXME("(%ld,%ld,%p,%ld,%p): stub\n",dwDesiredAccess,
398           dwShareMode, sa, dwFlags, lpScreenBufferData);
399     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
400     return INVALID_HANDLE_VALUE;
401 }
402
403
404 /***********************************************************************
405  *           GetConsoleScreenBufferInfo   (KERNEL32.190)
406  */
407 BOOL WINAPI GetConsoleScreenBufferInfo( HANDLE hConsoleOutput,
408                                           LPCONSOLE_SCREEN_BUFFER_INFO csbi )
409 {
410     csbi->dwSize.x = 80;
411     csbi->dwSize.y = 24;
412     csbi->dwCursorPosition.x = 0;
413     csbi->dwCursorPosition.y = 0;
414     csbi->wAttributes = 0;
415     csbi->srWindow.Left = 0;
416     csbi->srWindow.Right        = 79;
417     csbi->srWindow.Top  = 0;
418     csbi->srWindow.Bottom       = 23;
419     csbi->dwMaximumWindowSize.x = 80;
420     csbi->dwMaximumWindowSize.y = 24;
421     return TRUE;
422 }
423
424
425 /******************************************************************************
426  * SetConsoleActiveScreenBuffer [KERNEL32.623]  Sets buffer to current console
427  *
428  * RETURNS
429  *    Success: TRUE
430  *    Failure: FALSE
431  */
432 BOOL WINAPI SetConsoleActiveScreenBuffer(
433     HANDLE hConsoleOutput) /* [in] Handle to console screen buffer */
434 {
435     FIXME("(%x): stub\n", hConsoleOutput);
436     return FALSE;
437 }
438
439
440 /***********************************************************************
441  *            GetLargestConsoleWindowSize   (KERNEL32.226)
442  */
443 DWORD WINAPI GetLargestConsoleWindowSize( HANDLE hConsoleOutput )
444 {
445     return (DWORD)MAKELONG(80,24);
446 }
447
448 /***********************************************************************
449  *            FreeConsole (KERNEL32.267)
450  */
451 BOOL WINAPI FreeConsole(VOID)
452 {
453     return !server_call( REQ_FREE_CONSOLE );
454 }
455
456
457 /*************************************************************************
458  *              CONSOLE_OpenHandle
459  *
460  * Open a handle to the current process console.
461  */
462 HANDLE CONSOLE_OpenHandle( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
463 {
464     int ret = -1;
465     struct open_console_request *req = get_req_buffer();
466
467     req->output  = output;
468     req->access  = access;
469     req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
470     SetLastError(0);
471     if (!server_call( REQ_OPEN_CONSOLE )) ret = req->handle;
472     return ret;
473 }
474
475
476 /*************************************************************************
477  *              CONSOLE_make_complex                    [internal]
478  *
479  * Turns a CONSOLE kernel object into a complex one.
480  * (switches from output/input using the terminal where WINE was started to 
481  * its own xterm).
482  * 
483  * This makes simple commandline tools pipeable, while complex commandline 
484  * tools work without getting messed up by debugoutput.
485  * 
486  * All other functions should work indedependend from this call.
487  *
488  * To test for complex console: pid == 0 -> simple, otherwise complex.
489  */
490 static BOOL CONSOLE_make_complex(HANDLE handle)
491 {
492         struct set_console_fd_request *req = get_req_buffer();
493         struct termios term;
494         char buf[256];
495         char c = '\0';
496         int i,xpid,master,slave,pty_handle;
497
498         if (CONSOLE_GetPid( handle )) return TRUE; /* already complex */
499
500         MESSAGE("Console: Making console complex (creating an xterm)...\n");
501
502         if (tcgetattr(0, &term) < 0) {
503                 /* ignore failure, or we can't run from a script */
504         }
505         term.c_lflag = ~(ECHO|ICANON);
506
507         if (wine_openpty(&master, &slave, NULL, &term, NULL) < 0)
508             return FALSE;
509
510         if ((xpid=fork()) == 0) {
511                 tcsetattr(slave, TCSADRAIN, &term);
512                 close( slave );
513                 sprintf(buf, "-Sxx%d", master);
514                 /* "-fn vga" for VGA font. Harmless if vga is not present:
515                  *  xterm: unable to open font "vga", trying "fixed".... 
516                  */
517                 execlp("xterm", "xterm", buf, "-fn","vga",NULL);
518                 ERR("error creating AllocConsole xterm\n");
519                 exit(1);
520         }
521         pty_handle = FILE_DupUnixHandle( slave, GENERIC_READ | GENERIC_WRITE );
522         close( master );
523         close( slave );
524         if (pty_handle == -1) return FALSE;
525
526         /* most xterms like to print their window ID when used with -S;
527          * read it and continue before the user has a chance...
528          */
529         for (i = 0; i < 10000; i++)
530         {
531             BOOL ok = ReadFile( pty_handle, &c, 1, NULL, NULL );
532             if (!ok && !c) usleep(100); /* wait for xterm to be created */
533             else if (c == '\n') break;
534         }
535         if (i == 10000)
536         {
537             ERR("can't read xterm WID\n");
538             CloseHandle( pty_handle );
539             return FALSE;
540         }
541         req->handle = handle;
542         req->file_handle = pty_handle;
543         req->pid = xpid;
544         server_call( REQ_SET_CONSOLE_FD );
545         CloseHandle( pty_handle );
546
547         /* enable mouseclicks */
548         strcpy( buf, "\033[?1001s\033[?1000h" );
549         WriteFile(handle,buf,strlen(buf),NULL,NULL);
550
551         strcpy( buf, "\033]2;" );
552         if (GetConsoleTitleA( buf + 4, sizeof(buf) - 5 ))
553         {
554             strcat( buf, "\a" );
555             WriteFile(handle,buf,strlen(buf),NULL,NULL);
556         }
557         return TRUE;
558
559 }
560
561
562 /***********************************************************************
563  *            AllocConsole (KERNEL32.103)
564  *
565  * creates an xterm with a pty to our program
566  */
567 BOOL WINAPI AllocConsole(VOID)
568 {
569     struct alloc_console_request *req = get_req_buffer();
570     HANDLE hStderr;
571     int handle_in, handle_out;
572
573     TRACE("()\n");
574     req->access  = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
575     req->inherit = FALSE;
576     if (server_call( REQ_ALLOC_CONSOLE )) return FALSE;
577     handle_in = req->handle_in;
578     handle_out = req->handle_out;
579
580     if (!DuplicateHandle( GetCurrentProcess(), req->handle_out, GetCurrentProcess(), &hStderr,
581                           0, TRUE, DUPLICATE_SAME_ACCESS ))
582     {
583         CloseHandle( handle_in );
584         CloseHandle( handle_out );
585         FreeConsole();
586         return FALSE;
587     }
588
589     /* NT resets the STD_*_HANDLEs on console alloc */
590     SetStdHandle( STD_INPUT_HANDLE, handle_in );
591     SetStdHandle( STD_OUTPUT_HANDLE, handle_out );
592     SetStdHandle( STD_ERROR_HANDLE, hStderr );
593
594     SetLastError(ERROR_SUCCESS);
595     SetConsoleTitleA("Wine Console");
596     return TRUE;
597 }
598
599
600 /******************************************************************************
601  * GetConsoleCP [KERNEL32.295]  Returns the OEM code page for the console
602  *
603  * RETURNS
604  *    Code page code
605  */
606 UINT WINAPI GetConsoleCP(VOID)
607 {
608     return GetACP();
609 }
610
611
612 /***********************************************************************
613  *            GetConsoleOutputCP   (KERNEL32.189)
614  */
615 UINT WINAPI GetConsoleOutputCP(VOID)
616 {
617     return GetConsoleCP();
618 }
619
620 /***********************************************************************
621  *            GetConsoleMode   (KERNEL32.188)
622  */
623 BOOL WINAPI GetConsoleMode(HANDLE hcon,LPDWORD mode)
624 {
625     BOOL ret = FALSE;
626     struct get_console_mode_request *req = get_req_buffer();
627     req->handle = hcon;
628     if (!server_call( REQ_GET_CONSOLE_MODE ))
629     {
630         if (mode) *mode = req->mode;
631         ret = TRUE;
632     }
633     return ret;
634 }
635
636
637 /******************************************************************************
638  * SetConsoleMode [KERNEL32.628]  Sets input mode of console's input buffer
639  *
640  * PARAMS
641  *    hcon [I] Handle to console input or screen buffer
642  *    mode [I] Input or output mode to set
643  *
644  * RETURNS
645  *    Success: TRUE
646  *    Failure: FALSE
647  */
648 BOOL WINAPI SetConsoleMode( HANDLE hcon, DWORD mode )
649 {
650     struct set_console_mode_request *req = get_req_buffer();
651     req->handle = hcon;
652     req->mode = mode;
653     return !server_call( REQ_SET_CONSOLE_MODE );
654 }
655
656
657 /***********************************************************************
658  *            GetConsoleTitleA   (KERNEL32.191)
659  */
660 DWORD WINAPI GetConsoleTitleA(LPSTR title,DWORD size)
661 {
662     struct get_console_info_request *req = get_req_buffer();
663     DWORD ret = 0;
664     HANDLE hcon;
665
666     if ((hcon = CreateFileA( "CONOUT$", GENERIC_READ, 0, NULL,
667                                OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
668         return 0;
669     req->handle = hcon;
670     if (!server_call( REQ_GET_CONSOLE_INFO ))
671     {
672         lstrcpynA( title, req->title, size );
673         ret = strlen(req->title);
674     }
675     CloseHandle( hcon );
676     return ret;
677 }
678
679
680 /******************************************************************************
681  * GetConsoleTitle32W [KERNEL32.192]  Retrieves title string for console
682  *
683  * PARAMS
684  *    title [O] Address of buffer for title
685  *    size  [I] Size of buffer
686  *
687  * RETURNS
688  *    Success: Length of string copied
689  *    Failure: 0
690  */
691 DWORD WINAPI GetConsoleTitleW( LPWSTR title, DWORD size )
692 {
693     char *tmp;
694     DWORD ret;
695
696     if (!(tmp = HeapAlloc( GetProcessHeap(), 0, size ))) return 0;
697     ret = GetConsoleTitleA( tmp, size );
698     lstrcpyAtoW( title, tmp );
699     HeapFree( GetProcessHeap(), 0, tmp );
700     return ret;
701 }
702
703
704 /***********************************************************************
705  *            WriteConsoleA   (KERNEL32.729)
706  */
707 BOOL WINAPI WriteConsoleA( HANDLE hConsoleOutput,
708                                LPCVOID lpBuffer,
709                                DWORD nNumberOfCharsToWrite,
710                                LPDWORD lpNumberOfCharsWritten,
711                                LPVOID lpReserved )
712 {
713         /* FIXME: should I check if this is a console handle? */
714         return WriteFile(hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
715                          lpNumberOfCharsWritten, NULL);
716 }
717
718
719 #define CADD(c)                                                         \
720         if (bufused==curbufsize-1)                                      \
721             buffer = HeapReAlloc(GetProcessHeap(),0,buffer,(curbufsize+=100));\
722         buffer[bufused++]=c;
723 #define SADD(s) { char *x=s;while (*x) {CADD(*x);x++;}}
724
725 /***********************************************************************
726  *            WriteConsoleOutputA   (KERNEL32.732)
727  */
728 BOOL WINAPI WriteConsoleOutputA( HANDLE hConsoleOutput,
729                                      LPCHAR_INFO lpBuffer,
730                                      COORD dwBufferSize,
731                                      COORD dwBufferCoord,
732                                      LPSMALL_RECT lpWriteRegion)
733 {
734     int i,j,off=0,lastattr=-1;
735     int offbase;
736     char        sbuf[20],*buffer=NULL;
737     int         bufused=0,curbufsize = 100;
738     DWORD       res;
739     CONSOLE_SCREEN_BUFFER_INFO csbi;
740     const int colormap[8] = {
741         0,4,2,6,
742         1,5,3,7,
743     };
744     CONSOLE_make_complex(hConsoleOutput);
745     buffer = HeapAlloc(GetProcessHeap(),0,curbufsize);
746     offbase = (dwBufferCoord.y - 1) * dwBufferSize.x +
747               (dwBufferCoord.x - lpWriteRegion->Left);
748
749     TRACE("orig rect top = %d, bottom=%d, left=%d, right=%d\n",
750         lpWriteRegion->Top,
751         lpWriteRegion->Bottom,
752         lpWriteRegion->Left,
753         lpWriteRegion->Right
754     );
755
756     GetConsoleScreenBufferInfo(hConsoleOutput, &csbi);
757     sprintf(sbuf,"%c7",27);SADD(sbuf);
758
759     /* Step 1. Make (Bottom,Right) offset of intersection with
760        Screen Buffer                                              */
761     lpWriteRegion->Bottom = min(lpWriteRegion->Bottom, csbi.dwSize.y-1) - 
762                                 lpWriteRegion->Top;
763     lpWriteRegion->Right = min(lpWriteRegion->Right, csbi.dwSize.x-1) -
764                                 lpWriteRegion->Left;
765
766     /* Step 2. If either offset is negative, then no action 
767        should be performed. (Implies that requested rectangle is
768        outside the current screen buffer rectangle.)              */
769     if ((lpWriteRegion->Bottom < 0) ||
770         (lpWriteRegion->Right < 0)) {
771         /* readjust (Bottom Right) for rectangle */
772         lpWriteRegion->Bottom += lpWriteRegion->Top;
773         lpWriteRegion->Right += lpWriteRegion->Left;
774
775         TRACE("invisible rect top = %d, bottom=%d, left=%d, right=%d\n",
776             lpWriteRegion->Top,
777             lpWriteRegion->Bottom,
778             lpWriteRegion->Left,
779             lpWriteRegion->Right
780         );
781
782         HeapFree(GetProcessHeap(),0,buffer);
783         return TRUE;
784     }
785
786     /* Step 3. Intersect with source rectangle                    */
787     lpWriteRegion->Bottom = lpWriteRegion->Top - dwBufferCoord.y +
788              min(lpWriteRegion->Bottom + dwBufferCoord.y, dwBufferSize.y-1);
789     lpWriteRegion->Right = lpWriteRegion->Left - dwBufferCoord.x +
790              min(lpWriteRegion->Right + dwBufferCoord.x, dwBufferSize.x-1);
791
792     TRACE("clipped rect top = %d, bottom=%d, left=%d,right=%d\n",
793         lpWriteRegion->Top,
794         lpWriteRegion->Bottom,
795         lpWriteRegion->Left,
796         lpWriteRegion->Right
797     );
798
799     /* Validate above computations made sense, if not then issue
800        error and fudge to single character rectangle                  */
801     if ((lpWriteRegion->Bottom < lpWriteRegion->Top) ||
802         (lpWriteRegion->Right < lpWriteRegion->Left)) {
803        ERR("Invalid clipped rectangle top = %d, bottom=%d, left=%d,right=%d\n",
804               lpWriteRegion->Top,
805               lpWriteRegion->Bottom,
806               lpWriteRegion->Left,
807               lpWriteRegion->Right
808           );
809        lpWriteRegion->Bottom = lpWriteRegion->Top;
810        lpWriteRegion->Right = lpWriteRegion->Left;
811     }
812
813     /* Now do the real processing and move the characters    */
814     for (i=lpWriteRegion->Top;i<=lpWriteRegion->Bottom;i++) {
815         offbase += dwBufferSize.x;
816         sprintf(sbuf,"%c[%d;%dH",27,i+1,lpWriteRegion->Left+1);
817         SADD(sbuf);
818         for (j=lpWriteRegion->Left;j<=lpWriteRegion->Right;j++) {
819             off = j + offbase;
820             if (lastattr!=lpBuffer[off].Attributes) {
821                 lastattr = lpBuffer[off].Attributes;
822                 sprintf(sbuf,"%c[0;%s3%d;4%dm",
823                         27,
824                         (lastattr & FOREGROUND_INTENSITY)?"1;":"",
825                         colormap[lastattr&7],
826                         colormap[(lastattr&0x70)>>4]
827                 );
828                 /* FIXME: BACKGROUND_INTENSITY */
829                 SADD(sbuf);
830             }
831             CADD(lpBuffer[off].Char.AsciiChar);
832         }
833     }
834     sprintf(sbuf,"%c[0m%c8",27,27);SADD(sbuf);
835     WriteFile(hConsoleOutput,buffer,bufused,&res,NULL);
836     HeapFree(GetProcessHeap(),0,buffer);
837     return TRUE;
838 }
839
840 /***********************************************************************
841  *            WriteConsoleW   (KERNEL32.577)
842  */
843 BOOL WINAPI WriteConsoleW( HANDLE hConsoleOutput,
844                                LPCVOID lpBuffer,
845                                DWORD nNumberOfCharsToWrite,
846                                LPDWORD lpNumberOfCharsWritten,
847                                LPVOID lpReserved )
848 {
849         BOOL ret;
850         LPSTR xstring=HeapAlloc( GetProcessHeap(), 0, nNumberOfCharsToWrite );
851
852         lstrcpynWtoA( xstring,  lpBuffer,nNumberOfCharsToWrite);
853
854         /* FIXME: should I check if this is a console handle? */
855         ret= WriteFile(hConsoleOutput, xstring, nNumberOfCharsToWrite,
856                          lpNumberOfCharsWritten, NULL);
857         HeapFree( GetProcessHeap(), 0, xstring );
858         return ret;
859 }
860
861
862 /***********************************************************************
863  *            ReadConsoleA   (KERNEL32.419)
864  */
865 BOOL WINAPI ReadConsoleA( HANDLE hConsoleInput,
866                               LPVOID lpBuffer,
867                               DWORD nNumberOfCharsToRead,
868                               LPDWORD lpNumberOfCharsRead,
869                               LPVOID lpReserved )
870 {
871     int         charsread = 0;
872     LPSTR       xbuf = (LPSTR)lpBuffer;
873     LPINPUT_RECORD      ir;
874
875     TRACE("(%d,%p,%ld,%p,%p)\n",
876             hConsoleInput,lpBuffer,nNumberOfCharsToRead,
877             lpNumberOfCharsRead,lpReserved
878     );
879
880     CONSOLE_get_input(hConsoleInput,FALSE);
881
882     /* FIXME: should we read at least 1 char? The SDK does not say */
883     while (charsread<nNumberOfCharsToRead)
884     {
885         struct read_console_input_request *req = get_req_buffer();
886         req->handle = hConsoleInput;
887         req->count = 1;
888         req->flush = 1;
889         if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
890         if (!req->read) break;
891         ir = (LPINPUT_RECORD)(req+1);
892         if (!ir->Event.KeyEvent.bKeyDown)
893                 continue;
894         if (ir->EventType != KEY_EVENT)
895                 continue;
896         *xbuf++ = ir->Event.KeyEvent.uChar.AsciiChar; 
897         charsread++;
898     }
899     if (lpNumberOfCharsRead)
900         *lpNumberOfCharsRead = charsread;
901     return TRUE;
902 }
903
904 /***********************************************************************
905  *            ReadConsoleW   (KERNEL32.427)
906  */
907 BOOL WINAPI ReadConsoleW( HANDLE hConsoleInput,
908                               LPVOID lpBuffer,
909                               DWORD nNumberOfCharsToRead,
910                               LPDWORD lpNumberOfCharsRead,
911                               LPVOID lpReserved )
912 {
913     BOOL ret;
914     LPSTR buf = (LPSTR)HeapAlloc(GetProcessHeap(), 0, nNumberOfCharsToRead);
915
916     ret = ReadConsoleA(
917         hConsoleInput,
918         buf,
919         nNumberOfCharsToRead,
920         lpNumberOfCharsRead,
921         lpReserved
922     );
923     if (ret)
924         lstrcpynAtoW(lpBuffer,buf,nNumberOfCharsToRead);
925     HeapFree( GetProcessHeap(), 0, buf );
926     return ret;
927 }
928
929
930 /******************************************************************************
931  * ReadConsoleInput32A [KERNEL32.569]  Reads data from a console
932  *
933  * PARAMS
934  *    hConsoleInput        [I] Handle to console input buffer
935  *    lpBuffer             [O] Address of buffer for read data
936  *    nLength              [I] Number of records to read
937  *    lpNumberOfEventsRead [O] Address of number of records read
938  *
939  * RETURNS
940  *    Success: TRUE
941  *    Failure: FALSE
942  */
943 BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, LPINPUT_RECORD lpBuffer,
944                               DWORD nLength, LPDWORD lpNumberOfEventsRead)
945 {
946     struct read_console_input_request *req = get_req_buffer();
947
948     /* loop until we get at least one event */
949     for (;;)
950     {
951         req->handle = hConsoleInput;
952         req->count = nLength;
953         req->flush = 1;
954         if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
955         if (req->read)
956         {
957             memcpy( lpBuffer, req + 1, req->read * sizeof(*lpBuffer) );
958             if (lpNumberOfEventsRead) *lpNumberOfEventsRead = req->read;
959             return TRUE;
960         }
961         CONSOLE_get_input(hConsoleInput,TRUE);
962         /*WaitForSingleObject( hConsoleInput, INFINITE32 );*/
963     }
964 }
965
966
967 /***********************************************************************
968  *            ReadConsoleInput32W   (KERNEL32.570)
969  */
970 BOOL WINAPI ReadConsoleInputW( HANDLE handle, LPINPUT_RECORD buffer,
971                                    DWORD count, LPDWORD read )
972 {
973     /* FIXME: Fix this if we get UNICODE input. */
974     return ReadConsoleInputA( handle, buffer, count, read );
975 }
976
977
978 /***********************************************************************
979  *            FlushConsoleInputBuffer   (KERNEL32.132)
980  */
981 BOOL WINAPI FlushConsoleInputBuffer( HANDLE handle )
982 {
983     struct read_console_input_request *req = get_req_buffer();
984     req->handle = handle;
985     req->count = -1;  /* get all records */
986     req->flush = 1;
987     return !server_call( REQ_READ_CONSOLE_INPUT );
988 }
989
990
991 /***********************************************************************
992  *            PeekConsoleInputA   (KERNEL32.550)
993  *
994  * Gets 'count' first events (or less) from input queue.
995  *
996  * Does not need a complex console.
997  */
998 BOOL WINAPI PeekConsoleInputA( HANDLE handle, LPINPUT_RECORD buffer,
999                                    DWORD count, LPDWORD read )
1000 {
1001     struct read_console_input_request *req = get_req_buffer();
1002
1003     CONSOLE_get_input(handle,FALSE);
1004
1005     req->handle = handle;
1006     req->count = count;
1007     req->flush = 0;
1008     if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
1009     if (req->read) memcpy( buffer, req + 1, req->read * sizeof(*buffer) );
1010     if (read) *read = req->read;
1011     return TRUE;
1012 }
1013
1014
1015 /***********************************************************************
1016  *            PeekConsoleInputW   (KERNEL32.551)
1017  */
1018 BOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,
1019                                   LPINPUT_RECORD pirBuffer,
1020                                   DWORD cInRecords,
1021                                   LPDWORD lpcRead)
1022 {
1023     /* FIXME: Hmm. Fix this if we get UNICODE input. */
1024     return PeekConsoleInputA(hConsoleInput,pirBuffer,cInRecords,lpcRead);
1025 }
1026
1027
1028 /******************************************************************************
1029  * WriteConsoleInput32A [KERNEL32.730]  Write data to a console input buffer
1030  *
1031  */
1032 BOOL WINAPI WriteConsoleInputA( HANDLE handle, INPUT_RECORD *buffer,
1033                                 DWORD count, LPDWORD written )
1034 {
1035     struct write_console_input_request *req = get_req_buffer();
1036     const DWORD max = server_remaining( req + 1 ) / sizeof(INPUT_RECORD);
1037
1038     if (written) *written = 0;
1039     while (count)
1040     {
1041         DWORD len = count < max ? count : max;
1042         req->count = len;
1043         req->handle = handle;
1044         memcpy( req + 1, buffer, len * sizeof(*buffer) );
1045         if (server_call( REQ_WRITE_CONSOLE_INPUT )) return FALSE;
1046         if (written) *written += req->written;
1047         count -= len;
1048         buffer += len;
1049     }
1050     return TRUE;
1051 }
1052
1053
1054 /***********************************************************************
1055  *            SetConsoleTitle32A   (KERNEL32.476)
1056  *
1057  * Sets the console title.
1058  *
1059  * We do not necessarily need to create a complex console for that,
1060  * but should remember the title and set it on creation of the latter.
1061  * (not fixed at this time).
1062  */
1063 BOOL WINAPI SetConsoleTitleA(LPCSTR title)
1064 {
1065     struct set_console_info_request *req = get_req_buffer();
1066     HANDLE hcon;
1067     DWORD written;
1068
1069     if ((hcon = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL,
1070                                OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
1071         return FALSE;
1072     req->handle = hcon;
1073     req->mask = SET_CONSOLE_INFO_TITLE;
1074     lstrcpynA( req->title, title, server_remaining(req->title) );
1075     if (server_call( REQ_SET_CONSOLE_INFO )) goto error;
1076     if (CONSOLE_GetPid( hcon ))
1077     {
1078         /* only set title for complex console (own xterm) */
1079         WriteFile( hcon, "\033]2;", 4, &written, NULL );
1080         WriteFile( hcon, title, strlen(title), &written, NULL );
1081         WriteFile( hcon, "\a", 1, &written, NULL );
1082     }
1083     CloseHandle( hcon );
1084     return TRUE;
1085  error:
1086     CloseHandle( hcon );
1087     return FALSE;
1088 }
1089
1090
1091 /******************************************************************************
1092  * SetConsoleTitle32W [KERNEL32.477]  Sets title bar string for console
1093  *
1094  * PARAMS
1095  *    title [I] Address of new title
1096  *
1097  * NOTES
1098  *    This should not be calling the A version
1099  *
1100  * RETURNS
1101  *    Success: TRUE
1102  *    Failure: FALSE
1103  */
1104 BOOL WINAPI SetConsoleTitleW( LPCWSTR title )
1105 {
1106     BOOL ret;
1107
1108     LPSTR titleA = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
1109     ret = SetConsoleTitleA(titleA);
1110     HeapFree( GetProcessHeap(), 0, titleA );
1111     return ret;
1112 }
1113
1114 /******************************************************************************
1115  * SetConsoleCursorPosition [KERNEL32.627]
1116  * Sets the cursor position in console
1117  *
1118  * PARAMS
1119  *    hConsoleOutput   [I] Handle of console screen buffer
1120  *    dwCursorPosition [I] New cursor position coordinates
1121  *
1122  * RETURNS STD
1123  */
1124 BOOL WINAPI SetConsoleCursorPosition( HANDLE hcon, COORD pos )
1125 {
1126     char        xbuf[20];
1127     DWORD       xlen;
1128
1129     /* make console complex only if we change lines, not just in the line */
1130     if (pos.y)
1131         CONSOLE_make_complex(hcon);
1132
1133     TRACE("%d (%dx%d)\n", hcon, pos.x , pos.y );
1134     /* x are columns, y rows */
1135     if (pos.y) 
1136         /* full screen cursor absolute positioning */
1137         sprintf(xbuf,"%c[%d;%dH", 0x1B, pos.y+1, pos.x+1);
1138     else
1139         /* relative cursor positioning in line (\r to go to 0) */
1140         sprintf(xbuf,"\r%c[%dC", 0x1B, pos.x);
1141     /* FIXME: store internal if we start using own console buffers */
1142     WriteFile(hcon,xbuf,strlen(xbuf),&xlen,NULL);
1143     return TRUE;
1144 }
1145
1146 /***********************************************************************
1147  *            GetNumberOfConsoleInputEvents   (KERNEL32.246)
1148  */
1149 BOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hcon,LPDWORD nrofevents)
1150 {
1151     struct read_console_input_request *req = get_req_buffer();
1152
1153     CONSOLE_get_input(hcon,FALSE);
1154
1155     req->handle = hcon;
1156     req->count = -1;
1157     req->flush = 0;
1158     if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
1159     if (nrofevents) *nrofevents = req->read;
1160     return TRUE;
1161 }
1162
1163 /***********************************************************************
1164  *            GetNumberOfConsoleMouseButtons   (KERNEL32.358)
1165  */
1166 BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons)
1167 {
1168     FIXME("(%p): stub\n", nrofbuttons);
1169     *nrofbuttons = 2;
1170     return TRUE;
1171 }
1172
1173 /******************************************************************************
1174  * GetConsoleCursorInfo32 [KERNEL32.296]  Gets size and visibility of console
1175  *
1176  * PARAMS
1177  *    hcon  [I] Handle to console screen buffer
1178  *    cinfo [O] Address of cursor information
1179  *
1180  * RETURNS
1181  *    Success: TRUE
1182  *    Failure: FALSE
1183  */
1184 BOOL WINAPI GetConsoleCursorInfo( HANDLE hcon, LPCONSOLE_CURSOR_INFO cinfo )
1185 {
1186     struct get_console_info_request *req = get_req_buffer();
1187     req->handle = hcon;
1188     if (server_call( REQ_GET_CONSOLE_INFO )) return FALSE;
1189     if (cinfo)
1190     {
1191         cinfo->dwSize = req->cursor_size;
1192         cinfo->bVisible = req->cursor_visible;
1193     }
1194     return TRUE;
1195 }
1196
1197
1198 /******************************************************************************
1199  * SetConsoleCursorInfo32 [KERNEL32.626]  Sets size and visibility of cursor
1200  *
1201  * RETURNS
1202  *    Success: TRUE
1203  *    Failure: FALSE
1204  */
1205 BOOL WINAPI SetConsoleCursorInfo( 
1206     HANDLE hcon,                /* [in] Handle to console screen buffer */
1207     LPCONSOLE_CURSOR_INFO cinfo)  /* [in] Address of cursor information */
1208 {
1209     struct set_console_info_request *req = get_req_buffer();
1210     char        buf[8];
1211     DWORD       xlen;
1212
1213     CONSOLE_make_complex(hcon);
1214     sprintf(buf,"\033[?25%c",cinfo->bVisible?'h':'l');
1215     WriteFile(hcon,buf,strlen(buf),&xlen,NULL);
1216
1217     req->handle         = hcon;
1218     req->cursor_size    = cinfo->dwSize;
1219     req->cursor_visible = cinfo->bVisible;
1220     req->mask           = SET_CONSOLE_INFO_CURSOR;
1221     return !server_call( REQ_SET_CONSOLE_INFO );
1222 }
1223
1224
1225 /******************************************************************************
1226  * SetConsoleWindowInfo [KERNEL32.634]  Sets size and position of console
1227  *
1228  * RETURNS
1229  *    Success: TRUE
1230  *    Failure: FALSE
1231  */
1232 BOOL WINAPI SetConsoleWindowInfo(
1233     HANDLE hcon,       /* [in] Handle to console screen buffer */
1234     BOOL bAbsolute,    /* [in] Coordinate type flag */
1235     LPSMALL_RECT window) /* [in] Address of new window rectangle */
1236 {
1237     FIXME("(%x,%d,%p): stub\n", hcon, bAbsolute, window);
1238     return TRUE;
1239 }
1240
1241
1242 /******************************************************************************
1243  * SetConsoleTextAttribute32 [KERNEL32.631]  Sets colors for text
1244  *
1245  * Sets the foreground and background color attributes of characters
1246  * written to the screen buffer.
1247  *
1248  * RETURNS
1249  *    Success: TRUE
1250  *    Failure: FALSE
1251  */
1252 BOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttr)
1253 {
1254     const int colormap[8] = {
1255         0,4,2,6,
1256         1,5,3,7,
1257     };
1258     DWORD xlen;
1259     char buffer[20];
1260
1261     TRACE("(%d,%d)\n",hConsoleOutput,wAttr);
1262     sprintf(buffer,"%c[0;%s3%d;4%dm",
1263         27,
1264         (wAttr & FOREGROUND_INTENSITY)?"1;":"",
1265         colormap[wAttr&7],
1266         colormap[(wAttr&0x70)>>4]
1267     );
1268     WriteFile(hConsoleOutput,buffer,strlen(buffer),&xlen,NULL);
1269     return TRUE;
1270 }
1271
1272
1273 /******************************************************************************
1274  * SetConsoleScreenBufferSize [KERNEL32.630]  Changes size of console 
1275  *
1276  * PARAMS
1277  *    hConsoleOutput [I] Handle to console screen buffer
1278  *    dwSize         [I] New size in character rows and cols
1279  *
1280  * RETURNS
1281  *    Success: TRUE
1282  *    Failure: FALSE
1283  */
1284 BOOL WINAPI SetConsoleScreenBufferSize( HANDLE hConsoleOutput, 
1285                                           COORD dwSize )
1286 {
1287     FIXME("(%d,%dx%d): stub\n",hConsoleOutput,dwSize.x,dwSize.y);
1288     return TRUE;
1289 }
1290
1291
1292 /******************************************************************************
1293  * FillConsoleOutputCharacterA [KERNEL32.242]
1294  *
1295  * PARAMS
1296  *    hConsoleOutput    [I] Handle to screen buffer
1297  *    cCharacter        [I] Character to write
1298  *    nLength           [I] Number of cells to write to
1299  *    dwCoord           [I] Coords of first cell
1300  *    lpNumCharsWritten [O] Pointer to number of cells written
1301  *
1302  * RETURNS
1303  *    Success: TRUE
1304  *    Failure: FALSE
1305  */
1306 BOOL WINAPI FillConsoleOutputCharacterA(
1307     HANDLE hConsoleOutput,
1308     BYTE cCharacter,
1309     DWORD nLength,
1310     COORD dwCoord,
1311     LPDWORD lpNumCharsWritten)
1312 {
1313     long        count;
1314     DWORD       xlen;
1315
1316     SetConsoleCursorPosition(hConsoleOutput,dwCoord);
1317     for(count=0;count<nLength;count++)
1318         WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
1319     *lpNumCharsWritten = nLength;
1320     return TRUE;
1321 }
1322
1323
1324 /******************************************************************************
1325  * FillConsoleOutputCharacterW [KERNEL32.243]  Writes characters to console
1326  *
1327  * PARAMS
1328  *    hConsoleOutput    [I] Handle to screen buffer
1329  *    cCharacter        [I] Character to write
1330  *    nLength           [I] Number of cells to write to
1331  *    dwCoord           [I] Coords of first cell
1332  *    lpNumCharsWritten [O] Pointer to number of cells written
1333  *
1334  * RETURNS
1335  *    Success: TRUE
1336  *    Failure: FALSE
1337  */
1338 BOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,
1339                                             WCHAR cCharacter,
1340                                             DWORD nLength,
1341                                            COORD dwCoord, 
1342                                             LPDWORD lpNumCharsWritten)
1343 {
1344     long        count;
1345     DWORD       xlen;
1346
1347     SetConsoleCursorPosition(hConsoleOutput,dwCoord);
1348     /* FIXME: not quite correct ... but the lower part of UNICODE char comes
1349      * first 
1350      */
1351     for(count=0;count<nLength;count++)
1352         WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
1353     *lpNumCharsWritten = nLength;
1354     return TRUE;
1355 }
1356
1357
1358 /******************************************************************************
1359  * FillConsoleOutputAttribute [KERNEL32.241]  Sets attributes for console
1360  *
1361  * PARAMS
1362  *    hConsoleOutput    [I] Handle to screen buffer
1363  *    wAttribute        [I] Color attribute to write
1364  *    nLength           [I] Number of cells to write to
1365  *    dwCoord           [I] Coords of first cell
1366  *    lpNumAttrsWritten [O] Pointer to number of cells written
1367  *
1368  * RETURNS
1369  *    Success: TRUE
1370  *    Failure: FALSE
1371  */
1372 BOOL WINAPI FillConsoleOutputAttribute( HANDLE hConsoleOutput, 
1373               WORD wAttribute, DWORD nLength, COORD dwCoord, 
1374               LPDWORD lpNumAttrsWritten)
1375 {
1376     FIXME("(%d,%d,%ld,%dx%d,%p): stub\n", hConsoleOutput,
1377           wAttribute,nLength,dwCoord.x,dwCoord.y,lpNumAttrsWritten);
1378     *lpNumAttrsWritten = nLength;
1379     return TRUE;
1380 }
1381
1382 /******************************************************************************
1383  * ReadConsoleOutputCharacter32A [KERNEL32.573]
1384  * 
1385  * BUGS
1386  *   Unimplemented
1387  */
1388 BOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput, 
1389               LPSTR lpstr, DWORD dword, COORD coord, LPDWORD lpdword)
1390 {
1391     FIXME("(%d,%p,%ld,%dx%d,%p): stub\n", hConsoleOutput,lpstr,
1392           dword,coord.x,coord.y,lpdword);
1393     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1394     return FALSE;
1395 }
1396
1397
1398 /******************************************************************************
1399  * ScrollConsoleScreenBuffer [KERNEL32.612]
1400  * 
1401  * BUGS
1402  *   Unimplemented
1403  */
1404 BOOL WINAPI ScrollConsoleScreenBuffer( HANDLE hConsoleOutput, 
1405               LPSMALL_RECT lpScrollRect, LPSMALL_RECT lpClipRect,
1406               COORD dwDestOrigin, LPCHAR_INFO lpFill)
1407 {
1408     FIXME("(%d,%p,%p,%dx%d,%p): stub\n", hConsoleOutput,lpScrollRect,
1409           lpClipRect,dwDestOrigin.x,dwDestOrigin.y,lpFill);
1410     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1411     return FALSE;
1412 }