de0c740e58f41d58eedffe643a2c1345ed69f42f
[reactos.git] / win32ss / user / winsrv / consrv / condrv / text.c
1 /*
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)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <consrv.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 /*
20 * From MSDN:
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."
24 */
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)
28
29 #define ConsoleOutputAnsiToUnicodeChar(Console, dWChar, sChar) \
30 ASSERT((ULONG_PTR)dWChar != (ULONG_PTR)sChar); \
31 MultiByteToWideChar((Console)->OutputCodePage, 0, (sChar), 1, (dWChar), 1)
32
33 /* PRIVATE FUNCTIONS **********************************************************/
34
35 CONSOLE_IO_OBJECT_TYPE
36 TEXTMODE_BUFFER_GetType(PCONSOLE_SCREEN_BUFFER This)
37 {
38 // return This->Header.Type;
39 return TEXTMODE_BUFFER;
40 }
41
42 static CONSOLE_SCREEN_BUFFER_VTBL TextVtbl =
43 {
44 TEXTMODE_BUFFER_GetType,
45 };
46
47
48 /*static*/ VOID
49 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff);
50
51
52 NTSTATUS
53 CONSOLE_SCREEN_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
54 IN PCONSOLE Console,
55 IN PCONSOLE_SCREEN_BUFFER_VTBL Vtbl,
56 IN SIZE_T Size);
57 VOID
58 CONSOLE_SCREEN_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer);
59
60
61 NTSTATUS
62 TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
63 IN PCONSOLE Console,
64 IN HANDLE ProcessHandle,
65 IN PTEXTMODE_BUFFER_INFO TextModeInfo)
66 {
67 NTSTATUS Status = STATUS_SUCCESS;
68 PTEXTMODE_SCREEN_BUFFER NewBuffer = NULL;
69
70 UNREFERENCED_PARAMETER(ProcessHandle);
71
72 if (Console == NULL || Buffer == NULL || TextModeInfo == NULL)
73 return STATUS_INVALID_PARAMETER;
74
75 *Buffer = NULL;
76
77 Status = CONSOLE_SCREEN_BUFFER_Initialize((PCONSOLE_SCREEN_BUFFER*)&NewBuffer,
78 Console,
79 &TextVtbl,
80 sizeof(TEXTMODE_SCREEN_BUFFER));
81 if (!NT_SUCCESS(Status)) return Status;
82 NewBuffer->Header.Type = TEXTMODE_BUFFER;
83
84 NewBuffer->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
85 TextModeInfo->ScreenBufferSize.X *
86 TextModeInfo->ScreenBufferSize.Y *
87 sizeof(CHAR_INFO));
88 if (NewBuffer->Buffer == NULL)
89 {
90 CONSOLE_SCREEN_BUFFER_Destroy((PCONSOLE_SCREEN_BUFFER)NewBuffer);
91 return STATUS_INSUFFICIENT_RESOURCES;
92 }
93
94 NewBuffer->ScreenBufferSize = NewBuffer->OldScreenBufferSize
95 = TextModeInfo->ScreenBufferSize;
96 NewBuffer->ViewSize = NewBuffer->OldViewSize
97 = Console->ConsoleSize;
98
99 NewBuffer->ViewOrigin.X = NewBuffer->ViewOrigin.Y = 0;
100 NewBuffer->VirtualY = 0;
101
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);
105
106 NewBuffer->ScreenDefaultAttrib = TextModeInfo->ScreenAttrib;
107 NewBuffer->PopupDefaultAttrib = TextModeInfo->PopupAttrib;
108
109 /* Initialize buffer to be empty with default attributes */
110 for (NewBuffer->CursorPosition.Y = 0 ; NewBuffer->CursorPosition.Y < NewBuffer->ScreenBufferSize.Y; NewBuffer->CursorPosition.Y++)
111 {
112 ClearLineBuffer(NewBuffer);
113 }
114 NewBuffer->CursorPosition.X = NewBuffer->CursorPosition.Y = 0;
115
116 NewBuffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
117
118 *Buffer = (PCONSOLE_SCREEN_BUFFER)NewBuffer;
119 return STATUS_SUCCESS;
120 }
121
122 VOID
123 TEXTMODE_BUFFER_Destroy(IN OUT PCONSOLE_SCREEN_BUFFER Buffer)
124 {
125 PTEXTMODE_SCREEN_BUFFER Buff = (PTEXTMODE_SCREEN_BUFFER)Buffer;
126
127 /*
128 * IMPORTANT !! Reinitialize the type so that we don't enter a recursive
129 * infinite loop when calling CONSOLE_SCREEN_BUFFER_Destroy.
130 */
131 Buffer->Header.Type = SCREEN_BUFFER;
132
133 ConsoleFreeHeap(Buff->Buffer);
134
135 CONSOLE_SCREEN_BUFFER_Destroy(Buffer);
136 }
137
138
139 PCHAR_INFO
140 ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
141 {
142 return &Buff->Buffer[((Y + Buff->VirtualY) % Buff->ScreenBufferSize.Y) * Buff->ScreenBufferSize.X + X];
143 }
144
145 /*static*/ VOID
146 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff)
147 {
148 PCHAR_INFO Ptr = ConioCoordToPointer(Buff, 0, Buff->CursorPosition.Y);
149 SHORT Pos;
150
151 for (Pos = 0; Pos < Buff->ScreenBufferSize.X; Pos++, Ptr++)
152 {
153 /* Fill the cell */
154 Ptr->Char.UnicodeChar = L' ';
155 Ptr->Attributes = Buff->ScreenDefaultAttrib;
156 }
157 }
158
159 static VOID
160 ConioComputeUpdateRect(IN PTEXTMODE_SCREEN_BUFFER Buff,
161 IN OUT PSMALL_RECT UpdateRect,
162 IN PCOORD Start,
163 IN UINT Length)
164 {
165 if ((UINT)Buff->ScreenBufferSize.X <= Start->X + Length)
166 {
167 UpdateRect->Left = 0;
168 UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
169 }
170 else
171 {
172 UpdateRect->Left = Start->X;
173 UpdateRect->Right = Start->X + Length - 1;
174 }
175 UpdateRect->Top = Start->Y;
176 UpdateRect->Bottom = Start->Y + (Start->X + Length - 1) / Buff->ScreenBufferSize.X;
177 if (Buff->ScreenBufferSize.Y <= UpdateRect->Bottom)
178 {
179 UpdateRect->Bottom = Buff->ScreenBufferSize.Y - 1;
180 }
181 }
182
183 /*
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.
186 */
187 static VOID
188 ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
189 PSMALL_RECT SrcRegion,
190 PSMALL_RECT DstRegion,
191 PSMALL_RECT ClipRegion,
192 CHAR_INFO FillChar)
193 {
194 int Width = ConioRectWidth(SrcRegion);
195 int Height = ConioRectHeight(SrcRegion);
196 int SX, SY;
197 int DX, DY;
198 int XDelta, YDelta;
199 int i, j;
200
201 SY = SrcRegion->Top;
202 DY = DstRegion->Top;
203 YDelta = 1;
204 if (SY < DY)
205 {
206 /* Moving down: work from bottom up */
207 SY = SrcRegion->Bottom;
208 DY = DstRegion->Bottom;
209 YDelta = -1;
210 }
211 for (i = 0; i < Height; i++)
212 {
213 PCHAR_INFO SRow = ConioCoordToPointer(ScreenBuffer, 0, SY);
214 PCHAR_INFO DRow = ConioCoordToPointer(ScreenBuffer, 0, DY);
215
216 SX = SrcRegion->Left;
217 DX = DstRegion->Left;
218 XDelta = 1;
219 if (SX < DX)
220 {
221 /* Moving right: work from right to left */
222 SX = SrcRegion->Right;
223 DX = DstRegion->Right;
224 XDelta = -1;
225 }
226 for (j = 0; j < Width; j++)
227 {
228 CHAR_INFO Cell = SRow[SX];
229 if (SX >= ClipRegion->Left && SX <= ClipRegion->Right &&
230 SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
231 {
232 SRow[SX] = FillChar;
233 }
234 if (DX >= ClipRegion->Left && DX <= ClipRegion->Right &&
235 DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
236 {
237 DRow[DX] = Cell;
238 }
239 SX += XDelta;
240 DX += XDelta;
241 }
242 SY += YDelta;
243 DY += YDelta;
244 }
245 }
246
247 // FIXME!
248 NTSTATUS NTAPI
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);
255
256 NTSTATUS
257 ConioResizeBuffer(PCONSOLE Console,
258 PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
259 COORD Size)
260 {
261 PCHAR_INFO Buffer;
262 DWORD Offset = 0;
263 PCHAR_INFO ptr;
264 WORD CurrentAttribute;
265 USHORT CurrentY;
266 PCHAR_INFO OldBuffer;
267 DWORD i;
268 DWORD diff;
269
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;
273
274 if (Size.X == ScreenBuffer->ScreenBufferSize.X && Size.Y == ScreenBuffer->ScreenBufferSize.Y)
275 {
276 // FIXME: Trigger a buffer resize event ??
277 return STATUS_SUCCESS;
278 }
279
280 if (Console->FixedSize)
281 {
282 /*
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.
286 */
287 ScreenBuffer->OldScreenBufferSize = Size;
288 return STATUS_NOT_SUPPORTED; // STATUS_SUCCESS
289 }
290
291 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size.X * Size.Y * sizeof(CHAR_INFO));
292 if (!Buffer) return STATUS_NO_MEMORY;
293
294 DPRINT("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y);
295 OldBuffer = ScreenBuffer->Buffer;
296
297 for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++)
298 {
299 ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
300 if (Size.X <= ScreenBuffer->ScreenBufferSize.X)
301 {
302 /* Reduce size */
303 RtlCopyMemory(Buffer + Offset, ptr, Size.X * sizeof(CHAR_INFO));
304 Offset += Size.X;
305 }
306 else
307 {
308 /* Enlarge size */
309 RtlCopyMemory(Buffer + Offset, ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO));
310 Offset += ScreenBuffer->ScreenBufferSize.X;
311
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;
316
317 diff = Size.X - ScreenBuffer->ScreenBufferSize.X;
318
319 /* Zero-out the new part of the buffer */
320 for (i = 0; i < diff; i++)
321 {
322 ptr = Buffer + Offset;
323 ptr->Char.UnicodeChar = L' ';
324 ptr->Attributes = CurrentAttribute;
325 ++Offset;
326 }
327 }
328 }
329
330 if (Size.Y > ScreenBuffer->ScreenBufferSize.Y)
331 {
332 diff = Size.X * (Size.Y - ScreenBuffer->ScreenBufferSize.Y);
333
334 /* Zero-out the new part of the buffer */
335 for (i = 0; i < diff; i++)
336 {
337 ptr = Buffer + Offset;
338 ptr->Char.UnicodeChar = L' ';
339 ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib;
340 ++Offset;
341 }
342 }
343
344 (void)InterlockedExchangePointer((PVOID volatile*)&ScreenBuffer->Buffer, Buffer);
345 ConsoleFreeHeap(OldBuffer);
346 ScreenBuffer->ScreenBufferSize = ScreenBuffer->OldScreenBufferSize = Size;
347 ScreenBuffer->VirtualY = 0;
348
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;
358
359 /*
360 * Trigger a buffer resize event
361 */
362 if (Console->InputBuffer.Mode & ENABLE_WINDOW_INPUT)
363 {
364 ULONG NumEventsWritten;
365 INPUT_RECORD er;
366
367 er.EventType = WINDOW_BUFFER_SIZE_EVENT;
368 er.Event.WindowBufferSizeEvent.dwSize = ScreenBuffer->ScreenBufferSize;
369
370 // ConioProcessInputEvent(Console, &er);
371 ConDrvWriteConsoleInput(Console,
372 &Console->InputBuffer,
373 TRUE,
374 &er,
375 1,
376 &NumEventsWritten);
377 }
378
379 return STATUS_SUCCESS;
380 }
381
382 NTSTATUS NTAPI
383 ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console,
384 IN PTEXTMODE_SCREEN_BUFFER Buffer,
385 IN USHORT NewScreenAttrib,
386 IN USHORT NewPopupAttrib)
387 {
388 ULONG X, Y, Length;
389 PCHAR_INFO Ptr;
390
391 COORD TopLeft = {0};
392 ULONG NumCodesToWrite;
393 USHORT OldScreenAttrib, OldPopupAttrib;
394
395 if (Console == NULL || Buffer == NULL)
396 {
397 return STATUS_INVALID_PARAMETER;
398 }
399
400 /* Validity check */
401 ASSERT(Console == Buffer->Header.Console);
402
403 NumCodesToWrite = Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y;
404 OldScreenAttrib = Buffer->ScreenDefaultAttrib;
405 OldPopupAttrib = Buffer->PopupDefaultAttrib;
406
407 X = TopLeft.X;
408 Y = (TopLeft.Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
409 Length = NumCodesToWrite;
410
411 while (Length--)
412 {
413 Ptr = ConioCoordToPointer(Buffer, X, Y);
414
415 /*
416 * Change the current colors only if they are the old ones.
417 */
418
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);
424
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);
430
431 // ++Ptr;
432
433 if (++X == Buffer->ScreenBufferSize.X)
434 {
435 X = 0;
436
437 if (++Y == Buffer->ScreenBufferSize.Y)
438 {
439 Y = 0;
440 }
441 }
442 }
443
444 /* Save foreground and background colors for both screen and popup */
445 Buffer->ScreenDefaultAttrib = (NewScreenAttrib & 0x00FF);
446 Buffer->PopupDefaultAttrib = (NewPopupAttrib & 0x00FF);
447
448 /* Refresh the display if needed */
449 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
450 {
451 SMALL_RECT UpdateRect;
452 ConioComputeUpdateRect(Buffer, &UpdateRect, &TopLeft, NumCodesToWrite);
453 TermDrawRegion(Console, &UpdateRect);
454 }
455
456 return STATUS_SUCCESS;
457 }
458
459
460 /* PUBLIC DRIVER APIS *********************************************************/
461
462 NTSTATUS NTAPI
463 ConDrvReadConsoleOutput(IN PCONSOLE Console,
464 IN PTEXTMODE_SCREEN_BUFFER Buffer,
465 IN BOOLEAN Unicode,
466 OUT PCHAR_INFO CharInfo/*Buffer*/,
467 IN OUT PSMALL_RECT ReadRegion)
468 {
469 SHORT X, Y;
470 SMALL_RECT ScreenBuffer;
471 PCHAR_INFO CurCharInfo;
472 SMALL_RECT CapturedReadRegion;
473 PCHAR_INFO Ptr;
474
475 if (Console == NULL || Buffer == NULL || CharInfo == NULL || ReadRegion == NULL)
476 {
477 return STATUS_INVALID_PARAMETER;
478 }
479
480 /* Validity check */
481 ASSERT(Console == Buffer->Header.Console);
482
483 CapturedReadRegion = *ReadRegion;
484
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))
490 {
491 /*
492 * It is okay to have a ReadRegion completely outside
493 * the screen buffer. No data is read then.
494 */
495 return STATUS_SUCCESS;
496 }
497
498 CurCharInfo = CharInfo;
499
500 for (Y = CapturedReadRegion.Top; Y <= CapturedReadRegion.Bottom; ++Y)
501 {
502 Ptr = ConioCoordToPointer(Buffer, CapturedReadRegion.Left, Y);
503 for (X = CapturedReadRegion.Left; X <= CapturedReadRegion.Right; ++X)
504 {
505 if (Unicode)
506 {
507 CurCharInfo->Char.UnicodeChar = Ptr->Char.UnicodeChar;
508 }
509 else
510 {
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);
514 }
515 CurCharInfo->Attributes =
516 (Ptr->Attributes & ~(COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE));
517 ++Ptr;
518 ++CurCharInfo;
519 }
520 }
521
522 *ReadRegion = CapturedReadRegion;
523
524 return STATUS_SUCCESS;
525 }
526
527 NTSTATUS NTAPI
528 ConDrvWriteConsoleOutput(IN PCONSOLE Console,
529 IN PTEXTMODE_SCREEN_BUFFER Buffer,
530 IN BOOLEAN Unicode,
531 IN PCHAR_INFO CharInfo/*Buffer*/,
532 IN OUT PSMALL_RECT WriteRegion)
533 {
534 SHORT X, Y;
535 SMALL_RECT ScreenBuffer;
536 PCHAR_INFO CurCharInfo;
537 SMALL_RECT CapturedWriteRegion;
538 PCHAR_INFO Ptr;
539
540 if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
541 {
542 return STATUS_INVALID_PARAMETER;
543 }
544
545 /* Validity check */
546 ASSERT(Console == Buffer->Header.Console);
547
548 CapturedWriteRegion = *WriteRegion;
549
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))
555 {
556 /*
557 * It is okay to have a WriteRegion completely outside
558 * the screen buffer. No data is written then.
559 */
560 return STATUS_SUCCESS;
561 }
562
563 CurCharInfo = CharInfo;
564
565 for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
566 {
567 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
568 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
569 {
570 if (Unicode)
571 {
572 Ptr->Char.UnicodeChar = CurCharInfo->Char.UnicodeChar;
573 }
574 else
575 {
576 ConsoleOutputAnsiToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char.AsciiChar);
577 }
578 Ptr->Attributes = CurCharInfo->Attributes;
579 ++Ptr;
580 ++CurCharInfo;
581 }
582 }
583
584 TermDrawRegion(Console, &CapturedWriteRegion);
585
586 *WriteRegion = CapturedWriteRegion;
587
588 return STATUS_SUCCESS;
589 }
590
591 /*
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.
595 */
596 NTSTATUS NTAPI
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)
602 {
603 SHORT X, Y;
604 SMALL_RECT ScreenBuffer;
605 PCHAR_CELL CurCharInfo;
606 SMALL_RECT CapturedWriteRegion;
607 PCHAR_INFO Ptr;
608
609 if (Console == NULL || Buffer == NULL || CharInfo == NULL || WriteRegion == NULL)
610 {
611 return STATUS_INVALID_PARAMETER;
612 }
613
614 /* Validity check */
615 ASSERT(Console == Buffer->Header.Console);
616
617 CapturedWriteRegion = *WriteRegion;
618
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))
624 {
625 /*
626 * It is okay to have a WriteRegion completely outside
627 * the screen buffer. No data is written then.
628 */
629 return STATUS_SUCCESS;
630 }
631
632 // CurCharInfo = CharInfo;
633
634 for (Y = CapturedWriteRegion.Top; Y <= CapturedWriteRegion.Bottom; ++Y)
635 {
636 /**/CurCharInfo = CharInfo + Y * CharInfoSize.X + CapturedWriteRegion.Left;/**/
637
638 Ptr = ConioCoordToPointer(Buffer, CapturedWriteRegion.Left, Y);
639 for (X = CapturedWriteRegion.Left; X <= CapturedWriteRegion.Right; ++X)
640 {
641 ConsoleOutputAnsiToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char);
642 Ptr->Attributes = CurCharInfo->Attributes;
643 ++Ptr;
644 ++CurCharInfo;
645 }
646 }
647
648 return STATUS_SUCCESS;
649 }
650
651 NTSTATUS NTAPI
652 ConDrvWriteConsole(IN PCONSOLE Console,
653 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
654 IN BOOLEAN Unicode,
655 IN PVOID StringBuffer,
656 IN ULONG NumCharsToWrite,
657 OUT PULONG NumCharsWritten OPTIONAL)
658 {
659 NTSTATUS Status = STATUS_SUCCESS;
660 PWCHAR Buffer = NULL;
661 ULONG Written = 0;
662 ULONG Length;
663
664 if (Console == NULL || ScreenBuffer == NULL /* || StringBuffer == NULL */)
665 return STATUS_INVALID_PARAMETER;
666
667 /* Validity checks */
668 ASSERT(Console == ScreenBuffer->Header.Console);
669 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCharsToWrite == 0));
670
671 /* Stop here if the console is paused */
672 if (Console->UnpauseEvent != NULL) return STATUS_PENDING;
673
674 /* Convert the string to UNICODE */
675 if (Unicode)
676 {
677 Buffer = StringBuffer;
678 }
679 else
680 {
681 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
682 (PCHAR)StringBuffer,
683 NumCharsToWrite,
684 NULL, 0);
685 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
686 if (Buffer)
687 {
688 MultiByteToWideChar(Console->OutputCodePage, 0,
689 (PCHAR)StringBuffer,
690 NumCharsToWrite,
691 (PWCHAR)Buffer, Length);
692 }
693 else
694 {
695 Status = STATUS_NO_MEMORY;
696 }
697 }
698
699 /* Send it */
700 if (Buffer)
701 {
702 if (NT_SUCCESS(Status))
703 {
704 Status = TermWriteStream(Console,
705 ScreenBuffer,
706 Buffer,
707 NumCharsToWrite,
708 TRUE);
709 if (NT_SUCCESS(Status))
710 {
711 Written = NumCharsToWrite;
712 }
713 }
714
715 if (!Unicode) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
716 }
717
718 if (NumCharsWritten) *NumCharsWritten = Written;
719
720 return Status;
721 }
722
723 NTSTATUS FASTCALL
724 IntReadConsoleOutputStringAscii(IN PCONSOLE Console,
725 IN PTEXTMODE_SCREEN_BUFFER Buffer,
726 OUT PVOID StringBuffer,
727 IN ULONG NumCodesToRead,
728 IN PCOORD ReadCoord,
729 OUT PULONG NumCodesRead OPTIONAL)
730 {
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;
735 ULONG i;
736 PCHAR_INFO Ptr;
737 BOOL bCJK = Console->IsCJK;
738
739 for (i = 0; i < NumCodesToRead; ++i)
740 {
741 Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
742
743 ConsoleOutputUnicodeToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
744 ReadBuffer += CodeSize;
745
746 Xpos++;
747 if (Xpos == Buffer->ScreenBufferSize.X)
748 {
749 Xpos = 0;
750 Ypos++;
751 if (Ypos == Buffer->ScreenBufferSize.Y)
752 {
753 Ypos = 0;
754 }
755 }
756
757 /* For Chinese, Japanese and Korean */
758 if (bCJK && (Ptr->Attributes & COMMON_LVB_LEADING_BYTE))
759 {
760 Xpos++;
761 if (Xpos == Buffer->ScreenBufferSize.X)
762 {
763 Xpos = 0;
764 Ypos++;
765 if (Ypos == Buffer->ScreenBufferSize.Y)
766 {
767 Ypos = 0;
768 }
769 }
770 ++i;
771 }
772 }
773
774 if (NumCodesRead)
775 *NumCodesRead = i;
776
777 return STATUS_SUCCESS;
778 }
779
780 NTSTATUS FASTCALL
781 IntReadConsoleOutputStringUnicode(IN PCONSOLE Console,
782 IN PTEXTMODE_SCREEN_BUFFER Buffer,
783 OUT PVOID StringBuffer,
784 IN ULONG NumCodesToRead,
785 IN PCOORD ReadCoord,
786 OUT PULONG NumCodesRead OPTIONAL)
787 {
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;
793 PCHAR_INFO Ptr;
794 BOOL bCJK = Console->IsCJK;
795
796 for (i = 0; i < NumCodesToRead; ++i, ++nNumChars)
797 {
798 Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
799
800 *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
801 ReadBuffer += CodeSize;
802
803 Xpos++;
804 if (Xpos == Buffer->ScreenBufferSize.X)
805 {
806 Xpos = 0;
807 Ypos++;
808 if (Ypos == Buffer->ScreenBufferSize.Y)
809 {
810 Ypos = 0;
811 }
812 }
813
814 /* For Chinese, Japanese and Korean */
815 if (bCJK && (Ptr->Attributes & COMMON_LVB_LEADING_BYTE))
816 {
817 Xpos++;
818 if (Xpos == Buffer->ScreenBufferSize.X)
819 {
820 Xpos = 0;
821 Ypos++;
822 if (Ypos == Buffer->ScreenBufferSize.Y)
823 {
824 Ypos = 0;
825 }
826 }
827 ++i;
828 }
829 }
830
831 if (NumCodesRead)
832 *NumCodesRead = nNumChars;
833
834 return STATUS_SUCCESS;
835 }
836
837 NTSTATUS FASTCALL
838 IntReadConsoleOutputStringAttributes(IN PCONSOLE Console,
839 IN PTEXTMODE_SCREEN_BUFFER Buffer,
840 OUT PVOID StringBuffer,
841 IN ULONG NumCodesToRead,
842 IN PCOORD ReadCoord,
843 OUT PULONG NumCodesRead OPTIONAL)
844 {
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;
849 ULONG i;
850 PCHAR_INFO Ptr;
851
852 for (i = 0; i < NumCodesToRead; ++i)
853 {
854 Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
855
856 *(PWORD)ReadBuffer = Ptr->Attributes;
857 ReadBuffer += CodeSize;
858
859 Xpos++;
860 if (Xpos == Buffer->ScreenBufferSize.X)
861 {
862 Xpos = 0;
863 Ypos++;
864 if (Ypos == Buffer->ScreenBufferSize.Y)
865 {
866 Ypos = 0;
867 }
868 }
869 }
870
871 if (Xpos > 0 && Console->IsCJK)
872 {
873 ReadBuffer -= CodeSize;
874 *(PWORD)ReadBuffer &= ~COMMON_LVB_LEADING_BYTE;
875 }
876
877 if (NumCodesRead)
878 *NumCodesRead = NumCodesToRead;
879
880 return STATUS_SUCCESS;
881 }
882
883 NTSTATUS NTAPI
884 ConDrvReadConsoleOutputString(IN PCONSOLE Console,
885 IN PTEXTMODE_SCREEN_BUFFER Buffer,
886 IN CODE_TYPE CodeType,
887 OUT PVOID StringBuffer,
888 IN ULONG NumCodesToRead,
889 IN PCOORD ReadCoord,
890 OUT PULONG NumCodesRead OPTIONAL)
891 {
892 if (Console == NULL || Buffer == NULL || ReadCoord == NULL /* || EndCoord == NULL */)
893 {
894 return STATUS_INVALID_PARAMETER;
895 }
896
897 /* Validity checks */
898 ASSERT(Console == Buffer->Header.Console);
899 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToRead == 0));
900
901 if (NumCodesRead)
902 *NumCodesRead = 0;
903
904 switch (CodeType)
905 {
906 case CODE_ASCII:
907 return IntReadConsoleOutputStringAscii(Console,
908 Buffer,
909 StringBuffer,
910 NumCodesToRead,
911 ReadCoord,
912 NumCodesRead);
913
914 case CODE_UNICODE:
915 return IntReadConsoleOutputStringUnicode(Console,
916 Buffer,
917 StringBuffer,
918 NumCodesToRead,
919 ReadCoord,
920 NumCodesRead);
921
922 case CODE_ATTRIBUTE:
923 return IntReadConsoleOutputStringAttributes(Console,
924 Buffer,
925 StringBuffer,
926 NumCodesToRead,
927 ReadCoord,
928 NumCodesRead);
929
930 default:
931 return STATUS_INVALID_PARAMETER;
932 }
933 }
934
935 NTSTATUS NTAPI
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)
944 {
945 NTSTATUS Status = STATUS_SUCCESS;
946 PVOID WriteBuffer = NULL;
947 PWCHAR tmpString = NULL;
948 ULONG X, Y, Length; // , Written = 0;
949 ULONG CodeSize;
950 PCHAR_INFO Ptr;
951
952 if (Console == NULL || Buffer == NULL || WriteCoord == NULL /* || EndCoord == NULL */)
953 {
954 return STATUS_INVALID_PARAMETER;
955 }
956
957 /* Validity checks */
958 ASSERT(Console == Buffer->Header.Console);
959 ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToWrite == 0));
960
961 //
962 // FIXME: Make overflow checks on WriteCoord !!!!!!
963 //
964
965 if (NumCodesWritten) *NumCodesWritten = 0;
966
967 switch (CodeType)
968 {
969 case CODE_ASCII:
970 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
971 break;
972
973 case CODE_UNICODE:
974 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
975 break;
976
977 case CODE_ATTRIBUTE:
978 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
979 break;
980
981 default:
982 return STATUS_INVALID_PARAMETER;
983 }
984
985 if (CodeType == CODE_ASCII)
986 {
987 /* Convert the ASCII string into Unicode before writing it to the console */
988 Length = MultiByteToWideChar(Console->OutputCodePage, 0,
989 (PCHAR)StringBuffer,
990 NumCodesToWrite,
991 NULL, 0);
992 tmpString = WriteBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
993 if (WriteBuffer)
994 {
995 MultiByteToWideChar(Console->OutputCodePage, 0,
996 (PCHAR)StringBuffer,
997 NumCodesToWrite,
998 (PWCHAR)WriteBuffer, Length);
999 }
1000 else
1001 {
1002 Status = STATUS_NO_MEMORY;
1003 }
1004
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);
1010 }
1011 else
1012 {
1013 /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
1014 WriteBuffer = StringBuffer;
1015 }
1016
1017 if (WriteBuffer == NULL || !NT_SUCCESS(Status)) goto Cleanup;
1018
1019 X = WriteCoord->X;
1020 Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1021 Length = NumCodesToWrite;
1022
1023 while (Length--)
1024 {
1025 Ptr = ConioCoordToPointer(Buffer, X, Y);
1026
1027 switch (CodeType)
1028 {
1029 case CODE_ASCII:
1030 case CODE_UNICODE:
1031 Ptr->Char.UnicodeChar = *(PWCHAR)WriteBuffer;
1032 break;
1033
1034 case CODE_ATTRIBUTE:
1035 Ptr->Attributes = *(PWORD)WriteBuffer;
1036 break;
1037 }
1038 WriteBuffer = (PVOID)((ULONG_PTR)WriteBuffer + CodeSize);
1039 // ++Ptr;
1040
1041 // Written++;
1042 if (++X == Buffer->ScreenBufferSize.X)
1043 {
1044 X = 0;
1045
1046 if (++Y == Buffer->ScreenBufferSize.Y)
1047 {
1048 Y = 0;
1049 }
1050 }
1051 }
1052
1053 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1054 {
1055 SMALL_RECT UpdateRect;
1056 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
1057 TermDrawRegion(Console, &UpdateRect);
1058 }
1059
1060 // EndCoord->X = X;
1061 // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
1062
1063 Cleanup:
1064 if (tmpString) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString);
1065
1066 if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
1067 return Status;
1068 }
1069
1070 NTSTATUS NTAPI
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)
1078 {
1079 ULONG X, Y, i;
1080 PCHAR_INFO Ptr;
1081 BOOL bLead, bFullwidth;
1082
1083 if (Console == NULL || Buffer == NULL || WriteCoord == NULL)
1084 {
1085 return STATUS_INVALID_PARAMETER;
1086 }
1087
1088 /* Validity check */
1089 ASSERT(Console == Buffer->Header.Console);
1090
1091 //
1092 // FIXME: Make overflow checks on WriteCoord !!!!!!
1093 //
1094
1095 if (NumCodesWritten) *NumCodesWritten = 0;
1096
1097 if (CodeType == CODE_ASCII)
1098 {
1099 /* Conversion from the ASCII char to the UNICODE char */
1100 CODE_ELEMENT tmp;
1101 ConsoleOutputAnsiToUnicodeChar(Console, &tmp.UnicodeChar, &Code.AsciiChar);
1102 Code = tmp;
1103 }
1104
1105 X = WriteCoord->X;
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
1109
1110 /* For Chinese, Japanese and Korean */
1111 bLead = TRUE;
1112 bFullwidth = FALSE;
1113 if (Console->IsCJK)
1114 {
1115 bFullwidth = (mk_wcwidth_cjk(Code.UnicodeChar) == 2);
1116 if (X > 0)
1117 {
1118 Ptr = ConioCoordToPointer(Buffer, X - 1, Y);
1119 if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
1120 {
1121 Ptr->Char.UnicodeChar = L' ';
1122 Ptr->Attributes &= ~COMMON_LVB_LEADING_BYTE;
1123 }
1124 }
1125 }
1126
1127 for (i = 0; i < NumCodesToWrite; ++i)
1128 {
1129 Ptr = ConioCoordToPointer(Buffer, X, Y);
1130
1131 switch (CodeType)
1132 {
1133 case CODE_ASCII:
1134 case CODE_UNICODE:
1135 Ptr->Char.UnicodeChar = Code.UnicodeChar;
1136 Ptr->Attributes &= ~(COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE);
1137 if (bFullwidth)
1138 {
1139 if (bLead)
1140 Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
1141 else
1142 Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
1143 }
1144 break;
1145
1146 case CODE_ATTRIBUTE:
1147 Ptr->Attributes &= ~0xFF;
1148 Ptr->Attributes |= (Code.Attribute & 0xFF);
1149 break;
1150 }
1151 // ++Ptr;
1152
1153 // Written++;
1154 if (++X == Buffer->ScreenBufferSize.X)
1155 {
1156 X = 0;
1157
1158 if (++Y == Buffer->ScreenBufferSize.Y)
1159 {
1160 Y = 0;
1161 }
1162 }
1163
1164 bLead = !bLead;
1165 }
1166
1167 if ((NumCodesToWrite & 1) & bFullwidth)
1168 {
1169 if (X + Y * Buffer->ScreenBufferSize.X > 0)
1170 {
1171 Ptr = ConioCoordToPointer(Buffer, X - 1, Y);
1172 Ptr->Char.UnicodeChar = L' ';
1173 Ptr->Attributes &= ~(COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE);
1174 }
1175 }
1176
1177 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1178 {
1179 SMALL_RECT UpdateRect;
1180 ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
1181 TermDrawRegion(Console, &UpdateRect);
1182 }
1183
1184 if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
1185 return STATUS_SUCCESS;
1186 }
1187
1188 NTSTATUS NTAPI
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)
1197 {
1198 COORD LargestWindowSize;
1199
1200 if (Console == NULL || Buffer == NULL || ScreenBufferSize == NULL ||
1201 CursorPosition == NULL || ViewOrigin == NULL || ViewSize == NULL ||
1202 MaximumViewSize == NULL || Attributes == NULL)
1203 {
1204 return STATUS_INVALID_PARAMETER;
1205 }
1206
1207 /* Validity check */
1208 ASSERT(Console == Buffer->Header.Console);
1209
1210 *ScreenBufferSize = Buffer->ScreenBufferSize;
1211 *CursorPosition = Buffer->CursorPosition;
1212 *ViewOrigin = Buffer->ViewOrigin;
1213 *ViewSize = Buffer->ViewSize;
1214 *Attributes = Buffer->ScreenDefaultAttrib;
1215
1216 /*
1217 * Retrieve the largest possible console window size, taking
1218 * into account the size of the console screen buffer.
1219 */
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;
1224
1225 return STATUS_SUCCESS;
1226 }
1227
1228 NTSTATUS NTAPI
1229 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
1230 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1231 IN WORD Attributes)
1232 {
1233 if (Console == NULL || Buffer == NULL)
1234 return STATUS_INVALID_PARAMETER;
1235
1236 /* Validity check */
1237 ASSERT(Console == Buffer->Header.Console);
1238
1239 Buffer->ScreenDefaultAttrib = Attributes;
1240 return STATUS_SUCCESS;
1241 }
1242
1243 NTSTATUS NTAPI
1244 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
1245 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1246 IN PCOORD Size)
1247 {
1248 NTSTATUS Status;
1249
1250 if (Console == NULL || Buffer == NULL || Size == NULL)
1251 return STATUS_INVALID_PARAMETER;
1252
1253 /* Validity check */
1254 ASSERT(Console == Buffer->Header.Console);
1255
1256 Status = ConioResizeBuffer(Console, Buffer, *Size);
1257 if (NT_SUCCESS(Status)) TermResizeTerminal(Console);
1258
1259 return Status;
1260 }
1261
1262 NTSTATUS NTAPI
1263 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
1264 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1265 IN BOOLEAN Unicode,
1266 IN PSMALL_RECT ScrollRectangle,
1267 IN BOOLEAN UseClipRectangle,
1268 IN PSMALL_RECT ClipRectangle OPTIONAL,
1269 IN PCOORD DestinationOrigin,
1270 IN CHAR_INFO FillChar)
1271 {
1272 COORD CapturedDestinationOrigin;
1273 SMALL_RECT ScreenBuffer;
1274 SMALL_RECT SrcRegion;
1275 SMALL_RECT DstRegion;
1276 SMALL_RECT UpdateRegion;
1277 SMALL_RECT CapturedClipRectangle;
1278
1279 if (Console == NULL || Buffer == NULL || ScrollRectangle == NULL ||
1280 (UseClipRectangle ? ClipRectangle == NULL : FALSE) || DestinationOrigin == NULL)
1281 {
1282 return STATUS_INVALID_PARAMETER;
1283 }
1284
1285 /* Validity check */
1286 ASSERT(Console == Buffer->Header.Console);
1287
1288 CapturedDestinationOrigin = *DestinationOrigin;
1289
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))
1295 {
1296 return STATUS_SUCCESS;
1297 }
1298
1299 /* If the source was clipped on the left or top, adjust the destination accordingly */
1300 if (ScrollRectangle->Left < 0)
1301 {
1302 CapturedDestinationOrigin.X -= ScrollRectangle->Left;
1303 }
1304 if (ScrollRectangle->Top < 0)
1305 {
1306 CapturedDestinationOrigin.Y -= ScrollRectangle->Top;
1307 }
1308
1309 if (UseClipRectangle)
1310 {
1311 CapturedClipRectangle = *ClipRectangle;
1312 if (!ConioGetIntersection(&CapturedClipRectangle, &CapturedClipRectangle, &ScreenBuffer))
1313 {
1314 return STATUS_SUCCESS;
1315 }
1316 }
1317 else
1318 {
1319 CapturedClipRectangle = ScreenBuffer;
1320 }
1321
1322 ConioInitRect(&DstRegion,
1323 CapturedDestinationOrigin.Y,
1324 CapturedDestinationOrigin.X,
1325 CapturedDestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
1326 CapturedDestinationOrigin.X + ConioRectWidth(&SrcRegion ) - 1);
1327
1328 if (!Unicode)
1329 {
1330 WCHAR tmp;
1331 ConsoleOutputAnsiToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar);
1332 FillChar.Char.UnicodeChar = tmp;
1333 }
1334
1335 ConioMoveRegion(Buffer, &SrcRegion, &DstRegion, &CapturedClipRectangle, FillChar);
1336
1337 if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
1338 {
1339 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
1340 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &CapturedClipRectangle))
1341 {
1342 /* Draw update region */
1343 TermDrawRegion(Console, &UpdateRegion);
1344 }
1345 }
1346
1347 return STATUS_SUCCESS;
1348 }
1349
1350 NTSTATUS NTAPI
1351 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
1352 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1353 IN BOOLEAN Absolute,
1354 IN PSMALL_RECT WindowRect)
1355 {
1356 SMALL_RECT CapturedWindowRect;
1357 COORD LargestWindowSize;
1358
1359 if (Console == NULL || Buffer == NULL || WindowRect == NULL)
1360 return STATUS_INVALID_PARAMETER;
1361
1362 /* Validity check */
1363 ASSERT(Console == Buffer->Header.Console);
1364
1365 CapturedWindowRect = *WindowRect;
1366
1367 if (!Absolute)
1368 {
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;
1374 }
1375
1376 /*
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.
1383 */
1384 if ((CapturedWindowRect.Right < CapturedWindowRect.Left) ||
1385 (CapturedWindowRect.Bottom < CapturedWindowRect.Top))
1386 {
1387 return STATUS_INVALID_PARAMETER;
1388 }
1389
1390 /*
1391 * Forbid window sizes larger than the largest allowed console window size,
1392 * taking into account the size of the console screen buffer.
1393 */
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))
1399 {
1400 return STATUS_INVALID_PARAMETER;
1401 }
1402
1403 /* Shift the window rectangle coordinates if 'Left' or 'Top' are negative */
1404 if (CapturedWindowRect.Left < 0)
1405 {
1406 CapturedWindowRect.Right -= CapturedWindowRect.Left;
1407 CapturedWindowRect.Left = 0;
1408 }
1409 if (CapturedWindowRect.Top < 0)
1410 {
1411 CapturedWindowRect.Bottom -= CapturedWindowRect.Top;
1412 CapturedWindowRect.Top = 0;
1413 }
1414
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);
1418
1419 Buffer->ViewOrigin.X = CapturedWindowRect.Left;
1420 Buffer->ViewOrigin.Y = CapturedWindowRect.Top;
1421
1422 Buffer->ViewSize.X = CapturedWindowRect.Right - CapturedWindowRect.Left + 1;
1423 Buffer->ViewSize.Y = CapturedWindowRect.Bottom - CapturedWindowRect.Top + 1;
1424
1425 TermResizeTerminal(Console);
1426
1427 return STATUS_SUCCESS;
1428 }
1429
1430 /* EOF */