2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Driver DLL
4 * FILE: 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
,
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
,
64 IN HANDLE ProcessHandle
,
65 IN PTEXTMODE_BUFFER_INFO TextModeInfo
)
67 NTSTATUS Status
= STATUS_SUCCESS
;
68 PTEXTMODE_SCREEN_BUFFER NewBuffer
= NULL
;
70 UNREFERENCED_PARAMETER(ProcessHandle
);
72 if (Console
== NULL
|| Buffer
== NULL
|| TextModeInfo
== NULL
)
73 return STATUS_INVALID_PARAMETER
;
77 Status
= CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER
*)&NewBuffer
,
80 sizeof(TEXTMODE_SCREEN_BUFFER
));
81 if (!NT_SUCCESS(Status
)) return Status
;
82 NewBuffer
->Header
.Type
= TEXTMODE_BUFFER
;
84 NewBuffer
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
85 TextModeInfo
->ScreenBufferSize
.X
*
86 TextModeInfo
->ScreenBufferSize
.Y
*
88 if (NewBuffer
->Buffer
== NULL
)
90 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
91 return STATUS_INSUFFICIENT_RESOURCES
;
94 NewBuffer
->ScreenBufferSize
= NewBuffer
->OldScreenBufferSize
95 = TextModeInfo
->ScreenBufferSize
;
96 NewBuffer
->ViewSize
= NewBuffer
->OldViewSize
97 = Console
->ConsoleSize
;
99 NewBuffer
->ViewOrigin
.X
= NewBuffer
->ViewOrigin
.Y
= 0;
100 NewBuffer
->VirtualY
= 0;
102 NewBuffer
->CursorBlinkOn
= NewBuffer
->ForceCursorOff
= FALSE
;
103 NewBuffer
->CursorInfo
.bVisible
= (TextModeInfo
->IsCursorVisible
&& (TextModeInfo
->CursorSize
!= 0));
104 NewBuffer
->CursorInfo
.dwSize
= min(max(TextModeInfo
->CursorSize
, 0), 100);
106 NewBuffer
->ScreenDefaultAttrib
= TextModeInfo
->ScreenAttrib
;
107 NewBuffer
->PopupDefaultAttrib
= TextModeInfo
->PopupAttrib
;
109 /* Initialize buffer to be empty with default attributes */
110 for (NewBuffer
->CursorPosition
.Y
= 0 ; NewBuffer
->CursorPosition
.Y
< NewBuffer
->ScreenBufferSize
.Y
; NewBuffer
->CursorPosition
.Y
++)
112 ClearLineBuffer(NewBuffer
);
114 NewBuffer
->CursorPosition
.X
= NewBuffer
->CursorPosition
.Y
= 0;
116 NewBuffer
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
118 *Buffer
= (PCONSOLE_SCREEN_BUFFER
)NewBuffer
;
119 return STATUS_SUCCESS
;
123 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
)
125 PTEXTMODE_SCREEN_BUFFER Buff
= (PTEXTMODE_SCREEN_BUFFER
)Buffer
;
128 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
129 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
131 Buffer
->Header
.Type
= SCREEN_BUFFER
;
133 ConsoleFreeHeap(Buff
->Buffer
);
135 CONSOLE_SCREEN_BUFFER_Destroy(Buffer
);
140 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff
, ULONG X
, ULONG Y
)
142 return &Buff
->Buffer
[((Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
) * Buff
->ScreenBufferSize
.X
+ X
];
146 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
)
148 PCHAR_INFO Ptr
= ConioCoordToPointer(Buff
, 0, Buff
->CursorPosition
.Y
);
151 for (Pos
= 0; Pos
< Buff
->ScreenBufferSize
.X
; Pos
++, Ptr
++)
154 Ptr
->Char
.UnicodeChar
= L
' ';
155 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
160 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff
,
161 IN OUT PSMALL_RECT UpdateRect
,
165 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
167 UpdateRect
->Left
= 0;
171 UpdateRect
->Left
= Start
->X
;
173 if (Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
175 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
179 UpdateRect
->Right
= Start
->X
+ Length
- 1;
181 UpdateRect
->Top
= Start
->Y
;
182 UpdateRect
->Bottom
= Start
->Y
+ (Start
->X
+ Length
- 1) / Buff
->ScreenBufferSize
.X
;
183 if (Buff
->ScreenBufferSize
.Y
<= UpdateRect
->Bottom
)
185 UpdateRect
->Bottom
= Buff
->ScreenBufferSize
.Y
- 1;
190 * Move from one rectangle to another. We must be careful about the order that
191 * this is done, to avoid overwriting parts of the source before they are moved.
194 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
195 PSMALL_RECT SrcRegion
,
196 PSMALL_RECT DstRegion
,
197 PSMALL_RECT ClipRegion
,
200 int Width
= ConioRectWidth(SrcRegion
);
201 int Height
= ConioRectHeight(SrcRegion
);
212 /* Moving down: work from bottom up */
213 SY
= SrcRegion
->Bottom
;
214 DY
= DstRegion
->Bottom
;
217 for (i
= 0; i
< Height
; i
++)
219 PCHAR_INFO SRow
= ConioCoordToPointer(ScreenBuffer
, 0, SY
);
220 PCHAR_INFO DRow
= ConioCoordToPointer(ScreenBuffer
, 0, DY
);
222 SX
= SrcRegion
->Left
;
223 DX
= DstRegion
->Left
;
227 /* Moving right: work from right to left */
228 SX
= SrcRegion
->Right
;
229 DX
= DstRegion
->Right
;
232 for (j
= 0; j
< Width
; j
++)
234 CHAR_INFO Cell
= SRow
[SX
];
235 if (SX
>= ClipRegion
->Left
&& SX
<= ClipRegion
->Right
&&
236 SY
>= ClipRegion
->Top
&& SY
<= ClipRegion
->Bottom
)
240 if (DX
>= ClipRegion
->Left
&& DX
<= ClipRegion
->Right
&&
241 DY
>= ClipRegion
->Top
&& DY
<= ClipRegion
->Bottom
)
255 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
256 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
257 IN BOOLEAN AppendToEnd
,
258 IN PINPUT_RECORD InputRecord
,
259 IN ULONG NumEventsToWrite
,
260 OUT PULONG NumEventsWritten OPTIONAL
);
263 ConioResizeBuffer(PCONSOLE Console
,
264 PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
270 WORD CurrentAttribute
;
272 PCHAR_INFO OldBuffer
;
276 /* Buffer size is not allowed to be smaller than the view size */
277 if (Size
.X
< ScreenBuffer
->ViewSize
.X
|| Size
.Y
< ScreenBuffer
->ViewSize
.Y
)
278 return STATUS_INVALID_PARAMETER
;
280 if (Size
.X
== ScreenBuffer
->ScreenBufferSize
.X
&& Size
.Y
== ScreenBuffer
->ScreenBufferSize
.Y
)
282 // FIXME: Trigger a buffer resize event ??
283 return STATUS_SUCCESS
;
286 if (Console
->FixedSize
)
289 * The console is in fixed-size mode, so we cannot resize anything
290 * at the moment. However, keep those settings somewhere so that
291 * we can try to set them up when we will be allowed to do so.
293 ScreenBuffer
->OldScreenBufferSize
= Size
;
294 return STATUS_NOT_SUPPORTED
; // STATUS_SUCCESS
297 Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
.X
* Size
.Y
* sizeof(CHAR_INFO
));
298 if (!Buffer
) return STATUS_NO_MEMORY
;
300 DPRINT("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer
->ScreenBufferSize
.X
, ScreenBuffer
->ScreenBufferSize
.Y
, Size
.X
, Size
.Y
);
301 OldBuffer
= ScreenBuffer
->Buffer
;
303 for (CurrentY
= 0; CurrentY
< ScreenBuffer
->ScreenBufferSize
.Y
&& CurrentY
< Size
.Y
; CurrentY
++)
305 ptr
= ConioCoordToPointer(ScreenBuffer
, 0, CurrentY
);
306 if (Size
.X
<= ScreenBuffer
->ScreenBufferSize
.X
)
309 RtlCopyMemory(Buffer
+ Offset
, ptr
, Size
.X
* sizeof(CHAR_INFO
));
315 RtlCopyMemory(Buffer
+ Offset
, ptr
, ScreenBuffer
->ScreenBufferSize
.X
* sizeof(CHAR_INFO
));
316 Offset
+= ScreenBuffer
->ScreenBufferSize
.X
;
318 /* The attribute to be used is the one of the last cell of the current line */
319 CurrentAttribute
= ConioCoordToPointer(ScreenBuffer
,
320 ScreenBuffer
->ScreenBufferSize
.X
- 1,
321 CurrentY
)->Attributes
;
323 diff
= Size
.X
- ScreenBuffer
->ScreenBufferSize
.X
;
325 /* Zero-out the new part of the buffer */
326 for (i
= 0; i
< diff
; i
++)
328 ptr
= Buffer
+ Offset
;
329 ptr
->Char
.UnicodeChar
= L
' ';
330 ptr
->Attributes
= CurrentAttribute
;
336 if (Size
.Y
> ScreenBuffer
->ScreenBufferSize
.Y
)
338 diff
= Size
.X
* (Size
.Y
- ScreenBuffer
->ScreenBufferSize
.Y
);
340 /* Zero-out the new part of the buffer */
341 for (i
= 0; i
< diff
; i
++)
343 ptr
= Buffer
+ Offset
;
344 ptr
->Char
.UnicodeChar
= L
' ';
345 ptr
->Attributes
= ScreenBuffer
->ScreenDefaultAttrib
;
350 (void)InterlockedExchangePointer((PVOID
volatile*)&ScreenBuffer
->Buffer
, Buffer
);
351 ConsoleFreeHeap(OldBuffer
);
352 ScreenBuffer
->ScreenBufferSize
= ScreenBuffer
->OldScreenBufferSize
= Size
;
353 ScreenBuffer
->VirtualY
= 0;
355 /* Ensure cursor and window are within buffer */
356 if (ScreenBuffer
->CursorPosition
.X
>= Size
.X
)
357 ScreenBuffer
->CursorPosition
.X
= Size
.X
- 1;
358 if (ScreenBuffer
->CursorPosition
.Y
>= Size
.Y
)
359 ScreenBuffer
->CursorPosition
.Y
= Size
.Y
- 1;
360 if (ScreenBuffer
->ViewOrigin
.X
> Size
.X
- ScreenBuffer
->ViewSize
.X
)
361 ScreenBuffer
->ViewOrigin
.X
= Size
.X
- ScreenBuffer
->ViewSize
.X
;
362 if (ScreenBuffer
->ViewOrigin
.Y
> Size
.Y
- ScreenBuffer
->ViewSize
.Y
)
363 ScreenBuffer
->ViewOrigin
.Y
= Size
.Y
- ScreenBuffer
->ViewSize
.Y
;
366 * Trigger a buffer resize event
368 if (Console
->InputBuffer
.Mode
& ENABLE_WINDOW_INPUT
)
370 ULONG NumEventsWritten
;
373 er
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
374 er
.Event
.WindowBufferSizeEvent
.dwSize
= ScreenBuffer
->ScreenBufferSize
;
376 // ConioProcessInputEvent(Console, &er);
377 ConDrvWriteConsoleInput(Console
,
378 &Console
->InputBuffer
,
385 return STATUS_SUCCESS
;
389 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console
,
390 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
391 IN USHORT NewScreenAttrib
,
392 IN USHORT NewPopupAttrib
)
398 ULONG NumCodesToWrite
;
399 USHORT OldScreenAttrib
, OldPopupAttrib
;
401 if (Console
== NULL
|| Buffer
== NULL
)
403 return STATUS_INVALID_PARAMETER
;
407 ASSERT(Console
== Buffer
->Header
.Console
);
409 NumCodesToWrite
= Buffer
->ScreenBufferSize
.X
* Buffer
->ScreenBufferSize
.Y
;
410 OldScreenAttrib
= Buffer
->ScreenDefaultAttrib
;
411 OldPopupAttrib
= Buffer
->PopupDefaultAttrib
;
414 Y
= (TopLeft
.Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
415 Length
= NumCodesToWrite
;
417 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
418 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
422 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
423 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
426 * Change the current colors only if they are the old ones.
429 /* Foreground color */
430 if ((Ptr
->Attributes
& 0x0F) == (OldScreenAttrib
& 0x0F))
431 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewScreenAttrib
& 0x0F);
432 if ((Ptr
->Attributes
& 0x0F) == (OldPopupAttrib
& 0x0F))
433 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewPopupAttrib
& 0x0F);
435 /* Background color */
436 if ((Ptr
->Attributes
& 0xF0) == (OldScreenAttrib
& 0xF0))
437 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewScreenAttrib
& 0xF0);
438 if ((Ptr
->Attributes
& 0xF0) == (OldPopupAttrib
& 0xF0))
439 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewPopupAttrib
& 0xF0);
443 if (++X
== Buffer
->ScreenBufferSize
.X
)
447 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
454 /* Save foreground and background colors for both screen and popup */
455 Buffer
->ScreenDefaultAttrib
= (NewScreenAttrib
& 0x00FF);
456 Buffer
->PopupDefaultAttrib
= (NewPopupAttrib
& 0x00FF);
458 /* Refresh the display if needed */
459 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
461 SMALL_RECT UpdateRect
;
462 ConioComputeUpdateRect(Buffer
, &UpdateRect
, &TopLeft
, NumCodesToWrite
);
463 TermDrawRegion(Console
, &UpdateRect
);
466 return STATUS_SUCCESS
;
470 /* PUBLIC DRIVER APIS *********************************************************/
473 ConDrvReadConsoleOutput(IN PCONSOLE Console
,
474 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
476 OUT PCHAR_INFO CharInfo
/*Buffer*/,
477 IN OUT PSMALL_RECT ReadRegion
)
480 SMALL_RECT ScreenBuffer
;
481 PCHAR_INFO CurCharInfo
;
482 SMALL_RECT CapturedReadRegion
;
485 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| ReadRegion
== NULL
)
487 return STATUS_INVALID_PARAMETER
;
491 ASSERT(Console
== Buffer
->Header
.Console
);
493 CapturedReadRegion
= *ReadRegion
;
495 /* Make sure ReadRegion is inside the screen buffer */
496 ConioInitRect(&ScreenBuffer
, 0, 0,
497 Buffer
->ScreenBufferSize
.Y
- 1,
498 Buffer
->ScreenBufferSize
.X
- 1);
499 if (!ConioGetIntersection(&CapturedReadRegion
, &ScreenBuffer
, &CapturedReadRegion
))
502 * It is okay to have a ReadRegion completely outside
503 * the screen buffer. No data is read then.
505 return STATUS_SUCCESS
;
508 CurCharInfo
= CharInfo
;
510 for (Y
= CapturedReadRegion
.Top
; Y
<= CapturedReadRegion
.Bottom
; ++Y
)
512 Ptr
= ConioCoordToPointer(Buffer
, CapturedReadRegion
.Left
, Y
);
513 for (X
= CapturedReadRegion
.Left
; X
<= CapturedReadRegion
.Right
; ++X
)
517 CurCharInfo
->Char
.UnicodeChar
= Ptr
->Char
.UnicodeChar
;
521 // ConsoleOutputUnicodeToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
522 WideCharToMultiByte(Console
->OutputCodePage
, 0, &Ptr
->Char
.UnicodeChar
, 1,
523 &CurCharInfo
->Char
.AsciiChar
, 1, NULL
, NULL
);
525 CurCharInfo
->Attributes
= Ptr
->Attributes
;
531 *ReadRegion
= CapturedReadRegion
;
533 return STATUS_SUCCESS
;
537 ConDrvWriteConsoleOutput(IN PCONSOLE Console
,
538 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
540 IN PCHAR_INFO CharInfo
/*Buffer*/,
541 IN OUT PSMALL_RECT WriteRegion
)
544 SMALL_RECT ScreenBuffer
;
545 PCHAR_INFO CurCharInfo
;
546 SMALL_RECT CapturedWriteRegion
;
549 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
551 return STATUS_INVALID_PARAMETER
;
555 ASSERT(Console
== Buffer
->Header
.Console
);
557 CapturedWriteRegion
= *WriteRegion
;
559 /* Make sure WriteRegion is inside the screen buffer */
560 ConioInitRect(&ScreenBuffer
, 0, 0,
561 Buffer
->ScreenBufferSize
.Y
- 1,
562 Buffer
->ScreenBufferSize
.X
- 1);
563 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
566 * It is okay to have a WriteRegion completely outside
567 * the screen buffer. No data is written then.
569 return STATUS_SUCCESS
;
572 CurCharInfo
= CharInfo
;
574 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
576 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
577 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
581 Ptr
->Char
.UnicodeChar
= CurCharInfo
->Char
.UnicodeChar
;
585 ConsoleOutputAnsiToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
.AsciiChar
);
587 Ptr
->Attributes
= CurCharInfo
->Attributes
;
593 TermDrawRegion(Console
, &CapturedWriteRegion
);
595 *WriteRegion
= CapturedWriteRegion
;
597 return STATUS_SUCCESS
;
601 * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
602 * FIXME: This function MUST be moved into consrv/conoutput.c because only
603 * consrv knows how to manipulate VDM screenbuffers.
606 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console
,
607 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
608 IN PCHAR_CELL CharInfo
/*Buffer*/,
609 IN COORD CharInfoSize
,
610 IN PSMALL_RECT WriteRegion
)
613 SMALL_RECT ScreenBuffer
;
614 PCHAR_CELL CurCharInfo
;
615 SMALL_RECT CapturedWriteRegion
;
618 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
620 return STATUS_INVALID_PARAMETER
;
624 ASSERT(Console
== Buffer
->Header
.Console
);
626 CapturedWriteRegion
= *WriteRegion
;
628 /* Make sure WriteRegion is inside the screen buffer */
629 ConioInitRect(&ScreenBuffer
, 0, 0,
630 Buffer
->ScreenBufferSize
.Y
- 1,
631 Buffer
->ScreenBufferSize
.X
- 1);
632 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
635 * It is okay to have a WriteRegion completely outside
636 * the screen buffer. No data is written then.
638 return STATUS_SUCCESS
;
641 // CurCharInfo = CharInfo;
643 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
645 /**/CurCharInfo
= CharInfo
+ Y
* CharInfoSize
.X
+ CapturedWriteRegion
.Left
;/**/
647 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
648 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
650 ConsoleOutputAnsiToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
);
651 Ptr
->Attributes
= CurCharInfo
->Attributes
;
657 return STATUS_SUCCESS
;
661 ConDrvWriteConsole(IN PCONSOLE Console
,
662 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
664 IN PVOID StringBuffer
,
665 IN ULONG NumCharsToWrite
,
666 OUT PULONG NumCharsWritten OPTIONAL
)
668 NTSTATUS Status
= STATUS_SUCCESS
;
669 PWCHAR Buffer
= NULL
;
673 if (Console
== NULL
|| ScreenBuffer
== NULL
/* || StringBuffer == NULL */)
674 return STATUS_INVALID_PARAMETER
;
676 /* Validity checks */
677 ASSERT(Console
== ScreenBuffer
->Header
.Console
);
678 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCharsToWrite
== 0));
680 /* Stop here if the console is paused */
681 if (Console
->UnpauseEvent
!= NULL
) return STATUS_PENDING
;
683 /* Convert the string to UNICODE */
686 Buffer
= StringBuffer
;
690 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
694 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
697 MultiByteToWideChar(Console
->OutputCodePage
, 0,
700 (PWCHAR
)Buffer
, Length
);
704 Status
= STATUS_NO_MEMORY
;
711 if (NT_SUCCESS(Status
))
713 Status
= TermWriteStream(Console
,
718 if (NT_SUCCESS(Status
))
720 Written
= NumCharsToWrite
;
724 if (!Unicode
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
727 if (NumCharsWritten
) *NumCharsWritten
= Written
;
733 ConDrvReadConsoleOutputString(IN PCONSOLE Console
,
734 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
735 IN CODE_TYPE CodeType
,
736 OUT PVOID StringBuffer
,
737 IN ULONG NumCodesToRead
,
739 // OUT PCOORD EndCoord,
740 OUT PULONG NumCodesRead OPTIONAL
)
748 if (Console
== NULL
|| Buffer
== NULL
|| ReadCoord
== NULL
/* || EndCoord == NULL */)
750 return STATUS_INVALID_PARAMETER
;
753 /* Validity checks */
754 ASSERT(Console
== Buffer
->Header
.Console
);
755 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToRead
== 0));
758 // FIXME: Make overflow checks on ReadCoord !!!!!!
761 if (NumCodesRead
) *NumCodesRead
= 0;
766 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
770 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
774 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
778 return STATUS_INVALID_PARAMETER
;
781 ReadBuffer
= StringBuffer
;
783 Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
786 * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
788 * If the number of attributes (resp. characters) to be read from extends
789 * beyond the end of the specified screen buffer row, attributes (resp.
790 * characters) are read from the next row. If the number of attributes
791 * (resp. characters) to be read from extends beyond the end of the console
792 * screen buffer, attributes (resp. characters) up to the end of the console
793 * screen buffer are read.
795 * TODO: Do NOT loop up to NumCodesToRead, but stop before
796 * if we are going to overflow...
798 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
799 for (i
= 0; i
< min(NumCodesToRead
, Buffer
->ScreenBufferSize
.X
* Buffer
->ScreenBufferSize
.Y
); ++i
)
801 // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
802 Ptr
= &Buffer
->Buffer
[Xpos
+ Ypos
* Buffer
->ScreenBufferSize
.X
];
807 ConsoleOutputUnicodeToAnsiChar(Console
, (PCHAR
)ReadBuffer
, &Ptr
->Char
.UnicodeChar
);
811 *(PWCHAR
)ReadBuffer
= Ptr
->Char
.UnicodeChar
;
815 *(PWORD
)ReadBuffer
= Ptr
->Attributes
;
818 ReadBuffer
= (PVOID
)((ULONG_PTR
)ReadBuffer
+ CodeSize
);
823 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
828 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
835 // EndCoord->X = Xpos;
836 // EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y;
839 *NumCodesRead
= (ULONG
)((ULONG_PTR
)ReadBuffer
- (ULONG_PTR
)StringBuffer
) / CodeSize
;
842 return STATUS_SUCCESS
;
846 ConDrvWriteConsoleOutputString(IN PCONSOLE Console
,
847 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
848 IN CODE_TYPE CodeType
,
849 IN PVOID StringBuffer
,
850 IN ULONG NumCodesToWrite
,
851 IN PCOORD WriteCoord
,
852 // OUT PCOORD EndCoord,
853 OUT PULONG NumCodesWritten OPTIONAL
)
855 NTSTATUS Status
= STATUS_SUCCESS
;
856 PVOID WriteBuffer
= NULL
;
857 PWCHAR tmpString
= NULL
;
858 DWORD X
, Y
, Length
; // , Written = 0;
862 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
/* || EndCoord == NULL */)
864 return STATUS_INVALID_PARAMETER
;
867 /* Validity checks */
868 ASSERT(Console
== Buffer
->Header
.Console
);
869 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToWrite
== 0));
872 // FIXME: Make overflow checks on WriteCoord !!!!!!
875 if (NumCodesWritten
) *NumCodesWritten
= 0;
880 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
884 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
888 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
892 return STATUS_INVALID_PARAMETER
;
895 if (CodeType
== CODE_ASCII
)
897 /* Convert the ASCII string into Unicode before writing it to the console */
898 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
902 tmpString
= WriteBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
905 MultiByteToWideChar(Console
->OutputCodePage
, 0,
908 (PWCHAR
)WriteBuffer
, Length
);
912 Status
= STATUS_NO_MEMORY
;
915 // FIXME: Quick fix: fix the CodeType and CodeSize since the
916 // ASCII string was converted into UNICODE.
917 // A proper fix needs to be written.
918 CodeType
= CODE_UNICODE
;
919 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
923 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
924 WriteBuffer
= StringBuffer
;
927 if (WriteBuffer
== NULL
|| !NT_SUCCESS(Status
)) goto Cleanup
;
930 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
931 Length
= NumCodesToWrite
;
932 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
933 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
937 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
938 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
944 Ptr
->Char
.UnicodeChar
= *(PWCHAR
)WriteBuffer
;
948 Ptr
->Attributes
= *(PWORD
)WriteBuffer
;
951 WriteBuffer
= (PVOID
)((ULONG_PTR
)WriteBuffer
+ CodeSize
);
955 if (++X
== Buffer
->ScreenBufferSize
.X
)
959 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
966 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
968 SMALL_RECT UpdateRect
;
969 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
970 TermDrawRegion(Console
, &UpdateRect
);
974 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
977 if (tmpString
) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString
);
979 if (NumCodesWritten
) *NumCodesWritten
= NumCodesToWrite
; // Written;
984 ConDrvFillConsoleOutput(IN PCONSOLE Console
,
985 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
986 IN CODE_TYPE CodeType
,
987 IN CODE_ELEMENT Code
,
988 IN ULONG NumCodesToWrite
,
989 IN PCOORD WriteCoord
,
990 OUT PULONG NumCodesWritten OPTIONAL
)
992 DWORD X
, Y
, Length
; // , Written = 0;
995 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
)
997 return STATUS_INVALID_PARAMETER
;
1000 /* Validity check */
1001 ASSERT(Console
== Buffer
->Header
.Console
);
1004 // FIXME: Make overflow checks on WriteCoord !!!!!!
1007 if (NumCodesWritten
) *NumCodesWritten
= 0;
1009 if (CodeType
== CODE_ASCII
)
1011 /* Conversion from the ASCII char to the UNICODE char */
1013 ConsoleOutputAnsiToUnicodeChar(Console
, &tmp
.UnicodeChar
, &Code
.AsciiChar
);
1018 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1019 Length
= NumCodesToWrite
;
1020 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1021 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1025 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
1026 Ptr
= &Buffer
->Buffer
[X
+ Y
* Buffer
->ScreenBufferSize
.X
];
1032 Ptr
->Char
.UnicodeChar
= Code
.UnicodeChar
;
1035 case CODE_ATTRIBUTE
:
1036 Ptr
->Attributes
= Code
.Attribute
;
1042 if (++X
== Buffer
->ScreenBufferSize
.X
)
1046 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
1053 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1055 SMALL_RECT UpdateRect
;
1056 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1057 TermDrawRegion(Console
, &UpdateRect
);
1060 if (NumCodesWritten
) *NumCodesWritten
= NumCodesToWrite
; // Written;
1061 return STATUS_SUCCESS
;
1065 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console
,
1066 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1067 OUT PCOORD ScreenBufferSize
,
1068 OUT PCOORD CursorPosition
,
1069 OUT PCOORD ViewOrigin
,
1070 OUT PCOORD ViewSize
,
1071 OUT PCOORD MaximumViewSize
,
1072 OUT PWORD Attributes
)
1074 if (Console
== NULL
|| Buffer
== NULL
|| ScreenBufferSize
== NULL
||
1075 CursorPosition
== NULL
|| ViewOrigin
== NULL
|| ViewSize
== NULL
||
1076 MaximumViewSize
== NULL
|| Attributes
== NULL
)
1078 return STATUS_INVALID_PARAMETER
;
1081 /* Validity check */
1082 ASSERT(Console
== Buffer
->Header
.Console
);
1084 *ScreenBufferSize
= Buffer
->ScreenBufferSize
;
1085 *CursorPosition
= Buffer
->CursorPosition
;
1086 *ViewOrigin
= Buffer
->ViewOrigin
;
1087 *ViewSize
= Buffer
->ViewSize
;
1088 *Attributes
= Buffer
->ScreenDefaultAttrib
;
1090 // FIXME: Refine the computation
1091 *MaximumViewSize
= Buffer
->ScreenBufferSize
;
1093 return STATUS_SUCCESS
;
1097 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console
,
1098 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1101 if (Console
== NULL
|| Buffer
== NULL
)
1102 return STATUS_INVALID_PARAMETER
;
1104 /* Validity check */
1105 ASSERT(Console
== Buffer
->Header
.Console
);
1107 Buffer
->ScreenDefaultAttrib
= Attributes
;
1108 return STATUS_SUCCESS
;
1112 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console
,
1113 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1118 if (Console
== NULL
|| Buffer
== NULL
|| Size
== NULL
)
1119 return STATUS_INVALID_PARAMETER
;
1121 /* Validity check */
1122 ASSERT(Console
== Buffer
->Header
.Console
);
1124 Status
= ConioResizeBuffer(Console
, Buffer
, *Size
);
1125 if (NT_SUCCESS(Status
)) TermResizeTerminal(Console
);
1131 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console
,
1132 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1134 IN PSMALL_RECT ScrollRectangle
,
1135 IN BOOLEAN UseClipRectangle
,
1136 IN PSMALL_RECT ClipRectangle OPTIONAL
,
1137 IN PCOORD DestinationOrigin
,
1138 IN CHAR_INFO FillChar
)
1140 COORD CapturedDestinationOrigin
;
1141 SMALL_RECT ScreenBuffer
;
1142 SMALL_RECT SrcRegion
;
1143 SMALL_RECT DstRegion
;
1144 SMALL_RECT UpdateRegion
;
1145 SMALL_RECT CapturedClipRectangle
;
1147 if (Console
== NULL
|| Buffer
== NULL
|| ScrollRectangle
== NULL
||
1148 (UseClipRectangle
? ClipRectangle
== NULL
: FALSE
) || DestinationOrigin
== NULL
)
1150 return STATUS_INVALID_PARAMETER
;
1153 /* Validity check */
1154 ASSERT(Console
== Buffer
->Header
.Console
);
1156 CapturedDestinationOrigin
= *DestinationOrigin
;
1158 /* Make sure the source rectangle is inside the screen buffer */
1159 ConioInitRect(&ScreenBuffer
, 0, 0,
1160 Buffer
->ScreenBufferSize
.Y
- 1,
1161 Buffer
->ScreenBufferSize
.X
- 1);
1162 if (!ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, ScrollRectangle
))
1164 return STATUS_SUCCESS
;
1167 /* If the source was clipped on the left or top, adjust the destination accordingly */
1168 if (ScrollRectangle
->Left
< 0)
1170 CapturedDestinationOrigin
.X
-= ScrollRectangle
->Left
;
1172 if (ScrollRectangle
->Top
< 0)
1174 CapturedDestinationOrigin
.Y
-= ScrollRectangle
->Top
;
1177 if (UseClipRectangle
)
1179 CapturedClipRectangle
= *ClipRectangle
;
1180 if (!ConioGetIntersection(&CapturedClipRectangle
, &CapturedClipRectangle
, &ScreenBuffer
))
1182 return STATUS_SUCCESS
;
1187 CapturedClipRectangle
= ScreenBuffer
;
1190 ConioInitRect(&DstRegion
,
1191 CapturedDestinationOrigin
.Y
,
1192 CapturedDestinationOrigin
.X
,
1193 CapturedDestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
1194 CapturedDestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
1199 ConsoleOutputAnsiToUnicodeChar(Console
, &tmp
, &FillChar
.Char
.AsciiChar
);
1200 FillChar
.Char
.UnicodeChar
= tmp
;
1203 ConioMoveRegion(Buffer
, &SrcRegion
, &DstRegion
, &CapturedClipRectangle
, FillChar
);
1205 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1207 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
1208 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &CapturedClipRectangle
))
1210 /* Draw update region */
1211 TermDrawRegion(Console
, &UpdateRegion
);
1215 return STATUS_SUCCESS
;
1219 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console
,
1220 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1221 IN BOOLEAN Absolute
,
1222 IN PSMALL_RECT WindowRect
)
1224 SMALL_RECT CapturedWindowRect
;
1226 if (Console
== NULL
|| Buffer
== NULL
|| WindowRect
== NULL
)
1227 return STATUS_INVALID_PARAMETER
;
1229 /* Validity check */
1230 ASSERT(Console
== Buffer
->Header
.Console
);
1232 CapturedWindowRect
= *WindowRect
;
1234 if (Absolute
== FALSE
)
1236 /* Relative positions given. Transform them to absolute ones */
1237 CapturedWindowRect
.Left
+= Buffer
->ViewOrigin
.X
;
1238 CapturedWindowRect
.Top
+= Buffer
->ViewOrigin
.Y
;
1239 CapturedWindowRect
.Right
+= Buffer
->ViewOrigin
.X
+ Buffer
->ViewSize
.X
- 1;
1240 CapturedWindowRect
.Bottom
+= Buffer
->ViewOrigin
.Y
+ Buffer
->ViewSize
.Y
- 1;
1243 /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
1244 if ( (CapturedWindowRect
.Left
< 0) || (CapturedWindowRect
.Top
< 0) ||
1245 (CapturedWindowRect
.Right
>= Buffer
->ScreenBufferSize
.X
) ||
1246 (CapturedWindowRect
.Bottom
>= Buffer
->ScreenBufferSize
.Y
) ||
1247 (CapturedWindowRect
.Right
<= CapturedWindowRect
.Left
) ||
1248 (CapturedWindowRect
.Bottom
<= CapturedWindowRect
.Top
) )
1250 return STATUS_INVALID_PARAMETER
;
1253 Buffer
->ViewOrigin
.X
= CapturedWindowRect
.Left
;
1254 Buffer
->ViewOrigin
.Y
= CapturedWindowRect
.Top
;
1256 Buffer
->ViewSize
.X
= CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1;
1257 Buffer
->ViewSize
.Y
= CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1;
1259 // TermResizeTerminal(Console);
1261 return STATUS_SUCCESS
;