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 #define COMMON_LEAD_TRAIL (COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE)
19 /* GLOBALS ********************************************************************/
23 * "The lpMultiByteStr and lpWideCharStr pointers must not be the same.
24 * If they are the same, the function fails, and GetLastError returns
25 * ERROR_INVALID_PARAMETER."
27 #define ConsoleOutputUnicodeToAnsiChar(Console, dChar, sWChar) \
29 ASSERT((ULONG_PTR)(dChar) != (ULONG_PTR)(sWChar)); \
30 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL); \
33 #define ConsoleOutputAnsiToUnicodeChar(Console, dWChar, sChar) \
35 ASSERT((ULONG_PTR)(dWChar) != (ULONG_PTR)(sChar)); \
36 MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1); \
39 /* PRIVATE FUNCTIONS **********************************************************/
41 CONSOLE_IO_OBJECT_TYPE
42 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This
)
44 // return This->Header.Type;
45 return TEXTMODE_BUFFER
;
48 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl
=
50 TEXTMODE_BUFFER_GetType
,
55 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
);
59 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
61 IN PCONSOLE_SCREEN_BUFFER_VTBL Vtbl
,
64 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
);
68 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
70 IN HANDLE ProcessHandle
,
71 IN PTEXTMODE_BUFFER_INFO TextModeInfo
)
73 NTSTATUS Status
= STATUS_SUCCESS
;
74 PTEXTMODE_SCREEN_BUFFER NewBuffer
= NULL
;
76 UNREFERENCED_PARAMETER(ProcessHandle
);
78 if (Console
== NULL
|| Buffer
== NULL
|| TextModeInfo
== NULL
)
79 return STATUS_INVALID_PARAMETER
;
83 Status
= CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER
*)&NewBuffer
,
86 sizeof(TEXTMODE_SCREEN_BUFFER
));
87 if (!NT_SUCCESS(Status
)) return Status
;
88 NewBuffer
->Header
.Type
= TEXTMODE_BUFFER
;
90 NewBuffer
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
91 TextModeInfo
->ScreenBufferSize
.X
*
92 TextModeInfo
->ScreenBufferSize
.Y
*
94 if (NewBuffer
->Buffer
== NULL
)
96 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
97 return STATUS_INSUFFICIENT_RESOURCES
;
100 NewBuffer
->ScreenBufferSize
= NewBuffer
->OldScreenBufferSize
101 = TextModeInfo
->ScreenBufferSize
;
102 NewBuffer
->ViewSize
= NewBuffer
->OldViewSize
103 = Console
->ConsoleSize
;
105 NewBuffer
->ViewOrigin
.X
= NewBuffer
->ViewOrigin
.Y
= 0;
106 NewBuffer
->VirtualY
= 0;
108 NewBuffer
->CursorBlinkOn
= NewBuffer
->ForceCursorOff
= FALSE
;
109 NewBuffer
->CursorInfo
.bVisible
= (TextModeInfo
->IsCursorVisible
&& (TextModeInfo
->CursorSize
!= 0));
110 NewBuffer
->CursorInfo
.dwSize
= min(max(TextModeInfo
->CursorSize
, 0), 100);
112 NewBuffer
->ScreenDefaultAttrib
= TextModeInfo
->ScreenAttrib
;
113 NewBuffer
->PopupDefaultAttrib
= TextModeInfo
->PopupAttrib
;
115 /* Initialize buffer to be empty with default attributes */
116 for (NewBuffer
->CursorPosition
.Y
= 0 ; NewBuffer
->CursorPosition
.Y
< NewBuffer
->ScreenBufferSize
.Y
; NewBuffer
->CursorPosition
.Y
++)
118 ClearLineBuffer(NewBuffer
);
120 NewBuffer
->CursorPosition
.X
= NewBuffer
->CursorPosition
.Y
= 0;
122 NewBuffer
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
124 *Buffer
= (PCONSOLE_SCREEN_BUFFER
)NewBuffer
;
125 return STATUS_SUCCESS
;
129 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
)
131 PTEXTMODE_SCREEN_BUFFER Buff
= (PTEXTMODE_SCREEN_BUFFER
)Buffer
;
134 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
135 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
137 Buffer
->Header
.Type
= SCREEN_BUFFER
;
139 ConsoleFreeHeap(Buff
->Buffer
);
141 CONSOLE_SCREEN_BUFFER_Destroy(Buffer
);
146 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff
, ULONG X
, ULONG Y
)
148 return &Buff
->Buffer
[((Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
) * Buff
->ScreenBufferSize
.X
+ X
];
152 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
)
154 PCHAR_INFO Ptr
= ConioCoordToPointer(Buff
, 0, Buff
->CursorPosition
.Y
);
157 for (Pos
= 0; Pos
< Buff
->ScreenBufferSize
.X
; Pos
++, Ptr
++)
160 Ptr
->Char
.UnicodeChar
= L
' ';
161 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
166 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff
,
167 IN OUT PSMALL_RECT UpdateRect
,
171 if ((UINT
)Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
173 UpdateRect
->Left
= 0;
174 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
178 UpdateRect
->Left
= Start
->X
;
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
;
419 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
422 * Change the current colors only if they are the old ones.
425 /* Foreground color */
426 if ((Ptr
->Attributes
& 0x0F) == (OldScreenAttrib
& 0x0F))
427 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewScreenAttrib
& 0x0F);
428 if ((Ptr
->Attributes
& 0x0F) == (OldPopupAttrib
& 0x0F))
429 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewPopupAttrib
& 0x0F);
431 /* Background color */
432 if ((Ptr
->Attributes
& 0xF0) == (OldScreenAttrib
& 0xF0))
433 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewScreenAttrib
& 0xF0);
434 if ((Ptr
->Attributes
& 0xF0) == (OldPopupAttrib
& 0xF0))
435 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewPopupAttrib
& 0xF0);
439 if (++X
== Buffer
->ScreenBufferSize
.X
)
443 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
450 /* Save foreground and background colors for both screen and popup */
451 Buffer
->ScreenDefaultAttrib
= (NewScreenAttrib
& 0x00FF);
452 Buffer
->PopupDefaultAttrib
= (NewPopupAttrib
& 0x00FF);
454 /* Refresh the display if needed */
455 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
457 SMALL_RECT UpdateRect
;
458 ConioComputeUpdateRect(Buffer
, &UpdateRect
, &TopLeft
, NumCodesToWrite
);
459 TermDrawRegion(Console
, &UpdateRect
);
462 return STATUS_SUCCESS
;
466 /* PUBLIC DRIVER APIS *********************************************************/
469 ConDrvReadConsoleOutput(IN PCONSOLE Console
,
470 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
472 OUT PCHAR_INFO CharInfo
/*Buffer*/,
473 IN OUT PSMALL_RECT ReadRegion
)
476 SMALL_RECT ScreenBuffer
;
477 PCHAR_INFO CurCharInfo
;
478 SMALL_RECT CapturedReadRegion
;
481 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| ReadRegion
== NULL
)
483 return STATUS_INVALID_PARAMETER
;
487 ASSERT(Console
== Buffer
->Header
.Console
);
489 CapturedReadRegion
= *ReadRegion
;
491 /* Make sure ReadRegion is inside the screen buffer */
492 ConioInitRect(&ScreenBuffer
, 0, 0,
493 Buffer
->ScreenBufferSize
.Y
- 1,
494 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
& ~COMMON_LEAD_TRAIL
);
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,
558 Buffer
->ScreenBufferSize
.X
- 1);
559 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
562 * It is okay to have a WriteRegion completely outside
563 * the screen buffer. No data is written then.
565 return STATUS_SUCCESS
;
568 CurCharInfo
= CharInfo
;
570 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
572 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
573 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
577 Ptr
->Char
.UnicodeChar
= CurCharInfo
->Char
.UnicodeChar
;
581 ConsoleOutputAnsiToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
.AsciiChar
);
583 Ptr
->Attributes
= CurCharInfo
->Attributes
;
589 TermDrawRegion(Console
, &CapturedWriteRegion
);
591 *WriteRegion
= CapturedWriteRegion
;
593 return STATUS_SUCCESS
;
597 * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
598 * FIXME: This function MUST be moved into consrv/conoutput.c because only
599 * consrv knows how to manipulate VDM screenbuffers.
602 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console
,
603 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
604 IN PCHAR_CELL CharInfo
/*Buffer*/,
605 IN COORD CharInfoSize
,
606 IN PSMALL_RECT WriteRegion
)
609 SMALL_RECT ScreenBuffer
;
610 PCHAR_CELL CurCharInfo
;
611 SMALL_RECT CapturedWriteRegion
;
614 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
616 return STATUS_INVALID_PARAMETER
;
620 ASSERT(Console
== Buffer
->Header
.Console
);
622 CapturedWriteRegion
= *WriteRegion
;
624 /* Make sure WriteRegion is inside the screen buffer */
625 ConioInitRect(&ScreenBuffer
, 0, 0,
626 Buffer
->ScreenBufferSize
.Y
- 1,
627 Buffer
->ScreenBufferSize
.X
- 1);
628 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
631 * It is okay to have a WriteRegion completely outside
632 * the screen buffer. No data is written then.
634 return STATUS_SUCCESS
;
637 // CurCharInfo = CharInfo;
639 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
641 /**/CurCharInfo
= CharInfo
+ Y
* CharInfoSize
.X
+ CapturedWriteRegion
.Left
;/**/
643 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
644 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
646 ConsoleOutputAnsiToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
);
647 Ptr
->Attributes
= CurCharInfo
->Attributes
;
653 return STATUS_SUCCESS
;
657 ConDrvWriteConsole(IN PCONSOLE Console
,
658 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
660 IN PVOID StringBuffer
,
661 IN ULONG NumCharsToWrite
,
662 OUT PULONG NumCharsWritten OPTIONAL
)
664 NTSTATUS Status
= STATUS_SUCCESS
;
665 PWCHAR Buffer
= NULL
;
669 if (Console
== NULL
|| ScreenBuffer
== NULL
/* || StringBuffer == NULL */)
670 return STATUS_INVALID_PARAMETER
;
672 /* Validity checks */
673 ASSERT(Console
== ScreenBuffer
->Header
.Console
);
674 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCharsToWrite
== 0));
676 /* Stop here if the console is paused */
677 if (Console
->UnpauseEvent
!= NULL
) return STATUS_PENDING
;
679 /* Convert the string to UNICODE */
682 Buffer
= StringBuffer
;
686 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
690 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
693 MultiByteToWideChar(Console
->OutputCodePage
, 0,
696 (PWCHAR
)Buffer
, Length
);
700 Status
= STATUS_NO_MEMORY
;
707 if (NT_SUCCESS(Status
))
709 Status
= TermWriteStream(Console
,
714 if (NT_SUCCESS(Status
))
716 Written
= NumCharsToWrite
;
720 if (!Unicode
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
723 if (NumCharsWritten
) *NumCharsWritten
= Written
;
729 IntReadConsoleOutputStringAscii(IN PCONSOLE Console
,
730 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
731 OUT PVOID StringBuffer
,
732 IN ULONG NumCodesToRead
,
734 OUT PULONG NumCodesRead OPTIONAL
)
736 ULONG CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
737 LPBYTE ReadBuffer
= StringBuffer
;
738 SHORT Xpos
= ReadCoord
->X
;
739 SHORT Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
742 BOOLEAN bCJK
= Console
->IsCJK
;
744 for (i
= 0; i
< NumCodesToRead
; ++i
)
746 Ptr
= ConioCoordToPointer(Buffer
, Xpos
, Ypos
);
748 ConsoleOutputUnicodeToAnsiChar(Console
, (PCHAR
)ReadBuffer
, &Ptr
->Char
.UnicodeChar
);
749 ReadBuffer
+= CodeSize
;
752 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
756 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
762 /* For Chinese, Japanese and Korean */
763 if (bCJK
&& (Ptr
->Attributes
& COMMON_LVB_LEADING_BYTE
))
766 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
770 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
782 return STATUS_SUCCESS
;
786 IntReadConsoleOutputStringUnicode(IN PCONSOLE Console
,
787 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
788 OUT PVOID StringBuffer
,
789 IN ULONG NumCodesToRead
,
791 OUT PULONG NumCodesRead OPTIONAL
)
793 ULONG CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
794 LPBYTE ReadBuffer
= StringBuffer
;
795 SHORT Xpos
= ReadCoord
->X
;
796 SHORT Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
797 ULONG i
, nNumChars
= 0;
799 BOOLEAN bCJK
= Console
->IsCJK
;
801 for (i
= 0; i
< NumCodesToRead
; ++i
, ++nNumChars
)
803 Ptr
= ConioCoordToPointer(Buffer
, Xpos
, Ypos
);
805 *(PWCHAR
)ReadBuffer
= Ptr
->Char
.UnicodeChar
;
806 ReadBuffer
+= CodeSize
;
809 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
813 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
819 /* For Chinese, Japanese and Korean */
820 if (bCJK
&& (Ptr
->Attributes
& COMMON_LVB_LEADING_BYTE
))
823 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
827 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
837 *NumCodesRead
= nNumChars
;
839 return STATUS_SUCCESS
;
843 IntReadConsoleOutputStringAttributes(IN PCONSOLE Console
,
844 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
845 OUT PVOID StringBuffer
,
846 IN ULONG NumCodesToRead
,
848 OUT PULONG NumCodesRead OPTIONAL
)
850 ULONG CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
851 LPBYTE ReadBuffer
= StringBuffer
;
852 SHORT Xpos
= ReadCoord
->X
;
853 SHORT Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
857 for (i
= 0; i
< NumCodesToRead
; ++i
)
859 Ptr
= ConioCoordToPointer(Buffer
, Xpos
, Ypos
);
861 *(PWORD
)ReadBuffer
= Ptr
->Attributes
;
862 ReadBuffer
+= CodeSize
;
865 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
869 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
876 if (Xpos
> 0 && Console
->IsCJK
)
878 ReadBuffer
-= CodeSize
;
879 *(PWORD
)ReadBuffer
&= ~COMMON_LVB_LEADING_BYTE
;
883 *NumCodesRead
= NumCodesToRead
;
885 return STATUS_SUCCESS
;
889 ConDrvReadConsoleOutputString(IN PCONSOLE Console
,
890 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
891 IN CODE_TYPE CodeType
,
892 OUT PVOID StringBuffer
,
893 IN ULONG NumCodesToRead
,
895 OUT PULONG NumCodesRead OPTIONAL
)
897 if (Console
== NULL
|| Buffer
== NULL
|| ReadCoord
== NULL
/* || EndCoord == NULL */)
899 return STATUS_INVALID_PARAMETER
;
902 /* Validity checks */
903 ASSERT(Console
== Buffer
->Header
.Console
);
904 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToRead
== 0));
912 return IntReadConsoleOutputStringAscii(Console
,
920 return IntReadConsoleOutputStringUnicode(Console
,
928 return IntReadConsoleOutputStringAttributes(Console
,
936 return STATUS_INVALID_PARAMETER
;
941 IntWriteConsoleOutputStringUnicode(
943 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
944 IN PVOID StringBuffer
,
945 IN ULONG NumCodesToWrite
,
946 IN PCOORD WriteCoord
,
947 OUT PULONG NumCodesWritten OPTIONAL
)
949 NTSTATUS Status
= STATUS_SUCCESS
;
950 PWCHAR WriteBuffer
= StringBuffer
;
951 ULONG i
, X
, Y
, Length
;
953 BOOLEAN bCJK
= Console
->IsCJK
;
959 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
960 Length
= NumCodesToWrite
;
962 for (i
= 0; i
< Length
; ++i
)
964 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
966 Ptr
->Char
.UnicodeChar
= *WriteBuffer
;
970 if (X
== Buffer
->ScreenBufferSize
.X
)
974 if (Y
== Buffer
->ScreenBufferSize
.Y
)
980 /* For Chinese, Japanese and Korean */
981 if (bCJK
&& Ptr
->Char
.UnicodeChar
>= 0x80 &&
982 mk_wcwidth_cjk(Ptr
->Char
.UnicodeChar
) == 2)
984 /* A full-width character cannot cross a line boundary */
985 if (X
== Buffer
->ScreenBufferSize
.X
- 1)
987 /* go to next line */
990 if (Y
== Buffer
->ScreenBufferSize
.Y
)
994 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
997 /* the leading byte */
998 Ptr
->Attributes
= Buffer
->ScreenDefaultAttrib
;
999 Ptr
->Attributes
|= COMMON_LVB_LEADING_BYTE
;
1002 /* the trailing byte */
1003 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
1004 Ptr
->Attributes
= Buffer
->ScreenDefaultAttrib
;
1005 Ptr
->Attributes
|= COMMON_LVB_TRAILING_BYTE
;
1008 if (X
== Buffer
->ScreenBufferSize
.X
)
1012 if (Y
== Buffer
->ScreenBufferSize
.Y
)
1021 if (NumCodesWritten
)
1022 *NumCodesWritten
= NumCodesToWrite
;
1027 IntWriteConsoleOutputStringAscii(
1028 IN PCONSOLE Console
,
1029 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1030 IN PVOID StringBuffer
,
1031 IN ULONG NumCodesToWrite
,
1032 IN PCOORD WriteCoord
,
1033 OUT PULONG NumCodesWritten OPTIONAL
)
1041 if (NumCodesWritten
)
1042 *NumCodesWritten
= NumCodesToWrite
;
1044 return STATUS_SUCCESS
;
1047 /* Convert the ASCII string into Unicode before writing it to the console */
1048 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
1052 tmpString
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
1054 return STATUS_NO_MEMORY
;
1056 MultiByteToWideChar(Console
->OutputCodePage
, 0,
1061 Status
= IntWriteConsoleOutputStringUnicode(Console
,
1067 ConsoleFreeHeap(tmpString
);
1072 IntWriteConsoleOutputStringAttribute(
1073 IN PCONSOLE Console
,
1074 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1075 IN PVOID StringBuffer
,
1076 IN ULONG NumCodesToWrite
,
1077 IN PCOORD WriteCoord
,
1078 OUT PULONG NumCodesWritten OPTIONAL
)
1080 NTSTATUS Status
= STATUS_SUCCESS
;
1081 PWORD WriteBuffer
= StringBuffer
;
1082 ULONG i
, X
, Y
, Length
;
1089 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1090 Length
= NumCodesToWrite
;
1092 for (i
= 0; i
< Length
; ++i
)
1094 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
1096 Ptr
->Attributes
= (*WriteBuffer
& ~COMMON_LEAD_TRAIL
);
1100 if (X
== Buffer
->ScreenBufferSize
.X
)
1104 if (Y
== Buffer
->ScreenBufferSize
.Y
)
1112 if (NumCodesWritten
)
1113 *NumCodesWritten
= NumCodesToWrite
;
1118 ConDrvWriteConsoleOutputString(
1119 IN PCONSOLE Console
,
1120 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1121 IN CODE_TYPE CodeType
,
1122 IN PVOID StringBuffer
,
1123 IN ULONG NumCodesToWrite
,
1124 IN PCOORD WriteCoord
,
1125 OUT PULONG NumCodesWritten OPTIONAL
)
1128 SMALL_RECT UpdateRect
;
1130 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
/* || EndCoord == NULL */)
1132 return STATUS_INVALID_PARAMETER
;
1135 /* Validity checks */
1136 ASSERT(Console
== Buffer
->Header
.Console
);
1137 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToWrite
== 0));
1139 if (NumCodesWritten
)
1140 *NumCodesWritten
= 0;
1145 Status
= IntWriteConsoleOutputStringAscii(
1146 Console
, Buffer
, StringBuffer
, NumCodesToWrite
, WriteCoord
, NumCodesWritten
);
1150 Status
= IntWriteConsoleOutputStringUnicode(
1151 Console
, Buffer
, StringBuffer
, NumCodesToWrite
, WriteCoord
, NumCodesWritten
);
1154 case CODE_ATTRIBUTE
:
1155 Status
= IntWriteConsoleOutputStringAttribute(
1156 Console
, Buffer
, StringBuffer
, NumCodesToWrite
, WriteCoord
, NumCodesWritten
);
1160 Status
= STATUS_INVALID_PARAMETER
;
1164 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1166 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1167 TermDrawRegion(Console
, &UpdateRect
);
1174 ConDrvFillConsoleOutput(IN PCONSOLE Console
,
1175 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1176 IN CODE_TYPE CodeType
,
1177 IN CODE_ELEMENT Code
,
1178 IN ULONG NumCodesToWrite
,
1179 IN PCOORD WriteCoord
,
1180 OUT PULONG NumCodesWritten OPTIONAL
)
1184 BOOLEAN bLead
, bFullwidth
;
1186 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
)
1188 return STATUS_INVALID_PARAMETER
;
1191 /* Validity check */
1192 ASSERT(Console
== Buffer
->Header
.Console
);
1195 // FIXME: Make overflow checks on WriteCoord !!!!!!
1198 if (NumCodesWritten
) *NumCodesWritten
= 0;
1200 if (CodeType
== CODE_ASCII
)
1202 /* Conversion from the ASCII char to the UNICODE char */
1204 ConsoleOutputAnsiToUnicodeChar(Console
, &tmp
.UnicodeChar
, &Code
.AsciiChar
);
1209 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1210 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1211 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1213 /* For Chinese, Japanese and Korean */
1218 bFullwidth
= (mk_wcwidth_cjk(Code
.UnicodeChar
) == 2);
1221 Ptr
= ConioCoordToPointer(Buffer
, X
- 1, Y
);
1222 if (Ptr
->Attributes
& COMMON_LVB_LEADING_BYTE
)
1224 Ptr
->Char
.UnicodeChar
= L
' ';
1225 Ptr
->Attributes
&= ~COMMON_LVB_LEADING_BYTE
;
1230 for (i
= 0; i
< NumCodesToWrite
; ++i
)
1232 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
1238 Ptr
->Char
.UnicodeChar
= Code
.UnicodeChar
;
1239 Ptr
->Attributes
&= ~COMMON_LEAD_TRAIL
;
1243 Ptr
->Attributes
|= COMMON_LVB_LEADING_BYTE
;
1245 Ptr
->Attributes
|= COMMON_LVB_TRAILING_BYTE
;
1249 case CODE_ATTRIBUTE
:
1250 Ptr
->Attributes
&= ~COMMON_LEAD_TRAIL
;
1251 Ptr
->Attributes
|= (Code
.Attribute
& ~COMMON_LEAD_TRAIL
);
1256 if (X
== Buffer
->ScreenBufferSize
.X
)
1260 if (Y
== Buffer
->ScreenBufferSize
.Y
)
1269 if ((NumCodesToWrite
& 1) & bFullwidth
)
1271 if (X
+ Y
* Buffer
->ScreenBufferSize
.X
> 0)
1273 Ptr
= ConioCoordToPointer(Buffer
, X
- 1, Y
);
1274 Ptr
->Char
.UnicodeChar
= L
' ';
1275 Ptr
->Attributes
&= ~COMMON_LEAD_TRAIL
;
1279 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1281 SMALL_RECT UpdateRect
;
1282 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1283 TermDrawRegion(Console
, &UpdateRect
);
1286 if (NumCodesWritten
) *NumCodesWritten
= NumCodesToWrite
; // Written;
1287 return STATUS_SUCCESS
;
1291 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console
,
1292 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1293 OUT PCOORD ScreenBufferSize
,
1294 OUT PCOORD CursorPosition
,
1295 OUT PCOORD ViewOrigin
,
1296 OUT PCOORD ViewSize
,
1297 OUT PCOORD MaximumViewSize
,
1298 OUT PWORD Attributes
)
1300 COORD LargestWindowSize
;
1302 if (Console
== NULL
|| Buffer
== NULL
|| ScreenBufferSize
== NULL
||
1303 CursorPosition
== NULL
|| ViewOrigin
== NULL
|| ViewSize
== NULL
||
1304 MaximumViewSize
== NULL
|| Attributes
== NULL
)
1306 return STATUS_INVALID_PARAMETER
;
1309 /* Validity check */
1310 ASSERT(Console
== Buffer
->Header
.Console
);
1312 *ScreenBufferSize
= Buffer
->ScreenBufferSize
;
1313 *CursorPosition
= Buffer
->CursorPosition
;
1314 *ViewOrigin
= Buffer
->ViewOrigin
;
1315 *ViewSize
= Buffer
->ViewSize
;
1316 *Attributes
= Buffer
->ScreenDefaultAttrib
;
1319 * Retrieve the largest possible console window size, taking
1320 * into account the size of the console screen buffer.
1322 TermGetLargestConsoleWindowSize(Console
, &LargestWindowSize
);
1323 LargestWindowSize
.X
= min(LargestWindowSize
.X
, Buffer
->ScreenBufferSize
.X
);
1324 LargestWindowSize
.Y
= min(LargestWindowSize
.Y
, Buffer
->ScreenBufferSize
.Y
);
1325 *MaximumViewSize
= LargestWindowSize
;
1327 return STATUS_SUCCESS
;
1331 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console
,
1332 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1335 if (Console
== NULL
|| Buffer
== NULL
)
1336 return STATUS_INVALID_PARAMETER
;
1338 /* Validity check */
1339 ASSERT(Console
== Buffer
->Header
.Console
);
1341 Buffer
->ScreenDefaultAttrib
= Attributes
;
1342 return STATUS_SUCCESS
;
1346 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console
,
1347 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1352 if (Console
== NULL
|| Buffer
== NULL
|| Size
== NULL
)
1353 return STATUS_INVALID_PARAMETER
;
1355 /* Validity check */
1356 ASSERT(Console
== Buffer
->Header
.Console
);
1358 Status
= ConioResizeBuffer(Console
, Buffer
, *Size
);
1359 if (NT_SUCCESS(Status
)) TermResizeTerminal(Console
);
1365 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console
,
1366 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1368 IN PSMALL_RECT ScrollRectangle
,
1369 IN BOOLEAN UseClipRectangle
,
1370 IN PSMALL_RECT ClipRectangle OPTIONAL
,
1371 IN PCOORD DestinationOrigin
,
1372 IN CHAR_INFO FillChar
)
1374 COORD CapturedDestinationOrigin
;
1375 SMALL_RECT ScreenBuffer
;
1376 SMALL_RECT SrcRegion
;
1377 SMALL_RECT DstRegion
;
1378 SMALL_RECT UpdateRegion
;
1379 SMALL_RECT CapturedClipRectangle
;
1381 if (Console
== NULL
|| Buffer
== NULL
|| ScrollRectangle
== NULL
||
1382 (UseClipRectangle
? ClipRectangle
== NULL
: FALSE
) || DestinationOrigin
== NULL
)
1384 return STATUS_INVALID_PARAMETER
;
1387 /* Validity check */
1388 ASSERT(Console
== Buffer
->Header
.Console
);
1390 CapturedDestinationOrigin
= *DestinationOrigin
;
1392 /* Make sure the source rectangle is inside the screen buffer */
1393 ConioInitRect(&ScreenBuffer
, 0, 0,
1394 Buffer
->ScreenBufferSize
.Y
- 1,
1395 Buffer
->ScreenBufferSize
.X
- 1);
1396 if (!ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, ScrollRectangle
))
1398 return STATUS_SUCCESS
;
1401 /* If the source was clipped on the left or top, adjust the destination accordingly */
1402 if (ScrollRectangle
->Left
< 0)
1404 CapturedDestinationOrigin
.X
-= ScrollRectangle
->Left
;
1406 if (ScrollRectangle
->Top
< 0)
1408 CapturedDestinationOrigin
.Y
-= ScrollRectangle
->Top
;
1411 if (UseClipRectangle
)
1413 CapturedClipRectangle
= *ClipRectangle
;
1414 if (!ConioGetIntersection(&CapturedClipRectangle
, &CapturedClipRectangle
, &ScreenBuffer
))
1416 return STATUS_SUCCESS
;
1421 CapturedClipRectangle
= ScreenBuffer
;
1424 ConioInitRect(&DstRegion
,
1425 CapturedDestinationOrigin
.Y
,
1426 CapturedDestinationOrigin
.X
,
1427 CapturedDestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
1428 CapturedDestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
1433 ConsoleOutputAnsiToUnicodeChar(Console
, &tmp
, &FillChar
.Char
.AsciiChar
);
1434 FillChar
.Char
.UnicodeChar
= tmp
;
1437 ConioMoveRegion(Buffer
, &SrcRegion
, &DstRegion
, &CapturedClipRectangle
, FillChar
);
1439 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1441 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
1442 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &CapturedClipRectangle
))
1444 /* Draw update region */
1445 TermDrawRegion(Console
, &UpdateRegion
);
1449 return STATUS_SUCCESS
;
1453 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console
,
1454 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1455 IN BOOLEAN Absolute
,
1456 IN PSMALL_RECT WindowRect
)
1458 SMALL_RECT CapturedWindowRect
;
1459 COORD LargestWindowSize
;
1461 if (Console
== NULL
|| Buffer
== NULL
|| WindowRect
== NULL
)
1462 return STATUS_INVALID_PARAMETER
;
1464 /* Validity check */
1465 ASSERT(Console
== Buffer
->Header
.Console
);
1467 CapturedWindowRect
= *WindowRect
;
1471 /* Relative positions are given, transform them to absolute ones */
1472 CapturedWindowRect
.Left
+= Buffer
->ViewOrigin
.X
;
1473 CapturedWindowRect
.Top
+= Buffer
->ViewOrigin
.Y
;
1474 CapturedWindowRect
.Right
+= Buffer
->ViewOrigin
.X
+ Buffer
->ViewSize
.X
- 1;
1475 CapturedWindowRect
.Bottom
+= Buffer
->ViewOrigin
.Y
+ Buffer
->ViewSize
.Y
- 1;
1479 * The MSDN documentation on SetConsoleWindowInfo is partially wrong about
1480 * the performed checks this API performs. While it is correct that the
1481 * 'Right'/'Bottom' members cannot be strictly smaller than the 'Left'/'Top'
1482 * members, they can be equal.
1483 * Also, if the 'Left' or 'Top' members are negative, this is automatically
1484 * corrected for, and the window rectangle coordinates are shifted accordingly.
1486 if ((CapturedWindowRect
.Right
< CapturedWindowRect
.Left
) ||
1487 (CapturedWindowRect
.Bottom
< CapturedWindowRect
.Top
))
1489 return STATUS_INVALID_PARAMETER
;
1493 * Forbid window sizes larger than the largest allowed console window size,
1494 * taking into account the size of the console screen buffer.
1496 TermGetLargestConsoleWindowSize(Console
, &LargestWindowSize
);
1497 LargestWindowSize
.X
= min(LargestWindowSize
.X
, Buffer
->ScreenBufferSize
.X
);
1498 LargestWindowSize
.Y
= min(LargestWindowSize
.Y
, Buffer
->ScreenBufferSize
.Y
);
1499 if ((CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1 > LargestWindowSize
.X
) ||
1500 (CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1 > LargestWindowSize
.Y
))
1502 return STATUS_INVALID_PARAMETER
;
1505 /* Shift the window rectangle coordinates if 'Left' or 'Top' are negative */
1506 if (CapturedWindowRect
.Left
< 0)
1508 CapturedWindowRect
.Right
-= CapturedWindowRect
.Left
;
1509 CapturedWindowRect
.Left
= 0;
1511 if (CapturedWindowRect
.Top
< 0)
1513 CapturedWindowRect
.Bottom
-= CapturedWindowRect
.Top
;
1514 CapturedWindowRect
.Top
= 0;
1517 /* Clip the window rectangle to the screen buffer */
1518 CapturedWindowRect
.Right
= min(CapturedWindowRect
.Right
, Buffer
->ScreenBufferSize
.X
);
1519 CapturedWindowRect
.Bottom
= min(CapturedWindowRect
.Bottom
, Buffer
->ScreenBufferSize
.Y
);
1521 Buffer
->ViewOrigin
.X
= CapturedWindowRect
.Left
;
1522 Buffer
->ViewOrigin
.Y
= CapturedWindowRect
.Top
;
1524 Buffer
->ViewSize
.X
= CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1;
1525 Buffer
->ViewSize
.Y
= CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1;
1527 TermResizeTerminal(Console
);
1529 return STATUS_SUCCESS
;