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