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