2 * Win32 kernel functions
4 * Copyright 1995 Martin von Loewis and Cameron Heide
5 * Copyright 1997 Karl Garrison
6 * Copyright 1998 John Richardson
7 * Copyright 1998 Marcus Meissner
11 * - Completely lacks SCREENBUFFER interface.
12 * - No abstraction for something other than xterm.
13 * - Key input translation shouldn't use VkKeyScan and MapVirtualKey, since
14 * they are window (USER) driver dependend.
15 * - Output sometimes is buffered (We switched off buffering by ~ICANON ?)
17 /* Reference applications:
18 * - IDA (interactive disassembler) full version 3.75. Works.
19 * - LYNX/W32. Works mostly, some keys crash it.
28 #include <sys/ioctl.h>
29 #include <sys/types.h>
33 #ifdef HAVE_SYS_ERRNO_H
34 #include <sys/errno.h>
40 #include "wine/winuser16.h"
41 #include "wine/keyboard16.h"
49 #include "debugtools.h"
51 DEFAULT_DEBUG_CHANNEL(console)
54 /* FIXME: Should be in an internal header file. OK, so which one?
55 Used by CONSOLE_makecomplex. */
56 int wine_openpty(int *master, int *slave, char *name,
57 struct termios *term, struct winsize *winsize);
59 /****************************************************************************
62 static int CONSOLE_GetPid( HANDLE handle )
64 struct get_console_info_request *req = get_req_buffer();
66 if (server_call( REQ_GET_CONSOLE_INFO )) return 0;
70 /****************************************************************************
71 * XTERM_string_to_IR [internal]
73 * Transfers a string read from XTERM to INPUT_RECORDs and adds them to the
74 * queue. Does translation of vt100 style function keys and xterm-mouse clicks.
77 CONSOLE_string_to_IR( HANDLE hConsoleInput,unsigned char *buf,int len) {
83 unsigned char inchar = buf[j];
85 if (inchar!=27) { /* no escape -> 'normal' keyboard event */
86 ir.EventType = 1; /* Key_event */
88 ir.Event.KeyEvent.bKeyDown = 1;
89 ir.Event.KeyEvent.wRepeatCount = 0;
91 ir.Event.KeyEvent.dwControlKeyState = 0;
93 ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
96 ir.Event.KeyEvent.wVirtualKeyCode = VkKeyScan16(inchar);
97 if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0100)
98 ir.Event.KeyEvent.dwControlKeyState|=SHIFT_PRESSED;
99 if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0200)
100 ir.Event.KeyEvent.dwControlKeyState|=LEFT_CTRL_PRESSED;
101 if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0400)
102 ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
103 ir.Event.KeyEvent.wVirtualScanCode = MapVirtualKey16(
104 ir.Event.KeyEvent.wVirtualKeyCode & 0x00ff,
105 0 /* VirtualKeyCodes to ScanCode */
107 ir.Event.KeyEvent.uChar.AsciiChar = inchar;
109 if (inchar==127) { /* backspace */
110 ir.Event.KeyEvent.uChar.AsciiChar = '\b'; /* FIXME: hmm */
111 ir.Event.KeyEvent.wVirtualScanCode = 0x0e;
112 ir.Event.KeyEvent.wVirtualKeyCode = VK_BACK;
114 if ((inchar=='\n')||(inchar=='\r')) {
115 ir.Event.KeyEvent.uChar.AsciiChar = '\r';
116 ir.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
117 ir.Event.KeyEvent.wVirtualScanCode = 0x1c;
118 ir.Event.KeyEvent.dwControlKeyState = 0;
121 /* FIXME: find good values for ^X */
122 ir.Event.KeyEvent.wVirtualKeyCode = 0xdead;
123 ir.Event.KeyEvent.wVirtualScanCode = 0xbeef;
128 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
129 ir.Event.KeyEvent.bKeyDown = 0;
130 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
134 if ((j==len-1) || (buf[j+1]!='[')) {/* add ESCape on its own */
135 ir.EventType = 1; /* Key_event */
136 ir.Event.KeyEvent.bKeyDown = 1;
137 ir.Event.KeyEvent.wRepeatCount = 0;
139 ir.Event.KeyEvent.wVirtualKeyCode = VkKeyScan16(27);
140 ir.Event.KeyEvent.wVirtualScanCode = MapVirtualKey16(
141 ir.Event.KeyEvent.wVirtualKeyCode,0
143 ir.Event.KeyEvent.dwControlKeyState = 0;
144 ir.Event.KeyEvent.uChar.AsciiChar = 27;
145 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
146 ir.Event.KeyEvent.bKeyDown = 0;
147 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
150 for (k=j;k<len;k++) {
151 if (((buf[k]>='A') && (buf[k]<='Z')) ||
152 ((buf[k]>='a') && (buf[k]<='z')) ||
158 int subid,scancode=0;
160 ir.EventType = 1; /* Key_event */
161 ir.Event.KeyEvent.bKeyDown = 1;
162 ir.Event.KeyEvent.wRepeatCount = 0;
163 ir.Event.KeyEvent.dwControlKeyState = 0;
165 ir.Event.KeyEvent.wVirtualKeyCode = 0xad; /* FIXME */
166 ir.Event.KeyEvent.wVirtualScanCode = 0xad; /* FIXME */
167 ir.Event.KeyEvent.uChar.AsciiChar = 0;
171 sscanf(&buf[j+2],"%d",&subid);
173 case 2:/*INS */scancode = 0xe052;break;
174 case 3:/*DEL */scancode = 0xe053;break;
175 case 6:/*PGDW*/scancode = 0xe051;break;
176 case 5:/*PGUP*/scancode = 0xe049;break;
177 case 11:/*F1 */scancode = 0x003b;break;
178 case 12:/*F2 */scancode = 0x003c;break;
179 case 13:/*F3 */scancode = 0x003d;break;
180 case 14:/*F4 */scancode = 0x003e;break;
181 case 15:/*F5 */scancode = 0x003f;break;
182 case 17:/*F6 */scancode = 0x0040;break;
183 case 18:/*F7 */scancode = 0x0041;break;
184 case 19:/*F8 */scancode = 0x0042;break;
185 case 20:/*F9 */scancode = 0x0043;break;
186 case 21:/*F10 */scancode = 0x0044;break;
187 case 23:/*F11 */scancode = 0x00d9;break;
188 case 24:/*F12 */scancode = 0x00da;break;
189 /* FIXME: Shift-Fx */
191 FIXME("parse ESC[%d~\n",subid);
195 case 'A': /* Cursor Up */scancode = 0xe048;break;
196 case 'B': /* Cursor Down */scancode = 0xe050;break;
197 case 'D': /* Cursor Left */scancode = 0xe04b;break;
198 case 'C': /* Cursor Right */scancode = 0xe04d;break;
199 case 'F': /* End */scancode = 0xe04f;break;
200 case 'H': /* Home */scancode = 0xe047;break;
202 /* Mouse Button Press (ESCM<button+'!'><x+'!'><y+'!'>) or
203 * Release (ESCM#<x+'!'><y+'!'>
206 ir.EventType = MOUSE_EVENT;
207 ir.Event.MouseEvent.dwMousePosition.x = buf[k+2]-'!';
208 ir.Event.MouseEvent.dwMousePosition.y = buf[k+3]-'!';
210 ir.Event.MouseEvent.dwButtonState = 0;
212 ir.Event.MouseEvent.dwButtonState = 1<<(buf[k+1]-' ');
213 ir.Event.MouseEvent.dwEventFlags = 0; /* FIXME */
214 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk));
223 ir.Event.KeyEvent.wVirtualScanCode = scancode;
224 ir.Event.KeyEvent.wVirtualKeyCode = MapVirtualKey16(scancode,1);
225 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
226 ir.Event.KeyEvent.bKeyDown = 0;
227 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
235 /****************************************************************************
236 * CONSOLE_get_input (internal)
238 * Reads (nonblocking) as much input events as possible and stores them
239 * in an internal queue.
242 CONSOLE_get_input( HANDLE handle, BOOL blockwait )
244 char *buf = HeapAlloc(GetProcessHeap(),0,1);
251 if (WaitForSingleObject( handle, 0 )) break;
252 if (!ReadFile( handle, &inchar, 1, &res, NULL )) break;
253 if (!res) /* res 0 but readable means EOF? Hmm. */
255 buf = HeapReAlloc(GetProcessHeap(),0,buf,len+1);
258 CONSOLE_string_to_IR(handle,buf,len);
259 HeapFree(GetProcessHeap(),0,buf);
262 /******************************************************************************
263 * SetConsoleCtrlHandler [KERNEL32.459] Adds function to calling process list
266 * func [I] Address of handler function
267 * add [I] Handler to add or remove
274 * James Sutherland (JamesSutherland@gmx.de)
275 * Added global variables console_ignore_ctrl_c and handlers[]
276 * Does not yet do any error checking, or set LastError if failed.
277 * This doesn't yet matter, since these handlers are not yet called...!
279 static unsigned int console_ignore_ctrl_c = 0;
280 static HANDLER_ROUTINE *handlers[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
281 BOOL WINAPI SetConsoleCtrlHandler( HANDLER_ROUTINE *func, BOOL add )
283 unsigned int alloc_loop = sizeof(handlers)/sizeof(HANDLER_ROUTINE *);
284 unsigned int done = 0;
285 FIXME("(%p,%i) - no error checking or testing yet\n", func, add);
288 console_ignore_ctrl_c = add;
294 if (!handlers[alloc_loop] && !done)
296 handlers[alloc_loop] = func;
300 FIXME("Out of space on CtrlHandler table\n");
306 if (handlers[alloc_loop] == func && !done)
308 handlers[alloc_loop] = 0;
312 WARN("Attempt to remove non-installed CtrlHandler %p\n",
320 /******************************************************************************
321 * GenerateConsoleCtrlEvent [KERNEL32.275] Simulate a CTRL-C or CTRL-BREAK
324 * dwCtrlEvent [I] Type of event
325 * dwProcessGroupID [I] Process group ID to send event to
328 * Doesn't yet work...!
332 * Failure: False (and *should* [but doesn't] set LastError)
334 BOOL WINAPI GenerateConsoleCtrlEvent( DWORD dwCtrlEvent,
335 DWORD dwProcessGroupID )
337 if (dwCtrlEvent != CTRL_C_EVENT && dwCtrlEvent != CTRL_BREAK_EVENT)
339 ERR("invalid event %d for PGID %ld\n",
340 (unsigned short)dwCtrlEvent, dwProcessGroupID );
343 if (dwProcessGroupID == GetCurrentProcessId() )
345 FIXME("Attempt to send event %d to self - stub\n",
346 (unsigned short)dwCtrlEvent );
349 FIXME("event %d to external PGID %ld - not implemented yet\n",
350 (unsigned short)dwCtrlEvent, dwProcessGroupID );
355 /******************************************************************************
356 * CreateConsoleScreenBuffer [KERNEL32.151] Creates a console screen buffer
359 * dwDesiredAccess [I] Access flag
360 * dwShareMode [I] Buffer share mode
361 * sa [I] Security attributes
362 * dwFlags [I] Type of buffer to create
363 * lpScreenBufferData [I] Reserved
366 * Should call SetLastError
369 * Success: Handle to new console screen buffer
370 * Failure: INVALID_HANDLE_VALUE
372 HANDLE WINAPI CreateConsoleScreenBuffer( DWORD dwDesiredAccess,
373 DWORD dwShareMode, LPSECURITY_ATTRIBUTES sa,
374 DWORD dwFlags, LPVOID lpScreenBufferData )
376 FIXME("(%ld,%ld,%p,%ld,%p): stub\n",dwDesiredAccess,
377 dwShareMode, sa, dwFlags, lpScreenBufferData);
378 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
379 return INVALID_HANDLE_VALUE;
383 /***********************************************************************
384 * GetConsoleScreenBufferInfo (KERNEL32.190)
386 BOOL WINAPI GetConsoleScreenBufferInfo( HANDLE hConsoleOutput,
387 LPCONSOLE_SCREEN_BUFFER_INFO csbi )
391 csbi->dwCursorPosition.x = 0;
392 csbi->dwCursorPosition.y = 0;
393 csbi->wAttributes = 0;
394 csbi->srWindow.Left = 0;
395 csbi->srWindow.Right = 79;
396 csbi->srWindow.Top = 0;
397 csbi->srWindow.Bottom = 23;
398 csbi->dwMaximumWindowSize.x = 80;
399 csbi->dwMaximumWindowSize.y = 24;
404 /******************************************************************************
405 * SetConsoleActiveScreenBuffer [KERNEL32.623] Sets buffer to current console
411 BOOL WINAPI SetConsoleActiveScreenBuffer(
412 HANDLE hConsoleOutput) /* [in] Handle to console screen buffer */
414 FIXME("(%x): stub\n", hConsoleOutput);
419 /***********************************************************************
420 * GetLargestConsoleWindowSize (KERNEL32.226)
422 DWORD WINAPI GetLargestConsoleWindowSize( HANDLE hConsoleOutput )
424 return (DWORD)MAKELONG(80,24);
427 /***********************************************************************
428 * FreeConsole (KERNEL32.267)
430 BOOL WINAPI FreeConsole(VOID)
432 return !server_call( REQ_FREE_CONSOLE );
436 /*************************************************************************
439 * Open a handle to the current process console.
441 HANDLE CONSOLE_OpenHandle( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
444 struct open_console_request *req = get_req_buffer();
446 req->output = output;
447 req->access = access;
448 req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
450 if (!server_call( REQ_OPEN_CONSOLE )) ret = req->handle;
455 /*************************************************************************
456 * CONSOLE_make_complex [internal]
458 * Turns a CONSOLE kernel object into a complex one.
459 * (switches from output/input using the terminal where WINE was started to
462 * This makes simple commandline tools pipeable, while complex commandline
463 * tools work without getting messed up by debugoutput.
465 * All other functions should work indedependend from this call.
467 * To test for complex console: pid == 0 -> simple, otherwise complex.
469 static BOOL CONSOLE_make_complex(HANDLE handle)
471 struct set_console_fd_request *req = get_req_buffer();
475 int i,xpid,master,slave,pty_handle;
477 if (CONSOLE_GetPid( handle )) return TRUE; /* already complex */
479 MESSAGE("Console: Making console complex (creating an xterm)...\n");
481 if (tcgetattr(0, &term) < 0) {
482 /* ignore failure, or we can't run from a script */
484 term.c_lflag = ~(ECHO|ICANON);
486 if (wine_openpty(&master, &slave, NULL, &term, NULL) < 0)
489 if ((xpid=fork()) == 0) {
490 tcsetattr(slave, TCSADRAIN, &term);
492 sprintf(buf, "-Sxx%d", master);
493 /* "-fn vga" for VGA font. Harmless if vga is not present:
494 * xterm: unable to open font "vga", trying "fixed"....
496 execlp("xterm", "xterm", buf, "-fn","vga",NULL);
497 ERR("error creating AllocConsole xterm\n");
500 pty_handle = FILE_DupUnixHandle( slave, GENERIC_READ | GENERIC_WRITE );
503 if (pty_handle == -1) return FALSE;
505 /* most xterms like to print their window ID when used with -S;
506 * read it and continue before the user has a chance...
508 for (i = 0; i < 10000; i++)
510 BOOL ok = ReadFile( pty_handle, &c, 1, NULL, NULL );
511 if (!ok && !c) usleep(100); /* wait for xterm to be created */
512 else if (c == '\n') break;
516 ERR("can't read xterm WID\n");
517 CloseHandle( pty_handle );
520 req->handle = handle;
521 req->file_handle = pty_handle;
523 server_call( REQ_SET_CONSOLE_FD );
524 CloseHandle( pty_handle );
526 /* enable mouseclicks */
527 strcpy( buf, "\033[?1001s\033[?1000h" );
528 WriteFile(handle,buf,strlen(buf),NULL,NULL);
530 strcpy( buf, "\033]2;" );
531 if (GetConsoleTitleA( buf + 4, sizeof(buf) - 5 ))
534 WriteFile(handle,buf,strlen(buf),NULL,NULL);
541 /***********************************************************************
542 * AllocConsole (KERNEL32.103)
544 * creates an xterm with a pty to our program
546 BOOL WINAPI AllocConsole(VOID)
548 struct alloc_console_request *req = get_req_buffer();
550 int handle_in, handle_out;
553 req->access = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
554 req->inherit = FALSE;
555 if (server_call( REQ_ALLOC_CONSOLE )) return FALSE;
556 handle_in = req->handle_in;
557 handle_out = req->handle_out;
559 if (!DuplicateHandle( GetCurrentProcess(), req->handle_out, GetCurrentProcess(), &hStderr,
560 0, TRUE, DUPLICATE_SAME_ACCESS ))
562 CloseHandle( handle_in );
563 CloseHandle( handle_out );
568 /* NT resets the STD_*_HANDLEs on console alloc */
569 SetStdHandle( STD_INPUT_HANDLE, handle_in );
570 SetStdHandle( STD_OUTPUT_HANDLE, handle_out );
571 SetStdHandle( STD_ERROR_HANDLE, hStderr );
573 SetLastError(ERROR_SUCCESS);
574 SetConsoleTitleA("Wine Console");
579 /******************************************************************************
580 * GetConsoleCP [KERNEL32.295] Returns the OEM code page for the console
585 UINT WINAPI GetConsoleCP(VOID)
591 /***********************************************************************
592 * GetConsoleOutputCP (KERNEL32.189)
594 UINT WINAPI GetConsoleOutputCP(VOID)
596 return GetConsoleCP();
599 /***********************************************************************
600 * GetConsoleMode (KERNEL32.188)
602 BOOL WINAPI GetConsoleMode(HANDLE hcon,LPDWORD mode)
605 struct get_console_mode_request *req = get_req_buffer();
607 if (!server_call( REQ_GET_CONSOLE_MODE ))
609 if (mode) *mode = req->mode;
616 /******************************************************************************
617 * SetConsoleMode [KERNEL32.628] Sets input mode of console's input buffer
620 * hcon [I] Handle to console input or screen buffer
621 * mode [I] Input or output mode to set
627 BOOL WINAPI SetConsoleMode( HANDLE hcon, DWORD mode )
629 struct set_console_mode_request *req = get_req_buffer();
632 return !server_call( REQ_SET_CONSOLE_MODE );
636 /***********************************************************************
637 * GetConsoleTitleA (KERNEL32.191)
639 DWORD WINAPI GetConsoleTitleA(LPSTR title,DWORD size)
641 struct get_console_info_request *req = get_req_buffer();
645 if ((hcon = CreateFileA( "CONOUT$", GENERIC_READ, 0, NULL,
646 OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
649 if (!server_call( REQ_GET_CONSOLE_INFO ))
651 lstrcpynA( title, req->title, size );
652 ret = strlen(req->title);
659 /******************************************************************************
660 * GetConsoleTitle32W [KERNEL32.192] Retrieves title string for console
663 * title [O] Address of buffer for title
664 * size [I] Size of buffer
667 * Success: Length of string copied
670 DWORD WINAPI GetConsoleTitleW( LPWSTR title, DWORD size )
675 if (!(tmp = HeapAlloc( GetProcessHeap(), 0, size ))) return 0;
676 ret = GetConsoleTitleA( tmp, size );
677 lstrcpyAtoW( title, tmp );
678 HeapFree( GetProcessHeap(), 0, tmp );
683 /***********************************************************************
684 * WriteConsoleA (KERNEL32.729)
686 BOOL WINAPI WriteConsoleA( HANDLE hConsoleOutput,
688 DWORD nNumberOfCharsToWrite,
689 LPDWORD lpNumberOfCharsWritten,
692 /* FIXME: should I check if this is a console handle? */
693 return WriteFile(hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
694 lpNumberOfCharsWritten, NULL);
699 if (bufused==curbufsize-1) \
700 buffer = HeapReAlloc(GetProcessHeap(),0,buffer,(curbufsize+=100));\
702 #define SADD(s) { char *x=s;while (*x) {CADD(*x);x++;}}
704 /***********************************************************************
705 * WriteConsoleOutputA (KERNEL32.732)
707 BOOL WINAPI WriteConsoleOutputA( HANDLE hConsoleOutput,
708 LPCHAR_INFO lpBuffer,
711 LPSMALL_RECT lpWriteRegion)
713 int i,j,off=0,lastattr=-1;
715 char sbuf[20],*buffer=NULL;
716 int bufused=0,curbufsize = 100;
718 CONSOLE_SCREEN_BUFFER_INFO csbi;
719 const int colormap[8] = {
723 CONSOLE_make_complex(hConsoleOutput);
724 buffer = HeapAlloc(GetProcessHeap(),0,curbufsize);
725 offbase = (dwBufferCoord.y - 1) * dwBufferSize.x +
726 (dwBufferCoord.x - lpWriteRegion->Left);
728 TRACE("orig rect top = %d, bottom=%d, left=%d, right=%d\n",
730 lpWriteRegion->Bottom,
735 GetConsoleScreenBufferInfo(hConsoleOutput, &csbi);
737 /* Step 1. Make (Bottom,Right) offset of intersection with
739 lpWriteRegion->Bottom = min(lpWriteRegion->Bottom, csbi.dwSize.y-1) -
741 lpWriteRegion->Right = min(lpWriteRegion->Right, csbi.dwSize.x-1) -
744 /* Step 2. If either offset is negative, then no action
745 should be performed. (Implies that requested rectangle is
746 outside the current screen buffer rectangle.) */
747 if ((lpWriteRegion->Bottom < 0) ||
748 (lpWriteRegion->Right < 0)) {
749 /* readjust (Bottom Right) for rectangle */
750 lpWriteRegion->Bottom += lpWriteRegion->Top;
751 lpWriteRegion->Right += lpWriteRegion->Left;
753 TRACE("invisible rect top = %d, bottom=%d, left=%d, right=%d\n",
755 lpWriteRegion->Bottom,
760 HeapFree(GetProcessHeap(),0,buffer);
764 /* Step 3. Intersect with source rectangle */
765 lpWriteRegion->Bottom = lpWriteRegion->Top - dwBufferCoord.y +
766 min(lpWriteRegion->Bottom + dwBufferCoord.y, dwBufferSize.y-1);
767 lpWriteRegion->Right = lpWriteRegion->Left - dwBufferCoord.x +
768 min(lpWriteRegion->Right + dwBufferCoord.x, dwBufferSize.x-1);
770 TRACE("clipped rect top = %d, bottom=%d, left=%d,right=%d\n",
772 lpWriteRegion->Bottom,
777 /* Validate above computations made sense, if not then issue
778 error and fudge to single character rectangle */
779 if ((lpWriteRegion->Bottom < lpWriteRegion->Top) ||
780 (lpWriteRegion->Right < lpWriteRegion->Left)) {
781 ERR("Invalid clipped rectangle top = %d, bottom=%d, left=%d,right=%d\n",
783 lpWriteRegion->Bottom,
787 lpWriteRegion->Bottom = lpWriteRegion->Top;
788 lpWriteRegion->Right = lpWriteRegion->Left;
791 /* Now do the real processing and move the characters */
792 for (i=lpWriteRegion->Top;i<=lpWriteRegion->Bottom;i++) {
793 offbase += dwBufferSize.x;
794 sprintf(sbuf,"%c[%d;%dH",27,i+1,lpWriteRegion->Left+1);
796 for (j=lpWriteRegion->Left;j<=lpWriteRegion->Right;j++) {
798 if (lastattr!=lpBuffer[off].Attributes) {
799 lastattr = lpBuffer[off].Attributes;
800 sprintf(sbuf,"%c[0;%s3%d;4%dm",
802 (lastattr & FOREGROUND_INTENSITY)?"1;":"",
803 colormap[lastattr&7],
804 colormap[(lastattr&0x70)>>4]
806 /* FIXME: BACKGROUND_INTENSITY */
809 CADD(lpBuffer[off].Char.AsciiChar);
812 sprintf(sbuf,"%c[0m",27);SADD(sbuf);
813 WriteFile(hConsoleOutput,buffer,bufused,&res,NULL);
814 HeapFree(GetProcessHeap(),0,buffer);
818 /***********************************************************************
819 * WriteConsoleW (KERNEL32.577)
821 BOOL WINAPI WriteConsoleW( HANDLE hConsoleOutput,
823 DWORD nNumberOfCharsToWrite,
824 LPDWORD lpNumberOfCharsWritten,
828 LPSTR xstring=HeapAlloc( GetProcessHeap(), 0, nNumberOfCharsToWrite );
830 lstrcpynWtoA( xstring, lpBuffer,nNumberOfCharsToWrite);
832 /* FIXME: should I check if this is a console handle? */
833 ret= WriteFile(hConsoleOutput, xstring, nNumberOfCharsToWrite,
834 lpNumberOfCharsWritten, NULL);
835 HeapFree( GetProcessHeap(), 0, xstring );
840 /***********************************************************************
841 * ReadConsoleA (KERNEL32.419)
843 BOOL WINAPI ReadConsoleA( HANDLE hConsoleInput,
845 DWORD nNumberOfCharsToRead,
846 LPDWORD lpNumberOfCharsRead,
850 LPSTR xbuf = (LPSTR)lpBuffer;
853 TRACE("(%d,%p,%ld,%p,%p)\n",
854 hConsoleInput,lpBuffer,nNumberOfCharsToRead,
855 lpNumberOfCharsRead,lpReserved
858 CONSOLE_get_input(hConsoleInput,FALSE);
860 /* FIXME: should we read at least 1 char? The SDK does not say */
861 while (charsread<nNumberOfCharsToRead)
863 struct read_console_input_request *req = get_req_buffer();
864 req->handle = hConsoleInput;
867 if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
868 if (!req->read) break;
869 ir = (LPINPUT_RECORD)(req+1);
870 if (!ir->Event.KeyEvent.bKeyDown)
872 if (ir->EventType != KEY_EVENT)
874 *xbuf++ = ir->Event.KeyEvent.uChar.AsciiChar;
877 if (lpNumberOfCharsRead)
878 *lpNumberOfCharsRead = charsread;
882 /***********************************************************************
883 * ReadConsoleW (KERNEL32.427)
885 BOOL WINAPI ReadConsoleW( HANDLE hConsoleInput,
887 DWORD nNumberOfCharsToRead,
888 LPDWORD lpNumberOfCharsRead,
892 LPSTR buf = (LPSTR)HeapAlloc(GetProcessHeap(), 0, nNumberOfCharsToRead);
897 nNumberOfCharsToRead,
902 lstrcpynAtoW(lpBuffer,buf,nNumberOfCharsToRead);
903 HeapFree( GetProcessHeap(), 0, buf );
908 /******************************************************************************
909 * ReadConsoleInput32A [KERNEL32.569] Reads data from a console
912 * hConsoleInput [I] Handle to console input buffer
913 * lpBuffer [O] Address of buffer for read data
914 * nLength [I] Number of records to read
915 * lpNumberOfEventsRead [O] Address of number of records read
921 BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, LPINPUT_RECORD lpBuffer,
922 DWORD nLength, LPDWORD lpNumberOfEventsRead)
924 struct read_console_input_request *req = get_req_buffer();
926 /* loop until we get at least one event */
929 req->handle = hConsoleInput;
930 req->count = nLength;
932 if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
935 memcpy( lpBuffer, req + 1, req->read * sizeof(*lpBuffer) );
936 if (lpNumberOfEventsRead) *lpNumberOfEventsRead = req->read;
939 CONSOLE_get_input(hConsoleInput,TRUE);
940 /*WaitForSingleObject( hConsoleInput, INFINITE32 );*/
945 /***********************************************************************
946 * ReadConsoleInput32W (KERNEL32.570)
948 BOOL WINAPI ReadConsoleInputW( HANDLE handle, LPINPUT_RECORD buffer,
949 DWORD count, LPDWORD read )
951 /* FIXME: Fix this if we get UNICODE input. */
952 return ReadConsoleInputA( handle, buffer, count, read );
956 /***********************************************************************
957 * FlushConsoleInputBuffer (KERNEL32.132)
959 BOOL WINAPI FlushConsoleInputBuffer( HANDLE handle )
961 struct read_console_input_request *req = get_req_buffer();
962 req->handle = handle;
963 req->count = -1; /* get all records */
965 return !server_call( REQ_READ_CONSOLE_INPUT );
969 /***********************************************************************
970 * PeekConsoleInputA (KERNEL32.550)
972 * Gets 'count' first events (or less) from input queue.
974 * Does not need a complex console.
976 BOOL WINAPI PeekConsoleInputA( HANDLE handle, LPINPUT_RECORD buffer,
977 DWORD count, LPDWORD read )
979 struct read_console_input_request *req = get_req_buffer();
981 CONSOLE_get_input(handle,FALSE);
983 req->handle = handle;
986 if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
987 if (req->read) memcpy( buffer, req + 1, req->read * sizeof(*buffer) );
988 if (read) *read = req->read;
993 /***********************************************************************
994 * PeekConsoleInputW (KERNEL32.551)
996 BOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,
997 LPINPUT_RECORD pirBuffer,
1001 /* FIXME: Hmm. Fix this if we get UNICODE input. */
1002 return PeekConsoleInputA(hConsoleInput,pirBuffer,cInRecords,lpcRead);
1006 /******************************************************************************
1007 * WriteConsoleInput32A [KERNEL32.730] Write data to a console input buffer
1010 BOOL WINAPI WriteConsoleInputA( HANDLE handle, INPUT_RECORD *buffer,
1011 DWORD count, LPDWORD written )
1013 struct write_console_input_request *req = get_req_buffer();
1014 const DWORD max = server_remaining( req + 1 ) / sizeof(INPUT_RECORD);
1016 if (written) *written = 0;
1019 DWORD len = count < max ? count : max;
1021 req->handle = handle;
1022 memcpy( req + 1, buffer, len * sizeof(*buffer) );
1023 if (server_call( REQ_WRITE_CONSOLE_INPUT )) return FALSE;
1024 if (written) *written += req->written;
1032 /***********************************************************************
1033 * SetConsoleTitle32A (KERNEL32.476)
1035 * Sets the console title.
1037 * We do not necessarily need to create a complex console for that,
1038 * but should remember the title and set it on creation of the latter.
1039 * (not fixed at this time).
1041 BOOL WINAPI SetConsoleTitleA(LPCSTR title)
1043 struct set_console_info_request *req = get_req_buffer();
1047 if ((hcon = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL,
1048 OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
1051 req->mask = SET_CONSOLE_INFO_TITLE;
1052 lstrcpynA( req->title, title, server_remaining(req->title) );
1053 if (server_call( REQ_SET_CONSOLE_INFO )) goto error;
1054 if (CONSOLE_GetPid( hcon ))
1056 /* only set title for complex console (own xterm) */
1057 WriteFile( hcon, "\033]2;", 4, &written, NULL );
1058 WriteFile( hcon, title, strlen(title), &written, NULL );
1059 WriteFile( hcon, "\a", 1, &written, NULL );
1061 CloseHandle( hcon );
1064 CloseHandle( hcon );
1069 /******************************************************************************
1070 * SetConsoleTitle32W [KERNEL32.477] Sets title bar string for console
1073 * title [I] Address of new title
1076 * This should not be calling the A version
1082 BOOL WINAPI SetConsoleTitleW( LPCWSTR title )
1086 LPSTR titleA = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
1087 ret = SetConsoleTitleA(titleA);
1088 HeapFree( GetProcessHeap(), 0, titleA );
1092 /******************************************************************************
1093 * SetConsoleCursorPosition [KERNEL32.627]
1094 * Sets the cursor position in console
1097 * hConsoleOutput [I] Handle of console screen buffer
1098 * dwCursorPosition [I] New cursor position coordinates
1102 BOOL WINAPI SetConsoleCursorPosition( HANDLE hcon, COORD pos )
1107 /* make console complex only if we change lines, not just in the line */
1109 CONSOLE_make_complex(hcon);
1111 TRACE("%d (%dx%d)\n", hcon, pos.x , pos.y );
1112 /* x are columns, y rows */
1114 /* full screen cursor absolute positioning */
1115 sprintf(xbuf,"%c[%d;%dH", 0x1B, pos.y+1, pos.x+1);
1117 /* relative cursor positioning in line (\r to go to 0) */
1118 sprintf(xbuf,"\r%c[%dC", 0x1B, pos.x);
1119 /* FIXME: store internal if we start using own console buffers */
1120 WriteFile(hcon,xbuf,strlen(xbuf),&xlen,NULL);
1124 /***********************************************************************
1125 * GetNumberOfConsoleInputEvents (KERNEL32.246)
1127 BOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hcon,LPDWORD nrofevents)
1129 struct read_console_input_request *req = get_req_buffer();
1131 CONSOLE_get_input(hcon,FALSE);
1136 if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
1137 if (nrofevents) *nrofevents = req->read;
1141 /***********************************************************************
1142 * GetNumberOfConsoleMouseButtons (KERNEL32.358)
1144 BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons)
1146 FIXME("(%p): stub\n", nrofbuttons);
1151 /******************************************************************************
1152 * GetConsoleCursorInfo32 [KERNEL32.296] Gets size and visibility of console
1155 * hcon [I] Handle to console screen buffer
1156 * cinfo [O] Address of cursor information
1162 BOOL WINAPI GetConsoleCursorInfo( HANDLE hcon, LPCONSOLE_CURSOR_INFO cinfo )
1164 struct get_console_info_request *req = get_req_buffer();
1166 if (server_call( REQ_GET_CONSOLE_INFO )) return FALSE;
1169 cinfo->dwSize = req->cursor_size;
1170 cinfo->bVisible = req->cursor_visible;
1176 /******************************************************************************
1177 * SetConsoleCursorInfo32 [KERNEL32.626] Sets size and visibility of cursor
1183 BOOL WINAPI SetConsoleCursorInfo(
1184 HANDLE hcon, /* [in] Handle to console screen buffer */
1185 LPCONSOLE_CURSOR_INFO cinfo) /* [in] Address of cursor information */
1187 struct set_console_info_request *req = get_req_buffer();
1191 CONSOLE_make_complex(hcon);
1192 sprintf(buf,"\033[?25%c",cinfo->bVisible?'h':'l');
1193 WriteFile(hcon,buf,strlen(buf),&xlen,NULL);
1196 req->cursor_size = cinfo->dwSize;
1197 req->cursor_visible = cinfo->bVisible;
1198 req->mask = SET_CONSOLE_INFO_CURSOR;
1199 return !server_call( REQ_SET_CONSOLE_INFO );
1203 /******************************************************************************
1204 * SetConsoleWindowInfo [KERNEL32.634] Sets size and position of console
1210 BOOL WINAPI SetConsoleWindowInfo(
1211 HANDLE hcon, /* [in] Handle to console screen buffer */
1212 BOOL bAbsolute, /* [in] Coordinate type flag */
1213 LPSMALL_RECT window) /* [in] Address of new window rectangle */
1215 FIXME("(%x,%d,%p): stub\n", hcon, bAbsolute, window);
1220 /******************************************************************************
1221 * SetConsoleTextAttribute32 [KERNEL32.631] Sets colors for text
1223 * Sets the foreground and background color attributes of characters
1224 * written to the screen buffer.
1230 BOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttr)
1232 const int colormap[8] = {
1239 TRACE("(%d,%d)\n",hConsoleOutput,wAttr);
1240 sprintf(buffer,"%c[0;%s3%d;4%dm",
1242 (wAttr & FOREGROUND_INTENSITY)?"1;":"",
1244 colormap[(wAttr&0x70)>>4]
1246 WriteFile(hConsoleOutput,buffer,strlen(buffer),&xlen,NULL);
1251 /******************************************************************************
1252 * SetConsoleScreenBufferSize [KERNEL32.630] Changes size of console
1255 * hConsoleOutput [I] Handle to console screen buffer
1256 * dwSize [I] New size in character rows and cols
1262 BOOL WINAPI SetConsoleScreenBufferSize( HANDLE hConsoleOutput,
1265 FIXME("(%d,%dx%d): stub\n",hConsoleOutput,dwSize.x,dwSize.y);
1270 /******************************************************************************
1271 * FillConsoleOutputCharacterA [KERNEL32.242]
1274 * hConsoleOutput [I] Handle to screen buffer
1275 * cCharacter [I] Character to write
1276 * nLength [I] Number of cells to write to
1277 * dwCoord [I] Coords of first cell
1278 * lpNumCharsWritten [O] Pointer to number of cells written
1284 BOOL WINAPI FillConsoleOutputCharacterA(
1285 HANDLE hConsoleOutput,
1289 LPDWORD lpNumCharsWritten)
1294 SetConsoleCursorPosition(hConsoleOutput,dwCoord);
1295 for(count=0;count<nLength;count++)
1296 WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
1297 *lpNumCharsWritten = nLength;
1302 /******************************************************************************
1303 * FillConsoleOutputCharacterW [KERNEL32.243] Writes characters to console
1306 * hConsoleOutput [I] Handle to screen buffer
1307 * cCharacter [I] Character to write
1308 * nLength [I] Number of cells to write to
1309 * dwCoord [I] Coords of first cell
1310 * lpNumCharsWritten [O] Pointer to number of cells written
1316 BOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,
1320 LPDWORD lpNumCharsWritten)
1325 SetConsoleCursorPosition(hConsoleOutput,dwCoord);
1326 /* FIXME: not quite correct ... but the lower part of UNICODE char comes
1329 for(count=0;count<nLength;count++)
1330 WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
1331 *lpNumCharsWritten = nLength;
1336 /******************************************************************************
1337 * FillConsoleOutputAttribute [KERNEL32.241] Sets attributes for console
1340 * hConsoleOutput [I] Handle to screen buffer
1341 * wAttribute [I] Color attribute to write
1342 * nLength [I] Number of cells to write to
1343 * dwCoord [I] Coords of first cell
1344 * lpNumAttrsWritten [O] Pointer to number of cells written
1350 BOOL WINAPI FillConsoleOutputAttribute( HANDLE hConsoleOutput,
1351 WORD wAttribute, DWORD nLength, COORD dwCoord,
1352 LPDWORD lpNumAttrsWritten)
1354 FIXME("(%d,%d,%ld,%dx%d,%p): stub\n", hConsoleOutput,
1355 wAttribute,nLength,dwCoord.x,dwCoord.y,lpNumAttrsWritten);
1356 *lpNumAttrsWritten = nLength;
1360 /******************************************************************************
1361 * ReadConsoleOutputCharacter32A [KERNEL32.573]
1366 BOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput,
1367 LPSTR lpstr, DWORD dword, COORD coord, LPDWORD lpdword)
1369 FIXME("(%d,%p,%ld,%dx%d,%p): stub\n", hConsoleOutput,lpstr,
1370 dword,coord.x,coord.y,lpdword);
1371 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1376 /******************************************************************************
1377 * ScrollConsoleScreenBuffer [KERNEL32.612]
1382 BOOL WINAPI ScrollConsoleScreenBuffer( HANDLE hConsoleOutput,
1383 LPSMALL_RECT lpScrollRect, LPSMALL_RECT lpClipRect,
1384 COORD dwDestOrigin, LPCHAR_INFO lpFill)
1386 FIXME("(%d,%p,%p,%dx%d,%p): stub\n", hConsoleOutput,lpScrollRect,
1387 lpClipRect,dwDestOrigin.x,dwDestOrigin.y,lpFill);
1388 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);