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 ********************************************************************/
21 * "The lpMultiByteStr and lpWideCharStr pointers must not be the same.
22 * If they are the same, the function fails, and GetLastError returns
23 * ERROR_INVALID_PARAMETER."
25 #define ConsoleOutputUnicodeToAnsiChar(Console, dChar, sWChar) \
26 ASSERT((ULONG_PTR)dChar != (ULONG_PTR)sWChar); \
27 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
29 #define ConsoleOutputAnsiToUnicodeChar(Console, dWChar, sChar) \
30 ASSERT((ULONG_PTR)dWChar != (ULONG_PTR)sChar); \
31 MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
33 /* PRIVATE FUNCTIONS **********************************************************/
35 CONSOLE_IO_OBJECT_TYPE
36 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This
)
38 // return This->Header.Type;
39 return TEXTMODE_BUFFER
;
42 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl
=
44 TEXTMODE_BUFFER_GetType
,
49 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
);
53 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
54 IN OUT PCONSOLE Console
,
55 IN PCONSOLE_SCREEN_BUFFER_VTBL Vtbl
,
58 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
);
62 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
63 IN OUT PCONSOLE Console
,
64 IN PTEXTMODE_BUFFER_INFO TextModeInfo
)
66 NTSTATUS Status
= STATUS_SUCCESS
;
67 PTEXTMODE_SCREEN_BUFFER NewBuffer
= NULL
;
69 if (Console
== NULL
|| Buffer
== NULL
|| TextModeInfo
== NULL
)
70 return STATUS_INVALID_PARAMETER
;
74 Status
= CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER
*)&NewBuffer
,
77 sizeof(TEXTMODE_SCREEN_BUFFER
));
78 if (!NT_SUCCESS(Status
)) return Status
;
79 NewBuffer
->Header
.Type
= TEXTMODE_BUFFER
;
81 NewBuffer
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
82 TextModeInfo
->ScreenBufferSize
.X
*
83 TextModeInfo
->ScreenBufferSize
.Y
*
85 if (NewBuffer
->Buffer
== NULL
)
87 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
88 return STATUS_INSUFFICIENT_RESOURCES
;
91 NewBuffer
->ScreenBufferSize
= NewBuffer
->OldScreenBufferSize
92 = TextModeInfo
->ScreenBufferSize
;
93 NewBuffer
->ViewSize
= NewBuffer
->OldViewSize
94 = Console
->ConsoleSize
;
96 NewBuffer
->ViewOrigin
.X
= NewBuffer
->ViewOrigin
.Y
= 0;
97 NewBuffer
->VirtualY
= 0;
99 NewBuffer
->CursorBlinkOn
= NewBuffer
->ForceCursorOff
= FALSE
;
100 NewBuffer
->CursorInfo
.bVisible
= (TextModeInfo
->IsCursorVisible
&& (TextModeInfo
->CursorSize
!= 0));
101 NewBuffer
->CursorInfo
.dwSize
= min(max(TextModeInfo
->CursorSize
, 0), 100);
103 NewBuffer
->ScreenDefaultAttrib
= TextModeInfo
->ScreenAttrib
;
104 NewBuffer
->PopupDefaultAttrib
= TextModeInfo
->PopupAttrib
;
106 /* Initialize buffer to be empty with default attributes */
107 for (NewBuffer
->CursorPosition
.Y
= 0 ; NewBuffer
->CursorPosition
.Y
< NewBuffer
->ScreenBufferSize
.Y
; NewBuffer
->CursorPosition
.Y
++)
109 ClearLineBuffer(NewBuffer
);
111 NewBuffer
->CursorPosition
.X
= NewBuffer
->CursorPosition
.Y
= 0;
113 NewBuffer
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
115 *Buffer
= (PCONSOLE_SCREEN_BUFFER
)NewBuffer
;
116 return STATUS_SUCCESS
;
120 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
)
122 PTEXTMODE_SCREEN_BUFFER Buff
= (PTEXTMODE_SCREEN_BUFFER
)Buffer
;
125 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
126 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
128 Buffer
->Header
.Type
= SCREEN_BUFFER
;
130 ConsoleFreeHeap(Buff
->Buffer
);
132 CONSOLE_SCREEN_BUFFER_Destroy(Buffer
);
137 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff
, ULONG X
, ULONG Y
)
139 return &Buff
->Buffer
[((Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
) * Buff
->ScreenBufferSize
.X
+ X
];
143 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
)
145 PCHAR_INFO Ptr
= ConioCoordToPointer(Buff
, 0, Buff
->CursorPosition
.Y
);
148 for (Pos
= 0; Pos
< Buff
->ScreenBufferSize
.X
; Pos
++, Ptr
++)
151 Ptr
->Char
.UnicodeChar
= L
' ';
152 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
157 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff
,
158 IN OUT PSMALL_RECT UpdateRect
,
162 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
164 UpdateRect
->Left
= 0;
168 UpdateRect
->Left
= Start
->X
;
170 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
172 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
176 UpdateRect
->Right
= Start
->X
+ Length
- 1;
178 UpdateRect
->Top
= Start
->Y
;
179 UpdateRect
->Bottom
= Start
->Y
+ (Start
->X
+ Length
- 1) / Buff
->ScreenBufferSize
.X
;
180 if (Buff
->ScreenBufferSize
.Y
<= UpdateRect
->Bottom
)
182 UpdateRect
->Bottom
= Buff
->ScreenBufferSize
.Y
- 1;
187 * Move from one rectangle to another. We must be careful about the order that
188 * this is done, to avoid overwriting parts of the source before they are moved.
191 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
192 PSMALL_RECT SrcRegion
,
193 PSMALL_RECT DstRegion
,
194 PSMALL_RECT ClipRegion
,
197 int Width
= ConioRectWidth(SrcRegion
);
198 int Height
= ConioRectHeight(SrcRegion
);
209 /* Moving down: work from bottom up */
210 SY
= SrcRegion
->Bottom
;
211 DY
= DstRegion
->Bottom
;
214 for (i
= 0; i
< Height
; i
++)
216 PCHAR_INFO SRow
= ConioCoordToPointer(ScreenBuffer
, 0, SY
);
217 PCHAR_INFO DRow
= ConioCoordToPointer(ScreenBuffer
, 0, DY
);
219 SX
= SrcRegion
->Left
;
220 DX
= DstRegion
->Left
;
224 /* Moving right: work from right to left */
225 SX
= SrcRegion
->Right
;
226 DX
= DstRegion
->Right
;
229 for (j
= 0; j
< Width
; j
++)
231 CHAR_INFO Cell
= SRow
[SX
];
232 if (SX
>= ClipRegion
->Left
&& SX
<= ClipRegion
->Right
&&
233 SY
>= ClipRegion
->Top
&& SY
<= ClipRegion
->Bottom
)
237 if (DX
>= ClipRegion
->Left
&& DX
<= ClipRegion
->Right
&&
238 DY
>= ClipRegion
->Top
&& DY
<= ClipRegion
->Bottom
)
252 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
253 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
254 IN BOOLEAN AppendToEnd
,
255 IN PINPUT_RECORD InputRecord
,
256 IN ULONG NumEventsToWrite
,
257 OUT PULONG NumEventsWritten OPTIONAL
);
260 ConioResizeBuffer(PCONSOLE Console
,
261 PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
267 WORD CurrentAttribute
;
269 PCHAR_INFO OldBuffer
;
273 /* Buffer size is not allowed to be smaller than the view size */
274 if (Size
.X
< ScreenBuffer
->ViewSize
.X
|| Size
.Y
< ScreenBuffer
->ViewSize
.Y
)
275 return STATUS_INVALID_PARAMETER
;
277 if (Size
.X
== ScreenBuffer
->ScreenBufferSize
.X
&& Size
.Y
== ScreenBuffer
->ScreenBufferSize
.Y
)
279 // FIXME: Trigger a buffer resize event ??
280 return STATUS_SUCCESS
;
283 if (Console
->FixedSize
)
286 * The console is in fixed-size mode, so we cannot resize anything
287 * at the moment. However, keep those settings somewhere so that
288 * we can try to set them up when we will be allowed to do so.
290 ScreenBuffer
->OldScreenBufferSize
= Size
;
291 return STATUS_NOT_SUPPORTED
; // STATUS_SUCCESS
294 Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
.X
* Size
.Y
* sizeof(CHAR_INFO
));
295 if (!Buffer
) return STATUS_NO_MEMORY
;
297 DPRINT1("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer
->ScreenBufferSize
.X
, ScreenBuffer
->ScreenBufferSize
.Y
, Size
.X
, Size
.Y
);
298 OldBuffer
= ScreenBuffer
->Buffer
;
300 for (CurrentY
= 0; CurrentY
< ScreenBuffer
->ScreenBufferSize
.Y
&& CurrentY
< Size
.Y
; CurrentY
++)
302 ptr
= ConioCoordToPointer(ScreenBuffer
, 0, CurrentY
);
303 if (Size
.X
<= ScreenBuffer
->ScreenBufferSize
.X
)
306 RtlCopyMemory(Buffer
+ Offset
, ptr
, Size
.X
* sizeof(CHAR_INFO
));
312 RtlCopyMemory(Buffer
+ Offset
, ptr
, ScreenBuffer
->ScreenBufferSize
.X
* sizeof(CHAR_INFO
));
313 Offset
+= ScreenBuffer
->ScreenBufferSize
.X
;
315 /* The attribute to be used is the one of the last cell of the current line */
316 CurrentAttribute
= ConioCoordToPointer(ScreenBuffer
,
317 ScreenBuffer
->ScreenBufferSize
.X
- 1,
318 CurrentY
)->Attributes
;
320 diff
= Size
.X
- ScreenBuffer
->ScreenBufferSize
.X
;
322 /* Zero-out the new part of the buffer */
323 for (i
= 0; i
< diff
; i
++)
325 ptr
= Buffer
+ Offset
;
326 ptr
->Char
.UnicodeChar
= L
' ';
327 ptr
->Attributes
= CurrentAttribute
;
333 if (Size
.Y
> ScreenBuffer
->ScreenBufferSize
.Y
)
335 diff
= Size
.X
* (Size
.Y
- ScreenBuffer
->ScreenBufferSize
.Y
);
337 /* Zero-out the new part of the buffer */
338 for (i
= 0; i
< diff
; i
++)
340 ptr
= Buffer
+ Offset
;
341 ptr
->Char
.UnicodeChar
= L
' ';
342 ptr
->Attributes
= ScreenBuffer
->ScreenDefaultAttrib
;
347 (void)InterlockedExchangePointer((PVOID
volatile*)&ScreenBuffer
->Buffer
, Buffer
);
348 ConsoleFreeHeap(OldBuffer
);
349 ScreenBuffer
->ScreenBufferSize
= ScreenBuffer
->OldScreenBufferSize
= Size
;
350 ScreenBuffer
->VirtualY
= 0;
352 /* Ensure cursor and window are within buffer */
353 if (ScreenBuffer
->CursorPosition
.X
>= Size
.X
)
354 ScreenBuffer
->CursorPosition
.X
= Size
.X
- 1;
355 if (ScreenBuffer
->CursorPosition
.Y
>= Size
.Y
)
356 ScreenBuffer
->CursorPosition
.Y
= Size
.Y
- 1;
357 if (ScreenBuffer
->ViewOrigin
.X
> Size
.X
- ScreenBuffer
->ViewSize
.X
)
358 ScreenBuffer
->ViewOrigin
.X
= Size
.X
- ScreenBuffer
->ViewSize
.X
;
359 if (ScreenBuffer
->ViewOrigin
.Y
> Size
.Y
- ScreenBuffer
->ViewSize
.Y
)
360 ScreenBuffer
->ViewOrigin
.Y
= Size
.Y
- ScreenBuffer
->ViewSize
.Y
;
363 * Trigger a buffer resize event
365 if (Console
->InputBuffer
.Mode
& ENABLE_WINDOW_INPUT
)
367 ULONG NumEventsWritten
;
370 er
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
371 er
.Event
.WindowBufferSizeEvent
.dwSize
= ScreenBuffer
->ScreenBufferSize
;
373 // ConioProcessInputEvent(Console, &er);
374 ConDrvWriteConsoleInput(Console
,
375 &Console
->InputBuffer
,
382 return STATUS_SUCCESS
;
386 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console
,
387 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
388 IN USHORT NewScreenAttrib
,
389 IN USHORT NewPopupAttrib
)
395 ULONG NumCodesToWrite
;
396 USHORT OldScreenAttrib
, OldPopupAttrib
;
398 if (Console
== NULL
|| Buffer
== NULL
)
400 return STATUS_INVALID_PARAMETER
;
404 ASSERT(Console
== Buffer
->Header
.Console
);
406 NumCodesToWrite
= Buffer
->ScreenBufferSize
.X
* Buffer
->ScreenBufferSize
.Y
;
407 OldScreenAttrib
= Buffer
->ScreenDefaultAttrib
;
408 OldPopupAttrib
= Buffer
->PopupDefaultAttrib
;
411 Y
= (TopLeft
.Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
412 Length
= NumCodesToWrite
;
414 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
415 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
419 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
420 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
423 * Change the current colors only if they are the old ones.
426 /* Foreground color */
427 if ((Ptr
->Attributes
& 0x0F) == (OldScreenAttrib
& 0x0F))
428 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewScreenAttrib
& 0x0F);
429 if ((Ptr
->Attributes
& 0x0F) == (OldPopupAttrib
& 0x0F))
430 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewPopupAttrib
& 0x0F);
432 /* Background color */
433 if ((Ptr
->Attributes
& 0xF0) == (OldScreenAttrib
& 0xF0))
434 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewScreenAttrib
& 0xF0);
435 if ((Ptr
->Attributes
& 0xF0) == (OldPopupAttrib
& 0xF0))
436 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewPopupAttrib
& 0xF0);
440 if (++X
== Buffer
->ScreenBufferSize
.X
)
444 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
451 /* Save foreground and background colors for both screen and popup */
452 Buffer
->ScreenDefaultAttrib
= (NewScreenAttrib
& 0x00FF);
453 Buffer
->PopupDefaultAttrib
= (NewPopupAttrib
& 0x00FF);
455 /* Refresh the display if needed */
456 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
458 SMALL_RECT UpdateRect
;
459 ConioComputeUpdateRect(Buffer
, &UpdateRect
, &TopLeft
, NumCodesToWrite
);
460 TermDrawRegion(Console
, &UpdateRect
);
463 return STATUS_SUCCESS
;
467 /* PUBLIC DRIVER APIS *********************************************************/
470 ConDrvReadConsoleOutput(IN PCONSOLE Console
,
471 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
473 OUT PCHAR_INFO CharInfo
/*Buffer*/,
474 IN OUT PSMALL_RECT ReadRegion
)
477 SMALL_RECT ScreenBuffer
;
478 PCHAR_INFO CurCharInfo
;
479 SMALL_RECT CapturedReadRegion
;
482 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| ReadRegion
== NULL
)
484 return STATUS_INVALID_PARAMETER
;
488 ASSERT(Console
== Buffer
->Header
.Console
);
490 CapturedReadRegion
= *ReadRegion
;
492 /* Make sure ReadRegion is inside the screen buffer */
493 ConioInitRect(&ScreenBuffer
, 0, 0,
494 Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
495 if (!ConioGetIntersection(&CapturedReadRegion
, &ScreenBuffer
, &CapturedReadRegion
))
498 * It is okay to have a ReadRegion completely outside
499 * the screen buffer. No data is read then.
501 return STATUS_SUCCESS
;
504 CurCharInfo
= CharInfo
;
506 for (Y
= CapturedReadRegion
.Top
; Y
<= CapturedReadRegion
.Bottom
; ++Y
)
508 Ptr
= ConioCoordToPointer(Buffer
, CapturedReadRegion
.Left
, Y
);
509 for (X
= CapturedReadRegion
.Left
; X
<= CapturedReadRegion
.Right
; ++X
)
513 CurCharInfo
->Char
.UnicodeChar
= Ptr
->Char
.UnicodeChar
;
517 // ConsoleOutputUnicodeToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
518 WideCharToMultiByte(Console
->OutputCodePage
, 0, &Ptr
->Char
.UnicodeChar
, 1,
519 &CurCharInfo
->Char
.AsciiChar
, 1, NULL
, NULL
);
521 CurCharInfo
->Attributes
= Ptr
->Attributes
;
527 *ReadRegion
= CapturedReadRegion
;
529 return STATUS_SUCCESS
;
533 ConDrvWriteConsoleOutput(IN PCONSOLE Console
,
534 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
536 IN PCHAR_INFO CharInfo
/*Buffer*/,
537 IN OUT PSMALL_RECT WriteRegion
)
540 SMALL_RECT ScreenBuffer
;
541 PCHAR_INFO CurCharInfo
;
542 SMALL_RECT CapturedWriteRegion
;
545 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
547 return STATUS_INVALID_PARAMETER
;
551 ASSERT(Console
== Buffer
->Header
.Console
);
553 CapturedWriteRegion
= *WriteRegion
;
555 /* Make sure WriteRegion is inside the screen buffer */
556 ConioInitRect(&ScreenBuffer
, 0, 0,
557 Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
558 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
561 * It is okay to have a WriteRegion completely outside
562 * the screen buffer. No data is written then.
564 return STATUS_SUCCESS
;
567 CurCharInfo
= CharInfo
;
569 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
571 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
572 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
576 Ptr
->Char
.UnicodeChar
= CurCharInfo
->Char
.UnicodeChar
;
580 ConsoleOutputAnsiToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
.AsciiChar
);
582 Ptr
->Attributes
= CurCharInfo
->Attributes
;
588 TermDrawRegion(Console
, &CapturedWriteRegion
);
590 *WriteRegion
= CapturedWriteRegion
;
592 return STATUS_SUCCESS
;
596 * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
599 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console
,
600 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
601 IN PCHAR_CELL CharInfo
/*Buffer*/,
602 IN COORD CharInfoSize
,
603 IN OUT PSMALL_RECT WriteRegion
,
604 IN BOOLEAN DrawRegion
)
607 SMALL_RECT ScreenBuffer
;
608 PCHAR_CELL CurCharInfo
;
609 SMALL_RECT CapturedWriteRegion
;
612 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
614 return STATUS_INVALID_PARAMETER
;
618 ASSERT(Console
== Buffer
->Header
.Console
);
620 CapturedWriteRegion
= *WriteRegion
;
622 /* Make sure WriteRegion is inside the screen buffer */
623 ConioInitRect(&ScreenBuffer
, 0, 0,
624 Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
625 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
628 * It is okay to have a WriteRegion completely outside
629 * the screen buffer. No data is written then.
631 return STATUS_SUCCESS
;
634 // CurCharInfo = CharInfo;
636 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
638 /**/CurCharInfo
= CharInfo
+ Y
* CharInfoSize
.X
+ CapturedWriteRegion
.Left
;/**/
640 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
641 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
643 ConsoleOutputAnsiToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
);
644 Ptr
->Attributes
= CurCharInfo
->Attributes
;
650 if (DrawRegion
) TermDrawRegion(Console
, &CapturedWriteRegion
);
652 *WriteRegion
= CapturedWriteRegion
;
654 return STATUS_SUCCESS
;
658 ConDrvWriteConsole(IN PCONSOLE Console
,
659 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
661 IN PVOID StringBuffer
,
662 IN ULONG NumCharsToWrite
,
663 OUT PULONG NumCharsWritten OPTIONAL
)
665 NTSTATUS Status
= STATUS_SUCCESS
;
666 PWCHAR Buffer
= NULL
;
670 if (Console
== NULL
|| ScreenBuffer
== NULL
/* || StringBuffer == NULL */)
671 return STATUS_INVALID_PARAMETER
;
673 /* Validity checks */
674 ASSERT(Console
== ScreenBuffer
->Header
.Console
);
675 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCharsToWrite
== 0));
677 /* Stop here if the console is paused */
678 if (Console
->UnpauseEvent
!= NULL
) return STATUS_PENDING
;
680 /* Convert the string to UNICODE */
683 Buffer
= StringBuffer
;
687 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
691 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
694 MultiByteToWideChar(Console
->OutputCodePage
, 0,
697 (PWCHAR
)Buffer
, Length
);
701 Status
= STATUS_NO_MEMORY
;
708 if (NT_SUCCESS(Status
))
710 Status
= TermWriteStream(Console
,
715 if (NT_SUCCESS(Status
))
717 Written
= NumCharsToWrite
;
721 if (!Unicode
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
724 if (NumCharsWritten
) *NumCharsWritten
= Written
;
730 ConDrvReadConsoleOutputString(IN PCONSOLE Console
,
731 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
732 IN CODE_TYPE CodeType
,
733 OUT PVOID StringBuffer
,
734 IN ULONG NumCodesToRead
,
736 // OUT PCOORD EndCoord,
737 OUT PULONG NumCodesRead OPTIONAL
)
745 if (Console
== NULL
|| Buffer
== NULL
|| ReadCoord
== NULL
/* || EndCoord == NULL */)
747 return STATUS_INVALID_PARAMETER
;
750 /* Validity checks */
751 ASSERT(Console
== Buffer
->Header
.Console
);
752 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToRead
== 0));
755 // FIXME: Make overflow checks on ReadCoord !!!!!!
758 if (NumCodesRead
) *NumCodesRead
= 0;
763 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
767 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
771 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
775 return STATUS_INVALID_PARAMETER
;
778 ReadBuffer
= StringBuffer
;
780 Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
783 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
785 * If the number of attributes (resp. characters) to be read from extends
786 * beyond the end of the specified screen buffer row, attributes (resp.
787 * characters) are read from the next row. If the number of attributes
788 * (resp. characters) to be read from extends beyond the end of the console
789 * screen buffer, attributes (resp. characters) up to the end of the console
790 * screen buffer are read.
792 * TODO: Do NOT loop up to NumCodesToRead, but stop before
793 * if we are going to overflow...
795 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
796 for (i
= 0; i
< min(NumCodesToRead
, Buffer
->ScreenBufferSize
.X
* Buffer
->ScreenBufferSize
.Y
); ++i
)
798 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
799 Ptr
= &Buffer
->Buffer
[Xpos
+ Ypos
* Buffer
->ScreenBufferSize
.X
];
804 ConsoleOutputUnicodeToAnsiChar(Console
, (PCHAR
)ReadBuffer
, &Ptr
->Char
.UnicodeChar
);
808 *(PWCHAR
)ReadBuffer
= Ptr
->Char
.UnicodeChar
;
812 *(PWORD
)ReadBuffer
= Ptr
->Attributes
;
815 ReadBuffer
= (PVOID
)((ULONG_PTR
)ReadBuffer
+ CodeSize
);
820 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
825 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
832 // EndCoord->X = Xpos;
833 // EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y;
836 *NumCodesRead
= (ULONG
)((ULONG_PTR
)ReadBuffer
- (ULONG_PTR
)StringBuffer
) / CodeSize
;
839 return STATUS_SUCCESS
;
843 ConDrvWriteConsoleOutputString(IN PCONSOLE Console
,
844 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
845 IN CODE_TYPE CodeType
,
846 IN PVOID StringBuffer
,
847 IN ULONG NumCodesToWrite
,
848 IN PCOORD WriteCoord
,
849 // OUT PCOORD EndCoord,
850 OUT PULONG NumCodesWritten OPTIONAL
)
852 NTSTATUS Status
= STATUS_SUCCESS
;
853 PVOID WriteBuffer
= NULL
;
854 PWCHAR tmpString
= NULL
;
855 DWORD X
, Y
, Length
; // , Written = 0;
859 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
/* || EndCoord == NULL */)
861 return STATUS_INVALID_PARAMETER
;
864 /* Validity checks */
865 ASSERT(Console
== Buffer
->Header
.Console
);
866 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToWrite
== 0));
869 // FIXME: Make overflow checks on WriteCoord !!!!!!
872 if (NumCodesWritten
) *NumCodesWritten
= 0;
877 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
881 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
885 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
889 return STATUS_INVALID_PARAMETER
;
892 if (CodeType
== CODE_ASCII
)
894 /* Convert the ASCII string into Unicode before writing it to the console */
895 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
899 tmpString
= WriteBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
902 MultiByteToWideChar(Console
->OutputCodePage
, 0,
905 (PWCHAR
)WriteBuffer
, Length
);
909 Status
= STATUS_NO_MEMORY
;
912 // FIXME: Quick fix: fix the CodeType and CodeSize since the
913 // ASCII string was converted into UNICODE.
914 // A proper fix needs to be written.
915 CodeType
= CODE_UNICODE
;
916 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
920 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
921 WriteBuffer
= StringBuffer
;
924 if (WriteBuffer
== NULL
|| !NT_SUCCESS(Status
)) goto Cleanup
;
927 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
928 Length
= NumCodesToWrite
;
929 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
930 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
934 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
935 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
941 Ptr
->Char
.UnicodeChar
= *(PWCHAR
)WriteBuffer
;
945 Ptr
->Attributes
= *(PWORD
)WriteBuffer
;
948 WriteBuffer
= (PVOID
)((ULONG_PTR
)WriteBuffer
+ CodeSize
);
952 if (++X
== Buffer
->ScreenBufferSize
.X
)
956 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
963 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
965 SMALL_RECT UpdateRect
;
966 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
967 TermDrawRegion(Console
, &UpdateRect
);
971 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
974 if (tmpString
) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString
);
976 if (NumCodesWritten
) *NumCodesWritten
= NumCodesToWrite
; // Written;
981 ConDrvFillConsoleOutput(IN PCONSOLE Console
,
982 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
983 IN CODE_TYPE CodeType
,
984 IN CODE_ELEMENT Code
,
985 IN ULONG NumCodesToWrite
,
986 IN PCOORD WriteCoord
,
987 OUT PULONG NumCodesWritten OPTIONAL
)
989 DWORD X
, Y
, Length
; // , Written = 0;
992 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
)
994 return STATUS_INVALID_PARAMETER
;
998 ASSERT(Console
== Buffer
->Header
.Console
);
1001 // FIXME: Make overflow checks on WriteCoord !!!!!!
1004 if (NumCodesWritten
) *NumCodesWritten
= 0;
1006 if (CodeType
== CODE_ASCII
)
1008 /* Conversion from the ASCII char to the UNICODE char */
1010 ConsoleOutputAnsiToUnicodeChar(Console
, &tmp
.UnicodeChar
, &Code
.AsciiChar
);
1015 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1016 Length
= NumCodesToWrite
;
1017 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1018 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1022 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1023 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
1029 Ptr
->Char
.UnicodeChar
= Code
.UnicodeChar
;
1032 case CODE_ATTRIBUTE
:
1033 Ptr
->Attributes
= Code
.Attribute
;
1039 if (++X
== Buffer
->ScreenBufferSize
.X
)
1043 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
1050 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1052 SMALL_RECT UpdateRect
;
1053 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1054 TermDrawRegion(Console
, &UpdateRect
);
1057 if (NumCodesWritten
) *NumCodesWritten
= NumCodesToWrite
; // Written;
1058 return STATUS_SUCCESS
;
1062 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console
,
1063 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1064 OUT PCOORD ScreenBufferSize
,
1065 OUT PCOORD CursorPosition
,
1066 OUT PCOORD ViewOrigin
,
1067 OUT PCOORD ViewSize
,
1068 OUT PCOORD MaximumViewSize
,
1069 OUT PWORD Attributes
)
1071 if (Console
== NULL
|| Buffer
== NULL
|| ScreenBufferSize
== NULL
||
1072 CursorPosition
== NULL
|| ViewOrigin
== NULL
|| ViewSize
== NULL
||
1073 MaximumViewSize
== NULL
|| Attributes
== NULL
)
1075 return STATUS_INVALID_PARAMETER
;
1078 /* Validity check */
1079 ASSERT(Console
== Buffer
->Header
.Console
);
1081 *ScreenBufferSize
= Buffer
->ScreenBufferSize
;
1082 *CursorPosition
= Buffer
->CursorPosition
;
1083 *ViewOrigin
= Buffer
->ViewOrigin
;
1084 *ViewSize
= Buffer
->ViewSize
;
1085 *Attributes
= Buffer
->ScreenDefaultAttrib
;
1087 // FIXME: Refine the computation
1088 *MaximumViewSize
= Buffer
->ScreenBufferSize
;
1090 return STATUS_SUCCESS
;
1094 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console
,
1095 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1098 if (Console
== NULL
|| Buffer
== NULL
)
1099 return STATUS_INVALID_PARAMETER
;
1101 /* Validity check */
1102 ASSERT(Console
== Buffer
->Header
.Console
);
1104 Buffer
->ScreenDefaultAttrib
= Attributes
;
1105 return STATUS_SUCCESS
;
1109 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console
,
1110 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1115 if (Console
== NULL
|| Buffer
== NULL
|| Size
== NULL
)
1116 return STATUS_INVALID_PARAMETER
;
1118 /* Validity check */
1119 ASSERT(Console
== Buffer
->Header
.Console
);
1121 Status
= ConioResizeBuffer(Console
, Buffer
, *Size
);
1122 if (NT_SUCCESS(Status
)) TermResizeTerminal(Console
);
1128 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console
,
1129 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1131 IN PSMALL_RECT ScrollRectangle
,
1132 IN BOOLEAN UseClipRectangle
,
1133 IN PSMALL_RECT ClipRectangle OPTIONAL
,
1134 IN PCOORD DestinationOrigin
,
1135 IN CHAR_INFO FillChar
)
1137 COORD CapturedDestinationOrigin
;
1138 SMALL_RECT ScreenBuffer
;
1139 SMALL_RECT SrcRegion
;
1140 SMALL_RECT DstRegion
;
1141 SMALL_RECT UpdateRegion
;
1142 SMALL_RECT CapturedClipRectangle
;
1144 if (Console
== NULL
|| Buffer
== NULL
|| ScrollRectangle
== NULL
||
1145 (UseClipRectangle
? ClipRectangle
== NULL
: FALSE
) || DestinationOrigin
== NULL
)
1147 return STATUS_INVALID_PARAMETER
;
1150 /* Validity check */
1151 ASSERT(Console
== Buffer
->Header
.Console
);
1153 CapturedDestinationOrigin
= *DestinationOrigin
;
1155 /* Make sure the source rectangle is inside the screen buffer */
1156 ConioInitRect(&ScreenBuffer
, 0, 0,
1157 Buffer
->ScreenBufferSize
.Y
- 1, Buffer
->ScreenBufferSize
.X
- 1);
1158 if (!ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, ScrollRectangle
))
1160 return STATUS_SUCCESS
;
1163 /* If the source was clipped on the left or top, adjust the destination accordingly */
1164 if (ScrollRectangle
->Left
< 0)
1166 CapturedDestinationOrigin
.X
-= ScrollRectangle
->Left
;
1168 if (ScrollRectangle
->Top
< 0)
1170 CapturedDestinationOrigin
.Y
-= ScrollRectangle
->Top
;
1173 if (UseClipRectangle
)
1175 CapturedClipRectangle
= *ClipRectangle
;
1176 if (!ConioGetIntersection(&CapturedClipRectangle
, &CapturedClipRectangle
, &ScreenBuffer
))
1178 return STATUS_SUCCESS
;
1183 CapturedClipRectangle
= ScreenBuffer
;
1186 ConioInitRect(&DstRegion
,
1187 CapturedDestinationOrigin
.Y
,
1188 CapturedDestinationOrigin
.X
,
1189 CapturedDestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
1190 CapturedDestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
1195 ConsoleOutputAnsiToUnicodeChar(Console
, &tmp
, &FillChar
.Char
.AsciiChar
);
1196 FillChar
.Char
.UnicodeChar
= tmp
;
1199 ConioMoveRegion(Buffer
, &SrcRegion
, &DstRegion
, &CapturedClipRectangle
, FillChar
);
1201 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1203 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
1204 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &CapturedClipRectangle
))
1206 /* Draw update region */
1207 TermDrawRegion(Console
, &UpdateRegion
);
1211 return STATUS_SUCCESS
;
1215 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console
,
1216 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1217 IN BOOLEAN Absolute
,
1218 IN PSMALL_RECT WindowRect
)
1220 SMALL_RECT CapturedWindowRect
;
1222 if (Console
== NULL
|| Buffer
== NULL
|| WindowRect
== NULL
)
1223 return STATUS_INVALID_PARAMETER
;
1225 /* Validity check */
1226 ASSERT(Console
== Buffer
->Header
.Console
);
1228 CapturedWindowRect
= *WindowRect
;
1230 if (Absolute
== FALSE
)
1232 /* Relative positions given. Transform them to absolute ones */
1233 CapturedWindowRect
.Left
+= Buffer
->ViewOrigin
.X
;
1234 CapturedWindowRect
.Top
+= Buffer
->ViewOrigin
.Y
;
1235 CapturedWindowRect
.Right
+= Buffer
->ViewOrigin
.X
+ Buffer
->ViewSize
.X
- 1;
1236 CapturedWindowRect
.Bottom
+= Buffer
->ViewOrigin
.Y
+ Buffer
->ViewSize
.Y
- 1;
1239 /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
1240 if ( (CapturedWindowRect
.Left
< 0) || (CapturedWindowRect
.Top
< 0) ||
1241 (CapturedWindowRect
.Right
>= Buffer
->ScreenBufferSize
.X
) ||
1242 (CapturedWindowRect
.Bottom
>= Buffer
->ScreenBufferSize
.Y
) ||
1243 (CapturedWindowRect
.Right
<= CapturedWindowRect
.Left
) ||
1244 (CapturedWindowRect
.Bottom
<= CapturedWindowRect
.Top
) )
1246 return STATUS_INVALID_PARAMETER
;
1249 Buffer
->ViewOrigin
.X
= CapturedWindowRect
.Left
;
1250 Buffer
->ViewOrigin
.Y
= CapturedWindowRect
.Top
;
1252 Buffer
->ViewSize
.X
= CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1;
1253 Buffer
->ViewSize
.Y
= CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1;
1255 // TermResizeTerminal(Console);
1257 return STATUS_SUCCESS
;