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) \
28 ASSERT((ULONG_PTR)dChar != (ULONG_PTR)sWChar); \
29 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
31 #define ConsoleOutputAnsiToUnicodeChar(Console, dWChar, sChar) \
32 ASSERT((ULONG_PTR)dWChar != (ULONG_PTR)sChar); \
33 MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
35 /* PRIVATE FUNCTIONS **********************************************************/
37 CONSOLE_IO_OBJECT_TYPE
38 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This
)
40 // return This->Header.Type;
41 return TEXTMODE_BUFFER
;
44 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl
=
46 TEXTMODE_BUFFER_GetType
,
51 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
);
55 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
57 IN PCONSOLE_SCREEN_BUFFER_VTBL Vtbl
,
60 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
);
64 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER
* Buffer
,
66 IN HANDLE ProcessHandle
,
67 IN PTEXTMODE_BUFFER_INFO TextModeInfo
)
69 NTSTATUS Status
= STATUS_SUCCESS
;
70 PTEXTMODE_SCREEN_BUFFER NewBuffer
= NULL
;
72 UNREFERENCED_PARAMETER(ProcessHandle
);
74 if (Console
== NULL
|| Buffer
== NULL
|| TextModeInfo
== NULL
)
75 return STATUS_INVALID_PARAMETER
;
79 Status
= CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER
*)&NewBuffer
,
82 sizeof(TEXTMODE_SCREEN_BUFFER
));
83 if (!NT_SUCCESS(Status
)) return Status
;
84 NewBuffer
->Header
.Type
= TEXTMODE_BUFFER
;
86 NewBuffer
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
87 TextModeInfo
->ScreenBufferSize
.X
*
88 TextModeInfo
->ScreenBufferSize
.Y
*
90 if (NewBuffer
->Buffer
== NULL
)
92 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER
)NewBuffer
);
93 return STATUS_INSUFFICIENT_RESOURCES
;
96 NewBuffer
->ScreenBufferSize
= NewBuffer
->OldScreenBufferSize
97 = TextModeInfo
->ScreenBufferSize
;
98 NewBuffer
->ViewSize
= NewBuffer
->OldViewSize
99 = Console
->ConsoleSize
;
101 NewBuffer
->ViewOrigin
.X
= NewBuffer
->ViewOrigin
.Y
= 0;
102 NewBuffer
->VirtualY
= 0;
104 NewBuffer
->CursorBlinkOn
= NewBuffer
->ForceCursorOff
= FALSE
;
105 NewBuffer
->CursorInfo
.bVisible
= (TextModeInfo
->IsCursorVisible
&& (TextModeInfo
->CursorSize
!= 0));
106 NewBuffer
->CursorInfo
.dwSize
= min(max(TextModeInfo
->CursorSize
, 0), 100);
108 NewBuffer
->ScreenDefaultAttrib
= TextModeInfo
->ScreenAttrib
;
109 NewBuffer
->PopupDefaultAttrib
= TextModeInfo
->PopupAttrib
;
111 /* Initialize buffer to be empty with default attributes */
112 for (NewBuffer
->CursorPosition
.Y
= 0 ; NewBuffer
->CursorPosition
.Y
< NewBuffer
->ScreenBufferSize
.Y
; NewBuffer
->CursorPosition
.Y
++)
114 ClearLineBuffer(NewBuffer
);
116 NewBuffer
->CursorPosition
.X
= NewBuffer
->CursorPosition
.Y
= 0;
118 NewBuffer
->Mode
= ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
;
120 *Buffer
= (PCONSOLE_SCREEN_BUFFER
)NewBuffer
;
121 return STATUS_SUCCESS
;
125 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer
)
127 PTEXTMODE_SCREEN_BUFFER Buff
= (PTEXTMODE_SCREEN_BUFFER
)Buffer
;
130 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
131 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
133 Buffer
->Header
.Type
= SCREEN_BUFFER
;
135 ConsoleFreeHeap(Buff
->Buffer
);
137 CONSOLE_SCREEN_BUFFER_Destroy(Buffer
);
142 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff
, ULONG X
, ULONG Y
)
144 return &Buff
->Buffer
[((Y
+ Buff
->VirtualY
) % Buff
->ScreenBufferSize
.Y
) * Buff
->ScreenBufferSize
.X
+ X
];
148 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff
)
150 PCHAR_INFO Ptr
= ConioCoordToPointer(Buff
, 0, Buff
->CursorPosition
.Y
);
153 for (Pos
= 0; Pos
< Buff
->ScreenBufferSize
.X
; Pos
++, Ptr
++)
156 Ptr
->Char
.UnicodeChar
= L
' ';
157 Ptr
->Attributes
= Buff
->ScreenDefaultAttrib
;
162 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff
,
163 IN OUT PSMALL_RECT UpdateRect
,
167 if ((UINT
)Buff
->ScreenBufferSize
.X
<= Start
->X
+ Length
)
169 UpdateRect
->Left
= 0;
170 UpdateRect
->Right
= Buff
->ScreenBufferSize
.X
- 1;
174 UpdateRect
->Left
= Start
->X
;
175 UpdateRect
->Right
= Start
->X
+ Length
- 1;
177 UpdateRect
->Top
= Start
->Y
;
178 UpdateRect
->Bottom
= Start
->Y
+ (Start
->X
+ Length
- 1) / Buff
->ScreenBufferSize
.X
;
179 if (Buff
->ScreenBufferSize
.Y
<= UpdateRect
->Bottom
)
181 UpdateRect
->Bottom
= Buff
->ScreenBufferSize
.Y
- 1;
186 * Move from one rectangle to another. We must be careful about the order that
187 * this is done, to avoid overwriting parts of the source before they are moved.
190 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
191 PSMALL_RECT SrcRegion
,
192 PSMALL_RECT DstRegion
,
193 PSMALL_RECT ClipRegion
,
196 int Width
= ConioRectWidth(SrcRegion
);
197 int Height
= ConioRectHeight(SrcRegion
);
208 /* Moving down: work from bottom up */
209 SY
= SrcRegion
->Bottom
;
210 DY
= DstRegion
->Bottom
;
213 for (i
= 0; i
< Height
; i
++)
215 PCHAR_INFO SRow
= ConioCoordToPointer(ScreenBuffer
, 0, SY
);
216 PCHAR_INFO DRow
= ConioCoordToPointer(ScreenBuffer
, 0, DY
);
218 SX
= SrcRegion
->Left
;
219 DX
= DstRegion
->Left
;
223 /* Moving right: work from right to left */
224 SX
= SrcRegion
->Right
;
225 DX
= DstRegion
->Right
;
228 for (j
= 0; j
< Width
; j
++)
230 CHAR_INFO Cell
= SRow
[SX
];
231 if (SX
>= ClipRegion
->Left
&& SX
<= ClipRegion
->Right
&&
232 SY
>= ClipRegion
->Top
&& SY
<= ClipRegion
->Bottom
)
236 if (DX
>= ClipRegion
->Left
&& DX
<= ClipRegion
->Right
&&
237 DY
>= ClipRegion
->Top
&& DY
<= ClipRegion
->Bottom
)
251 ConDrvWriteConsoleInput(IN PCONSOLE Console
,
252 IN PCONSOLE_INPUT_BUFFER InputBuffer
,
253 IN BOOLEAN AppendToEnd
,
254 IN PINPUT_RECORD InputRecord
,
255 IN ULONG NumEventsToWrite
,
256 OUT PULONG NumEventsWritten OPTIONAL
);
259 ConioResizeBuffer(PCONSOLE Console
,
260 PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
266 WORD CurrentAttribute
;
268 PCHAR_INFO OldBuffer
;
272 /* Buffer size is not allowed to be smaller than the view size */
273 if (Size
.X
< ScreenBuffer
->ViewSize
.X
|| Size
.Y
< ScreenBuffer
->ViewSize
.Y
)
274 return STATUS_INVALID_PARAMETER
;
276 if (Size
.X
== ScreenBuffer
->ScreenBufferSize
.X
&& Size
.Y
== ScreenBuffer
->ScreenBufferSize
.Y
)
278 // FIXME: Trigger a buffer resize event ??
279 return STATUS_SUCCESS
;
282 if (Console
->FixedSize
)
285 * The console is in fixed-size mode, so we cannot resize anything
286 * at the moment. However, keep those settings somewhere so that
287 * we can try to set them up when we will be allowed to do so.
289 ScreenBuffer
->OldScreenBufferSize
= Size
;
290 return STATUS_NOT_SUPPORTED
; // STATUS_SUCCESS
293 Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
.X
* Size
.Y
* sizeof(CHAR_INFO
));
294 if (!Buffer
) return STATUS_NO_MEMORY
;
296 DPRINT("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer
->ScreenBufferSize
.X
, ScreenBuffer
->ScreenBufferSize
.Y
, Size
.X
, Size
.Y
);
297 OldBuffer
= ScreenBuffer
->Buffer
;
299 for (CurrentY
= 0; CurrentY
< ScreenBuffer
->ScreenBufferSize
.Y
&& CurrentY
< Size
.Y
; CurrentY
++)
301 ptr
= ConioCoordToPointer(ScreenBuffer
, 0, CurrentY
);
302 if (Size
.X
<= ScreenBuffer
->ScreenBufferSize
.X
)
305 RtlCopyMemory(Buffer
+ Offset
, ptr
, Size
.X
* sizeof(CHAR_INFO
));
311 RtlCopyMemory(Buffer
+ Offset
, ptr
, ScreenBuffer
->ScreenBufferSize
.X
* sizeof(CHAR_INFO
));
312 Offset
+= ScreenBuffer
->ScreenBufferSize
.X
;
314 /* The attribute to be used is the one of the last cell of the current line */
315 CurrentAttribute
= ConioCoordToPointer(ScreenBuffer
,
316 ScreenBuffer
->ScreenBufferSize
.X
- 1,
317 CurrentY
)->Attributes
;
319 diff
= Size
.X
- ScreenBuffer
->ScreenBufferSize
.X
;
321 /* Zero-out the new part of the buffer */
322 for (i
= 0; i
< diff
; i
++)
324 ptr
= Buffer
+ Offset
;
325 ptr
->Char
.UnicodeChar
= L
' ';
326 ptr
->Attributes
= CurrentAttribute
;
332 if (Size
.Y
> ScreenBuffer
->ScreenBufferSize
.Y
)
334 diff
= Size
.X
* (Size
.Y
- ScreenBuffer
->ScreenBufferSize
.Y
);
336 /* Zero-out the new part of the buffer */
337 for (i
= 0; i
< diff
; i
++)
339 ptr
= Buffer
+ Offset
;
340 ptr
->Char
.UnicodeChar
= L
' ';
341 ptr
->Attributes
= ScreenBuffer
->ScreenDefaultAttrib
;
346 (void)InterlockedExchangePointer((PVOID
volatile*)&ScreenBuffer
->Buffer
, Buffer
);
347 ConsoleFreeHeap(OldBuffer
);
348 ScreenBuffer
->ScreenBufferSize
= ScreenBuffer
->OldScreenBufferSize
= Size
;
349 ScreenBuffer
->VirtualY
= 0;
351 /* Ensure cursor and window are within buffer */
352 if (ScreenBuffer
->CursorPosition
.X
>= Size
.X
)
353 ScreenBuffer
->CursorPosition
.X
= Size
.X
- 1;
354 if (ScreenBuffer
->CursorPosition
.Y
>= Size
.Y
)
355 ScreenBuffer
->CursorPosition
.Y
= Size
.Y
- 1;
356 if (ScreenBuffer
->ViewOrigin
.X
> Size
.X
- ScreenBuffer
->ViewSize
.X
)
357 ScreenBuffer
->ViewOrigin
.X
= Size
.X
- ScreenBuffer
->ViewSize
.X
;
358 if (ScreenBuffer
->ViewOrigin
.Y
> Size
.Y
- ScreenBuffer
->ViewSize
.Y
)
359 ScreenBuffer
->ViewOrigin
.Y
= Size
.Y
- ScreenBuffer
->ViewSize
.Y
;
362 * Trigger a buffer resize event
364 if (Console
->InputBuffer
.Mode
& ENABLE_WINDOW_INPUT
)
366 ULONG NumEventsWritten
;
369 er
.EventType
= WINDOW_BUFFER_SIZE_EVENT
;
370 er
.Event
.WindowBufferSizeEvent
.dwSize
= ScreenBuffer
->ScreenBufferSize
;
372 // ConioProcessInputEvent(Console, &er);
373 ConDrvWriteConsoleInput(Console
,
374 &Console
->InputBuffer
,
381 return STATUS_SUCCESS
;
385 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console
,
386 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
387 IN USHORT NewScreenAttrib
,
388 IN USHORT NewPopupAttrib
)
394 ULONG NumCodesToWrite
;
395 USHORT OldScreenAttrib
, OldPopupAttrib
;
397 if (Console
== NULL
|| Buffer
== NULL
)
399 return STATUS_INVALID_PARAMETER
;
403 ASSERT(Console
== Buffer
->Header
.Console
);
405 NumCodesToWrite
= Buffer
->ScreenBufferSize
.X
* Buffer
->ScreenBufferSize
.Y
;
406 OldScreenAttrib
= Buffer
->ScreenDefaultAttrib
;
407 OldPopupAttrib
= Buffer
->PopupDefaultAttrib
;
410 Y
= (TopLeft
.Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
411 Length
= NumCodesToWrite
;
415 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
418 * Change the current colors only if they are the old ones.
421 /* Foreground color */
422 if ((Ptr
->Attributes
& 0x0F) == (OldScreenAttrib
& 0x0F))
423 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewScreenAttrib
& 0x0F);
424 if ((Ptr
->Attributes
& 0x0F) == (OldPopupAttrib
& 0x0F))
425 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFFF0) | (NewPopupAttrib
& 0x0F);
427 /* Background color */
428 if ((Ptr
->Attributes
& 0xF0) == (OldScreenAttrib
& 0xF0))
429 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewScreenAttrib
& 0xF0);
430 if ((Ptr
->Attributes
& 0xF0) == (OldPopupAttrib
& 0xF0))
431 Ptr
->Attributes
= (Ptr
->Attributes
& 0xFF0F) | (NewPopupAttrib
& 0xF0);
435 if (++X
== Buffer
->ScreenBufferSize
.X
)
439 if (++Y
== Buffer
->ScreenBufferSize
.Y
)
446 /* Save foreground and background colors for both screen and popup */
447 Buffer
->ScreenDefaultAttrib
= (NewScreenAttrib
& 0x00FF);
448 Buffer
->PopupDefaultAttrib
= (NewPopupAttrib
& 0x00FF);
450 /* Refresh the display if needed */
451 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
453 SMALL_RECT UpdateRect
;
454 ConioComputeUpdateRect(Buffer
, &UpdateRect
, &TopLeft
, NumCodesToWrite
);
455 TermDrawRegion(Console
, &UpdateRect
);
458 return STATUS_SUCCESS
;
462 /* PUBLIC DRIVER APIS *********************************************************/
465 ConDrvReadConsoleOutput(IN PCONSOLE Console
,
466 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
468 OUT PCHAR_INFO CharInfo
/*Buffer*/,
469 IN OUT PSMALL_RECT ReadRegion
)
472 SMALL_RECT ScreenBuffer
;
473 PCHAR_INFO CurCharInfo
;
474 SMALL_RECT CapturedReadRegion
;
477 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| ReadRegion
== NULL
)
479 return STATUS_INVALID_PARAMETER
;
483 ASSERT(Console
== Buffer
->Header
.Console
);
485 CapturedReadRegion
= *ReadRegion
;
487 /* Make sure ReadRegion is inside the screen buffer */
488 ConioInitRect(&ScreenBuffer
, 0, 0,
489 Buffer
->ScreenBufferSize
.Y
- 1,
490 Buffer
->ScreenBufferSize
.X
- 1);
491 if (!ConioGetIntersection(&CapturedReadRegion
, &ScreenBuffer
, &CapturedReadRegion
))
494 * It is okay to have a ReadRegion completely outside
495 * the screen buffer. No data is read then.
497 return STATUS_SUCCESS
;
500 CurCharInfo
= CharInfo
;
502 for (Y
= CapturedReadRegion
.Top
; Y
<= CapturedReadRegion
.Bottom
; ++Y
)
504 Ptr
= ConioCoordToPointer(Buffer
, CapturedReadRegion
.Left
, Y
);
505 for (X
= CapturedReadRegion
.Left
; X
<= CapturedReadRegion
.Right
; ++X
)
509 CurCharInfo
->Char
.UnicodeChar
= Ptr
->Char
.UnicodeChar
;
513 // ConsoleOutputUnicodeToAnsiChar(Console, &CurCharInfo->Char.AsciiChar, &Ptr->Char.UnicodeChar);
514 WideCharToMultiByte(Console
->OutputCodePage
, 0, &Ptr
->Char
.UnicodeChar
, 1,
515 &CurCharInfo
->Char
.AsciiChar
, 1, NULL
, NULL
);
517 CurCharInfo
->Attributes
= (Ptr
->Attributes
& ~COMMON_LEAD_TRAIL
);
523 *ReadRegion
= CapturedReadRegion
;
525 return STATUS_SUCCESS
;
529 ConDrvWriteConsoleOutput(IN PCONSOLE Console
,
530 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
532 IN PCHAR_INFO CharInfo
/*Buffer*/,
533 IN OUT PSMALL_RECT WriteRegion
)
536 SMALL_RECT ScreenBuffer
;
537 PCHAR_INFO CurCharInfo
;
538 SMALL_RECT CapturedWriteRegion
;
541 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
543 return STATUS_INVALID_PARAMETER
;
547 ASSERT(Console
== Buffer
->Header
.Console
);
549 CapturedWriteRegion
= *WriteRegion
;
551 /* Make sure WriteRegion is inside the screen buffer */
552 ConioInitRect(&ScreenBuffer
, 0, 0,
553 Buffer
->ScreenBufferSize
.Y
- 1,
554 Buffer
->ScreenBufferSize
.X
- 1);
555 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
558 * It is okay to have a WriteRegion completely outside
559 * the screen buffer. No data is written then.
561 return STATUS_SUCCESS
;
564 CurCharInfo
= CharInfo
;
566 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
568 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
569 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
573 Ptr
->Char
.UnicodeChar
= CurCharInfo
->Char
.UnicodeChar
;
577 ConsoleOutputAnsiToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
.AsciiChar
);
579 Ptr
->Attributes
= CurCharInfo
->Attributes
;
585 TermDrawRegion(Console
, &CapturedWriteRegion
);
587 *WriteRegion
= CapturedWriteRegion
;
589 return STATUS_SUCCESS
;
593 * NOTE: This function is strongly inspired by ConDrvWriteConsoleOutput...
594 * FIXME: This function MUST be moved into consrv/conoutput.c because only
595 * consrv knows how to manipulate VDM screenbuffers.
598 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console
,
599 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
600 IN PCHAR_CELL CharInfo
/*Buffer*/,
601 IN COORD CharInfoSize
,
602 IN PSMALL_RECT WriteRegion
)
605 SMALL_RECT ScreenBuffer
;
606 PCHAR_CELL CurCharInfo
;
607 SMALL_RECT CapturedWriteRegion
;
610 if (Console
== NULL
|| Buffer
== NULL
|| CharInfo
== NULL
|| WriteRegion
== NULL
)
612 return STATUS_INVALID_PARAMETER
;
616 ASSERT(Console
== Buffer
->Header
.Console
);
618 CapturedWriteRegion
= *WriteRegion
;
620 /* Make sure WriteRegion is inside the screen buffer */
621 ConioInitRect(&ScreenBuffer
, 0, 0,
622 Buffer
->ScreenBufferSize
.Y
- 1,
623 Buffer
->ScreenBufferSize
.X
- 1);
624 if (!ConioGetIntersection(&CapturedWriteRegion
, &ScreenBuffer
, &CapturedWriteRegion
))
627 * It is okay to have a WriteRegion completely outside
628 * the screen buffer. No data is written then.
630 return STATUS_SUCCESS
;
633 // CurCharInfo = CharInfo;
635 for (Y
= CapturedWriteRegion
.Top
; Y
<= CapturedWriteRegion
.Bottom
; ++Y
)
637 /**/CurCharInfo
= CharInfo
+ Y
* CharInfoSize
.X
+ CapturedWriteRegion
.Left
;/**/
639 Ptr
= ConioCoordToPointer(Buffer
, CapturedWriteRegion
.Left
, Y
);
640 for (X
= CapturedWriteRegion
.Left
; X
<= CapturedWriteRegion
.Right
; ++X
)
642 ConsoleOutputAnsiToUnicodeChar(Console
, &Ptr
->Char
.UnicodeChar
, &CurCharInfo
->Char
);
643 Ptr
->Attributes
= CurCharInfo
->Attributes
;
649 return STATUS_SUCCESS
;
653 ConDrvWriteConsole(IN PCONSOLE Console
,
654 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer
,
656 IN PVOID StringBuffer
,
657 IN ULONG NumCharsToWrite
,
658 OUT PULONG NumCharsWritten OPTIONAL
)
660 NTSTATUS Status
= STATUS_SUCCESS
;
661 PWCHAR Buffer
= NULL
;
665 if (Console
== NULL
|| ScreenBuffer
== NULL
/* || StringBuffer == NULL */)
666 return STATUS_INVALID_PARAMETER
;
668 /* Validity checks */
669 ASSERT(Console
== ScreenBuffer
->Header
.Console
);
670 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCharsToWrite
== 0));
672 /* Stop here if the console is paused */
673 if (Console
->UnpauseEvent
!= NULL
) return STATUS_PENDING
;
675 /* Convert the string to UNICODE */
678 Buffer
= StringBuffer
;
682 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
686 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Length
* sizeof(WCHAR
));
689 MultiByteToWideChar(Console
->OutputCodePage
, 0,
692 (PWCHAR
)Buffer
, Length
);
696 Status
= STATUS_NO_MEMORY
;
703 if (NT_SUCCESS(Status
))
705 Status
= TermWriteStream(Console
,
710 if (NT_SUCCESS(Status
))
712 Written
= NumCharsToWrite
;
716 if (!Unicode
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
719 if (NumCharsWritten
) *NumCharsWritten
= Written
;
725 IntReadConsoleOutputStringAscii(IN PCONSOLE Console
,
726 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
727 OUT PVOID StringBuffer
,
728 IN ULONG NumCodesToRead
,
730 OUT PULONG NumCodesRead OPTIONAL
)
732 ULONG CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
733 LPBYTE ReadBuffer
= StringBuffer
;
734 SHORT Xpos
= ReadCoord
->X
;
735 SHORT Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
738 BOOLEAN bCJK
= Console
->IsCJK
;
740 for (i
= 0; i
< NumCodesToRead
; ++i
)
742 Ptr
= ConioCoordToPointer(Buffer
, Xpos
, Ypos
);
744 ConsoleOutputUnicodeToAnsiChar(Console
, (PCHAR
)ReadBuffer
, &Ptr
->Char
.UnicodeChar
);
745 ReadBuffer
+= CodeSize
;
748 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
752 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
758 /* For Chinese, Japanese and Korean */
759 if (bCJK
&& (Ptr
->Attributes
& COMMON_LVB_LEADING_BYTE
))
762 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
766 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
778 return STATUS_SUCCESS
;
782 IntReadConsoleOutputStringUnicode(IN PCONSOLE Console
,
783 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
784 OUT PVOID StringBuffer
,
785 IN ULONG NumCodesToRead
,
787 OUT PULONG NumCodesRead OPTIONAL
)
789 ULONG CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
790 LPBYTE ReadBuffer
= StringBuffer
;
791 SHORT Xpos
= ReadCoord
->X
;
792 SHORT Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
793 ULONG i
, nNumChars
= 0;
795 BOOLEAN bCJK
= Console
->IsCJK
;
797 for (i
= 0; i
< NumCodesToRead
; ++i
, ++nNumChars
)
799 Ptr
= ConioCoordToPointer(Buffer
, Xpos
, Ypos
);
801 *(PWCHAR
)ReadBuffer
= Ptr
->Char
.UnicodeChar
;
802 ReadBuffer
+= CodeSize
;
805 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
809 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
815 /* For Chinese, Japanese and Korean */
816 if (bCJK
&& (Ptr
->Attributes
& COMMON_LVB_LEADING_BYTE
))
819 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
823 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
833 *NumCodesRead
= nNumChars
;
835 return STATUS_SUCCESS
;
839 IntReadConsoleOutputStringAttributes(IN PCONSOLE Console
,
840 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
841 OUT PVOID StringBuffer
,
842 IN ULONG NumCodesToRead
,
844 OUT PULONG NumCodesRead OPTIONAL
)
846 ULONG CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
847 LPBYTE ReadBuffer
= StringBuffer
;
848 SHORT Xpos
= ReadCoord
->X
;
849 SHORT Ypos
= (ReadCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
853 for (i
= 0; i
< NumCodesToRead
; ++i
)
855 Ptr
= ConioCoordToPointer(Buffer
, Xpos
, Ypos
);
857 *(PWORD
)ReadBuffer
= Ptr
->Attributes
;
858 ReadBuffer
+= CodeSize
;
861 if (Xpos
== Buffer
->ScreenBufferSize
.X
)
865 if (Ypos
== Buffer
->ScreenBufferSize
.Y
)
872 if (Xpos
> 0 && Console
->IsCJK
)
874 ReadBuffer
-= CodeSize
;
875 *(PWORD
)ReadBuffer
&= ~COMMON_LVB_LEADING_BYTE
;
879 *NumCodesRead
= NumCodesToRead
;
881 return STATUS_SUCCESS
;
885 ConDrvReadConsoleOutputString(IN PCONSOLE Console
,
886 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
887 IN CODE_TYPE CodeType
,
888 OUT PVOID StringBuffer
,
889 IN ULONG NumCodesToRead
,
891 OUT PULONG NumCodesRead OPTIONAL
)
893 if (Console
== NULL
|| Buffer
== NULL
|| ReadCoord
== NULL
/* || EndCoord == NULL */)
895 return STATUS_INVALID_PARAMETER
;
898 /* Validity checks */
899 ASSERT(Console
== Buffer
->Header
.Console
);
900 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToRead
== 0));
908 return IntReadConsoleOutputStringAscii(Console
,
916 return IntReadConsoleOutputStringUnicode(Console
,
924 return IntReadConsoleOutputStringAttributes(Console
,
932 return STATUS_INVALID_PARAMETER
;
937 IntWriteConsoleOutputStringUnicode(
939 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
940 IN PVOID StringBuffer
,
941 IN ULONG NumCodesToWrite
,
942 IN PCOORD WriteCoord
,
943 OUT PULONG NumCodesWritten OPTIONAL
)
945 NTSTATUS Status
= STATUS_SUCCESS
;
946 PWCHAR WriteBuffer
= StringBuffer
;
947 ULONG i
, X
, Y
, Length
;
949 BOOLEAN bCJK
= Console
->IsCJK
;
955 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
956 Length
= NumCodesToWrite
;
958 for (i
= 0; i
< Length
; ++i
)
960 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
962 Ptr
->Char
.UnicodeChar
= *WriteBuffer
;
966 if (X
== Buffer
->ScreenBufferSize
.X
)
970 if (Y
== Buffer
->ScreenBufferSize
.Y
)
976 /* For Chinese, Japanese and Korean */
977 if (bCJK
&& Ptr
->Char
.UnicodeChar
>= 0x80 &&
978 mk_wcwidth_cjk(Ptr
->Char
.UnicodeChar
) == 2)
980 /* A full-width character cannot cross a line boundary */
981 if (X
== Buffer
->ScreenBufferSize
.X
- 1)
983 /* go to next line */
986 if (Y
== Buffer
->ScreenBufferSize
.Y
)
990 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
993 /* the leading byte */
994 Ptr
->Attributes
= Buffer
->ScreenDefaultAttrib
;
995 Ptr
->Attributes
|= COMMON_LVB_LEADING_BYTE
;
998 /* the trailing byte */
999 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
1000 Ptr
->Attributes
= Buffer
->ScreenDefaultAttrib
;
1001 Ptr
->Attributes
|= COMMON_LVB_TRAILING_BYTE
;
1004 if (X
== Buffer
->ScreenBufferSize
.X
)
1008 if (Y
== Buffer
->ScreenBufferSize
.Y
)
1017 if (NumCodesWritten
)
1018 *NumCodesWritten
= NumCodesToWrite
;
1023 IntWriteConsoleOutputStringAscii(
1024 IN PCONSOLE Console
,
1025 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1026 IN PVOID StringBuffer
,
1027 IN ULONG NumCodesToWrite
,
1028 IN PCOORD WriteCoord
,
1029 OUT PULONG NumCodesWritten OPTIONAL
)
1037 if (NumCodesWritten
)
1038 *NumCodesWritten
= NumCodesToWrite
;
1040 return STATUS_SUCCESS
;
1043 /* Convert the ASCII string into Unicode before writing it to the console */
1044 Length
= MultiByteToWideChar(Console
->OutputCodePage
, 0,
1048 tmpString
= ConsoleAllocHeap(0, Length
* sizeof(WCHAR
));
1050 return STATUS_NO_MEMORY
;
1052 MultiByteToWideChar(Console
->OutputCodePage
, 0,
1057 Status
= IntWriteConsoleOutputStringUnicode(Console
,
1063 ConsoleFreeHeap(tmpString
);
1068 IntWriteConsoleOutputStringAttribute(
1069 IN PCONSOLE Console
,
1070 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1071 IN PVOID StringBuffer
,
1072 IN ULONG NumCodesToWrite
,
1073 IN PCOORD WriteCoord
,
1074 OUT PULONG NumCodesWritten OPTIONAL
)
1076 NTSTATUS Status
= STATUS_SUCCESS
;
1077 PWORD WriteBuffer
= StringBuffer
;
1078 ULONG i
, X
, Y
, Length
;
1085 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1086 Length
= NumCodesToWrite
;
1088 for (i
= 0; i
< Length
; ++i
)
1090 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
1092 Ptr
->Attributes
= (*WriteBuffer
& ~COMMON_LEAD_TRAIL
);
1096 if (X
== Buffer
->ScreenBufferSize
.X
)
1100 if (Y
== Buffer
->ScreenBufferSize
.Y
)
1108 if (NumCodesWritten
)
1109 *NumCodesWritten
= NumCodesToWrite
;
1114 ConDrvWriteConsoleOutputString(
1115 IN PCONSOLE Console
,
1116 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1117 IN CODE_TYPE CodeType
,
1118 IN PVOID StringBuffer
,
1119 IN ULONG NumCodesToWrite
,
1120 IN PCOORD WriteCoord
,
1121 OUT PULONG NumCodesWritten OPTIONAL
)
1124 SMALL_RECT UpdateRect
;
1126 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
/* || EndCoord == NULL */)
1128 return STATUS_INVALID_PARAMETER
;
1131 /* Validity checks */
1132 ASSERT(Console
== Buffer
->Header
.Console
);
1133 ASSERT((StringBuffer
!= NULL
) || (StringBuffer
== NULL
&& NumCodesToWrite
== 0));
1135 if (NumCodesWritten
)
1136 *NumCodesWritten
= 0;
1141 Status
= IntWriteConsoleOutputStringAscii(
1142 Console
, Buffer
, StringBuffer
, NumCodesToWrite
, WriteCoord
, NumCodesWritten
);
1146 Status
= IntWriteConsoleOutputStringUnicode(
1147 Console
, Buffer
, StringBuffer
, NumCodesToWrite
, WriteCoord
, NumCodesWritten
);
1150 case CODE_ATTRIBUTE
:
1151 Status
= IntWriteConsoleOutputStringAttribute(
1152 Console
, Buffer
, StringBuffer
, NumCodesToWrite
, WriteCoord
, NumCodesWritten
);
1156 Status
= STATUS_INVALID_PARAMETER
;
1160 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1162 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1163 TermDrawRegion(Console
, &UpdateRect
);
1170 ConDrvFillConsoleOutput(IN PCONSOLE Console
,
1171 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1172 IN CODE_TYPE CodeType
,
1173 IN CODE_ELEMENT Code
,
1174 IN ULONG NumCodesToWrite
,
1175 IN PCOORD WriteCoord
,
1176 OUT PULONG NumCodesWritten OPTIONAL
)
1180 BOOLEAN bLead
, bFullwidth
;
1182 if (Console
== NULL
|| Buffer
== NULL
|| WriteCoord
== NULL
)
1184 return STATUS_INVALID_PARAMETER
;
1187 /* Validity check */
1188 ASSERT(Console
== Buffer
->Header
.Console
);
1191 // FIXME: Make overflow checks on WriteCoord !!!!!!
1194 if (NumCodesWritten
) *NumCodesWritten
= 0;
1196 if (CodeType
== CODE_ASCII
)
1198 /* Conversion from the ASCII char to the UNICODE char */
1200 ConsoleOutputAnsiToUnicodeChar(Console
, &tmp
.UnicodeChar
, &Code
.AsciiChar
);
1205 Y
= (WriteCoord
->Y
+ Buffer
->VirtualY
) % Buffer
->ScreenBufferSize
.Y
;
1206 // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
1207 // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
1209 /* For Chinese, Japanese and Korean */
1214 bFullwidth
= (mk_wcwidth_cjk(Code
.UnicodeChar
) == 2);
1217 Ptr
= ConioCoordToPointer(Buffer
, X
- 1, Y
);
1218 if (Ptr
->Attributes
& COMMON_LVB_LEADING_BYTE
)
1220 Ptr
->Char
.UnicodeChar
= L
' ';
1221 Ptr
->Attributes
&= ~COMMON_LVB_LEADING_BYTE
;
1226 for (i
= 0; i
< NumCodesToWrite
; ++i
)
1228 Ptr
= ConioCoordToPointer(Buffer
, X
, Y
);
1234 Ptr
->Char
.UnicodeChar
= Code
.UnicodeChar
;
1235 Ptr
->Attributes
&= ~COMMON_LEAD_TRAIL
;
1239 Ptr
->Attributes
|= COMMON_LVB_LEADING_BYTE
;
1241 Ptr
->Attributes
|= COMMON_LVB_TRAILING_BYTE
;
1245 case CODE_ATTRIBUTE
:
1246 Ptr
->Attributes
&= ~COMMON_LEAD_TRAIL
;
1247 Ptr
->Attributes
|= (Code
.Attribute
& ~COMMON_LEAD_TRAIL
);
1252 if (X
== Buffer
->ScreenBufferSize
.X
)
1256 if (Y
== Buffer
->ScreenBufferSize
.Y
)
1265 if ((NumCodesToWrite
& 1) & bFullwidth
)
1267 if (X
+ Y
* Buffer
->ScreenBufferSize
.X
> 0)
1269 Ptr
= ConioCoordToPointer(Buffer
, X
- 1, Y
);
1270 Ptr
->Char
.UnicodeChar
= L
' ';
1271 Ptr
->Attributes
&= ~COMMON_LEAD_TRAIL
;
1275 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1277 SMALL_RECT UpdateRect
;
1278 ConioComputeUpdateRect(Buffer
, &UpdateRect
, WriteCoord
, NumCodesToWrite
);
1279 TermDrawRegion(Console
, &UpdateRect
);
1282 if (NumCodesWritten
) *NumCodesWritten
= NumCodesToWrite
; // Written;
1283 return STATUS_SUCCESS
;
1287 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console
,
1288 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1289 OUT PCOORD ScreenBufferSize
,
1290 OUT PCOORD CursorPosition
,
1291 OUT PCOORD ViewOrigin
,
1292 OUT PCOORD ViewSize
,
1293 OUT PCOORD MaximumViewSize
,
1294 OUT PWORD Attributes
)
1296 COORD LargestWindowSize
;
1298 if (Console
== NULL
|| Buffer
== NULL
|| ScreenBufferSize
== NULL
||
1299 CursorPosition
== NULL
|| ViewOrigin
== NULL
|| ViewSize
== NULL
||
1300 MaximumViewSize
== NULL
|| Attributes
== NULL
)
1302 return STATUS_INVALID_PARAMETER
;
1305 /* Validity check */
1306 ASSERT(Console
== Buffer
->Header
.Console
);
1308 *ScreenBufferSize
= Buffer
->ScreenBufferSize
;
1309 *CursorPosition
= Buffer
->CursorPosition
;
1310 *ViewOrigin
= Buffer
->ViewOrigin
;
1311 *ViewSize
= Buffer
->ViewSize
;
1312 *Attributes
= Buffer
->ScreenDefaultAttrib
;
1315 * Retrieve the largest possible console window size, taking
1316 * into account the size of the console screen buffer.
1318 TermGetLargestConsoleWindowSize(Console
, &LargestWindowSize
);
1319 LargestWindowSize
.X
= min(LargestWindowSize
.X
, Buffer
->ScreenBufferSize
.X
);
1320 LargestWindowSize
.Y
= min(LargestWindowSize
.Y
, Buffer
->ScreenBufferSize
.Y
);
1321 *MaximumViewSize
= LargestWindowSize
;
1323 return STATUS_SUCCESS
;
1327 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console
,
1328 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1331 if (Console
== NULL
|| Buffer
== NULL
)
1332 return STATUS_INVALID_PARAMETER
;
1334 /* Validity check */
1335 ASSERT(Console
== Buffer
->Header
.Console
);
1337 Buffer
->ScreenDefaultAttrib
= Attributes
;
1338 return STATUS_SUCCESS
;
1342 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console
,
1343 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1348 if (Console
== NULL
|| Buffer
== NULL
|| Size
== NULL
)
1349 return STATUS_INVALID_PARAMETER
;
1351 /* Validity check */
1352 ASSERT(Console
== Buffer
->Header
.Console
);
1354 Status
= ConioResizeBuffer(Console
, Buffer
, *Size
);
1355 if (NT_SUCCESS(Status
)) TermResizeTerminal(Console
);
1361 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console
,
1362 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1364 IN PSMALL_RECT ScrollRectangle
,
1365 IN BOOLEAN UseClipRectangle
,
1366 IN PSMALL_RECT ClipRectangle OPTIONAL
,
1367 IN PCOORD DestinationOrigin
,
1368 IN CHAR_INFO FillChar
)
1370 COORD CapturedDestinationOrigin
;
1371 SMALL_RECT ScreenBuffer
;
1372 SMALL_RECT SrcRegion
;
1373 SMALL_RECT DstRegion
;
1374 SMALL_RECT UpdateRegion
;
1375 SMALL_RECT CapturedClipRectangle
;
1377 if (Console
== NULL
|| Buffer
== NULL
|| ScrollRectangle
== NULL
||
1378 (UseClipRectangle
? ClipRectangle
== NULL
: FALSE
) || DestinationOrigin
== NULL
)
1380 return STATUS_INVALID_PARAMETER
;
1383 /* Validity check */
1384 ASSERT(Console
== Buffer
->Header
.Console
);
1386 CapturedDestinationOrigin
= *DestinationOrigin
;
1388 /* Make sure the source rectangle is inside the screen buffer */
1389 ConioInitRect(&ScreenBuffer
, 0, 0,
1390 Buffer
->ScreenBufferSize
.Y
- 1,
1391 Buffer
->ScreenBufferSize
.X
- 1);
1392 if (!ConioGetIntersection(&SrcRegion
, &ScreenBuffer
, ScrollRectangle
))
1394 return STATUS_SUCCESS
;
1397 /* If the source was clipped on the left or top, adjust the destination accordingly */
1398 if (ScrollRectangle
->Left
< 0)
1400 CapturedDestinationOrigin
.X
-= ScrollRectangle
->Left
;
1402 if (ScrollRectangle
->Top
< 0)
1404 CapturedDestinationOrigin
.Y
-= ScrollRectangle
->Top
;
1407 if (UseClipRectangle
)
1409 CapturedClipRectangle
= *ClipRectangle
;
1410 if (!ConioGetIntersection(&CapturedClipRectangle
, &CapturedClipRectangle
, &ScreenBuffer
))
1412 return STATUS_SUCCESS
;
1417 CapturedClipRectangle
= ScreenBuffer
;
1420 ConioInitRect(&DstRegion
,
1421 CapturedDestinationOrigin
.Y
,
1422 CapturedDestinationOrigin
.X
,
1423 CapturedDestinationOrigin
.Y
+ ConioRectHeight(&SrcRegion
) - 1,
1424 CapturedDestinationOrigin
.X
+ ConioRectWidth(&SrcRegion
) - 1);
1429 ConsoleOutputAnsiToUnicodeChar(Console
, &tmp
, &FillChar
.Char
.AsciiChar
);
1430 FillChar
.Char
.UnicodeChar
= tmp
;
1433 ConioMoveRegion(Buffer
, &SrcRegion
, &DstRegion
, &CapturedClipRectangle
, FillChar
);
1435 if ((PCONSOLE_SCREEN_BUFFER
)Buffer
== Console
->ActiveBuffer
)
1437 ConioGetUnion(&UpdateRegion
, &SrcRegion
, &DstRegion
);
1438 if (ConioGetIntersection(&UpdateRegion
, &UpdateRegion
, &CapturedClipRectangle
))
1440 /* Draw update region */
1441 TermDrawRegion(Console
, &UpdateRegion
);
1445 return STATUS_SUCCESS
;
1449 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console
,
1450 IN PTEXTMODE_SCREEN_BUFFER Buffer
,
1451 IN BOOLEAN Absolute
,
1452 IN PSMALL_RECT WindowRect
)
1454 SMALL_RECT CapturedWindowRect
;
1455 COORD LargestWindowSize
;
1457 if (Console
== NULL
|| Buffer
== NULL
|| WindowRect
== NULL
)
1458 return STATUS_INVALID_PARAMETER
;
1460 /* Validity check */
1461 ASSERT(Console
== Buffer
->Header
.Console
);
1463 CapturedWindowRect
= *WindowRect
;
1467 /* Relative positions are given, transform them to absolute ones */
1468 CapturedWindowRect
.Left
+= Buffer
->ViewOrigin
.X
;
1469 CapturedWindowRect
.Top
+= Buffer
->ViewOrigin
.Y
;
1470 CapturedWindowRect
.Right
+= Buffer
->ViewOrigin
.X
+ Buffer
->ViewSize
.X
- 1;
1471 CapturedWindowRect
.Bottom
+= Buffer
->ViewOrigin
.Y
+ Buffer
->ViewSize
.Y
- 1;
1475 * The MSDN documentation on SetConsoleWindowInfo is partially wrong about
1476 * the performed checks this API performs. While it is correct that the
1477 * 'Right'/'Bottom' members cannot be strictly smaller than the 'Left'/'Top'
1478 * members, they can be equal.
1479 * Also, if the 'Left' or 'Top' members are negative, this is automatically
1480 * corrected for, and the window rectangle coordinates are shifted accordingly.
1482 if ((CapturedWindowRect
.Right
< CapturedWindowRect
.Left
) ||
1483 (CapturedWindowRect
.Bottom
< CapturedWindowRect
.Top
))
1485 return STATUS_INVALID_PARAMETER
;
1489 * Forbid window sizes larger than the largest allowed console window size,
1490 * taking into account the size of the console screen buffer.
1492 TermGetLargestConsoleWindowSize(Console
, &LargestWindowSize
);
1493 LargestWindowSize
.X
= min(LargestWindowSize
.X
, Buffer
->ScreenBufferSize
.X
);
1494 LargestWindowSize
.Y
= min(LargestWindowSize
.Y
, Buffer
->ScreenBufferSize
.Y
);
1495 if ((CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1 > LargestWindowSize
.X
) ||
1496 (CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1 > LargestWindowSize
.Y
))
1498 return STATUS_INVALID_PARAMETER
;
1501 /* Shift the window rectangle coordinates if 'Left' or 'Top' are negative */
1502 if (CapturedWindowRect
.Left
< 0)
1504 CapturedWindowRect
.Right
-= CapturedWindowRect
.Left
;
1505 CapturedWindowRect
.Left
= 0;
1507 if (CapturedWindowRect
.Top
< 0)
1509 CapturedWindowRect
.Bottom
-= CapturedWindowRect
.Top
;
1510 CapturedWindowRect
.Top
= 0;
1513 /* Clip the window rectangle to the screen buffer */
1514 CapturedWindowRect
.Right
= min(CapturedWindowRect
.Right
, Buffer
->ScreenBufferSize
.X
);
1515 CapturedWindowRect
.Bottom
= min(CapturedWindowRect
.Bottom
, Buffer
->ScreenBufferSize
.Y
);
1517 Buffer
->ViewOrigin
.X
= CapturedWindowRect
.Left
;
1518 Buffer
->ViewOrigin
.Y
= CapturedWindowRect
.Top
;
1520 Buffer
->ViewSize
.X
= CapturedWindowRect
.Right
- CapturedWindowRect
.Left
+ 1;
1521 Buffer
->ViewSize
.Y
= CapturedWindowRect
.Bottom
- CapturedWindowRect
.Top
+ 1;
1523 TermResizeTerminal(Console
);
1525 return STATUS_SUCCESS
;