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