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
,
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 ((UINT
)Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
167 UpdateRect
->Left
= 0;
168 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
172 UpdateRect
->Left
= Start
->X
;
173 UpdateRect
->Right
= Start
->X
+ Length
- 1;
175 UpdateRect
->Top
= Start
->Y
;
176 UpdateRect
->Bottom
= Start
->Y
+ (Start
->X
+ Length
- 1) / Buff
->ScreenBufferSize
.X
;
177 if (Buff
->ScreenBufferSize
.Y
<= UpdateRect
->Bottom
)
179 UpdateRect
->Bottom
= Buff
->ScreenBufferSize
.Y
- 1;
184 * Move from one rectangle to another. We must be careful about the order that
185 * this is done, to avoid overwriting parts of the source before they are moved.
188 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
189 PSMALL_RECT SrcRegion
,
190 PSMALL_RECT DstRegion
,
191 PSMALL_RECT ClipRegion
,
194 int Width
= ConioRectWidth(SrcRegion
);
195 int Height
= ConioRectHeight(SrcRegion
);
206 /* Moving down: work from bottom up */
207 SY
= SrcRegion
->Bottom
;
208 DY
= DstRegion
->Bottom
;
211 for (i
= 0; i
< Height
; i
++)
213 PCHAR_INFO SRow
= ConioCoordToPointer(ScreenBuffer
, 0, SY
);
214 PCHAR_INFO DRow
= ConioCoordToPointer(ScreenBuffer
, 0, DY
);
216 SX
= SrcRegion
->Left
;
217 DX
= DstRegion
->Left
;
221 /* Moving right: work from right to left */
222 SX
= SrcRegion
->Right
;
223 DX
= DstRegion
->Right
;
226 for (j
= 0; j
< Width
; j
++)
228 CHAR_INFO Cell
= SRow
[SX
];
229 if (SX
>= ClipRegion
->Left
&& SX
<= ClipRegion
->Right
&&
230 SY
>= ClipRegion
->Top
&& SY
<= ClipRegion
->Bottom
)
234 if (DX
>= ClipRegion
->Left
&& DX
<= ClipRegion
->Right
&&
235 DY
>= ClipRegion
->Top
&& DY
<= ClipRegion
->Bottom
)
249 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
250 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
251 IN BOOLEAN AppendToEnd
,
252 IN PINPUT_RECORD InputRecord
,
253 IN ULONG NumEventsToWrite
,
254 OUT PULONG NumEventsWritten OPTIONAL
);
257 ConioResizeBuffer(PCONSOLE Console
,
258 PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
264 WORD CurrentAttribute
;
266 PCHAR_INFO OldBuffer
;
270 /* Buffer size is not allowed to be smaller than the view size */
271 if (Size
.X
< ScreenBuffer
->ViewSize
.X
|| Size
.Y
< ScreenBuffer
->ViewSize
.Y
)
272 return STATUS_INVALID_PARAMETER
;
274 if (Size
.X
== ScreenBuffer
->ScreenBufferSize
.X
&& Size
.Y
== ScreenBuffer
->ScreenBufferSize
.Y
)
276 // FIXME: Trigger a buffer resize event ??
277 return STATUS_SUCCESS
;
280 if (Console
->FixedSize
)
283 * The console is in fixed-size mode, so we cannot resize anything
284 * at the moment. However, keep those settings somewhere so that
285 * we can try to set them up when we will be allowed to do so.
287 ScreenBuffer
->OldScreenBufferSize
= Size
;
288 return STATUS_NOT_SUPPORTED
; // STATUS_SUCCESS
291 Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
.X
* Size
.Y
* sizeof(CHAR_INFO
));
292 if (!Buffer
) return STATUS_NO_MEMORY
;
294 DPRINT("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer
->ScreenBufferSize
.X
, ScreenBuffer
->ScreenBufferSize
.Y
, Size
.X
, Size
.Y
);
295 OldBuffer
= ScreenBuffer
->Buffer
;
297 for (CurrentY
= 0; CurrentY
< ScreenBuffer
->ScreenBufferSize
.Y
&& CurrentY
< Size
.Y
; CurrentY
++)
299 ptr
= ConioCoordToPointer(ScreenBuffer
, 0, CurrentY
);
300 if (Size
.X
<= ScreenBuffer
->ScreenBufferSize
.X
)
303 RtlCopyMemory(Buffer
+ Offset
, ptr
, Size
.X
* sizeof(CHAR_INFO
));
309 RtlCopyMemory(Buffer
+ Offset
, ptr
, ScreenBuffer
->ScreenBufferSize
.X
* sizeof(CHAR_INFO
));
310 Offset
+= ScreenBuffer
->ScreenBufferSize
.X
;
312 /* The attribute to be used is the one of the last cell of the current line */
313 CurrentAttribute
= ConioCoordToPointer(ScreenBuffer
,
314 ScreenBuffer
->ScreenBufferSize
.X
- 1,
315 CurrentY
)->Attributes
;
317 diff
= Size
.X
- ScreenBuffer
->ScreenBufferSize
.X
;
319 /* Zero-out the new part of the buffer */
320 for (i
= 0; i
< diff
; i
++)
322 ptr
= Buffer
+ Offset
;
323 ptr
->Char
.UnicodeChar
= L
' ';
324 ptr
->Attributes
= CurrentAttribute
;
330 if (Size
.Y
> ScreenBuffer
->ScreenBufferSize
.Y
)
332 diff
= Size
.X
* (Size
.Y
- ScreenBuffer
->ScreenBufferSize
.Y
);
334 /* Zero-out the new part of the buffer */
335 for (i
= 0; i
< diff
; i
++)
337 ptr
= Buffer
+ Offset
;
338 ptr
->Char
.UnicodeChar
= L
' ';
339 ptr
->Attributes
= ScreenBuffer
->ScreenDefaultAttrib
;
344 (void)InterlockedExchangePointer((PVOID
volatile*)&ScreenBuffer
->Buffer
, Buffer
);
345 ConsoleFreeHeap(OldBuffer
);
346 ScreenBuffer
->ScreenBufferSize
= ScreenBuffer
->OldScreenBufferSize
= Size
;
347 ScreenBuffer
->VirtualY
= 0;
349 /* Ensure cursor and window are within buffer */
350 if (ScreenBuffer
->CursorPosition
.X
>= Size
.X
)
351 ScreenBuffer
->CursorPosition
.X
= Size
.X
- 1;
352 if (ScreenBuffer
->CursorPosition
.Y
>= Size
.Y
)
353 ScreenBuffer
->CursorPosition
.Y
= Size
.Y
- 1;
354 if (ScreenBuffer
->ViewOrigin
.X
> Size
.X
- ScreenBuffer
->ViewSize
.X
)
355 ScreenBuffer
->ViewOrigin
.X
= Size
.X
- ScreenBuffer
->ViewSize
.X
;
356 if (ScreenBuffer
->ViewOrigin
.Y
> Size
.Y
- ScreenBuffer
->ViewSize
.Y
)
357 ScreenBuffer
->ViewOrigin
.Y
= Size
.Y
- ScreenBuffer
->ViewSize
.Y
;
360 * Trigger a buffer resize event
362 if (Console
->InputBuffer
.Mode
& ENABLE_WINDOW_INPUT
)
364 ULONG NumEventsWritten
;
367 er
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
368 er
.Event
.WindowBufferSizeEvent
.dwSize
= ScreenBuffer
->ScreenBufferSize
;
370 // ConioProcessInputEvent(Console, &er);
371 ConDrvWriteConsoleInput(Console
,
372 &Console
->InputBuffer
,
379 return STATUS_SUCCESS
;
383 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console
,
384 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
385 IN USHORT NewScreenAttrib
,
386 IN USHORT NewPopupAttrib
)
392 ULONG NumCodesToWrite
;
393 USHORT OldScreenAttrib
, OldPopupAttrib
;
395 if (Console
== NULL
|| Buffer
== NULL
)
397 return STATUS_INVALID_PARAMETER
;
401 ASSERT(Console
== Buffer
->Header
.Console
);
403 NumCodesToWrite
= Buffer
->ScreenBufferSize
.X
* Buffer
->ScreenBufferSize
.Y
;
404 OldScreenAttrib
= Buffer
->ScreenDefaultAttrib
;
405 OldPopupAttrib
= Buffer
->PopupDefaultAttrib
;
408 Y
= (TopLeft
.Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
409 Length
= NumCodesToWrite
;
413 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
416 * Change the current colors only if they are the old ones.
419 /* Foreground color */
420 if ((Ptr
->Attributes
& 0x0F) == (OldScreenAttrib
& 0x0F))
421 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewScreenAttrib
& 0x0F);
422 if ((Ptr
->Attributes
& 0x0F) == (OldPopupAttrib
& 0x0F))
423 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewPopupAttrib
& 0x0F);
425 /* Background color */
426 if ((Ptr
->Attributes
& 0xF0) == (OldScreenAttrib
& 0xF0))
427 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewScreenAttrib
& 0xF0);
428 if ((Ptr
->Attributes
& 0xF0) == (OldPopupAttrib
& 0xF0))
429 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewPopupAttrib
& 0xF0);
433 if (++X
== Buffer
->ScreenBufferSize
.X
)
437 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
444 /* Save foreground and background colors for both screen and popup */
445 Buffer
->ScreenDefaultAttrib
= (NewScreenAttrib
& 0x00FF);
446 Buffer
->PopupDefaultAttrib
= (NewPopupAttrib
& 0x00FF);
448 /* Refresh the display if needed */
449 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
451 SMALL_RECT UpdateRect
;
452 ConioComputeUpdateRect(Buffer
, &UpdateRect
, &TopLeft
, NumCodesToWrite
);
453 TermDrawRegion(Console
, &UpdateRect
);
456 return STATUS_SUCCESS
;
460 /* PUBLIC DRIVER APIS *********************************************************/
463 ConDrvReadConsoleOutput(IN PCONSOLE Console
,
464 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
466 OUT PCHAR_INFO CharInfo
/*Buffer*/,
467 IN OUT PSMALL_RECT ReadRegion
)
470 SMALL_RECT ScreenBuffer
;
471 PCHAR_INFO CurCharInfo
;
472 SMALL_RECT CapturedReadRegion
;
475 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| ReadRegion
== NULL
)
477 return STATUS_INVALID_PARAMETER
;
481 ASSERT(Console
== Buffer
->Header
.Console
);
483 CapturedReadRegion
= *ReadRegion
;
485 /* Make sure ReadRegion is inside the screen buffer */
486 ConioInitRect(&ScreenBuffer
, 0, 0,
487 Buffer
->ScreenBufferSize
.Y
- 1,
488 Buffer
->ScreenBufferSize
.X
- 1);
489 if (!ConioGetIntersection(&CapturedReadRegion
, &ScreenBuffer
, &CapturedReadRegion
))
492 * It is okay to have a ReadRegion completely outside
493 * the screen buffer. No data is read then.
495 return STATUS_SUCCESS
;
498 CurCharInfo
= CharInfo
;
500 for (Y
= CapturedReadRegion
.Top
; Y
<= CapturedReadRegion
.Bottom
; ++Y
)
502 Ptr
= ConioCoordToPointer(Buffer
, CapturedReadRegion
.Left
, Y
);
503 for (X
= CapturedReadRegion
.Left
; X
<= CapturedReadRegion
.Right
; ++X
)
507 CurCharInfo
->Char
.UnicodeChar
= Ptr
->Char
.UnicodeChar
;
511 // ConsoleOutputUnicodeToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
512 WideCharToMultiByte(Console
->OutputCodePage
, 0, &Ptr
->Char
.UnicodeChar
, 1,
513 &CurCharInfo
->Char
.AsciiChar
, 1, NULL
, NULL
);
515 CurCharInfo
->Attributes
=
516 (Ptr
->Attributes
& ~(COMMON_LVB_LEADING_BYTE
| COMMON_LVB_TRAILING_BYTE
));
522 *ReadRegion
= CapturedReadRegion
;
524 return STATUS_SUCCESS
;
528 ConDrvWriteConsoleOutput(IN PCONSOLE Console
,
529 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
531 IN PCHAR_INFO CharInfo
/*Buffer*/,
532 IN OUT PSMALL_RECT WriteRegion
)
535 SMALL_RECT ScreenBuffer
;
536 PCHAR_INFO CurCharInfo
;
537 SMALL_RECT CapturedWriteRegion
;
540 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
542 return STATUS_INVALID_PARAMETER
;
546 ASSERT(Console
== Buffer
->Header
.Console
);
548 CapturedWriteRegion
= *WriteRegion
;
550 /* Make sure WriteRegion is inside the screen buffer */
551 ConioInitRect(&ScreenBuffer
, 0, 0,
552 Buffer
->ScreenBufferSize
.Y
- 1,
553 Buffer
->ScreenBufferSize
.X
- 1);
554 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
557 * It is okay to have a WriteRegion completely outside
558 * the screen buffer. No data is written then.
560 return STATUS_SUCCESS
;
563 CurCharInfo
= CharInfo
;
565 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
567 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
568 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
572 Ptr
->Char
.UnicodeChar
= CurCharInfo
->Char
.UnicodeChar
;
576 ConsoleOutputAnsiToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
.AsciiChar
);
578 Ptr
->Attributes
= CurCharInfo
->Attributes
;
584 TermDrawRegion(Console
, &CapturedWriteRegion
);
586 *WriteRegion
= CapturedWriteRegion
;
588 return STATUS_SUCCESS
;
592 * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
593 * FIXME: This function MUST be moved into consrv/conoutput.c because only
594 * consrv knows how to manipulate VDM screenbuffers.
597 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console
,
598 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
599 IN PCHAR_CELL CharInfo
/*Buffer*/,
600 IN COORD CharInfoSize
,
601 IN PSMALL_RECT WriteRegion
)
604 SMALL_RECT ScreenBuffer
;
605 PCHAR_CELL CurCharInfo
;
606 SMALL_RECT CapturedWriteRegion
;
609 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
611 return STATUS_INVALID_PARAMETER
;
615 ASSERT(Console
== Buffer
->Header
.Console
);
617 CapturedWriteRegion
= *WriteRegion
;
619 /* Make sure WriteRegion is inside the screen buffer */
620 ConioInitRect(&ScreenBuffer
, 0, 0,
621 Buffer
->ScreenBufferSize
.Y
- 1,
622 Buffer
->ScreenBufferSize
.X
- 1);
623 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
626 * It is okay to have a WriteRegion completely outside
627 * the screen buffer. No data is written then.
629 return STATUS_SUCCESS
;
632 // CurCharInfo = CharInfo;
634 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
636 /**/CurCharInfo
= CharInfo
+ Y
* CharInfoSize
.X
+ CapturedWriteRegion
.Left
;/**/
638 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
639 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
641 ConsoleOutputAnsiToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
);
642 Ptr
->Attributes
= CurCharInfo
->Attributes
;
648 return STATUS_SUCCESS
;
652 ConDrvWriteConsole(IN PCONSOLE Console
,
653 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
655 IN PVOID StringBuffer
,
656 IN ULONG NumCharsToWrite
,
657 OUT PULONG NumCharsWritten OPTIONAL
)
659 NTSTATUS Status
= STATUS_SUCCESS
;
660 PWCHAR Buffer
= NULL
;
664 if (Console
== NULL
|| ScreenBuffer
== NULL
/* || StringBuffer == NULL */)
665 return STATUS_INVALID_PARAMETER
;
667 /* Validity checks */
668 ASSERT(Console
== ScreenBuffer
->Header
.Console
);
669 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCharsToWrite
== 0));
671 /* Stop here if the console is paused */
672 if (Console
->UnpauseEvent
!= NULL
) return STATUS_PENDING
;
674 /* Convert the string to UNICODE */
677 Buffer
= StringBuffer
;
681 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
685 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
688 MultiByteToWideChar(Console
->OutputCodePage
, 0,
691 (PWCHAR
)Buffer
, Length
);
695 Status
= STATUS_NO_MEMORY
;
702 if (NT_SUCCESS(Status
))
704 Status
= TermWriteStream(Console
,
709 if (NT_SUCCESS(Status
))
711 Written
= NumCharsToWrite
;
715 if (!Unicode
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
718 if (NumCharsWritten
) *NumCharsWritten
= Written
;
724 IntReadConsoleOutputStringAscii(IN PCONSOLE Console
,
725 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
726 OUT PVOID StringBuffer
,
727 IN ULONG NumCodesToRead
,
729 OUT PULONG NumCodesRead OPTIONAL
)
731 ULONG CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
732 LPBYTE ReadBuffer
= StringBuffer
;
733 SHORT Xpos
= ReadCoord
->X
;
734 SHORT Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
737 BOOL bCJK
= Console
->IsCJK
;
739 for (i
= 0; i
< NumCodesToRead
; ++i
)
741 Ptr
= ConioCoordToPointer(Buffer
, Xpos
, Ypos
);
743 ConsoleOutputUnicodeToAnsiChar(Console
, (PCHAR
)ReadBuffer
, &Ptr
->Char
.UnicodeChar
);
744 ReadBuffer
+= CodeSize
;
747 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
751 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
757 /* For Chinese, Japanese and Korean */
758 if (bCJK
&& (Ptr
->Attributes
& COMMON_LVB_LEADING_BYTE
))
761 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
765 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
777 return STATUS_SUCCESS
;
781 IntReadConsoleOutputStringUnicode(IN PCONSOLE Console
,
782 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
783 OUT PVOID StringBuffer
,
784 IN ULONG NumCodesToRead
,
786 OUT PULONG NumCodesRead OPTIONAL
)
788 ULONG CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
789 LPBYTE ReadBuffer
= StringBuffer
;
790 SHORT Xpos
= ReadCoord
->X
;
791 SHORT Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
792 ULONG i
, nNumChars
= 0;
794 BOOL bCJK
= Console
->IsCJK
;
796 for (i
= 0; i
< NumCodesToRead
; ++i
, ++nNumChars
)
798 Ptr
= ConioCoordToPointer(Buffer
, Xpos
, Ypos
);
800 *(PWCHAR
)ReadBuffer
= Ptr
->Char
.UnicodeChar
;
801 ReadBuffer
+= CodeSize
;
804 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
808 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
814 /* For Chinese, Japanese and Korean */
815 if (bCJK
&& (Ptr
->Attributes
& COMMON_LVB_LEADING_BYTE
))
818 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
822 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
832 *NumCodesRead
= nNumChars
;
834 return STATUS_SUCCESS
;
838 IntReadConsoleOutputStringAttributes(IN PCONSOLE Console
,
839 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
840 OUT PVOID StringBuffer
,
841 IN ULONG NumCodesToRead
,
843 OUT PULONG NumCodesRead OPTIONAL
)
845 ULONG CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
846 LPBYTE ReadBuffer
= StringBuffer
;
847 SHORT Xpos
= ReadCoord
->X
;
848 SHORT Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
852 for (i
= 0; i
< NumCodesToRead
; ++i
)
854 Ptr
= ConioCoordToPointer(Buffer
, Xpos
, Ypos
);
856 *(PWORD
)ReadBuffer
= Ptr
->Attributes
;
857 ReadBuffer
+= CodeSize
;
860 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
864 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
871 if (Xpos
> 0 && Console
->IsCJK
)
873 ReadBuffer
-= CodeSize
;
874 *(PWORD
)ReadBuffer
&= ~COMMON_LVB_LEADING_BYTE
;
878 *NumCodesRead
= NumCodesToRead
;
880 return STATUS_SUCCESS
;
884 ConDrvReadConsoleOutputString(IN PCONSOLE Console
,
885 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
886 IN CODE_TYPE CodeType
,
887 OUT PVOID StringBuffer
,
888 IN ULONG NumCodesToRead
,
890 OUT PULONG NumCodesRead OPTIONAL
)
892 if (Console
== NULL
|| Buffer
== NULL
|| ReadCoord
== NULL
/* || EndCoord == NULL */)
894 return STATUS_INVALID_PARAMETER
;
897 /* Validity checks */
898 ASSERT(Console
== Buffer
->Header
.Console
);
899 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToRead
== 0));
907 return IntReadConsoleOutputStringAscii(Console
,
915 return IntReadConsoleOutputStringUnicode(Console
,
923 return IntReadConsoleOutputStringAttributes(Console
,
931 return STATUS_INVALID_PARAMETER
;
936 ConDrvWriteConsoleOutputString(IN PCONSOLE Console
,
937 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
938 IN CODE_TYPE CodeType
,
939 IN PVOID StringBuffer
,
940 IN ULONG NumCodesToWrite
,
941 IN PCOORD WriteCoord
,
942 // OUT PCOORD EndCoord,
943 OUT PULONG NumCodesWritten OPTIONAL
)
945 NTSTATUS Status
= STATUS_SUCCESS
;
946 PVOID WriteBuffer
= NULL
;
947 PWCHAR tmpString
= NULL
;
948 ULONG X
, Y
, Length
; // , Written = 0;
952 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
/* || EndCoord == NULL */)
954 return STATUS_INVALID_PARAMETER
;
957 /* Validity checks */
958 ASSERT(Console
== Buffer
->Header
.Console
);
959 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToWrite
== 0));
962 // FIXME: Make overflow checks on WriteCoord !!!!!!
965 if (NumCodesWritten
) *NumCodesWritten
= 0;
970 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
974 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
978 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
982 return STATUS_INVALID_PARAMETER
;
985 if (CodeType
== CODE_ASCII
)
987 /* Convert the ASCII string into Unicode before writing it to the console */
988 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
992 tmpString
= WriteBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
995 MultiByteToWideChar(Console
->OutputCodePage
, 0,
998 (PWCHAR
)WriteBuffer
, Length
);
1002 Status
= STATUS_NO_MEMORY
;
1005 // FIXME: Quick fix: fix the CodeType and CodeSize since the
1006 // ASCII string was converted into UNICODE.
1007 // A proper fix needs to be written.
1008 CodeType
= CODE_UNICODE
;
1009 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
1013 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
1014 WriteBuffer
= StringBuffer
;
1017 if (WriteBuffer
== NULL
|| !NT_SUCCESS(Status
)) goto Cleanup
;
1020 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1021 Length
= NumCodesToWrite
;
1025 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
1031 Ptr
->Char
.UnicodeChar
= *(PWCHAR
)WriteBuffer
;
1034 case CODE_ATTRIBUTE
:
1035 Ptr
->Attributes
= *(PWORD
)WriteBuffer
;
1038 WriteBuffer
= (PVOID
)((ULONG_PTR
)WriteBuffer
+ CodeSize
);
1042 if (++X
== Buffer
->ScreenBufferSize
.X
)
1046 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
1053 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1055 SMALL_RECT UpdateRect
;
1056 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1057 TermDrawRegion(Console
, &UpdateRect
);
1061 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1064 if (tmpString
) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString
);
1066 if (NumCodesWritten
) *NumCodesWritten
= NumCodesToWrite
; // Written;
1071 ConDrvFillConsoleOutput(IN PCONSOLE Console
,
1072 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1073 IN CODE_TYPE CodeType
,
1074 IN CODE_ELEMENT Code
,
1075 IN ULONG NumCodesToWrite
,
1076 IN PCOORD WriteCoord
,
1077 OUT PULONG NumCodesWritten OPTIONAL
)
1081 BOOL bLead
, bFullwidth
;
1083 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
)
1085 return STATUS_INVALID_PARAMETER
;
1088 /* Validity check */
1089 ASSERT(Console
== Buffer
->Header
.Console
);
1092 // FIXME: Make overflow checks on WriteCoord !!!!!!
1095 if (NumCodesWritten
) *NumCodesWritten
= 0;
1097 if (CodeType
== CODE_ASCII
)
1099 /* Conversion from the ASCII char to the UNICODE char */
1101 ConsoleOutputAnsiToUnicodeChar(Console
, &tmp
.UnicodeChar
, &Code
.AsciiChar
);
1106 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1107 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1108 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1110 /* For Chinese, Japanese and Korean */
1115 bFullwidth
= (mk_wcwidth_cjk(Code
.UnicodeChar
) == 2);
1118 Ptr
= ConioCoordToPointer(Buffer
, X
- 1, Y
);
1119 if (Ptr
->Attributes
& COMMON_LVB_LEADING_BYTE
)
1121 Ptr
->Char
.UnicodeChar
= L
' ';
1122 Ptr
->Attributes
&= ~COMMON_LVB_LEADING_BYTE
;
1127 for (i
= 0; i
< NumCodesToWrite
; ++i
)
1129 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
1135 Ptr
->Char
.UnicodeChar
= Code
.UnicodeChar
;
1136 Ptr
->Attributes
&= ~(COMMON_LVB_LEADING_BYTE
| COMMON_LVB_TRAILING_BYTE
);
1140 Ptr
->Attributes
|= COMMON_LVB_LEADING_BYTE
;
1142 Ptr
->Attributes
|= COMMON_LVB_TRAILING_BYTE
;
1146 case CODE_ATTRIBUTE
:
1147 Ptr
->Attributes
&= ~0xFF;
1148 Ptr
->Attributes
|= (Code
.Attribute
& 0xFF);
1154 if (++X
== Buffer
->ScreenBufferSize
.X
)
1158 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
1167 if ((NumCodesToWrite
& 1) & bFullwidth
)
1169 if (X
+ Y
* Buffer
->ScreenBufferSize
.X
> 0)
1171 Ptr
= ConioCoordToPointer(Buffer
, X
- 1, Y
);
1172 Ptr
->Char
.UnicodeChar
= L
' ';
1173 Ptr
->Attributes
&= ~(COMMON_LVB_LEADING_BYTE
| COMMON_LVB_TRAILING_BYTE
);
1177 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1179 SMALL_RECT UpdateRect
;
1180 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1181 TermDrawRegion(Console
, &UpdateRect
);
1184 if (NumCodesWritten
) *NumCodesWritten
= NumCodesToWrite
; // Written;
1185 return STATUS_SUCCESS
;
1189 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console
,
1190 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1191 OUT PCOORD ScreenBufferSize
,
1192 OUT PCOORD CursorPosition
,
1193 OUT PCOORD ViewOrigin
,
1194 OUT PCOORD ViewSize
,
1195 OUT PCOORD MaximumViewSize
,
1196 OUT PWORD Attributes
)
1198 COORD LargestWindowSize
;
1200 if (Console
== NULL
|| Buffer
== NULL
|| ScreenBufferSize
== NULL
||
1201 CursorPosition
== NULL
|| ViewOrigin
== NULL
|| ViewSize
== NULL
||
1202 MaximumViewSize
== NULL
|| Attributes
== NULL
)
1204 return STATUS_INVALID_PARAMETER
;
1207 /* Validity check */
1208 ASSERT(Console
== Buffer
->Header
.Console
);
1210 *ScreenBufferSize
= Buffer
->ScreenBufferSize
;
1211 *CursorPosition
= Buffer
->CursorPosition
;
1212 *ViewOrigin
= Buffer
->ViewOrigin
;
1213 *ViewSize
= Buffer
->ViewSize
;
1214 *Attributes
= Buffer
->ScreenDefaultAttrib
;
1217 * Retrieve the largest possible console window size, taking
1218 * into account the size of the console screen buffer.
1220 TermGetLargestConsoleWindowSize(Console
, &LargestWindowSize
);
1221 LargestWindowSize
.X
= min(LargestWindowSize
.X
, Buffer
->ScreenBufferSize
.X
);
1222 LargestWindowSize
.Y
= min(LargestWindowSize
.Y
, Buffer
->ScreenBufferSize
.Y
);
1223 *MaximumViewSize
= LargestWindowSize
;
1225 return STATUS_SUCCESS
;
1229 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console
,
1230 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1233 if (Console
== NULL
|| Buffer
== NULL
)
1234 return STATUS_INVALID_PARAMETER
;
1236 /* Validity check */
1237 ASSERT(Console
== Buffer
->Header
.Console
);
1239 Buffer
->ScreenDefaultAttrib
= Attributes
;
1240 return STATUS_SUCCESS
;
1244 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console
,
1245 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1250 if (Console
== NULL
|| Buffer
== NULL
|| Size
== NULL
)
1251 return STATUS_INVALID_PARAMETER
;
1253 /* Validity check */
1254 ASSERT(Console
== Buffer
->Header
.Console
);
1256 Status
= ConioResizeBuffer(Console
, Buffer
, *Size
);
1257 if (NT_SUCCESS(Status
)) TermResizeTerminal(Console
);
1263 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console
,
1264 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1266 IN PSMALL_RECT ScrollRectangle
,
1267 IN BOOLEAN UseClipRectangle
,
1268 IN PSMALL_RECT ClipRectangle OPTIONAL
,
1269 IN PCOORD DestinationOrigin
,
1270 IN CHAR_INFO FillChar
)
1272 COORD CapturedDestinationOrigin
;
1273 SMALL_RECT ScreenBuffer
;
1274 SMALL_RECT SrcRegion
;
1275 SMALL_RECT DstRegion
;
1276 SMALL_RECT UpdateRegion
;
1277 SMALL_RECT CapturedClipRectangle
;
1279 if (Console
== NULL
|| Buffer
== NULL
|| ScrollRectangle
== NULL
||
1280 (UseClipRectangle
? ClipRectangle
== NULL
: FALSE
) || DestinationOrigin
== NULL
)
1282 return STATUS_INVALID_PARAMETER
;
1285 /* Validity check */
1286 ASSERT(Console
== Buffer
->Header
.Console
);
1288 CapturedDestinationOrigin
= *DestinationOrigin
;
1290 /* Make sure the source rectangle is inside the screen buffer */
1291 ConioInitRect(&ScreenBuffer
, 0, 0,
1292 Buffer
->ScreenBufferSize
.Y
- 1,
1293 Buffer
->ScreenBufferSize
.X
- 1);
1294 if (!ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, ScrollRectangle
))
1296 return STATUS_SUCCESS
;
1299 /* If the source was clipped on the left or top, adjust the destination accordingly */
1300 if (ScrollRectangle
->Left
< 0)
1302 CapturedDestinationOrigin
.X
-= ScrollRectangle
->Left
;
1304 if (ScrollRectangle
->Top
< 0)
1306 CapturedDestinationOrigin
.Y
-= ScrollRectangle
->Top
;
1309 if (UseClipRectangle
)
1311 CapturedClipRectangle
= *ClipRectangle
;
1312 if (!ConioGetIntersection(&CapturedClipRectangle
, &CapturedClipRectangle
, &ScreenBuffer
))
1314 return STATUS_SUCCESS
;
1319 CapturedClipRectangle
= ScreenBuffer
;
1322 ConioInitRect(&DstRegion
,
1323 CapturedDestinationOrigin
.Y
,
1324 CapturedDestinationOrigin
.X
,
1325 CapturedDestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
1326 CapturedDestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
1331 ConsoleOutputAnsiToUnicodeChar(Console
, &tmp
, &FillChar
.Char
.AsciiChar
);
1332 FillChar
.Char
.UnicodeChar
= tmp
;
1335 ConioMoveRegion(Buffer
, &SrcRegion
, &DstRegion
, &CapturedClipRectangle
, FillChar
);
1337 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1339 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
1340 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &CapturedClipRectangle
))
1342 /* Draw update region */
1343 TermDrawRegion(Console
, &UpdateRegion
);
1347 return STATUS_SUCCESS
;
1351 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console
,
1352 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1353 IN BOOLEAN Absolute
,
1354 IN PSMALL_RECT WindowRect
)
1356 SMALL_RECT CapturedWindowRect
;
1357 COORD LargestWindowSize
;
1359 if (Console
== NULL
|| Buffer
== NULL
|| WindowRect
== NULL
)
1360 return STATUS_INVALID_PARAMETER
;
1362 /* Validity check */
1363 ASSERT(Console
== Buffer
->Header
.Console
);
1365 CapturedWindowRect
= *WindowRect
;
1369 /* Relative positions are given, transform them to absolute ones */
1370 CapturedWindowRect
.Left
+= Buffer
->ViewOrigin
.X
;
1371 CapturedWindowRect
.Top
+= Buffer
->ViewOrigin
.Y
;
1372 CapturedWindowRect
.Right
+= Buffer
->ViewOrigin
.X
+ Buffer
->ViewSize
.X
- 1;
1373 CapturedWindowRect
.Bottom
+= Buffer
->ViewOrigin
.Y
+ Buffer
->ViewSize
.Y
- 1;
1377 * The MSDN documentation on SetConsoleWindowInfo is partially wrong about
1378 * the performed checks this API performs. While it is correct that the
1379 * 'Right'/'Bottom' members cannot be strictly smaller than the 'Left'/'Top'
1380 * members, they can be equal.
1381 * Also, if the 'Left' or 'Top' members are negative, this is automatically
1382 * corrected for, and the window rectangle coordinates are shifted accordingly.
1384 if ((CapturedWindowRect
.Right
< CapturedWindowRect
.Left
) ||
1385 (CapturedWindowRect
.Bottom
< CapturedWindowRect
.Top
))
1387 return STATUS_INVALID_PARAMETER
;
1391 * Forbid window sizes larger than the largest allowed console window size,
1392 * taking into account the size of the console screen buffer.
1394 TermGetLargestConsoleWindowSize(Console
, &LargestWindowSize
);
1395 LargestWindowSize
.X
= min(LargestWindowSize
.X
, Buffer
->ScreenBufferSize
.X
);
1396 LargestWindowSize
.Y
= min(LargestWindowSize
.Y
, Buffer
->ScreenBufferSize
.Y
);
1397 if ((CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1 > LargestWindowSize
.X
) ||
1398 (CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1 > LargestWindowSize
.Y
))
1400 return STATUS_INVALID_PARAMETER
;
1403 /* Shift the window rectangle coordinates if 'Left' or 'Top' are negative */
1404 if (CapturedWindowRect
.Left
< 0)
1406 CapturedWindowRect
.Right
-= CapturedWindowRect
.Left
;
1407 CapturedWindowRect
.Left
= 0;
1409 if (CapturedWindowRect
.Top
< 0)
1411 CapturedWindowRect
.Bottom
-= CapturedWindowRect
.Top
;
1412 CapturedWindowRect
.Top
= 0;
1415 /* Clip the window rectangle to the screen buffer */
1416 CapturedWindowRect
.Right
= min(CapturedWindowRect
.Right
, Buffer
->ScreenBufferSize
.X
);
1417 CapturedWindowRect
.Bottom
= min(CapturedWindowRect
.Bottom
, Buffer
->ScreenBufferSize
.Y
);
1419 Buffer
->ViewOrigin
.X
= CapturedWindowRect
.Left
;
1420 Buffer
->ViewOrigin
.Y
= CapturedWindowRect
.Top
;
1422 Buffer
->ViewSize
.X
= CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1;
1423 Buffer
->ViewSize
.Y
= CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1;
1425 TermResizeTerminal(Console
);
1427 return STATUS_SUCCESS
;