Stubs for Get/SetProcessDefaultLayout.
[wine.git] / win32 / console.c
blob0284cc8f8774dbc904fd9a2d0ca259fcc46a5e5a
1 /*
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
8 */
10 /* FIXME:
11 * - Completely lacks SCREENBUFFER interface.
12 * - No abstraction for something other than xterm.
13 * - Key input translation shouldn't use VkKeyScan and MapVirtualKey, since
14 * they are window (USER) driver dependend.
15 * - Output sometimes is buffered (We switched off buffering by ~ICANON ?)
17 /* Reference applications:
18 * - IDA (interactive disassembler) full version 3.75. Works.
19 * - LYNX/W32. Works mostly, some keys crash it.
22 #include "config.h"
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <termios.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #ifdef HAVE_SYS_ERRNO_H
34 #include <sys/errno.h>
35 #endif
36 #include <signal.h>
37 #include <assert.h>
39 #include "winbase.h"
40 #include "wine/winuser16.h"
41 #include "wine/keyboard16.h"
42 #include "thread.h"
43 #include "file.h"
44 #include "process.h"
45 #include "winerror.h"
46 #include "wincon.h"
47 #include "heap.h"
48 #include "server.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 /****************************************************************************
60 * CONSOLE_GetPid
62 static int CONSOLE_GetPid( HANDLE handle )
64 struct get_console_info_request *req = get_req_buffer();
65 req->handle = handle;
66 if (server_call( REQ_GET_CONSOLE_INFO )) return 0;
67 return req->pid;
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.
76 static void
77 CONSOLE_string_to_IR( HANDLE hConsoleInput,unsigned char *buf,int len) {
78 int j,k;
79 INPUT_RECORD ir;
80 DWORD junk;
82 for (j=0;j<len;j++) {
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;
92 if (inchar & 0x80) {
93 ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
94 inchar &= ~0x80;
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;
113 } else {
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;
119 } else {
120 if (inchar<' ') {
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 ));
131 continue;
133 /* inchar is ESC */
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 ));
148 continue;
150 for (k=j;k<len;k++) {
151 if (((buf[k]>='A') && (buf[k]<='Z')) ||
152 ((buf[k]>='a') && (buf[k]<='z')) ||
153 (buf[k]=='~')
155 break;
157 if (k<len) {
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;
169 switch (buf[k]) {
170 case '~':
171 sscanf(&buf[j+2],"%d",&subid);
172 switch (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 */
190 default:
191 FIXME("parse ESC[%d~\n",subid);
192 break;
194 break;
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;
201 case 'M':
202 /* Mouse Button Press (ESCM<button+'!'><x+'!'><y+'!'>) or
203 * Release (ESCM#<x+'!'><y+'!'>
205 if (k<len-3) {
206 ir.EventType = MOUSE_EVENT;
207 ir.Event.MouseEvent.dwMousePosition.x = buf[k+2]-'!';
208 ir.Event.MouseEvent.dwMousePosition.y = buf[k+3]-'!';
209 if (buf[k+1]=='#')
210 ir.Event.MouseEvent.dwButtonState = 0;
211 else
212 ir.Event.MouseEvent.dwButtonState = 1<<(buf[k+1]-' ');
213 ir.Event.MouseEvent.dwEventFlags = 0; /* FIXME */
214 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk));
215 j=k+3;
217 break;
218 case 'c':
219 j=k;
220 break;
222 if (scancode) {
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 ));
228 j=k;
229 continue;
235 /****************************************************************************
236 * CONSOLE_get_input (internal)
238 * Reads (nonblocking) as much input events as possible and stores them
239 * in an internal queue.
241 static void
242 CONSOLE_get_input( HANDLE handle, BOOL blockwait )
244 char *buf = HeapAlloc(GetProcessHeap(),0,1);
245 int len = 0;
247 while (1)
249 DWORD res;
250 char inchar;
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. */
254 break;
255 buf = HeapReAlloc(GetProcessHeap(),0,buf,len+1);
256 buf[len++]=inchar;
258 CONSOLE_string_to_IR(handle,buf,len);
259 HeapFree(GetProcessHeap(),0,buf);
262 /******************************************************************************
263 * SetConsoleCtrlHandler [KERNEL32.459] Adds function to calling process list
265 * PARAMS
266 * func [I] Address of handler function
267 * add [I] Handler to add or remove
269 * RETURNS
270 * Success: TRUE
271 * Failure: FALSE
273 * CHANGED
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);
286 if (!func)
288 console_ignore_ctrl_c = add;
289 return TRUE;
291 if (add)
293 for (;alloc_loop--;)
294 if (!handlers[alloc_loop] && !done)
296 handlers[alloc_loop] = func;
297 done++;
299 if (!done)
300 FIXME("Out of space on CtrlHandler table\n");
301 return(done);
303 else
305 for (;alloc_loop--;)
306 if (handlers[alloc_loop] == func && !done)
308 handlers[alloc_loop] = 0;
309 done++;
311 if (!done)
312 WARN("Attempt to remove non-installed CtrlHandler %p\n",
313 func);
314 return (done);
316 return (done);
320 /******************************************************************************
321 * GenerateConsoleCtrlEvent [KERNEL32.275] Simulate a CTRL-C or CTRL-BREAK
323 * PARAMS
324 * dwCtrlEvent [I] Type of event
325 * dwProcessGroupID [I] Process group ID to send event to
327 * NOTES
328 * Doesn't yet work...!
330 * RETURNS
331 * Success: True
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 );
341 return FALSE;
343 if (dwProcessGroupID == GetCurrentProcessId() )
345 FIXME("Attempt to send event %d to self - stub\n",
346 (unsigned short)dwCtrlEvent );
347 return FALSE;
349 FIXME("event %d to external PGID %ld - not implemented yet\n",
350 (unsigned short)dwCtrlEvent, dwProcessGroupID );
351 return FALSE;
355 /******************************************************************************
356 * CreateConsoleScreenBuffer [KERNEL32.151] Creates a console screen buffer
358 * PARAMS
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
365 * NOTES
366 * Should call SetLastError
368 * RETURNS
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 )
389 csbi->dwSize.x = 80;
390 csbi->dwSize.y = 24;
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;
400 return TRUE;
404 /******************************************************************************
405 * SetConsoleActiveScreenBuffer [KERNEL32.623] Sets buffer to current console
407 * RETURNS
408 * Success: TRUE
409 * Failure: FALSE
411 BOOL WINAPI SetConsoleActiveScreenBuffer(
412 HANDLE hConsoleOutput) /* [in] Handle to console screen buffer */
414 FIXME("(%x): stub\n", hConsoleOutput);
415 return FALSE;
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 /*************************************************************************
437 * CONSOLE_OpenHandle
439 * Open a handle to the current process console.
441 HANDLE CONSOLE_OpenHandle( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
443 int ret = -1;
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);
449 SetLastError(0);
450 if (!server_call( REQ_OPEN_CONSOLE )) ret = req->handle;
451 return ret;
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
460 * its own xterm).
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();
472 struct termios term;
473 char buf[256];
474 char c = '\0';
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)
487 return FALSE;
489 if ((xpid=fork()) == 0) {
490 tcsetattr(slave, TCSADRAIN, &term);
491 close( slave );
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");
498 exit(1);
500 pty_handle = FILE_DupUnixHandle( slave, GENERIC_READ | GENERIC_WRITE );
501 close( master );
502 close( slave );
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;
514 if (i == 10000)
516 ERR("can't read xterm WID\n");
517 CloseHandle( pty_handle );
518 return FALSE;
520 req->handle = handle;
521 req->file_handle = pty_handle;
522 req->pid = xpid;
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 ))
533 strcat( buf, "\a" );
534 WriteFile(handle,buf,strlen(buf),NULL,NULL);
536 return TRUE;
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();
549 HANDLE hStderr;
550 int handle_in, handle_out;
552 TRACE("()\n");
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 );
564 FreeConsole();
565 return FALSE;
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");
575 return TRUE;
579 /******************************************************************************
580 * GetConsoleCP [KERNEL32.295] Returns the OEM code page for the console
582 * RETURNS
583 * Code page code
585 UINT WINAPI GetConsoleCP(VOID)
587 return GetACP();
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)
604 BOOL ret = FALSE;
605 struct get_console_mode_request *req = get_req_buffer();
606 req->handle = hcon;
607 if (!server_call( REQ_GET_CONSOLE_MODE ))
609 if (mode) *mode = req->mode;
610 ret = TRUE;
612 return ret;
616 /******************************************************************************
617 * SetConsoleMode [KERNEL32.628] Sets input mode of console's input buffer
619 * PARAMS
620 * hcon [I] Handle to console input or screen buffer
621 * mode [I] Input or output mode to set
623 * RETURNS
624 * Success: TRUE
625 * Failure: FALSE
627 BOOL WINAPI SetConsoleMode( HANDLE hcon, DWORD mode )
629 struct set_console_mode_request *req = get_req_buffer();
630 req->handle = hcon;
631 req->mode = mode;
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();
642 DWORD ret = 0;
643 HANDLE hcon;
645 if ((hcon = CreateFileA( "CONOUT$", GENERIC_READ, 0, NULL,
646 OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
647 return 0;
648 req->handle = hcon;
649 if (!server_call( REQ_GET_CONSOLE_INFO ))
651 lstrcpynA( title, req->title, size );
652 ret = strlen(req->title);
654 CloseHandle( hcon );
655 return ret;
659 /******************************************************************************
660 * GetConsoleTitle32W [KERNEL32.192] Retrieves title string for console
662 * PARAMS
663 * title [O] Address of buffer for title
664 * size [I] Size of buffer
666 * RETURNS
667 * Success: Length of string copied
668 * Failure: 0
670 DWORD WINAPI GetConsoleTitleW( LPWSTR title, DWORD size )
672 char *tmp;
673 DWORD ret;
675 if (!(tmp = HeapAlloc( GetProcessHeap(), 0, size ))) return 0;
676 ret = GetConsoleTitleA( tmp, size );
677 lstrcpyAtoW( title, tmp );
678 HeapFree( GetProcessHeap(), 0, tmp );
679 return ret;
683 /***********************************************************************
684 * WriteConsoleA (KERNEL32.729)
686 BOOL WINAPI WriteConsoleA( HANDLE hConsoleOutput,
687 LPCVOID lpBuffer,
688 DWORD nNumberOfCharsToWrite,
689 LPDWORD lpNumberOfCharsWritten,
690 LPVOID lpReserved )
692 /* FIXME: should I check if this is a console handle? */
693 return WriteFile(hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
694 lpNumberOfCharsWritten, NULL);
698 #define CADD(c) \
699 if (bufused==curbufsize-1) \
700 buffer = HeapReAlloc(GetProcessHeap(),0,buffer,(curbufsize+=100));\
701 buffer[bufused++]=c;
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,
709 COORD dwBufferSize,
710 COORD dwBufferCoord,
711 LPSMALL_RECT lpWriteRegion)
713 int i,j,off=0,lastattr=-1;
714 int offbase;
715 char sbuf[20],*buffer=NULL;
716 int bufused=0,curbufsize = 100;
717 DWORD res;
718 CONSOLE_SCREEN_BUFFER_INFO csbi;
719 const int colormap[8] = {
720 0,4,2,6,
721 1,5,3,7,
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",
729 lpWriteRegion->Top,
730 lpWriteRegion->Bottom,
731 lpWriteRegion->Left,
732 lpWriteRegion->Right
735 GetConsoleScreenBufferInfo(hConsoleOutput, &csbi);
737 /* Step 1. Make (Bottom,Right) offset of intersection with
738 Screen Buffer */
739 lpWriteRegion->Bottom = min(lpWriteRegion->Bottom, csbi.dwSize.y-1) -
740 lpWriteRegion->Top;
741 lpWriteRegion->Right = min(lpWriteRegion->Right, csbi.dwSize.x-1) -
742 lpWriteRegion->Left;
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",
754 lpWriteRegion->Top,
755 lpWriteRegion->Bottom,
756 lpWriteRegion->Left,
757 lpWriteRegion->Right
760 HeapFree(GetProcessHeap(),0,buffer);
761 return TRUE;
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",
771 lpWriteRegion->Top,
772 lpWriteRegion->Bottom,
773 lpWriteRegion->Left,
774 lpWriteRegion->Right
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",
782 lpWriteRegion->Top,
783 lpWriteRegion->Bottom,
784 lpWriteRegion->Left,
785 lpWriteRegion->Right
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);
795 SADD(sbuf);
796 for (j=lpWriteRegion->Left;j<=lpWriteRegion->Right;j++) {
797 off = j + offbase;
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 */
807 SADD(sbuf);
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);
815 return TRUE;
818 /***********************************************************************
819 * WriteConsoleW (KERNEL32.577)
821 BOOL WINAPI WriteConsoleW( HANDLE hConsoleOutput,
822 LPCVOID lpBuffer,
823 DWORD nNumberOfCharsToWrite,
824 LPDWORD lpNumberOfCharsWritten,
825 LPVOID lpReserved )
827 BOOL ret;
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 );
836 return ret;
840 /***********************************************************************
841 * ReadConsoleA (KERNEL32.419)
843 BOOL WINAPI ReadConsoleA( HANDLE hConsoleInput,
844 LPVOID lpBuffer,
845 DWORD nNumberOfCharsToRead,
846 LPDWORD lpNumberOfCharsRead,
847 LPVOID lpReserved )
849 int charsread = 0;
850 LPSTR xbuf = (LPSTR)lpBuffer;
851 LPINPUT_RECORD ir;
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;
865 req->count = 1;
866 req->flush = 1;
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)
871 continue;
872 if (ir->EventType != KEY_EVENT)
873 continue;
874 *xbuf++ = ir->Event.KeyEvent.uChar.AsciiChar;
875 charsread++;
877 if (lpNumberOfCharsRead)
878 *lpNumberOfCharsRead = charsread;
879 return TRUE;
882 /***********************************************************************
883 * ReadConsoleW (KERNEL32.427)
885 BOOL WINAPI ReadConsoleW( HANDLE hConsoleInput,
886 LPVOID lpBuffer,
887 DWORD nNumberOfCharsToRead,
888 LPDWORD lpNumberOfCharsRead,
889 LPVOID lpReserved )
891 BOOL ret;
892 LPSTR buf = (LPSTR)HeapAlloc(GetProcessHeap(), 0, nNumberOfCharsToRead);
894 ret = ReadConsoleA(
895 hConsoleInput,
896 buf,
897 nNumberOfCharsToRead,
898 lpNumberOfCharsRead,
899 lpReserved
901 if (ret)
902 lstrcpynAtoW(lpBuffer,buf,nNumberOfCharsToRead);
903 HeapFree( GetProcessHeap(), 0, buf );
904 return ret;
908 /******************************************************************************
909 * ReadConsoleInput32A [KERNEL32.569] Reads data from a console
911 * PARAMS
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
917 * RETURNS
918 * Success: TRUE
919 * Failure: FALSE
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 */
927 for (;;)
929 req->handle = hConsoleInput;
930 req->count = nLength;
931 req->flush = 1;
932 if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
933 if (req->read)
935 memcpy( lpBuffer, req + 1, req->read * sizeof(*lpBuffer) );
936 if (lpNumberOfEventsRead) *lpNumberOfEventsRead = req->read;
937 return TRUE;
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 */
964 req->flush = 1;
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;
984 req->count = count;
985 req->flush = 0;
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;
989 return TRUE;
993 /***********************************************************************
994 * PeekConsoleInputW (KERNEL32.551)
996 BOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,
997 LPINPUT_RECORD pirBuffer,
998 DWORD cInRecords,
999 LPDWORD lpcRead)
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;
1017 while (count)
1019 DWORD len = count < max ? count : max;
1020 req->count = len;
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;
1025 count -= len;
1026 buffer += len;
1028 return TRUE;
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();
1044 HANDLE hcon;
1045 DWORD written;
1047 if ((hcon = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL,
1048 OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
1049 return FALSE;
1050 req->handle = hcon;
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 );
1062 return TRUE;
1063 error:
1064 CloseHandle( hcon );
1065 return FALSE;
1069 /******************************************************************************
1070 * SetConsoleTitle32W [KERNEL32.477] Sets title bar string for console
1072 * PARAMS
1073 * title [I] Address of new title
1075 * NOTES
1076 * This should not be calling the A version
1078 * RETURNS
1079 * Success: TRUE
1080 * Failure: FALSE
1082 BOOL WINAPI SetConsoleTitleW( LPCWSTR title )
1084 BOOL ret;
1086 LPSTR titleA = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
1087 ret = SetConsoleTitleA(titleA);
1088 HeapFree( GetProcessHeap(), 0, titleA );
1089 return ret;
1092 /******************************************************************************
1093 * SetConsoleCursorPosition [KERNEL32.627]
1094 * Sets the cursor position in console
1096 * PARAMS
1097 * hConsoleOutput [I] Handle of console screen buffer
1098 * dwCursorPosition [I] New cursor position coordinates
1100 * RETURNS STD
1102 BOOL WINAPI SetConsoleCursorPosition( HANDLE hcon, COORD pos )
1104 char xbuf[20];
1105 DWORD xlen;
1107 /* make console complex only if we change lines, not just in the line */
1108 if (pos.y)
1109 CONSOLE_make_complex(hcon);
1111 TRACE("%d (%dx%d)\n", hcon, pos.x , pos.y );
1112 /* x are columns, y rows */
1113 if (pos.y)
1114 /* full screen cursor absolute positioning */
1115 sprintf(xbuf,"%c[%d;%dH", 0x1B, pos.y+1, pos.x+1);
1116 else
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);
1121 return TRUE;
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);
1133 req->handle = hcon;
1134 req->count = -1;
1135 req->flush = 0;
1136 if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
1137 if (nrofevents) *nrofevents = req->read;
1138 return TRUE;
1141 /***********************************************************************
1142 * GetNumberOfConsoleMouseButtons (KERNEL32.358)
1144 BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons)
1146 FIXME("(%p): stub\n", nrofbuttons);
1147 *nrofbuttons = 2;
1148 return TRUE;
1151 /******************************************************************************
1152 * GetConsoleCursorInfo32 [KERNEL32.296] Gets size and visibility of console
1154 * PARAMS
1155 * hcon [I] Handle to console screen buffer
1156 * cinfo [O] Address of cursor information
1158 * RETURNS
1159 * Success: TRUE
1160 * Failure: FALSE
1162 BOOL WINAPI GetConsoleCursorInfo( HANDLE hcon, LPCONSOLE_CURSOR_INFO cinfo )
1164 struct get_console_info_request *req = get_req_buffer();
1165 req->handle = hcon;
1166 if (server_call( REQ_GET_CONSOLE_INFO )) return FALSE;
1167 if (cinfo)
1169 cinfo->dwSize = req->cursor_size;
1170 cinfo->bVisible = req->cursor_visible;
1172 return TRUE;
1176 /******************************************************************************
1177 * SetConsoleCursorInfo32 [KERNEL32.626] Sets size and visibility of cursor
1179 * RETURNS
1180 * Success: TRUE
1181 * Failure: FALSE
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();
1188 char buf[8];
1189 DWORD xlen;
1191 CONSOLE_make_complex(hcon);
1192 sprintf(buf,"\033[?25%c",cinfo->bVisible?'h':'l');
1193 WriteFile(hcon,buf,strlen(buf),&xlen,NULL);
1195 req->handle = hcon;
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
1206 * RETURNS
1207 * Success: TRUE
1208 * Failure: FALSE
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);
1216 return TRUE;
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.
1226 * RETURNS
1227 * Success: TRUE
1228 * Failure: FALSE
1230 BOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttr)
1232 const int colormap[8] = {
1233 0,4,2,6,
1234 1,5,3,7,
1236 DWORD xlen;
1237 char buffer[20];
1239 TRACE("(%d,%d)\n",hConsoleOutput,wAttr);
1240 sprintf(buffer,"%c[0;%s3%d;4%dm",
1242 (wAttr & FOREGROUND_INTENSITY)?"1;":"",
1243 colormap[wAttr&7],
1244 colormap[(wAttr&0x70)>>4]
1246 WriteFile(hConsoleOutput,buffer,strlen(buffer),&xlen,NULL);
1247 return TRUE;
1251 /******************************************************************************
1252 * SetConsoleScreenBufferSize [KERNEL32.630] Changes size of console
1254 * PARAMS
1255 * hConsoleOutput [I] Handle to console screen buffer
1256 * dwSize [I] New size in character rows and cols
1258 * RETURNS
1259 * Success: TRUE
1260 * Failure: FALSE
1262 BOOL WINAPI SetConsoleScreenBufferSize( HANDLE hConsoleOutput,
1263 COORD dwSize )
1265 FIXME("(%d,%dx%d): stub\n",hConsoleOutput,dwSize.x,dwSize.y);
1266 return TRUE;
1270 /******************************************************************************
1271 * FillConsoleOutputCharacterA [KERNEL32.242]
1273 * PARAMS
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
1280 * RETURNS
1281 * Success: TRUE
1282 * Failure: FALSE
1284 BOOL WINAPI FillConsoleOutputCharacterA(
1285 HANDLE hConsoleOutput,
1286 BYTE cCharacter,
1287 DWORD nLength,
1288 COORD dwCoord,
1289 LPDWORD lpNumCharsWritten)
1291 long count;
1292 DWORD xlen;
1294 SetConsoleCursorPosition(hConsoleOutput,dwCoord);
1295 for(count=0;count<nLength;count++)
1296 WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
1297 *lpNumCharsWritten = nLength;
1298 return TRUE;
1302 /******************************************************************************
1303 * FillConsoleOutputCharacterW [KERNEL32.243] Writes characters to console
1305 * PARAMS
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
1312 * RETURNS
1313 * Success: TRUE
1314 * Failure: FALSE
1316 BOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,
1317 WCHAR cCharacter,
1318 DWORD nLength,
1319 COORD dwCoord,
1320 LPDWORD lpNumCharsWritten)
1322 long count;
1323 DWORD xlen;
1325 SetConsoleCursorPosition(hConsoleOutput,dwCoord);
1326 /* FIXME: not quite correct ... but the lower part of UNICODE char comes
1327 * first
1329 for(count=0;count<nLength;count++)
1330 WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
1331 *lpNumCharsWritten = nLength;
1332 return TRUE;
1336 /******************************************************************************
1337 * FillConsoleOutputAttribute [KERNEL32.241] Sets attributes for console
1339 * PARAMS
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
1346 * RETURNS
1347 * Success: TRUE
1348 * Failure: FALSE
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;
1357 return TRUE;
1360 /******************************************************************************
1361 * ReadConsoleOutputCharacter32A [KERNEL32.573]
1363 * BUGS
1364 * Unimplemented
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);
1372 return FALSE;
1376 /******************************************************************************
1377 * ScrollConsoleScreenBuffer [KERNEL32.612]
1379 * BUGS
1380 * Unimplemented
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);
1389 return FALSE;