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 *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 /* PRIVATE FUNCTIONS **********************************************************/
21 CONSOLE_IO_OBJECT_TYPE
22 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This
)
24 // return This->Header.Type;
25 return TEXTMODE_BUFFER
;
28 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl
=
30 TEXTMODE_BUFFER_GetType
,
35 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
);
39 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
40 IN OUT PCONSOLE Console
,
41 IN PCONSOLE_SCREEN_BUFFER_VTBL Vtbl
,
44 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
);
48 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
49 IN OUT PCONSOLE Console
,
50 IN PTEXTMODE_BUFFER_INFO TextModeInfo
)
52 NTSTATUS Status
= STATUS_SUCCESS
;
53 PTEXTMODE_SCREEN_BUFFER NewBuffer
= NULL
;
55 if (Console
== NULL
|| Buffer
== NULL
|| TextModeInfo
== NULL
)
56 return STATUS_INVALID_PARAMETER
;
60 Status
= CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER
*)&NewBuffer
,
63 sizeof(TEXTMODE_SCREEN_BUFFER
));
64 if (!NT_SUCCESS(Status
)) return Status
;
65 NewBuffer
->Header
.Type
= TEXTMODE_BUFFER
;
67 NewBuffer
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
68 TextModeInfo
->ScreenBufferSize
.X
*
69 TextModeInfo
->ScreenBufferSize
.Y
*
71 if (NewBuffer
->Buffer
== NULL
)
73 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
74 return STATUS_INSUFFICIENT_RESOURCES
;
77 NewBuffer
->ScreenBufferSize
= NewBuffer
->OldScreenBufferSize
78 = TextModeInfo
->ScreenBufferSize
;
79 NewBuffer
->ViewSize
= NewBuffer
->OldViewSize
80 = Console
->ConsoleSize
;
82 NewBuffer
->ViewOrigin
.X
= NewBuffer
->ViewOrigin
.Y
= 0;
83 NewBuffer
->VirtualY
= 0;
85 NewBuffer
->CursorBlinkOn
= NewBuffer
->ForceCursorOff
= FALSE
;
86 NewBuffer
->CursorInfo
.bVisible
= (TextModeInfo
->IsCursorVisible
&& (TextModeInfo
->CursorSize
!= 0));
87 NewBuffer
->CursorInfo
.dwSize
= min(max(TextModeInfo
->CursorSize
, 0), 100);
89 NewBuffer
->ScreenDefaultAttrib
= TextModeInfo
->ScreenAttrib
;
90 NewBuffer
->PopupDefaultAttrib
= TextModeInfo
->PopupAttrib
;
92 /* Initialize buffer to be empty with default attributes */
93 for (NewBuffer
->CursorPosition
.Y
= 0 ; NewBuffer
->CursorPosition
.Y
< NewBuffer
->ScreenBufferSize
.Y
; NewBuffer
->CursorPosition
.Y
++)
95 ClearLineBuffer(NewBuffer
);
97 NewBuffer
->CursorPosition
.X
= NewBuffer
->CursorPosition
.Y
= 0;
99 NewBuffer
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
101 *Buffer
= (PCONSOLE_SCREEN_BUFFER
)NewBuffer
;
102 return STATUS_SUCCESS
;
106 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
)
108 PTEXTMODE_SCREEN_BUFFER Buff
= (PTEXTMODE_SCREEN_BUFFER
)Buffer
;
111 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
112 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
114 Buffer
->Header
.Type
= SCREEN_BUFFER
;
116 ConsoleFreeHeap(Buff
->Buffer
);
118 CONSOLE_SCREEN_BUFFER_Destroy(Buffer
);
123 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff
, ULONG X
, ULONG Y
)
125 return &Buff
->Buffer
[((Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
) * Buff
->ScreenBufferSize
.X
+ X
];
129 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
)
131 PCHAR_INFO Ptr
= ConioCoordToPointer(Buff
, 0, Buff
->CursorPosition
.Y
);
134 for (Pos
= 0; Pos
< Buff
->ScreenBufferSize
.X
; Pos
++, Ptr
++)
137 Ptr
->Char
.UnicodeChar
= L
' ';
138 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
143 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff
,
144 IN OUT PSMALL_RECT UpdateRect
,
148 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
150 UpdateRect
->Left
= 0;
154 UpdateRect
->Left
= Start
->X
;
156 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
158 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
162 UpdateRect
->Right
= Start
->X
+ Length
- 1;
164 UpdateRect
->Top
= Start
->Y
;
165 UpdateRect
->Bottom
= Start
->Y
+ (Start
->X
+ Length
- 1) / Buff
->ScreenBufferSize
.X
;
166 if (Buff
->ScreenBufferSize
.Y
<= UpdateRect
->Bottom
)
168 UpdateRect
->Bottom
= Buff
->ScreenBufferSize
.Y
- 1;
173 * Move from one rectangle to another. We must be careful about the order that
174 * this is done, to avoid overwriting parts of the source before they are moved.
177 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
178 PSMALL_RECT SrcRegion
,
179 PSMALL_RECT DstRegion
,
180 PSMALL_RECT ClipRegion
,
183 int Width
= ConioRectWidth(SrcRegion
);
184 int Height
= ConioRectHeight(SrcRegion
);
195 /* Moving down: work from bottom up */
196 SY
= SrcRegion
->Bottom
;
197 DY
= DstRegion
->Bottom
;
200 for (i
= 0; i
< Height
; i
++)
202 PCHAR_INFO SRow
= ConioCoordToPointer(ScreenBuffer
, 0, SY
);
203 PCHAR_INFO DRow
= ConioCoordToPointer(ScreenBuffer
, 0, DY
);
205 SX
= SrcRegion
->Left
;
206 DX
= DstRegion
->Left
;
210 /* Moving right: work from right to left */
211 SX
= SrcRegion
->Right
;
212 DX
= DstRegion
->Right
;
215 for (j
= 0; j
< Width
; j
++)
217 CHAR_INFO Cell
= SRow
[SX
];
218 if (SX
>= ClipRegion
->Left
&& SX
<= ClipRegion
->Right
&&
219 SY
>= ClipRegion
->Top
&& SY
<= ClipRegion
->Bottom
)
223 if (DX
>= ClipRegion
->Left
&& DX
<= ClipRegion
->Right
&&
224 DY
>= ClipRegion
->Top
&& DY
<= ClipRegion
->Bottom
)
238 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
239 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
240 IN BOOLEAN AppendToEnd
,
241 IN PINPUT_RECORD InputRecord
,
242 IN ULONG NumEventsToWrite
,
243 OUT PULONG NumEventsWritten OPTIONAL
);
246 ConioResizeBuffer(PCONSOLE Console
,
247 PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
253 WORD CurrentAttribute
;
255 PCHAR_INFO OldBuffer
;
259 /* Buffer size is not allowed to be smaller than the view size */
260 if (Size
.X
< ScreenBuffer
->ViewSize
.X
|| Size
.Y
< ScreenBuffer
->ViewSize
.Y
)
261 return STATUS_INVALID_PARAMETER
;
263 if (Size
.X
== ScreenBuffer
->ScreenBufferSize
.X
&& Size
.Y
== ScreenBuffer
->ScreenBufferSize
.Y
)
265 // FIXME: Trigger a buffer resize event ??
266 return STATUS_SUCCESS
;
269 if (Console
->FixedSize
)
272 * The console is in fixed-size mode, so we cannot resize anything
273 * at the moment. However, keep those settings somewhere so that
274 * we can try to set them up when we will be allowed to do so.
276 ScreenBuffer
->OldScreenBufferSize
= Size
;
277 return STATUS_NOT_SUPPORTED
; // STATUS_SUCCESS
280 Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
.X
* Size
.Y
* sizeof(CHAR_INFO
));
281 if (!Buffer
) return STATUS_NO_MEMORY
;
283 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer
->ScreenBufferSize
.X
, ScreenBuffer
->ScreenBufferSize
.Y
, Size
.X
, Size
.Y
);
284 OldBuffer
= ScreenBuffer
->Buffer
;
286 for (CurrentY
= 0; CurrentY
< ScreenBuffer
->ScreenBufferSize
.Y
&& CurrentY
< Size
.Y
; CurrentY
++)
288 ptr
= ConioCoordToPointer(ScreenBuffer
, 0, CurrentY
);
289 if (Size
.X
<= ScreenBuffer
->ScreenBufferSize
.X
)
292 RtlCopyMemory(Buffer
+ Offset
, ptr
, Size
.X
* sizeof(CHAR_INFO
));
298 RtlCopyMemory(Buffer
+ Offset
, ptr
, ScreenBuffer
->ScreenBufferSize
.X
* sizeof(CHAR_INFO
));
299 Offset
+= ScreenBuffer
->ScreenBufferSize
.X
;
301 /* The attribute to be used is the one of the last cell of the current line */
302 CurrentAttribute
= ConioCoordToPointer(ScreenBuffer
,
303 ScreenBuffer
->ScreenBufferSize
.X
- 1,
304 CurrentY
)->Attributes
;
306 diff
= Size
.X
- ScreenBuffer
->ScreenBufferSize
.X
;
308 /* Zero-out the new part of the buffer */
309 for (i
= 0; i
< diff
; i
++)
311 ptr
= Buffer
+ Offset
;
312 ptr
->Char
.UnicodeChar
= L
' ';
313 ptr
->Attributes
= CurrentAttribute
;
319 if (Size
.Y
> ScreenBuffer
->ScreenBufferSize
.Y
)
321 diff
= Size
.X
* (Size
.Y
- ScreenBuffer
->ScreenBufferSize
.Y
);
323 /* Zero-out the new part of the buffer */
324 for (i
= 0; i
< diff
; i
++)
326 ptr
= Buffer
+ Offset
;
327 ptr
->Char
.UnicodeChar
= L
' ';
328 ptr
->Attributes
= ScreenBuffer
->ScreenDefaultAttrib
;
333 (void)InterlockedExchangePointer((PVOID
volatile*)&ScreenBuffer
->Buffer
, Buffer
);
334 ConsoleFreeHeap(OldBuffer
);
335 ScreenBuffer
->ScreenBufferSize
= ScreenBuffer
->OldScreenBufferSize
= Size
;
336 ScreenBuffer
->VirtualY
= 0;
338 /* Ensure cursor and window are within buffer */
339 if (ScreenBuffer
->CursorPosition
.X
>= Size
.X
)
340 ScreenBuffer
->CursorPosition
.X
= Size
.X
- 1;
341 if (ScreenBuffer
->CursorPosition
.Y
>= Size
.Y
)
342 ScreenBuffer
->CursorPosition
.Y
= Size
.Y
- 1;
343 if (ScreenBuffer
->ViewOrigin
.X
> Size
.X
- ScreenBuffer
->ViewSize
.X
)
344 ScreenBuffer
->ViewOrigin
.X
= Size
.X
- ScreenBuffer
->ViewSize
.X
;
345 if (ScreenBuffer
->ViewOrigin
.Y
> Size
.Y
- ScreenBuffer
->ViewSize
.Y
)
346 ScreenBuffer
->ViewOrigin
.Y
= Size
.Y
- ScreenBuffer
->ViewSize
.Y
;
349 * Trigger a buffer resize event
351 if (Console
->InputBuffer
.Mode
& ENABLE_WINDOW_INPUT
)
353 ULONG NumEventsWritten
;
356 er
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
357 er
.Event
.WindowBufferSizeEvent
.dwSize
= ScreenBuffer
->ScreenBufferSize
;
359 // ConioProcessInputEvent(Console, &er);
360 ConDrvWriteConsoleInput(Console
,
361 &Console
->InputBuffer
,
368 return STATUS_SUCCESS
;
372 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console
,
373 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
374 IN USHORT NewScreenAttrib
,
375 IN USHORT NewPopupAttrib
)
381 ULONG NumCodesToWrite
;
382 USHORT OldScreenAttrib
, OldPopupAttrib
;
384 if (Console
== NULL
|| Buffer
== NULL
)
386 return STATUS_INVALID_PARAMETER
;
390 ASSERT(Console
== Buffer
->Header
.Console
);
392 NumCodesToWrite
= Buffer
->ScreenBufferSize
.X
* Buffer
->ScreenBufferSize
.Y
;
393 OldScreenAttrib
= Buffer
->ScreenDefaultAttrib
;
394 OldPopupAttrib
= Buffer
->PopupDefaultAttrib
;
397 Y
= (TopLeft
.Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
398 Length
= NumCodesToWrite
;
400 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
401 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
405 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
406 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
409 * Change the current colors only if they are the old ones.
412 /* Foreground color */
413 if ((Ptr
->Attributes
& 0x0F) == (OldScreenAttrib
& 0x0F))
414 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewScreenAttrib
& 0x0F);
415 if ((Ptr
->Attributes
& 0x0F) == (OldPopupAttrib
& 0x0F))
416 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewPopupAttrib
& 0x0F);
418 /* Background color */
419 if ((Ptr
->Attributes
& 0xF0) == (OldScreenAttrib
& 0xF0))
420 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewScreenAttrib
& 0xF0);
421 if ((Ptr
->Attributes
& 0xF0) == (OldPopupAttrib
& 0xF0))
422 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewPopupAttrib
& 0xF0);
426 if (++X
== Buffer
->ScreenBufferSize
.X
)
430 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
437 /* Save foreground and background colors for both screen and popup */
438 Buffer
->ScreenDefaultAttrib
= (NewScreenAttrib
& 0x00FF);
439 Buffer
->PopupDefaultAttrib
= (NewPopupAttrib
& 0x00FF);
441 /* Refresh the display if needed */
442 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
444 SMALL_RECT UpdateRect
;
445 ConioComputeUpdateRect(Buffer
, &UpdateRect
, &TopLeft
, NumCodesToWrite
);
446 TermDrawRegion(Console
, &UpdateRect
);
449 return STATUS_SUCCESS
;
453 /* PUBLIC DRIVER APIS *********************************************************/
456 ConDrvReadConsoleOutput(IN PCONSOLE Console
,
457 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
459 OUT PCHAR_INFO CharInfo
/*Buffer*/,
460 IN OUT PSMALL_RECT ReadRegion
)
463 SMALL_RECT ScreenBuffer
;
464 PCHAR_INFO CurCharInfo
;
465 SMALL_RECT CapturedReadRegion
;
468 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| ReadRegion
== NULL
)
470 return STATUS_INVALID_PARAMETER
;
474 ASSERT(Console
== Buffer
->Header
.Console
);
476 CapturedReadRegion
= *ReadRegion
;
478 /* Make sure ReadRegion is inside the screen buffer */
479 ConioInitRect(&ScreenBuffer
, 0, 0,
480 Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
481 if (!ConioGetIntersection(&CapturedReadRegion
, &ScreenBuffer
, &CapturedReadRegion
))
484 * It is okay to have a ReadRegion completely outside
485 * the screen buffer. No data is read then.
487 return STATUS_SUCCESS
;
490 CurCharInfo
= CharInfo
;
492 for (Y
= CapturedReadRegion
.Top
; Y
<= CapturedReadRegion
.Bottom
; ++Y
)
494 Ptr
= ConioCoordToPointer(Buffer
, CapturedReadRegion
.Left
, Y
);
495 for (X
= CapturedReadRegion
.Left
; X
<= CapturedReadRegion
.Right
; ++X
)
499 CurCharInfo
->Char
.UnicodeChar
= Ptr
->Char
.UnicodeChar
;
503 // ConsoleUnicodeCharToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
504 WideCharToMultiByte(Console
->OutputCodePage
, 0, &Ptr
->Char
.UnicodeChar
, 1,
505 &CurCharInfo
->Char
.AsciiChar
, 1, NULL
, NULL
);
507 CurCharInfo
->Attributes
= Ptr
->Attributes
;
513 *ReadRegion
= CapturedReadRegion
;
515 return STATUS_SUCCESS
;
519 ConDrvWriteConsoleOutput(IN PCONSOLE Console
,
520 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
522 IN PCHAR_INFO CharInfo
/*Buffer*/,
523 IN OUT PSMALL_RECT WriteRegion
)
526 SMALL_RECT ScreenBuffer
;
527 PCHAR_INFO CurCharInfo
;
528 SMALL_RECT CapturedWriteRegion
;
531 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
533 return STATUS_INVALID_PARAMETER
;
537 ASSERT(Console
== Buffer
->Header
.Console
);
539 CapturedWriteRegion
= *WriteRegion
;
541 /* Make sure WriteRegion is inside the screen buffer */
542 ConioInitRect(&ScreenBuffer
, 0, 0,
543 Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
544 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
547 * It is okay to have a WriteRegion completely outside
548 * the screen buffer. No data is written then.
550 return STATUS_SUCCESS
;
553 CurCharInfo
= CharInfo
;
555 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
557 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
558 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
562 Ptr
->Char
.UnicodeChar
= CurCharInfo
->Char
.UnicodeChar
;
566 ConsoleAnsiCharToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
.AsciiChar
);
568 Ptr
->Attributes
= CurCharInfo
->Attributes
;
574 TermDrawRegion(Console
, &CapturedWriteRegion
);
576 *WriteRegion
= CapturedWriteRegion
;
578 return STATUS_SUCCESS
;
582 * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
585 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console
,
586 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
587 IN PCHAR_CELL CharInfo
/*Buffer*/,
588 IN COORD CharInfoSize
,
589 IN OUT PSMALL_RECT WriteRegion
,
590 IN BOOLEAN DrawRegion
)
593 SMALL_RECT ScreenBuffer
;
594 PCHAR_CELL CurCharInfo
;
595 SMALL_RECT CapturedWriteRegion
;
598 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
600 return STATUS_INVALID_PARAMETER
;
604 ASSERT(Console
== Buffer
->Header
.Console
);
606 CapturedWriteRegion
= *WriteRegion
;
608 /* Make sure WriteRegion is inside the screen buffer */
609 ConioInitRect(&ScreenBuffer
, 0, 0,
610 Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
611 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
614 * It is okay to have a WriteRegion completely outside
615 * the screen buffer. No data is written then.
617 return STATUS_SUCCESS
;
620 // CurCharInfo = CharInfo;
622 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
624 /**/CurCharInfo
= CharInfo
+ Y
* CharInfoSize
.X
+ CapturedWriteRegion
.Left
;/**/
626 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
627 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
629 ConsoleAnsiCharToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
);
630 Ptr
->Attributes
= CurCharInfo
->Attributes
;
636 if (DrawRegion
) TermDrawRegion(Console
, &CapturedWriteRegion
);
638 *WriteRegion
= CapturedWriteRegion
;
640 return STATUS_SUCCESS
;
644 ConDrvWriteConsole(IN PCONSOLE Console
,
645 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
647 IN PVOID StringBuffer
,
648 IN ULONG NumCharsToWrite
,
649 OUT PULONG NumCharsWritten OPTIONAL
)
651 NTSTATUS Status
= STATUS_SUCCESS
;
652 PWCHAR Buffer
= NULL
;
656 if (Console
== NULL
|| ScreenBuffer
== NULL
/* || StringBuffer == NULL */)
657 return STATUS_INVALID_PARAMETER
;
659 /* Validity checks */
660 ASSERT(Console
== ScreenBuffer
->Header
.Console
);
661 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCharsToWrite
== 0));
663 /* Stop here if the console is paused */
664 if (Console
->UnpauseEvent
!= NULL
) return STATUS_PENDING
;
666 /* Convert the string to UNICODE */
669 Buffer
= StringBuffer
;
673 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
677 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
680 MultiByteToWideChar(Console
->OutputCodePage
, 0,
683 (PWCHAR
)Buffer
, Length
);
687 Status
= STATUS_NO_MEMORY
;
694 if (NT_SUCCESS(Status
))
696 Status
= TermWriteStream(Console
,
701 if (NT_SUCCESS(Status
))
703 Written
= NumCharsToWrite
;
707 if (!Unicode
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
710 if (NumCharsWritten
) *NumCharsWritten
= Written
;
716 ConDrvReadConsoleOutputString(IN PCONSOLE Console
,
717 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
718 IN CODE_TYPE CodeType
,
719 OUT PVOID StringBuffer
,
720 IN ULONG NumCodesToRead
,
722 // OUT PCOORD EndCoord,
723 OUT PULONG NumCodesRead OPTIONAL
)
731 if (Console
== NULL
|| Buffer
== NULL
|| ReadCoord
== NULL
/* || EndCoord == NULL */)
733 return STATUS_INVALID_PARAMETER
;
736 /* Validity checks */
737 ASSERT(Console
== Buffer
->Header
.Console
);
738 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToRead
== 0));
741 // FIXME: Make overflow checks on ReadCoord !!!!!!
744 if (NumCodesRead
) *NumCodesRead
= 0;
749 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
753 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
757 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
761 return STATUS_INVALID_PARAMETER
;
764 ReadBuffer
= StringBuffer
;
766 Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
769 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
771 * If the number of attributes (resp. characters) to be read from extends
772 * beyond the end of the specified screen buffer row, attributes (resp.
773 * characters) are read from the next row. If the number of attributes
774 * (resp. characters) to be read from extends beyond the end of the console
775 * screen buffer, attributes (resp. characters) up to the end of the console
776 * screen buffer are read.
778 * TODO: Do NOT loop up to NumCodesToRead, but stop before
779 * if we are going to overflow...
781 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
782 for (i
= 0; i
< min(NumCodesToRead
, Buffer
->ScreenBufferSize
.X
* Buffer
->ScreenBufferSize
.Y
); ++i
)
784 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
785 Ptr
= &Buffer
->Buffer
[Xpos
+ Ypos
* Buffer
->ScreenBufferSize
.X
];
790 ConsoleUnicodeCharToAnsiChar(Console
, (PCHAR
)ReadBuffer
, &Ptr
->Char
.UnicodeChar
);
794 *(PWCHAR
)ReadBuffer
= Ptr
->Char
.UnicodeChar
;
798 *(PWORD
)ReadBuffer
= Ptr
->Attributes
;
801 ReadBuffer
= (PVOID
)((ULONG_PTR
)ReadBuffer
+ CodeSize
);
806 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
811 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
818 // EndCoord->X = Xpos;
819 // EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y;
822 *NumCodesRead
= (ULONG
)((ULONG_PTR
)ReadBuffer
- (ULONG_PTR
)StringBuffer
) / CodeSize
;
825 return STATUS_SUCCESS
;
829 ConDrvWriteConsoleOutputString(IN PCONSOLE Console
,
830 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
831 IN CODE_TYPE CodeType
,
832 IN PVOID StringBuffer
,
833 IN ULONG NumCodesToWrite
,
834 IN PCOORD WriteCoord
,
835 // OUT PCOORD EndCoord,
836 OUT PULONG NumCodesWritten OPTIONAL
)
838 NTSTATUS Status
= STATUS_SUCCESS
;
839 PVOID WriteBuffer
= NULL
;
840 PWCHAR tmpString
= NULL
;
841 DWORD X
, Y
, Length
; // , Written = 0;
845 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
/* || EndCoord == NULL */)
847 return STATUS_INVALID_PARAMETER
;
850 /* Validity checks */
851 ASSERT(Console
== Buffer
->Header
.Console
);
852 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToWrite
== 0));
855 // FIXME: Make overflow checks on WriteCoord !!!!!!
858 if (NumCodesWritten
) *NumCodesWritten
= 0;
863 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
867 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
871 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
875 return STATUS_INVALID_PARAMETER
;
878 if (CodeType
== CODE_ASCII
)
880 /* Convert the ASCII string into Unicode before writing it to the console */
881 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
885 tmpString
= WriteBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
888 MultiByteToWideChar(Console
->OutputCodePage
, 0,
891 (PWCHAR
)WriteBuffer
, Length
);
895 Status
= STATUS_NO_MEMORY
;
898 // FIXME: Quick fix: fix the CodeType and CodeSize since the
899 // ASCII string was converted into UNICODE.
900 // A proper fix needs to be written.
901 CodeType
= CODE_UNICODE
;
902 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
906 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
907 WriteBuffer
= StringBuffer
;
910 if (WriteBuffer
== NULL
|| !NT_SUCCESS(Status
)) goto Cleanup
;
913 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
914 Length
= NumCodesToWrite
;
915 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
916 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
920 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
921 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
927 Ptr
->Char
.UnicodeChar
= *(PWCHAR
)WriteBuffer
;
931 Ptr
->Attributes
= *(PWORD
)WriteBuffer
;
934 WriteBuffer
= (PVOID
)((ULONG_PTR
)WriteBuffer
+ CodeSize
);
938 if (++X
== Buffer
->ScreenBufferSize
.X
)
942 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
949 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
951 SMALL_RECT UpdateRect
;
952 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
953 TermDrawRegion(Console
, &UpdateRect
);
957 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
960 if (tmpString
) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString
);
962 if (NumCodesWritten
) *NumCodesWritten
= NumCodesToWrite
; // Written;
967 ConDrvFillConsoleOutput(IN PCONSOLE Console
,
968 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
969 IN CODE_TYPE CodeType
,
970 IN CODE_ELEMENT Code
,
971 IN ULONG NumCodesToWrite
,
972 IN PCOORD WriteCoord
,
973 OUT PULONG NumCodesWritten OPTIONAL
)
975 DWORD X
, Y
, Length
; // , Written = 0;
978 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
)
980 return STATUS_INVALID_PARAMETER
;
984 ASSERT(Console
== Buffer
->Header
.Console
);
987 // FIXME: Make overflow checks on WriteCoord !!!!!!
990 if (NumCodesWritten
) *NumCodesWritten
= 0;
992 if (CodeType
== CODE_ASCII
)
994 /* Conversion from the ASCII char to the UNICODE char */
996 ConsoleAnsiCharToUnicodeChar(Console
, &tmp
.UnicodeChar
, &Code
.AsciiChar
);
1001 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1002 Length
= NumCodesToWrite
;
1003 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1004 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1008 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1009 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
1015 Ptr
->Char
.UnicodeChar
= Code
.UnicodeChar
;
1018 case CODE_ATTRIBUTE
:
1019 Ptr
->Attributes
= Code
.Attribute
;
1025 if (++X
== Buffer
->ScreenBufferSize
.X
)
1029 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
1036 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1038 SMALL_RECT UpdateRect
;
1039 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1040 TermDrawRegion(Console
, &UpdateRect
);
1043 if (NumCodesWritten
) *NumCodesWritten
= NumCodesToWrite
; // Written;
1044 return STATUS_SUCCESS
;
1048 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console
,
1049 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1050 OUT PCOORD ScreenBufferSize
,
1051 OUT PCOORD CursorPosition
,
1052 OUT PCOORD ViewOrigin
,
1053 OUT PCOORD ViewSize
,
1054 OUT PCOORD MaximumViewSize
,
1055 OUT PWORD Attributes
)
1057 if (Console
== NULL
|| Buffer
== NULL
|| ScreenBufferSize
== NULL
||
1058 CursorPosition
== NULL
|| ViewOrigin
== NULL
|| ViewSize
== NULL
||
1059 MaximumViewSize
== NULL
|| Attributes
== NULL
)
1061 return STATUS_INVALID_PARAMETER
;
1064 /* Validity check */
1065 ASSERT(Console
== Buffer
->Header
.Console
);
1067 *ScreenBufferSize
= Buffer
->ScreenBufferSize
;
1068 *CursorPosition
= Buffer
->CursorPosition
;
1069 *ViewOrigin
= Buffer
->ViewOrigin
;
1070 *ViewSize
= Buffer
->ViewSize
;
1071 *Attributes
= Buffer
->ScreenDefaultAttrib
;
1073 // FIXME: Refine the computation
1074 *MaximumViewSize
= Buffer
->ScreenBufferSize
;
1076 return STATUS_SUCCESS
;
1080 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console
,
1081 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1084 if (Console
== NULL
|| Buffer
== NULL
)
1085 return STATUS_INVALID_PARAMETER
;
1087 /* Validity check */
1088 ASSERT(Console
== Buffer
->Header
.Console
);
1090 Buffer
->ScreenDefaultAttrib
= Attributes
;
1091 return STATUS_SUCCESS
;
1095 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console
,
1096 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1101 if (Console
== NULL
|| Buffer
== NULL
|| Size
== NULL
)
1102 return STATUS_INVALID_PARAMETER
;
1104 /* Validity check */
1105 ASSERT(Console
== Buffer
->Header
.Console
);
1107 Status
= ConioResizeBuffer(Console
, Buffer
, *Size
);
1108 if (NT_SUCCESS(Status
)) TermResizeTerminal(Console
);
1114 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console
,
1115 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1117 IN PSMALL_RECT ScrollRectangle
,
1118 IN BOOLEAN UseClipRectangle
,
1119 IN PSMALL_RECT ClipRectangle OPTIONAL
,
1120 IN PCOORD DestinationOrigin
,
1121 IN CHAR_INFO FillChar
)
1123 COORD CapturedDestinationOrigin
;
1124 SMALL_RECT ScreenBuffer
;
1125 SMALL_RECT SrcRegion
;
1126 SMALL_RECT DstRegion
;
1127 SMALL_RECT UpdateRegion
;
1128 SMALL_RECT CapturedClipRectangle
;
1130 if (Console
== NULL
|| Buffer
== NULL
|| ScrollRectangle
== NULL
||
1131 (UseClipRectangle
? ClipRectangle
== NULL
: FALSE
) || DestinationOrigin
== NULL
)
1133 return STATUS_INVALID_PARAMETER
;
1136 /* Validity check */
1137 ASSERT(Console
== Buffer
->Header
.Console
);
1139 CapturedDestinationOrigin
= *DestinationOrigin
;
1141 /* Make sure the source rectangle is inside the screen buffer */
1142 ConioInitRect(&ScreenBuffer
, 0, 0,
1143 Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
1144 if (!ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, ScrollRectangle
))
1146 return STATUS_SUCCESS
;
1149 /* If the source was clipped on the left or top, adjust the destination accordingly */
1150 if (ScrollRectangle
->Left
< 0)
1152 CapturedDestinationOrigin
.X
-= ScrollRectangle
->Left
;
1154 if (ScrollRectangle
->Top
< 0)
1156 CapturedDestinationOrigin
.Y
-= ScrollRectangle
->Top
;
1159 if (UseClipRectangle
)
1161 CapturedClipRectangle
= *ClipRectangle
;
1162 if (!ConioGetIntersection(&CapturedClipRectangle
, &CapturedClipRectangle
, &ScreenBuffer
))
1164 return STATUS_SUCCESS
;
1169 CapturedClipRectangle
= ScreenBuffer
;
1172 ConioInitRect(&DstRegion
,
1173 CapturedDestinationOrigin
.Y
,
1174 CapturedDestinationOrigin
.X
,
1175 CapturedDestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
1176 CapturedDestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
1181 ConsoleAnsiCharToUnicodeChar(Console
, &tmp
, &FillChar
.Char
.AsciiChar
);
1182 FillChar
.Char
.UnicodeChar
= tmp
;
1185 ConioMoveRegion(Buffer
, &SrcRegion
, &DstRegion
, &CapturedClipRectangle
, FillChar
);
1187 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1189 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
1190 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &CapturedClipRectangle
))
1192 /* Draw update region */
1193 TermDrawRegion(Console
, &UpdateRegion
);
1197 return STATUS_SUCCESS
;
1201 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console
,
1202 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1203 IN BOOLEAN Absolute
,
1204 IN PSMALL_RECT WindowRect
)
1206 SMALL_RECT CapturedWindowRect
;
1208 if (Console
== NULL
|| Buffer
== NULL
|| WindowRect
== NULL
)
1209 return STATUS_INVALID_PARAMETER
;
1211 /* Validity check */
1212 ASSERT(Console
== Buffer
->Header
.Console
);
1214 CapturedWindowRect
= *WindowRect
;
1216 if (Absolute
== FALSE
)
1218 /* Relative positions given. Transform them to absolute ones */
1219 CapturedWindowRect
.Left
+= Buffer
->ViewOrigin
.X
;
1220 CapturedWindowRect
.Top
+= Buffer
->ViewOrigin
.Y
;
1221 CapturedWindowRect
.Right
+= Buffer
->ViewOrigin
.X
+ Buffer
->ViewSize
.X
- 1;
1222 CapturedWindowRect
.Bottom
+= Buffer
->ViewOrigin
.Y
+ Buffer
->ViewSize
.Y
- 1;
1225 /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
1226 if ( (CapturedWindowRect
.Left
< 0) || (CapturedWindowRect
.Top
< 0) ||
1227 (CapturedWindowRect
.Right
>= Buffer
->ScreenBufferSize
.X
) ||
1228 (CapturedWindowRect
.Bottom
>= Buffer
->ScreenBufferSize
.Y
) ||
1229 (CapturedWindowRect
.Right
<= CapturedWindowRect
.Left
) ||
1230 (CapturedWindowRect
.Bottom
<= CapturedWindowRect
.Top
) )
1232 return STATUS_INVALID_PARAMETER
;
1235 Buffer
->ViewOrigin
.X
= CapturedWindowRect
.Left
;
1236 Buffer
->ViewOrigin
.Y
= CapturedWindowRect
.Top
;
1238 Buffer
->ViewSize
.X
= CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1;
1239 Buffer
->ViewSize
.Y
= CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1;
1241 // TermResizeTerminal(Console);
1243 return STATUS_SUCCESS
;