00217 :
00218
00219 This routine writes a string to
the screen, processing any embedded
00220 unicode characters. The string
is also copied to
the input buffer,
if
00221
the output mode
is line mode.
00222
00223 Arguments:
00224
00225 ScreenInfo - Pointer to screen buffer information structure.
00226
00227 lpBufferBackupLimit - Pointer to beginning of buffer.
00228
00229 lpBuffer - Pointer to buffer to copy string to. assumed to be at least
00230 as
long as lpRealUnicodeString. This pointer
is updated to point to
the
00231 next position in
the buffer.
00232
00233 lpRealUnicodeString - Pointer to string to write.
00234
00235 NumBytes - On input, number of bytes to write. On output, number of
00236 bytes written.
00237
00238 NumSpaces - On output,
the number of spaces consumed by
the written characters.
00239
00240
dwFlags -
00241
WC_DESTRUCTIVE_BACKSPACE backspace overwrites characters.
00242
WC_KEEP_CURSOR_VISIBLE change window origin desirable when hit rt. edge
00243
WC_ECHO if called by Read (echoing characters)
00244
WC_FALSIFY_UNICODE if RealUnicodeToFalseUnicode need be called.
00245
00246 Return Value:
00247
00248 Note:
00249
00250 This routine does not process tabs and backspace properly. That code
00251 will be implemented as part of
the line editing services.
00252
00253 --*/
00254
00255 {
00256
DWORD BufferSize;
00257 COORD CursorPosition;
00258
NTSTATUS Status;
00259 ULONG NumChars;
00260
static WCHAR Blanks[
TAB_SIZE] = {
UNICODE_SPACE,
00261
UNICODE_SPACE,
00262
UNICODE_SPACE,
00263
UNICODE_SPACE,
00264
UNICODE_SPACE,
00265
UNICODE_SPACE,
00266
UNICODE_SPACE,
00267
UNICODE_SPACE };
00268
SHORT XPosition;
00269 WCHAR LocalBuffer[
LOCAL_BUFFER_SIZE];
00270 PWCHAR LocalBufPtr;
00271 ULONG i,j;
00272 SMALL_RECT Region;
00273 ULONG TabSize;
00274
DWORD TempNumSpaces;
00275 WCHAR Char;
00276 WCHAR RealUnicodeChar;
00277 WORD Attributes;
00278 PWCHAR lpString;
00279 PWCHAR lpAllocatedString;
00280
BOOL fUnprocessed = ((ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT) == 0);
00281
#ifdef WWSB_FE
00282
CHAR LocalBufferA[
LOCAL_BUFFER_SIZE];
00283 PCHAR LocalBufPtrA;
00284
#endif
00285
00286
ConsoleHideCursor(ScreenInfo);
00287
00288 Attributes = ScreenInfo->Attributes;
00289
BufferSize = *NumBytes;
00290 *NumBytes = 0;
00291 TempNumSpaces = 0;
00292
00293 lpAllocatedString =
NULL;
00294
if (
dwFlags &
WC_FALSIFY_UNICODE) {
00295
00296
00297
00298
00299 lpString =
ConsoleHeapAlloc(
MAKE_TAG( TMP_TAG ),BufferSize);
00300
if (lpString ==
NULL) {
00301
Status = STATUS_NO_MEMORY;
00302
goto ExitWriteChars;
00303 }
00304
00305 lpAllocatedString = lpString;
00306 RtlCopyMemory(lpString, lpRealUnicodeString, BufferSize);
00307
Status =
RealUnicodeToFalseUnicode(lpString,
00308 BufferSize /
sizeof(WCHAR),
00309 ScreenInfo->Console->OutputCP
00310 );
00311
if (!
NT_SUCCESS(Status)) {
00312
goto ExitWriteChars;
00313 }
00314 }
else {
00315 lpString = lpRealUnicodeString;
00316 }
00317
00318
while (*NumBytes <
BufferSize) {
00319
00320
00321
00322
00323
00324
00325 XPosition = ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
00326 i=0;
00327 LocalBufPtr = LocalBuffer;
00328
#ifdef WWSB_FE
00329
LocalBufPtrA = LocalBufferA;
00330
#endif
00331
while (*NumBytes <
BufferSize &&
00332 i <
LOCAL_BUFFER_SIZE &&
00333 XPosition < ScreenInfo->ScreenBufferSize.X) {
00334 Char = *lpString;
00335 RealUnicodeChar = *lpRealUnicodeString;
00336
if (!
IS_GLYPH_CHAR(RealUnicodeChar) || fUnprocessed) {
00337
#ifdef WWSB_FE
00338
if (IsConsoleFullWidth(ScreenInfo->Console->hDC,
00339 ScreenInfo->Console->OutputCP,Char)) {
00340
if (i < (
LOCAL_BUFFER_SIZE-1) &&
00341 XPosition < (ScreenInfo->ScreenBufferSize.X-1)) {
00342 *LocalBufPtr++ = Char;
00343 *LocalBufPtrA++ = ATTR_LEADING_BYTE;
00344 *LocalBufPtr++ = Char;
00345 *LocalBufPtrA++ = ATTR_TRAILING_BYTE;
00346 XPosition+=2;
00347 i+=2;
00348 lpBuffer++;
00349 }
00350
else
00351
goto EndWhile;
00352 }
00353
else {
00354
#endif
00355
*LocalBufPtr = Char;
00356 LocalBufPtr++;
00357 XPosition++;
00358 i++;
00359 lpBuffer++;
00360
#ifdef WWSB_FE
00361
*LocalBufPtrA++ = 0;
00362 }
00363
#endif
00364
}
else {
00365
ASSERT(ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT);
00366
switch (RealUnicodeChar) {
00367
case UNICODE_BELL:
00368
if (
dwFlags &
WC_ECHO) {
00369
goto CtrlChar;
00370 }
else {
00371
SendNotifyMessage(ScreenInfo->Console->hWnd,
00372 CM_BEEP,
00373 0,
00374 0x47474747);
00375 }
00376
break;
00377
case UNICODE_BACKSPACE:
00378
00379
00380
00381
00382
00383
00384
00385
00386
goto EndWhile;
00387
break;
00388
case UNICODE_TAB:
00389 TabSize =
NUMBER_OF_SPACES_IN_TAB(XPosition);
00390 XPosition = (
SHORT)(XPosition + TabSize);
00391
if (XPosition >= ScreenInfo->ScreenBufferSize.X) {
00392
goto EndWhile;
00393 }
00394
for (j=0;j<TabSize && i<
LOCAL_BUFFER_SIZE;j++,i++) {
00395 *LocalBufPtr = (WCHAR)
' ';
00396 LocalBufPtr++;
00397
#ifdef WWSB_FE
00398
*LocalBufPtrA++ = 0;
00399
#endif
00400
}
00401 lpBuffer++;
00402
break;
00403
case UNICODE_LINEFEED:
00404
case UNICODE_CARRIAGERETURN:
00405
goto EndWhile;
00406
default:
00407
00408
00409
00410
00411
00412
if ((
dwFlags &
WC_ECHO) && (
IS_CONTROL_CHAR(RealUnicodeChar))) {
00413
00414 CtrlChar:
if (i < (
LOCAL_BUFFER_SIZE-1)) {
00415 *LocalBufPtr = (WCHAR)
'^';
00416 LocalBufPtr++;
00417 XPosition++;
00418 i++;
00419 *LocalBufPtr = (WCHAR)(RealUnicodeChar+(WCHAR)
'@');
00420 LocalBufPtr++;
00421 XPosition++;
00422 i++;
00423 lpBuffer++;
00424
#ifdef WWSB_FE
00425
*LocalBufPtrA++ = 0;
00426 *LocalBufPtrA++ = 0;
00427
#endif
00428
}
00429
else {
00430
goto EndWhile;
00431 }
00432 }
else {
00433
if (!(ScreenInfo->Flags &
CONSOLE_OEMFONT_DISPLAY) ||
00434 (ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
00435
00436
00437
00438
00439
00440
#ifdef WWSB_FE
00441
WORD CharType;
00442
00443 GetStringTypeW(CT_CTYPE1,&RealUnicodeChar,1,&CharType);
00444
if (CharType == C1_CNTRL)
00445
ConvertOutputToUnicode(ScreenInfo->Console->OutputCP,
00446 &(
char)RealUnicodeChar,
00447 1,
00448 LocalBufPtr,
00449 1);
00450
else
00451 *LocalBufPtr = Char;
00452
#else
00453
*LocalBufPtr = SB_CharToWcharGlyph(
00454 ScreenInfo->Console->OutputCP,
00455 (
char)RealUnicodeChar);
00456
#endif
00457
}
else {
00458 *LocalBufPtr = Char;
00459 }
00460 LocalBufPtr++;
00461 XPosition++;
00462 i++;
00463 lpBuffer++;
00464
#ifdef WWSB_FE
00465
*LocalBufPtrA++ = 0;
00466
#endif
00467
}
00468 }
00469 }
00470 lpString++;
00471 lpRealUnicodeString++;
00472 *NumBytes +=
sizeof(WCHAR);
00473 }
00474 EndWhile:
00475
if (i != 0) {
00476
00477
00478
00479
00480
00481
if (i > (ULONG)ScreenInfo->ScreenBufferSize.X - ScreenInfo->BufferInfo.TextInfo.CursorPosition.X) {
00482 i = (ULONG)ScreenInfo->ScreenBufferSize.X - ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
00483 }
00484
00485
#ifdef WWSB_FE
00486
FE_StreamWriteToScreenBuffer(LocalBuffer,
00487 (SHORT)i,
00488 ScreenInfo,
00489 LocalBufferA
00490 );
00491
#else
00492
SB_StreamWriteToScreenBuffer(LocalBuffer,
00493 (SHORT)i,
00494 ScreenInfo
00495 );
00496
#endif
00497
Region.Left = ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
00498 Region.Right = (
SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X + i - 1);
00499 Region.Top = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
00500 Region.Bottom = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
00501
WWSB_WriteToScreen(ScreenInfo,&Region);
00502 TempNumSpaces += i;
00503 CursorPosition.X = (
SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X + i);
00504 CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
00505
Status =
WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
00506 dwFlags & WC_KEEP_CURSOR_VISIBLE,ScrollY);
00507
if (*NumBytes ==
BufferSize) {
00508
ConsoleShowCursor(ScreenInfo);
00509
if (ARGUMENT_PRESENT(NumSpaces)) {
00510 *NumSpaces = TempNumSpaces;
00511 }
00512
Status = STATUS_SUCCESS;
00513
goto ExitWriteChars;
00514 }
00515
continue;
00516 }
else if (*NumBytes ==
BufferSize) {
00517
00518
ASSERT(ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT);
00519
00520
00521
if (ARGUMENT_PRESENT(NumSpaces)) {
00522 *NumSpaces = TempNumSpaces;
00523 }
00524
ConsoleShowCursor(ScreenInfo);
00525
Status = STATUS_SUCCESS;
00526
goto ExitWriteChars;
00527 }
00528
00529
ASSERT(ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT);
00530
switch (*lpString) {
00531
case UNICODE_BACKSPACE:
00532
00533
00534
00535
00536
00537
00538 CursorPosition = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
00539 TempNumSpaces -= 1;
00540
if (lpBuffer == lpBufferBackupLimit) {
00541 CursorPosition.X-=1;
00542 }
00543
else {
00544 PWCHAR pBuffer;
00545 WCHAR TmpBuffer[
LOCAL_BUFFER_SIZE];
00546 PWCHAR Tmp,Tmp2;
00547 WCHAR LastChar;
00548 ULONG i;
00549
00550
if (lpBuffer-lpBufferBackupLimit >
LOCAL_BUFFER_SIZE) {
00551 pBuffer = (PWCHAR)
ConsoleHeapAlloc(
MAKE_TAG( TMP_TAG ),(ULONG)(lpBuffer-lpBufferBackupLimit) *
sizeof(WCHAR));
00552
if (pBuffer ==
NULL) {
00553
Status = STATUS_NO_MEMORY;
00554
goto ExitWriteChars;
00555 }
00556 }
else {
00557 pBuffer = TmpBuffer;
00558 }
00559
00560
for (i=0,Tmp2=pBuffer,Tmp=lpBufferBackupLimit;
00561 i<(ULONG)(lpBuffer-lpBufferBackupLimit);
00562 i++,Tmp++) {
00563
if (*Tmp ==
UNICODE_BACKSPACE) {
00564
if (Tmp2 > pBuffer) {
00565 Tmp2--;
00566 }
00567 }
else {
00568
ASSERT(Tmp2 >= pBuffer);
00569 *Tmp2++ = *Tmp;
00570 }
00571
00572 }
00573
if (Tmp2 == pBuffer) {
00574 LastChar = (WCHAR)
' ';
00575 }
else {
00576 LastChar = *(Tmp2-1);
00577 }
00578
if (pBuffer != TmpBuffer) {
00579
ConsoleHeapFree(pBuffer);
00580 }
00581
00582
if (LastChar ==
UNICODE_TAB) {
00583 CursorPosition.X -=
00584 (
SHORT)(
RetrieveNumberOfSpaces(OriginalXPosition,
00585 lpBufferBackupLimit,
00586 (ULONG)(lpBuffer - lpBufferBackupLimit - 1),
00587 ScreenInfo->Console,
00588 ScreenInfo->Console->OutputCP
00589 ));
00590
if (CursorPosition.X < 0) {
00591 CursorPosition.X = (ScreenInfo->ScreenBufferSize.X - 1)/
TAB_SIZE;
00592 CursorPosition.X *=
TAB_SIZE;
00593 CursorPosition.X += 1;
00594 CursorPosition.Y -= 1;
00595 }
00596 }
00597
else if (
IS_CONTROL_CHAR(LastChar)) {
00598 CursorPosition.X-=1;
00599 TempNumSpaces -= 1;
00600
00601
00602
00603
00604
00605
if (
dwFlags &
WC_DESTRUCTIVE_BACKSPACE) {
00606 NumChars = 1;
00607
Status =
WWSB_WriteOutputString(ScreenInfo,
00608 Blanks, CursorPosition,
00609 CONSOLE_FALSE_UNICODE,
00610 &NumChars, NULL);
00611
Status =
WWSB_FillOutput(ScreenInfo,
00612 Attributes, CursorPosition,
00613 CONSOLE_ATTRIBUTE, &NumChars);
00614 }
00615 CursorPosition.X-=1;
00616 }
00617
#ifdef WWSB_FE
00618
else if (IsConsoleFullWidth(ScreenInfo->Console->hDC,
00619 ScreenInfo->Console->OutputCP,LastChar))
00620 {
00621 CursorPosition.X-=1;
00622 TempNumSpaces -= 1;
00623
00624
Status =
WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
00625 dwFlags & WC_KEEP_CURSOR_VISIBLE,ScrollY);
00626
if (
dwFlags &
WC_DESTRUCTIVE_BACKSPACE) {
00627 NumChars = 1;
00628
Status =
WWSB_WriteOutputString(ScreenInfo,
00629 Blanks, ScreenInfo->BufferInfo.TextInfo.CursorPosition,
00630 CONSOLE_FALSE_UNICODE,
00631 &NumChars, NULL);
00632
Status =
WWSB_FillOutput(ScreenInfo,
00633 Attributes, ScreenInfo->BufferInfo.TextInfo.CursorPosition,
00634 CONSOLE_ATTRIBUTE, &NumChars);
00635 }
00636 CursorPosition.X-=1;
00637 }
00638
#endif
00639
else {
00640 CursorPosition.X--;
00641 }
00642 }
00643
if ((
dwFlags &
WC_LIMIT_BACKSPACE) && (CursorPosition.X < 0)) {
00644 CursorPosition.X = 0;
00645 KdPrint((
"CONSRV: Ignoring backspace to previous line\n"));
00646 }
00647
Status =
WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
00648 (dwFlags & WC_KEEP_CURSOR_VISIBLE) != 0,ScrollY);
00649
if (
dwFlags &
WC_DESTRUCTIVE_BACKSPACE) {
00650 NumChars = 1;
00651
Status =
WWSB_WriteOutputString(ScreenInfo,
00652 Blanks, ScreenInfo->BufferInfo.TextInfo.CursorPosition,
00653 CONSOLE_FALSE_UNICODE,
00654 &NumChars, NULL);
00655
Status =
WWSB_FillOutput(ScreenInfo,
00656 Attributes, ScreenInfo->BufferInfo.TextInfo.CursorPosition,
00657 CONSOLE_ATTRIBUTE, &NumChars);
00658 }
00659
#ifdef WWSB_FE
00660
if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X == 0 &&
00661 (ScreenInfo->OutputMode & ENABLE_WRAP_AT_EOL_OUTPUT) &&
00662 lpBuffer > lpBufferBackupLimit) {
00663
if (CheckBisectProcessW(ScreenInfo,
00664 ScreenInfo->Console->OutputCP,
00665 lpBufferBackupLimit,
00666 (ULONG)(lpBuffer+1-lpBufferBackupLimit),
00667 ScreenInfo->ScreenBufferSize.X-OriginalXPosition,
00668 OriginalXPosition,
00669 dwFlags & WC_ECHO)) {
00670 CursorPosition.X = ScreenInfo->ScreenBufferSize.X-1;
00671 CursorPosition.Y = (
SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y-1);
00672
Status =
WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
00673 dwFlags & WC_KEEP_CURSOR_VISIBLE,ScrollY);
00674 }
00675 }
00676
#endif
00677
break;
00678
case UNICODE_TAB:
00679 TabSize =
NUMBER_OF_SPACES_IN_TAB(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X);
00680 CursorPosition.X = (
SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X + TabSize);
00681
00682
00683
00684
00685
00686
00687
00688
00689 lpBuffer++;
00690
00691 TempNumSpaces += TabSize;
00692
if (CursorPosition.X >= ScreenInfo->ScreenBufferSize.X) {
00693 NumChars = ScreenInfo->ScreenBufferSize.X - ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
00694 CursorPosition.X = 0;
00695 CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+1;
00696 }
00697
else {
00698 NumChars = CursorPosition.X - ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
00699 CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
00700 }
00701
Status =
WWSB_WriteOutputString(ScreenInfo,
00702 Blanks,
00703 ScreenInfo->BufferInfo.TextInfo.CursorPosition,
00704 CONSOLE_FALSE_UNICODE,
00705 &NumChars,
00706 NULL);
00707
Status =
WWSB_FillOutput(ScreenInfo,
00708 Attributes, ScreenInfo->BufferInfo.TextInfo.CursorPosition,
00709 CONSOLE_ATTRIBUTE,
00710 &NumChars);
00711
Status =
WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
00712 (dwFlags & WC_KEEP_CURSOR_VISIBLE) != 0,ScrollY);
00713
break;
00714
case UNICODE_CARRIAGERETURN:
00715
00716
00717
00718
00719
00720
00721
00722 lpBuffer++;
00723 CursorPosition.X = 0;
00724 CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
00725
Status =
WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
00726 (dwFlags & WC_KEEP_CURSOR_VISIBLE) != 0,ScrollY);
00727
break;
00728
case UNICODE_LINEFEED:
00729
00730
00731
00732
00733
00734 lpBuffer++;
00735 CursorPosition.X = 0;
00736 CursorPosition.Y = (
SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+1);
00737
Status =
WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
00738 (dwFlags & WC_KEEP_CURSOR_VISIBLE) != 0,ScrollY);
00739
break;
00740
default:
00741
#ifdef WWSB_FE
00742
Char = *lpString;
00743
if (Char >= (WCHAR)
' ' &&
00744 IsConsoleFullWidth(ScreenInfo->Console->hDC,
00745 ScreenInfo->Console->OutputCP,Char) &&
00746 XPosition >= (ScreenInfo->ScreenBufferSize.X-1) &&
00747 (ScreenInfo->OutputMode & ENABLE_WRAP_AT_EOL_OUTPUT)) {
00748
00749
SHORT RowIndex;
00750
PROW Row;
00751 PWCHAR Char;
00752 COORD TargetPoint;
00753 PCHAR AttrP;
00754
00755 TargetPoint = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
00756 RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
00757 Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
00758 Char = &Row->
CharRow.
Chars[TargetPoint.X];
00759 AttrP = &Row->
CharRow.KAttrs[TargetPoint.X];
00760
00761
if (*AttrP & ATTR_TRAILING_BYTE)
00762 {
00763 *(Char-1) =
UNICODE_SPACE;
00764 *Char =
UNICODE_SPACE;
00765 *AttrP = 0;
00766 *(AttrP-1) = 0;
00767
00768 Region.Left = ScreenInfo->BufferInfo.TextInfo.CursorPosition.X-1;
00769 Region.Right = (
SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X);
00770 Region.Top = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
00771 Region.Bottom = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
00772
WWSB_WriteToScreen(ScreenInfo,&Region);
00773 }
00774
00775 CursorPosition.X = 0;
00776 CursorPosition.Y = (
SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+1);
00777
Status =
WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
00778 dwFlags & WC_KEEP_CURSOR_VISIBLE,ScrollY);
00779
continue;
00780 }
00781
#endif
00782
break;
00783 }
00784
if (!
NT_SUCCESS(Status)) {
00785
ConsoleShowCursor(ScreenInfo);
00786
goto ExitWriteChars;
00787 }
00788
00789 *NumBytes +=
sizeof(WCHAR);
00790 lpString++;
00791 lpRealUnicodeString++;
00792 }
00793
00794
if (ARGUMENT_PRESENT(NumSpaces)) {
00795 *NumSpaces = TempNumSpaces;
00796 }
00797
ConsoleShowCursor(ScreenInfo);
00798
00799
Status = STATUS_SUCCESS;
00800
00801 ExitWriteChars:
00802
if (lpAllocatedString) {
00803
ConsoleHeapFree(lpAllocatedString);
00804 }
00805
return Status;
00806 }