2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Driver DLL
4 * FILE: win32ss/user/winsrv/consrv/condrv/text.c
5 * PURPOSE: Console Output Functions for text-mode screen-buffers
6 * PROGRAMMERS: Jeffrey Morlan
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
13 #include "include/conio.h"
14 #include "include/conio2.h"
15 #include "conoutput.h"
22 /* GLOBALS ********************************************************************/
27 /* PRIVATE FUNCTIONS **********************************************************/
29 CONSOLE_IO_OBJECT_TYPE
30 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This
)
32 // return This->Header.Type;
33 return TEXTMODE_BUFFER
;
36 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl
=
38 TEXTMODE_BUFFER_GetType
,
43 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
);
47 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
48 IN OUT PCONSOLE Console
,
51 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
);
55 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
56 IN OUT PCONSOLE Console
,
57 IN PTEXTMODE_BUFFER_INFO TextModeInfo
)
59 NTSTATUS Status
= STATUS_SUCCESS
;
60 PTEXTMODE_SCREEN_BUFFER NewBuffer
= NULL
;
62 if (Console
== NULL
|| Buffer
== NULL
|| TextModeInfo
== NULL
)
63 return STATUS_INVALID_PARAMETER
;
67 Status
= CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER
*)&NewBuffer
,
69 sizeof(TEXTMODE_SCREEN_BUFFER
));
70 if (!NT_SUCCESS(Status
)) return Status
;
71 NewBuffer
->Header
.Type
= TEXTMODE_BUFFER
;
72 NewBuffer
->Vtbl
= &TextVtbl
;
74 NewBuffer
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
75 TextModeInfo
->ScreenBufferSize
.X
*
76 TextModeInfo
->ScreenBufferSize
.Y
*
78 if (NewBuffer
->Buffer
== NULL
)
80 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
81 return STATUS_INSUFFICIENT_RESOURCES
;
84 NewBuffer
->ScreenBufferSize
= NewBuffer
->OldScreenBufferSize
85 = TextModeInfo
->ScreenBufferSize
;
86 NewBuffer
->ViewSize
= NewBuffer
->OldViewSize
87 = Console
->ConsoleSize
;
89 NewBuffer
->ViewOrigin
.X
= NewBuffer
->ViewOrigin
.Y
= 0;
90 NewBuffer
->VirtualY
= 0;
92 NewBuffer
->CursorBlinkOn
= NewBuffer
->ForceCursorOff
= FALSE
;
93 NewBuffer
->CursorInfo
.bVisible
= (TextModeInfo
->IsCursorVisible
&& (TextModeInfo
->CursorSize
!= 0));
94 NewBuffer
->CursorInfo
.dwSize
= min(max(TextModeInfo
->CursorSize
, 0), 100);
96 NewBuffer
->ScreenDefaultAttrib
= TextModeInfo
->ScreenAttrib
;
97 NewBuffer
->PopupDefaultAttrib
= TextModeInfo
->PopupAttrib
;
99 /* Initialize buffer to be empty with default attributes */
100 for (NewBuffer
->CursorPosition
.Y
= 0 ; NewBuffer
->CursorPosition
.Y
< NewBuffer
->ScreenBufferSize
.Y
; NewBuffer
->CursorPosition
.Y
++)
102 ClearLineBuffer(NewBuffer
);
104 NewBuffer
->CursorPosition
.X
= NewBuffer
->CursorPosition
.Y
= 0;
106 NewBuffer
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
108 *Buffer
= (PCONSOLE_SCREEN_BUFFER
)NewBuffer
;
109 return STATUS_SUCCESS
;
113 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
)
115 PTEXTMODE_SCREEN_BUFFER Buff
= (PTEXTMODE_SCREEN_BUFFER
)Buffer
;
118 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
119 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
121 Buffer
->Header
.Type
= SCREEN_BUFFER
;
123 ConsoleFreeHeap(Buff
->Buffer
);
125 CONSOLE_SCREEN_BUFFER_Destroy(Buffer
);
130 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff
, ULONG X
, ULONG Y
)
132 return &Buff
->Buffer
[((Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
) * Buff
->ScreenBufferSize
.X
+ X
];
136 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
)
138 PCHAR_INFO Ptr
= ConioCoordToPointer(Buff
, 0, Buff
->CursorPosition
.Y
);
141 for (Pos
= 0; Pos
< Buff
->ScreenBufferSize
.X
; Pos
++, Ptr
++)
144 Ptr
->Char
.UnicodeChar
= L
' ';
145 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
149 static __inline BOOLEAN
150 ConioGetIntersection(OUT PSMALL_RECT Intersection
,
151 IN PSMALL_RECT Rect1
,
152 IN PSMALL_RECT Rect2
)
154 if ( ConioIsRectEmpty(Rect1
) ||
155 ConioIsRectEmpty(Rect2
) ||
156 (Rect1
->Top
> Rect2
->Bottom
) ||
157 (Rect1
->Left
> Rect2
->Right
) ||
158 (Rect1
->Bottom
< Rect2
->Top
) ||
159 (Rect1
->Right
< Rect2
->Left
) )
161 /* The rectangles do not intersect */
162 ConioInitRect(Intersection
, 0, -1, 0, -1);
166 ConioInitRect(Intersection
,
167 max(Rect1
->Top
, Rect2
->Top
),
168 max(Rect1
->Left
, Rect2
->Left
),
169 min(Rect1
->Bottom
, Rect2
->Bottom
),
170 min(Rect1
->Right
, Rect2
->Right
));
175 static __inline BOOLEAN
176 ConioGetUnion(OUT PSMALL_RECT Union
,
177 IN PSMALL_RECT Rect1
,
178 IN PSMALL_RECT Rect2
)
180 if (ConioIsRectEmpty(Rect1
))
182 if (ConioIsRectEmpty(Rect2
))
184 ConioInitRect(Union
, 0, -1, 0, -1);
192 else if (ConioIsRectEmpty(Rect2
))
199 min(Rect1
->Top
, Rect2
->Top
),
200 min(Rect1
->Left
, Rect2
->Left
),
201 max(Rect1
->Bottom
, Rect2
->Bottom
),
202 max(Rect1
->Right
, Rect2
->Right
));
209 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff
,
210 IN OUT PSMALL_RECT UpdateRect
,
214 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
216 UpdateRect
->Left
= 0;
220 UpdateRect
->Left
= Start
->X
;
222 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
224 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
228 UpdateRect
->Right
= Start
->X
+ Length
- 1;
230 UpdateRect
->Top
= Start
->Y
;
231 UpdateRect
->Bottom
= Start
->Y
+ (Start
->X
+ Length
- 1) / Buff
->ScreenBufferSize
.X
;
232 if (Buff
->ScreenBufferSize
.Y
<= UpdateRect
->Bottom
)
234 UpdateRect
->Bottom
= Buff
->ScreenBufferSize
.Y
- 1;
239 * Move from one rectangle to another. We must be careful about the order that
240 * this is done, to avoid overwriting parts of the source before they are moved.
243 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
244 PSMALL_RECT SrcRegion
,
245 PSMALL_RECT DstRegion
,
246 PSMALL_RECT ClipRegion
,
249 int Width
= ConioRectWidth(SrcRegion
);
250 int Height
= ConioRectHeight(SrcRegion
);
261 /* Moving down: work from bottom up */
262 SY
= SrcRegion
->Bottom
;
263 DY
= DstRegion
->Bottom
;
266 for (i
= 0; i
< Height
; i
++)
268 PCHAR_INFO SRow
= ConioCoordToPointer(ScreenBuffer
, 0, SY
);
269 PCHAR_INFO DRow
= ConioCoordToPointer(ScreenBuffer
, 0, DY
);
271 SX
= SrcRegion
->Left
;
272 DX
= DstRegion
->Left
;
276 /* Moving right: work from right to left */
277 SX
= SrcRegion
->Right
;
278 DX
= DstRegion
->Right
;
281 for (j
= 0; j
< Width
; j
++)
283 CHAR_INFO Cell
= SRow
[SX
];
284 if (SX
>= ClipRegion
->Left
&& SX
<= ClipRegion
->Right
&&
285 SY
>= ClipRegion
->Top
&& SY
<= ClipRegion
->Bottom
)
289 if (DX
>= ClipRegion
->Left
&& DX
<= ClipRegion
->Right
&&
290 DY
>= ClipRegion
->Top
&& DY
<= ClipRegion
->Bottom
)
303 ConioEffectiveCursorSize(PCONSOLE Console
, DWORD Scale
)
305 DWORD Size
= (Console
->ActiveBuffer
->CursorInfo
.dwSize
* Scale
+ 99) / 100;
306 /* If line input in progress, perhaps adjust for insert toggle */
307 if (Console
->LineBuffer
&& !Console
->LineComplete
&& Console
->LineInsertToggle
)
308 return (Size
* 2 <= Scale
) ? (Size
* 2) : (Size
/ 2);
313 ConioResizeBuffer(PCONSOLE Console
,
314 PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
320 WORD CurrentAttribute
;
322 PCHAR_INFO OldBuffer
;
326 /* Buffer size is not allowed to be smaller than the view size */
327 if (Size
.X
< ScreenBuffer
->ViewSize
.X
|| Size
.Y
< ScreenBuffer
->ViewSize
.Y
)
328 return STATUS_INVALID_PARAMETER
;
330 if (Size
.X
== ScreenBuffer
->ScreenBufferSize
.X
&& Size
.Y
== ScreenBuffer
->ScreenBufferSize
.Y
)
332 // FIXME: Trigger a buffer resize event ??
333 return STATUS_SUCCESS
;
336 if (Console
->FixedSize
)
339 * The console is in fixed-size mode, so we cannot resize anything
340 * at the moment. However, keep those settings somewhere so that
341 * we can try to set them up when we will be allowed to do so.
343 ScreenBuffer
->OldScreenBufferSize
= Size
;
344 return STATUS_NOT_SUPPORTED
; // STATUS_SUCCESS
347 Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
.X
* Size
.Y
* sizeof(CHAR_INFO
));
348 if (!Buffer
) return STATUS_NO_MEMORY
;
350 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer
->ScreenBufferSize
.X
, ScreenBuffer
->ScreenBufferSize
.Y
, Size
.X
, Size
.Y
);
351 OldBuffer
= ScreenBuffer
->Buffer
;
353 for (CurrentY
= 0; CurrentY
< ScreenBuffer
->ScreenBufferSize
.Y
&& CurrentY
< Size
.Y
; CurrentY
++)
355 ptr
= ConioCoordToPointer(ScreenBuffer
, 0, CurrentY
);
356 if (Size
.X
<= ScreenBuffer
->ScreenBufferSize
.X
)
359 RtlCopyMemory(Buffer
+ Offset
, ptr
, Size
.X
* sizeof(CHAR_INFO
));
365 RtlCopyMemory(Buffer
+ Offset
, ptr
, ScreenBuffer
->ScreenBufferSize
.X
* sizeof(CHAR_INFO
));
366 Offset
+= ScreenBuffer
->ScreenBufferSize
.X
;
368 /* The attribute to be used is the one of the last cell of the current line */
369 CurrentAttribute
= ConioCoordToPointer(ScreenBuffer
,
370 ScreenBuffer
->ScreenBufferSize
.X
- 1,
371 CurrentY
)->Attributes
;
373 diff
= Size
.X
- ScreenBuffer
->ScreenBufferSize
.X
;
375 /* Zero-out the new part of the buffer */
376 for (i
= 0; i
< diff
; i
++)
378 ptr
= Buffer
+ Offset
;
379 ptr
->Char
.UnicodeChar
= L
' ';
380 ptr
->Attributes
= CurrentAttribute
;
386 if (Size
.Y
> ScreenBuffer
->ScreenBufferSize
.Y
)
388 diff
= Size
.X
* (Size
.Y
- ScreenBuffer
->ScreenBufferSize
.Y
);
390 /* Zero-out the new part of the buffer */
391 for (i
= 0; i
< diff
; i
++)
393 ptr
= Buffer
+ Offset
;
394 ptr
->Char
.UnicodeChar
= L
' ';
395 ptr
->Attributes
= ScreenBuffer
->ScreenDefaultAttrib
;
400 (void)InterlockedExchangePointer((PVOID
volatile*)&ScreenBuffer
->Buffer
, Buffer
);
401 ConsoleFreeHeap(OldBuffer
);
402 ScreenBuffer
->ScreenBufferSize
= ScreenBuffer
->OldScreenBufferSize
= Size
;
403 ScreenBuffer
->VirtualY
= 0;
405 /* Ensure cursor and window are within buffer */
406 if (ScreenBuffer
->CursorPosition
.X
>= Size
.X
)
407 ScreenBuffer
->CursorPosition
.X
= Size
.X
- 1;
408 if (ScreenBuffer
->CursorPosition
.Y
>= Size
.Y
)
409 ScreenBuffer
->CursorPosition
.Y
= Size
.Y
- 1;
410 if (ScreenBuffer
->ViewOrigin
.X
> Size
.X
- ScreenBuffer
->ViewSize
.X
)
411 ScreenBuffer
->ViewOrigin
.X
= Size
.X
- ScreenBuffer
->ViewSize
.X
;
412 if (ScreenBuffer
->ViewOrigin
.Y
> Size
.Y
- ScreenBuffer
->ViewSize
.Y
)
413 ScreenBuffer
->ViewOrigin
.Y
= Size
.Y
- ScreenBuffer
->ViewSize
.Y
;
416 * Trigger a buffer resize event
418 if (Console
->InputBuffer
.Mode
& ENABLE_WINDOW_INPUT
)
422 er
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
423 er
.Event
.WindowBufferSizeEvent
.dwSize
= ScreenBuffer
->ScreenBufferSize
;
425 ConioProcessInputEvent(Console
, &er
);
428 return STATUS_SUCCESS
;
432 ConioNextLine(PTEXTMODE_SCREEN_BUFFER Buff
, PSMALL_RECT UpdateRect
, PUINT ScrolledLines
)
434 /* If we hit bottom, slide the viewable screen */
435 if (++Buff
->CursorPosition
.Y
== Buff
->ScreenBufferSize
.Y
)
437 Buff
->CursorPosition
.Y
--;
438 if (++Buff
->VirtualY
== Buff
->ScreenBufferSize
.Y
)
443 ClearLineBuffer(Buff
);
444 if (UpdateRect
->Top
!= 0)
449 UpdateRect
->Left
= 0;
450 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
451 UpdateRect
->Bottom
= Buff
->CursorPosition
.Y
;
455 ConioWriteConsole(PCONSOLE Console
,
456 PTEXTMODE_SCREEN_BUFFER Buff
,
463 SMALL_RECT UpdateRect
;
464 SHORT CursorStartX
, CursorStartY
;
467 CursorStartX
= Buff
->CursorPosition
.X
;
468 CursorStartY
= Buff
->CursorPosition
.Y
;
469 UpdateRect
.Left
= Buff
->ScreenBufferSize
.X
;
470 UpdateRect
.Top
= Buff
->CursorPosition
.Y
;
471 UpdateRect
.Right
= -1;
472 UpdateRect
.Bottom
= Buff
->CursorPosition
.Y
;
475 for (i
= 0; i
< Length
; i
++)
478 * If we are in processed mode, interpret special characters and
479 * display them correctly. Otherwise, just put them into the buffer.
481 if (Buff
->Mode
& ENABLE_PROCESSED_OUTPUT
)
484 if (Buffer
[i
] == L
'\r')
486 Buff
->CursorPosition
.X
= 0;
487 UpdateRect
.Left
= min(UpdateRect
.Left
, Buff
->CursorPosition
.X
);
488 UpdateRect
.Right
= max(UpdateRect
.Right
, Buff
->CursorPosition
.X
);
492 else if (Buffer
[i
] == L
'\n')
494 Buff
->CursorPosition
.X
= 0;
495 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
499 else if (Buffer
[i
] == L
'\b')
501 /* Only handle BS if we're not on the first pos of the first line */
502 if (0 != Buff
->CursorPosition
.X
|| 0 != Buff
->CursorPosition
.Y
)
504 if (0 == Buff
->CursorPosition
.X
)
506 /* slide virtual position up */
507 Buff
->CursorPosition
.X
= Buff
->ScreenBufferSize
.X
- 1;
508 Buff
->CursorPosition
.Y
--;
509 UpdateRect
.Top
= min(UpdateRect
.Top
, Buff
->CursorPosition
.Y
);
513 Buff
->CursorPosition
.X
--;
515 Ptr
= ConioCoordToPointer(Buff
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
516 Ptr
->Char
.UnicodeChar
= L
' ';
517 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
518 UpdateRect
.Left
= min(UpdateRect
.Left
, Buff
->CursorPosition
.X
);
519 UpdateRect
.Right
= max(UpdateRect
.Right
, Buff
->CursorPosition
.X
);
524 else if (Buffer
[i
] == L
'\t')
528 UpdateRect
.Left
= min(UpdateRect
.Left
, Buff
->CursorPosition
.X
);
529 EndX
= (Buff
->CursorPosition
.X
+ TAB_WIDTH
) & ~(TAB_WIDTH
- 1);
530 EndX
= min(EndX
, (UINT
)Buff
->ScreenBufferSize
.X
);
531 Ptr
= ConioCoordToPointer(Buff
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
532 while (Buff
->CursorPosition
.X
< EndX
)
534 Ptr
->Char
.UnicodeChar
= L
' ';
535 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
537 Buff
->CursorPosition
.X
++;
539 UpdateRect
.Right
= max(UpdateRect
.Right
, Buff
->CursorPosition
.X
- 1);
540 if (Buff
->CursorPosition
.X
== Buff
->ScreenBufferSize
.X
)
542 if (Buff
->Mode
& ENABLE_WRAP_AT_EOL_OUTPUT
)
544 Buff
->CursorPosition
.X
= 0;
545 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
549 Buff
->CursorPosition
.X
--;
555 // else if (Buffer[i] == L'\a')
557 // // FIXME: This MUST BE moved to the terminal emulator frontend!!
558 // DPRINT1("Bell\n");
559 // // SendNotifyMessage(Console->hWindow, PM_CONSOLE_BEEP, 0, 0);
563 UpdateRect
.Left
= min(UpdateRect
.Left
, Buff
->CursorPosition
.X
);
564 UpdateRect
.Right
= max(UpdateRect
.Right
, Buff
->CursorPosition
.X
);
566 Ptr
= ConioCoordToPointer(Buff
, Buff
->CursorPosition
.X
, Buff
->CursorPosition
.Y
);
567 Ptr
->Char
.UnicodeChar
= Buffer
[i
];
568 if (Attrib
) Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
570 Buff
->CursorPosition
.X
++;
571 if (Buff
->CursorPosition
.X
== Buff
->ScreenBufferSize
.X
)
573 if (Buff
->Mode
& ENABLE_WRAP_AT_EOL_OUTPUT
)
575 Buff
->CursorPosition
.X
= 0;
576 ConioNextLine(Buff
, &UpdateRect
, &ScrolledLines
);
580 Buff
->CursorPosition
.X
= CursorStartX
;
585 if (!ConioIsRectEmpty(&UpdateRect
) && (PCONSOLE_SCREEN_BUFFER
)Buff
== Console
->ActiveBuffer
)
587 ConioWriteStream(Console
, &UpdateRect
, CursorStartX
, CursorStartY
,
588 ScrolledLines
, Buffer
, Length
);
591 return STATUS_SUCCESS
;
595 /* PUBLIC DRIVER APIS *********************************************************/
598 ConDrvReadConsoleOutput(IN PCONSOLE Console
,
599 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
601 OUT PCHAR_INFO CharInfo
/*Buffer*/,
602 IN PCOORD BufferSize
,
603 IN PCOORD BufferCoord
,
604 IN OUT PSMALL_RECT ReadRegion
)
606 PCHAR_INFO CurCharInfo
;
608 SMALL_RECT CapturedReadRegion
;
609 SMALL_RECT ScreenRect
;
615 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
||
616 BufferSize
== NULL
|| BufferCoord
== NULL
|| ReadRegion
== NULL
)
618 return STATUS_INVALID_PARAMETER
;
622 ASSERT(Console
== Buffer
->Header
.Console
);
624 CapturedReadRegion
= *ReadRegion
;
626 /* FIXME: Is this correct? */
627 CodePage
= Console
->OutputCodePage
;
629 SizeX
= min(BufferSize
->X
- BufferCoord
->X
, ConioRectWidth(&CapturedReadRegion
));
630 SizeY
= min(BufferSize
->Y
- BufferCoord
->Y
, ConioRectHeight(&CapturedReadRegion
));
631 CapturedReadRegion
.Right
= CapturedReadRegion
.Left
+ SizeX
;
632 CapturedReadRegion
.Bottom
= CapturedReadRegion
.Top
+ SizeY
;
634 ConioInitRect(&ScreenRect
, 0, 0, Buffer
->ScreenBufferSize
.Y
, Buffer
->ScreenBufferSize
.X
);
635 if (!ConioGetIntersection(&CapturedReadRegion
, &ScreenRect
, &CapturedReadRegion
))
637 return STATUS_SUCCESS
;
640 for (i
= 0, Y
= CapturedReadRegion
.Top
; Y
< CapturedReadRegion
.Bottom
; ++i
, ++Y
)
642 CurCharInfo
= CharInfo
+ (i
* BufferSize
->X
);
644 Ptr
= ConioCoordToPointer(Buffer
, CapturedReadRegion
.Left
, Y
);
645 for (X
= CapturedReadRegion
.Left
; X
< CapturedReadRegion
.Right
; ++X
)
649 CurCharInfo
->Char
.UnicodeChar
= Ptr
->Char
.UnicodeChar
;
653 // ConsoleUnicodeCharToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
654 WideCharToMultiByte(CodePage
, 0, &Ptr
->Char
.UnicodeChar
, 1,
655 &CurCharInfo
->Char
.AsciiChar
, 1, NULL
, NULL
);
657 CurCharInfo
->Attributes
= Ptr
->Attributes
;
663 ReadRegion
->Left
= CapturedReadRegion
.Left
;
664 ReadRegion
->Top
= CapturedReadRegion
.Top
;
665 ReadRegion
->Right
= CapturedReadRegion
.Left
+ SizeX
- 1;
666 ReadRegion
->Bottom
= CapturedReadRegion
.Top
+ SizeY
- 1;
668 return STATUS_SUCCESS
;
672 ConDrvWriteConsoleOutput(IN PCONSOLE Console
,
673 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
675 IN PCHAR_INFO CharInfo
/*Buffer*/,
676 IN PCOORD BufferSize
,
677 IN PCOORD BufferCoord
,
678 IN OUT PSMALL_RECT WriteRegion
)
680 SHORT i
, X
, Y
, SizeX
, SizeY
;
681 SMALL_RECT ScreenBuffer
;
682 PCHAR_INFO CurCharInfo
;
683 SMALL_RECT CapturedWriteRegion
;
686 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
||
687 BufferSize
== NULL
|| BufferCoord
== NULL
|| WriteRegion
== NULL
)
689 return STATUS_INVALID_PARAMETER
;
693 ASSERT(Console
== Buffer
->Header
.Console
);
695 CapturedWriteRegion
= *WriteRegion
;
697 SizeX
= min(BufferSize
->X
- BufferCoord
->X
, ConioRectWidth(&CapturedWriteRegion
));
698 SizeY
= min(BufferSize
->Y
- BufferCoord
->Y
, ConioRectHeight(&CapturedWriteRegion
));
699 CapturedWriteRegion
.Right
= CapturedWriteRegion
.Left
+ SizeX
- 1;
700 CapturedWriteRegion
.Bottom
= CapturedWriteRegion
.Top
+ SizeY
- 1;
702 /* Make sure WriteRegion is inside the screen buffer */
703 ConioInitRect(&ScreenBuffer
, 0, 0, Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
704 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
707 * It is okay to have a WriteRegion completely outside
708 * the screen buffer. No data is written then.
710 return STATUS_SUCCESS
;
713 for (i
= 0, Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; i
++, Y
++)
715 CurCharInfo
= CharInfo
+ (i
+ BufferCoord
->Y
) * BufferSize
->X
+ BufferCoord
->X
;
717 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
718 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; X
++)
722 Ptr
->Char
.UnicodeChar
= CurCharInfo
->Char
.UnicodeChar
;
726 ConsoleAnsiCharToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
.AsciiChar
);
728 Ptr
->Attributes
= CurCharInfo
->Attributes
;
734 ConioDrawRegion(Console
, &CapturedWriteRegion
);
736 WriteRegion
->Left
= CapturedWriteRegion
.Left
;
737 WriteRegion
->Top
= CapturedWriteRegion
.Top
;
738 WriteRegion
->Right
= CapturedWriteRegion
.Left
+ SizeX
- 1;
739 WriteRegion
->Bottom
= CapturedWriteRegion
.Top
+ SizeY
- 1;
741 return STATUS_SUCCESS
;
745 ConDrvWriteConsole(IN PCONSOLE Console
,
746 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
748 IN PVOID StringBuffer
,
749 IN ULONG NumCharsToWrite
,
750 OUT PULONG NumCharsWritten OPTIONAL
)
752 NTSTATUS Status
= STATUS_SUCCESS
;
753 PWCHAR Buffer
= NULL
;
757 if (Console
== NULL
|| ScreenBuffer
== NULL
/* || StringBuffer == NULL */)
758 return STATUS_INVALID_PARAMETER
;
760 /* Validity checks */
761 ASSERT(Console
== ScreenBuffer
->Header
.Console
);
762 ASSERT( (StringBuffer
!= NULL
&& NumCharsToWrite
>= 0) ||
763 (StringBuffer
== NULL
&& NumCharsToWrite
== 0) );
765 // if (Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION))
766 if (Console
->PauseFlags
&& Console
->UnpauseEvent
!= NULL
)
768 return STATUS_PENDING
;
773 Buffer
= StringBuffer
;
777 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
781 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
784 MultiByteToWideChar(Console
->OutputCodePage
, 0,
787 (PWCHAR
)Buffer
, Length
);
791 Status
= STATUS_NO_MEMORY
;
797 if (NT_SUCCESS(Status
))
799 Status
= ConioWriteConsole(Console
,
804 if (NT_SUCCESS(Status
))
806 Written
= NumCharsToWrite
;
810 if (!Unicode
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
813 if (NumCharsWritten
) *NumCharsWritten
= Written
;
819 ConDrvReadConsoleOutputString(IN PCONSOLE Console
,
820 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
821 IN CODE_TYPE CodeType
,
822 OUT PVOID StringBuffer
,
823 IN ULONG NumCodesToRead
,
826 OUT PULONG CodesRead
)
834 if (Console
== NULL
|| Buffer
== NULL
||
835 ReadCoord
== NULL
|| EndCoord
== NULL
|| CodesRead
== NULL
)
837 return STATUS_INVALID_PARAMETER
;
840 /* Validity checks */
841 ASSERT(Console
== Buffer
->Header
.Console
);
842 ASSERT( (StringBuffer
!= NULL
&& NumCodesToRead
>= 0) ||
843 (StringBuffer
== NULL
&& NumCodesToRead
== 0) );
848 CodeSize
= sizeof(CHAR
);
852 CodeSize
= sizeof(WCHAR
);
856 CodeSize
= sizeof(WORD
);
860 return STATUS_INVALID_PARAMETER
;
863 ReadBuffer
= StringBuffer
;
865 Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
868 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
870 * If the number of attributes (resp. characters) to be read from extends
871 * beyond the end of the specified screen buffer row, attributes (resp.
872 * characters) are read from the next row. If the number of attributes
873 * (resp. characters) to be read from extends beyond the end of the console
874 * screen buffer, attributes (resp. characters) up to the end of the console
875 * screen buffer are read.
877 * TODO: Do NOT loop up to NumCodesToRead, but stop before
878 * if we are going to overflow...
880 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
881 for (i
= 0; i
< min(NumCodesToRead
, Buffer
->ScreenBufferSize
.X
* Buffer
->ScreenBufferSize
.Y
); ++i
)
883 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
884 Ptr
= &Buffer
->Buffer
[Xpos
+ Ypos
* Buffer
->ScreenBufferSize
.X
];
889 ConsoleUnicodeCharToAnsiChar(Console
, (PCHAR
)ReadBuffer
, &Ptr
->Char
.UnicodeChar
);
893 *(PWCHAR
)ReadBuffer
= Ptr
->Char
.UnicodeChar
;
897 *(PWORD
)ReadBuffer
= Ptr
->Attributes
;
900 ReadBuffer
= (PVOID
)((ULONG_PTR
)ReadBuffer
+ CodeSize
);
905 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
910 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
919 // case CODE_UNICODE:
920 // *(PWCHAR)ReadBuffer = 0;
924 // *(PCHAR)ReadBuffer = 0;
927 // case CODE_ATTRIBUTE:
928 // *(PWORD)ReadBuffer = 0;
933 EndCoord
->Y
= (Ypos
- Buffer
->VirtualY
+ Buffer
->ScreenBufferSize
.Y
) % Buffer
->ScreenBufferSize
.Y
;
935 *CodesRead
= (ULONG
)((ULONG_PTR
)ReadBuffer
- (ULONG_PTR
)StringBuffer
) / CodeSize
;
938 return STATUS_SUCCESS
;
942 ConDrvWriteConsoleOutputString(IN PCONSOLE Console
,
943 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
944 IN CODE_TYPE CodeType
,
945 IN PVOID StringBuffer
,
946 IN ULONG NumCodesToWrite
,
947 IN PCOORD WriteCoord
/*,
949 OUT PULONG CodesWritten */)
951 NTSTATUS Status
= STATUS_SUCCESS
;
952 PVOID WriteBuffer
= NULL
;
953 PWCHAR tmpString
= NULL
;
954 DWORD X
, Y
, Length
; // , Written = 0;
956 SMALL_RECT UpdateRect
;
959 if (Console
== NULL
|| Buffer
== NULL
||
960 WriteCoord
== NULL
/* || EndCoord == NULL || CodesWritten == NULL */)
962 return STATUS_INVALID_PARAMETER
;
965 /* Validity checks */
966 ASSERT(Console
== Buffer
->Header
.Console
);
967 ASSERT( (StringBuffer
!= NULL
&& NumCodesToWrite
>= 0) ||
968 (StringBuffer
== NULL
&& NumCodesToWrite
== 0) );
973 CodeSize
= sizeof(CHAR
);
977 CodeSize
= sizeof(WCHAR
);
981 CodeSize
= sizeof(WORD
);
985 return STATUS_INVALID_PARAMETER
;
988 if (CodeType
== CODE_ASCII
)
990 /* Convert the ASCII string into Unicode before writing it to the console */
991 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
995 tmpString
= WriteBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
998 MultiByteToWideChar(Console
->OutputCodePage
, 0,
1001 (PWCHAR
)WriteBuffer
, Length
);
1005 Status
= STATUS_NO_MEMORY
;
1010 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
1011 WriteBuffer
= StringBuffer
;
1014 if (WriteBuffer
== NULL
|| !NT_SUCCESS(Status
)) goto Cleanup
;
1017 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1018 Length
= NumCodesToWrite
;
1019 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1020 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1024 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1025 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
1031 Ptr
->Char
.UnicodeChar
= *(PWCHAR
)WriteBuffer
;
1034 case CODE_ATTRIBUTE
:
1035 Ptr
->Attributes
= *(PWORD
)WriteBuffer
;
1038 WriteBuffer
= (PVOID
)((ULONG_PTR
)WriteBuffer
+ CodeSize
);
1042 if (++X
== Buffer
->ScreenBufferSize
.X
)
1046 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
1053 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1055 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1056 ConioDrawRegion(Console
, &UpdateRect
);
1060 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1063 if (tmpString
) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString
);
1065 // CodesWritten = Written;
1070 ConDrvFillConsoleOutput(IN PCONSOLE Console
,
1071 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1072 IN CODE_TYPE CodeType
,
1074 IN ULONG NumCodesToWrite
,
1075 IN PCOORD WriteCoord
/*,
1076 OUT PULONG CodesWritten */)
1078 DWORD X
, Y
, Length
; // , Written = 0;
1080 SMALL_RECT UpdateRect
;
1082 if (Console
== NULL
|| Buffer
== NULL
|| Code
== NULL
||
1083 WriteCoord
== NULL
/* || CodesWritten == NULL */)
1085 return STATUS_INVALID_PARAMETER
;
1088 /* Validity check */
1089 ASSERT(Console
== Buffer
->Header
.Console
);
1095 /* On-place conversion from the ASCII char to the UNICODE char */
1096 ConsoleAnsiCharToUnicodeChar(Console
, &Code
->UnicodeChar
, &Code
->AsciiChar
);
1099 Code
= &Code
->UnicodeChar
;
1102 case CODE_ATTRIBUTE
:
1103 Code
= &Code
->Attribute
;
1107 if (CodeType
== CODE_ASCII
)
1109 /* On-place conversion from the ASCII char to the UNICODE char */
1110 // FIXME: What if Code points to an invalid memory zone ??
1111 ConsoleAnsiCharToUnicodeChar(Console
, (PWCHAR
)Code
, (PCHAR
)Code
);
1116 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1117 Length
= NumCodesToWrite
;
1118 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1119 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1123 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1124 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
1130 Ptr
->Char
.UnicodeChar
= *(PWCHAR
)Code
;
1133 case CODE_ATTRIBUTE
:
1134 Ptr
->Attributes
= *(PWORD
)Code
;
1140 if (++X
== Buffer
->ScreenBufferSize
.X
)
1144 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
1151 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1153 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1154 ConioDrawRegion(Console
, &UpdateRect
);
1157 // CodesWritten = Written; // NumCodesToWrite;
1158 return STATUS_SUCCESS
;
1162 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console
,
1163 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1164 OUT PCONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo
)
1166 if (Console
== NULL
|| Buffer
== NULL
|| ScreenBufferInfo
== NULL
)
1167 return STATUS_INVALID_PARAMETER
;
1169 /* Validity check */
1170 ASSERT(Console
== Buffer
->Header
.Console
);
1172 ScreenBufferInfo
->dwSize
= Buffer
->ScreenBufferSize
;
1173 ScreenBufferInfo
->dwCursorPosition
= Buffer
->CursorPosition
;
1174 ScreenBufferInfo
->wAttributes
= Buffer
->ScreenDefaultAttrib
;
1175 ScreenBufferInfo
->srWindow
.Left
= Buffer
->ViewOrigin
.X
;
1176 ScreenBufferInfo
->srWindow
.Top
= Buffer
->ViewOrigin
.Y
;
1177 ScreenBufferInfo
->srWindow
.Right
= Buffer
->ViewOrigin
.X
+ Buffer
->ViewSize
.X
- 1;
1178 ScreenBufferInfo
->srWindow
.Bottom
= Buffer
->ViewOrigin
.Y
+ Buffer
->ViewSize
.Y
- 1;
1180 // FIXME: Refine the computation
1181 ScreenBufferInfo
->dwMaximumWindowSize
= Buffer
->ScreenBufferSize
;
1183 return STATUS_SUCCESS
;
1187 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console
,
1188 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1191 if (Console
== NULL
|| Buffer
== NULL
)
1192 return STATUS_INVALID_PARAMETER
;
1194 /* Validity check */
1195 ASSERT(Console
== Buffer
->Header
.Console
);
1197 Buffer
->ScreenDefaultAttrib
= Attribute
;
1198 return STATUS_SUCCESS
;
1202 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console
,
1203 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1208 if (Console
== NULL
|| Buffer
== NULL
|| Size
== NULL
)
1209 return STATUS_INVALID_PARAMETER
;
1211 /* Validity check */
1212 ASSERT(Console
== Buffer
->Header
.Console
);
1214 Status
= ConioResizeBuffer(Console
, Buffer
, *Size
);
1215 if (NT_SUCCESS(Status
)) ConioResizeTerminal(Console
);
1221 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console
,
1222 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1224 IN PSMALL_RECT ScrollRectangle
,
1225 IN BOOLEAN UseClipRectangle
,
1226 IN PSMALL_RECT ClipRectangle OPTIONAL
,
1227 IN PCOORD DestinationOrigin
,
1228 IN CHAR_INFO FillChar
)
1230 COORD CapturedDestinationOrigin
;
1231 SMALL_RECT ScreenBuffer
;
1232 SMALL_RECT SrcRegion
;
1233 SMALL_RECT DstRegion
;
1234 SMALL_RECT UpdateRegion
;
1235 SMALL_RECT CapturedClipRectangle
;
1237 if (Console
== NULL
|| Buffer
== NULL
|| ScrollRectangle
== NULL
||
1238 (UseClipRectangle
? ClipRectangle
== NULL
: FALSE
) || DestinationOrigin
== NULL
)
1240 return STATUS_INVALID_PARAMETER
;
1243 /* Validity check */
1244 ASSERT(Console
== Buffer
->Header
.Console
);
1246 CapturedDestinationOrigin
= *DestinationOrigin
;
1248 /* Make sure the source rectangle is inside the screen buffer */
1249 ConioInitRect(&ScreenBuffer
, 0, 0, Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
1250 if (!ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, ScrollRectangle
))
1252 return STATUS_SUCCESS
;
1255 /* If the source was clipped on the left or top, adjust the destination accordingly */
1256 if (ScrollRectangle
->Left
< 0)
1258 CapturedDestinationOrigin
.X
-= ScrollRectangle
->Left
;
1260 if (ScrollRectangle
->Top
< 0)
1262 CapturedDestinationOrigin
.Y
-= ScrollRectangle
->Top
;
1265 if (UseClipRectangle
)
1267 CapturedClipRectangle
= *ClipRectangle
;
1268 if (!ConioGetIntersection(&CapturedClipRectangle
, &CapturedClipRectangle
, &ScreenBuffer
))
1270 return STATUS_SUCCESS
;
1275 CapturedClipRectangle
= ScreenBuffer
;
1278 ConioInitRect(&DstRegion
,
1279 CapturedDestinationOrigin
.Y
,
1280 CapturedDestinationOrigin
.X
,
1281 CapturedDestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
1282 CapturedDestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
1285 ConsoleAnsiCharToUnicodeChar(Console
, &FillChar
.Char
.UnicodeChar
, &FillChar
.Char
.AsciiChar
);
1287 ConioMoveRegion(Buffer
, &SrcRegion
, &DstRegion
, &CapturedClipRectangle
, FillChar
);
1289 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1291 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
1292 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &CapturedClipRectangle
))
1294 /* Draw update region */
1295 ConioDrawRegion(Console
, &UpdateRegion
);
1299 return STATUS_SUCCESS
;
1303 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console
,
1304 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1305 IN BOOLEAN Absolute
,
1306 IN PSMALL_RECT WindowRect
)
1308 SMALL_RECT CapturedWindowRect
;
1310 if (Console
== NULL
|| Buffer
== NULL
|| WindowRect
== NULL
)
1311 return STATUS_INVALID_PARAMETER
;
1313 /* Validity check */
1314 ASSERT(Console
== Buffer
->Header
.Console
);
1316 CapturedWindowRect
= *WindowRect
;
1318 if (Absolute
== FALSE
)
1320 /* Relative positions given. Transform them to absolute ones */
1321 CapturedWindowRect
.Left
+= Buffer
->ViewOrigin
.X
;
1322 CapturedWindowRect
.Top
+= Buffer
->ViewOrigin
.Y
;
1323 CapturedWindowRect
.Right
+= Buffer
->ViewOrigin
.X
+ Buffer
->ViewSize
.X
- 1;
1324 CapturedWindowRect
.Bottom
+= Buffer
->ViewOrigin
.Y
+ Buffer
->ViewSize
.Y
- 1;
1327 /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
1328 if ( (CapturedWindowRect
.Left
< 0) || (CapturedWindowRect
.Top
< 0) ||
1329 (CapturedWindowRect
.Right
>= Buffer
->ScreenBufferSize
.X
) ||
1330 (CapturedWindowRect
.Bottom
>= Buffer
->ScreenBufferSize
.Y
) ||
1331 (CapturedWindowRect
.Right
<= CapturedWindowRect
.Left
) ||
1332 (CapturedWindowRect
.Bottom
<= CapturedWindowRect
.Top
) )
1334 return STATUS_INVALID_PARAMETER
;
1337 Buffer
->ViewOrigin
.X
= CapturedWindowRect
.Left
;
1338 Buffer
->ViewOrigin
.Y
= CapturedWindowRect
.Top
;
1340 Buffer
->ViewSize
.X
= CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1;
1341 Buffer
->ViewSize
.Y
= CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1;
1343 return STATUS_SUCCESS
;