Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6182 lines
202 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. output.c
  5. Abstract:
  6. This file implements the video buffer management.
  7. Author:
  8. Therese Stowell (thereses) 6-Nov-1990
  9. Revision History:
  10. Notes:
  11. ScreenBuffer data structure overview:
  12. each screen buffer has an array of ROW structures. each ROW structure
  13. contains the data for one row of text. the data stored for one row of
  14. text is a character array and an attribute array. the character array
  15. is allocated the full length of the row from the heap, regardless of the
  16. non-space length. we also maintain the non-space length. the character
  17. array is initialized to spaces. the attribute
  18. array is run length encoded (i.e 5 BLUE, 3 RED). if there is only one
  19. attribute for the whole row (the normal case), it is stored in the ATTR_ROW
  20. structure. otherwise the attr string is allocated from the heap.
  21. ROW - CHAR_ROW - CHAR string
  22. \ \ length of char string
  23. \
  24. ATTR_ROW - ATTR_PAIR string
  25. \ length of attr pair string
  26. ROW
  27. ROW
  28. ROW
  29. ScreenInfo->Rows points to the ROW array. ScreenInfo->Rows[0] is not
  30. necessarily the top row. ScreenInfo->BufferInfo.TextInfo.FirstRow contains the index of
  31. the top row. That means scrolling (if scrolling entire screen)
  32. merely involves changing the FirstRow index,
  33. filling in the last row, and updating the screen.
  34. --*/
  35. #include "precomp.h"
  36. #pragma hdrstop
  37. //#define PROFILE_GDI
  38. #ifdef PROFILE_GDI
  39. LONG ScrollDCCount;
  40. LONG ExtTextOutCount;
  41. LONG TextColor = 1;
  42. #define SCROLLDC_CALL ScrollDCCount++
  43. #define TEXTOUT_CALL ExtTextOutCount++
  44. #define TEXTCOLOR_CALL TextColor++
  45. #else
  46. #define SCROLLDC_CALL
  47. #define TEXTOUT_CALL
  48. #define TEXTCOLOR_CALL
  49. #endif // PROFILE_GDI
  50. #define ITEM_MAX_SIZE 256
  51. // NOTE: we use this to communicate with progman - see Q105446 for details.
  52. typedef struct _PMIconData {
  53. DWORD dwResSize;
  54. DWORD dwVer;
  55. BYTE iResource; // icon resource
  56. } PMICONDATA, *LPPMICONDATA;
  57. //
  58. // Screen dimensions
  59. //
  60. int ConsoleFullScreenX;
  61. int ConsoleFullScreenY;
  62. int ConsoleCaptionY;
  63. int MinimumWidthX;
  64. SHORT VerticalScrollSize;
  65. SHORT HorizontalScrollSize;
  66. SHORT VerticalClientToWindow;
  67. SHORT HorizontalClientToWindow;
  68. PCHAR_INFO ScrollBuffer;
  69. ULONG ScrollBufferSize;
  70. CRITICAL_SECTION ScrollBufferLock;
  71. // this value keeps track of the number of existing console windows.
  72. // if a window is created when this value is zero, the Face Names
  73. // must be reenumerated because no WM_FONTCHANGE message was processed
  74. // if there's no window.
  75. LONG gnConsoleWindows;
  76. BOOL gfInitSystemMetrics;
  77. BOOL UsePolyTextOut;
  78. HRGN ghrgnScroll;
  79. LPRGNDATA gprgnData;
  80. ULONG gucWheelScrollLines;
  81. UINT guCaretBlinkTime;
  82. #define GRGNDATASIZE (sizeof(RGNDATAHEADER) + (6 * sizeof(RECTL)))
  83. #define LockScrollBuffer() RtlEnterCriticalSection(&ScrollBufferLock)
  84. #define UnlockScrollBuffer() RtlLeaveCriticalSection(&ScrollBufferLock)
  85. #define SetWindowConsole(hWnd, Console) SetWindowLongPtr((hWnd), GWLP_USERDATA, (LONG_PTR)(Console))
  86. #ifdef LATER
  87. #ifndef IS_IME_KBDLAYOUT
  88. #define IS_IME_KBDLAYOUT(hkl) ((((ULONG_PTR)(hkl)) & 0xf0000000) == 0xe0000000)
  89. #endif
  90. #endif
  91. VOID GetNonBiDiKeyboardLayout(
  92. HKL *phklActive);
  93. VOID FreeConsoleBitmap(
  94. IN PSCREEN_INFORMATION ScreenInfo);
  95. VOID
  96. ScrollIfNecessary(
  97. IN PCONSOLE_INFORMATION Console,
  98. IN PSCREEN_INFORMATION ScreenInfo
  99. );
  100. VOID
  101. ProcessResizeWindow(
  102. IN PSCREEN_INFORMATION ScreenInfo,
  103. IN PCONSOLE_INFORMATION Console,
  104. IN LPWINDOWPOS WindowPos
  105. );
  106. NTSTATUS
  107. AllocateScrollBuffer(
  108. DWORD Size
  109. );
  110. VOID FreeScrollBuffer ( VOID );
  111. VOID
  112. InternalUpdateScrollBars(
  113. IN PSCREEN_INFORMATION ScreenInfo
  114. );
  115. #if defined(FE_SB)
  116. BOOL
  117. SB_PolyTextOutCandidate(
  118. IN PSCREEN_INFORMATION ScreenInfo,
  119. IN PSMALL_RECT Region
  120. );
  121. VOID
  122. SB_ConsolePolyTextOut(
  123. IN PSCREEN_INFORMATION ScreenInfo,
  124. IN PSMALL_RECT Region
  125. );
  126. #endif
  127. VOID
  128. InitializeSystemMetrics( VOID )
  129. {
  130. RECT WindowSize;
  131. gfInitSystemMetrics = FALSE;
  132. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &gucWheelScrollLines, FALSE);
  133. ConsoleFullScreenX = GetSystemMetrics(SM_CXFULLSCREEN);
  134. ConsoleFullScreenY = GetSystemMetrics(SM_CYFULLSCREEN);
  135. ConsoleCaptionY = GetSystemMetrics(SM_CYCAPTION);
  136. VerticalScrollSize = (SHORT)GetSystemMetrics(SM_CXVSCROLL);
  137. HorizontalScrollSize = (SHORT)GetSystemMetrics(SM_CYHSCROLL);
  138. WindowSize.left = WindowSize.top = 0;
  139. WindowSize.right = WindowSize.bottom = 50;
  140. AdjustWindowRectEx(&WindowSize,
  141. CONSOLE_WINDOW_FLAGS,
  142. FALSE,
  143. CONSOLE_WINDOW_EX_FLAGS
  144. );
  145. VerticalClientToWindow = (SHORT)(WindowSize.right-WindowSize.left-50);
  146. HorizontalClientToWindow = (SHORT)(WindowSize.bottom-WindowSize.top-50);
  147. #ifdef LATER
  148. gfIsIMEEnabled = !!GetSystemMetrics(SM_IMMENABLED);
  149. RIPMSG1(RIP_VERBOSE, "InitializeSystemMetrics: gfIsIMEEnabled=%d", gfIsIMEEnabled);
  150. #endif
  151. guCaretBlinkTime = GetCaretBlinkTime();
  152. }
  153. VOID
  154. GetWindowLimits(
  155. IN PSCREEN_INFORMATION ScreenInfo,
  156. OUT PWINDOW_LIMITS WindowLimits
  157. )
  158. {
  159. HMONITOR hMonitor;
  160. MONITORINFO MonitorInfo = {sizeof(MonitorInfo)};
  161. COORD FontSize;
  162. //
  163. // If the system metrics have changed or there aren't any console
  164. // windows around, reinitialize the global valeus.
  165. //
  166. if (gfInitSystemMetrics || gnConsoleWindows == 0) {
  167. InitializeSystemMetrics();
  168. }
  169. if (ScreenInfo->Console &&
  170. (ScreenInfo->Console->hWnd || !(ScreenInfo->Console->Flags & CONSOLE_AUTO_POSITION)) &&
  171. ((hMonitor = MonitorFromRect(&ScreenInfo->Console->WindowRect, MONITOR_DEFAULTTOPRIMARY)) != NULL) &&
  172. GetMonitorInfo(hMonitor, &MonitorInfo)) {
  173. WindowLimits->FullScreenSize.X = (SHORT)(MonitorInfo.rcWork.right - MonitorInfo.rcWork.left);
  174. WindowLimits->FullScreenSize.Y = (SHORT)(MonitorInfo.rcWork.bottom - MonitorInfo.rcWork.top - ConsoleCaptionY);
  175. } else {
  176. WindowLimits->FullScreenSize.X = (SHORT)ConsoleFullScreenX;
  177. WindowLimits->FullScreenSize.Y = (SHORT)ConsoleFullScreenY;
  178. }
  179. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  180. FontSize = SCR_FONTSIZE(ScreenInfo);
  181. } else {
  182. FontSize.X = 1;
  183. FontSize.Y = 1;
  184. }
  185. WindowLimits->MinimumWindowSize.X = ((MinimumWidthX - VerticalClientToWindow + FontSize.X - 1) / FontSize.X);
  186. WindowLimits->MinimumWindowSize.Y = 1;
  187. WindowLimits->MaximumWindowSize.X = min(WindowLimits->FullScreenSize.X/FontSize.X, ScreenInfo->ScreenBufferSize.X);
  188. WindowLimits->MaximumWindowSize.X = max(WindowLimits->MaximumWindowSize.X, WindowLimits->MinimumWindowSize.X);
  189. WindowLimits->MaximumWindowSize.Y = min(WindowLimits->FullScreenSize.Y/FontSize.Y, ScreenInfo->ScreenBufferSize.Y);
  190. WindowLimits->MaxWindow.X = WindowLimits->MaximumWindowSize.X*FontSize.X + VerticalClientToWindow;
  191. WindowLimits->MaxWindow.Y = WindowLimits->MaximumWindowSize.Y*FontSize.Y + HorizontalClientToWindow;
  192. }
  193. VOID
  194. InitializeScreenInfo( VOID )
  195. {
  196. HDC hDC;
  197. InitializeMouseButtons();
  198. MinimumWidthX = GetSystemMetrics(SM_CXMIN);
  199. InitializeSystemMetrics();
  200. hDC = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
  201. if (hDC != NULL) {
  202. UsePolyTextOut = GetDeviceCaps(hDC, TEXTCAPS) & TC_SCROLLBLT;
  203. DeleteDC(hDC);
  204. }
  205. }
  206. NTSTATUS
  207. DoCreateScreenBuffer(
  208. IN PCONSOLE_INFORMATION Console,
  209. IN PCONSOLE_INFO ConsoleInfo
  210. )
  211. /*++
  212. this routine figures out what parameters to pass to CreateScreenBuffer,
  213. based on the data from STARTUPINFO and the defaults in win.ini,
  214. then calls CreateScreenBuffer.
  215. --*/
  216. {
  217. CHAR_INFO Fill,PopupFill;
  218. COORD dwScreenBufferSize, dwWindowSize;
  219. NTSTATUS Status;
  220. int FontIndexWant;
  221. if (ConsoleInfo->dwStartupFlags & STARTF_USESHOWWINDOW) {
  222. Console->wShowWindow = ConsoleInfo->wShowWindow;
  223. } else {
  224. Console->wShowWindow = SW_SHOWNORMAL;
  225. }
  226. //
  227. // Get values from consoleinfo (which was initialized through link).
  228. //
  229. Fill.Attributes = ConsoleInfo->wFillAttribute;
  230. Fill.Char.UnicodeChar = (WCHAR)' ';
  231. PopupFill.Attributes = ConsoleInfo->wPopupFillAttribute;
  232. PopupFill.Char.UnicodeChar = (WCHAR)' ';
  233. dwScreenBufferSize = ConsoleInfo->dwScreenBufferSize;
  234. if (!(ConsoleInfo->dwStartupFlags & STARTF_USECOUNTCHARS)) {
  235. if (Console->Flags & CONSOLE_NO_WINDOW) {
  236. dwScreenBufferSize.X = min(dwScreenBufferSize.X, 80);
  237. dwScreenBufferSize.Y = min(dwScreenBufferSize.Y, 25);
  238. }
  239. }
  240. if (dwScreenBufferSize.X == 0) {
  241. dwScreenBufferSize.X = 1;
  242. }
  243. if (dwScreenBufferSize.Y == 0) {
  244. dwScreenBufferSize.Y = 1;
  245. }
  246. //
  247. // Grab font
  248. //
  249. #if defined(FE_SB)
  250. FontIndexWant = FindCreateFont(ConsoleInfo->uFontFamily,
  251. ConsoleInfo->FaceName,
  252. ConsoleInfo->dwFontSize,
  253. ConsoleInfo->uFontWeight,
  254. ConsoleInfo->uCodePage
  255. );
  256. #else
  257. FontIndexWant = FindCreateFont(ConsoleInfo->uFontFamily,
  258. ConsoleInfo->FaceName,
  259. ConsoleInfo->dwFontSize,
  260. ConsoleInfo->uFontWeight);
  261. #endif
  262. //
  263. // grab window size information
  264. //
  265. dwWindowSize = ConsoleInfo->dwWindowSize;
  266. if (ConsoleInfo->dwStartupFlags & STARTF_USESIZE) {
  267. dwWindowSize.X /= FontInfo[FontIndexWant].Size.X;
  268. dwWindowSize.Y /= FontInfo[FontIndexWant].Size.Y;
  269. } else if (Console->Flags & CONSOLE_NO_WINDOW) {
  270. dwWindowSize.X = min(dwWindowSize.X, 80);
  271. dwWindowSize.Y = min(dwWindowSize.Y, 25);
  272. }
  273. if (dwWindowSize.X == 0)
  274. dwWindowSize.X = 1;
  275. if (dwWindowSize.Y == 0)
  276. dwWindowSize.Y = 1;
  277. if (dwScreenBufferSize.X < dwWindowSize.X)
  278. dwScreenBufferSize.X = dwWindowSize.X;
  279. if (dwScreenBufferSize.Y < dwWindowSize.Y)
  280. dwScreenBufferSize.Y = dwWindowSize.Y;
  281. Console->dwWindowOriginX = ConsoleInfo->dwWindowOrigin.X;
  282. Console->dwWindowOriginY = ConsoleInfo->dwWindowOrigin.Y;
  283. if (ConsoleInfo->bAutoPosition) {
  284. Console->Flags |= CONSOLE_AUTO_POSITION;
  285. Console->dwWindowOriginX = CW_USEDEFAULT;
  286. } else {
  287. Console->WindowRect.left = Console->dwWindowOriginX;
  288. Console->WindowRect.top = Console->dwWindowOriginY;
  289. Console->WindowRect.right = Console->dwWindowOriginX + dwWindowSize.X * FontInfo[FontIndexWant].Size.X;
  290. Console->WindowRect.bottom = Console->dwWindowOriginY + dwWindowSize.Y * FontInfo[FontIndexWant].Size.Y;
  291. }
  292. #ifdef i386
  293. if (FullScreenInitialized && !GetSystemMetrics(SM_REMOTESESSION)) {
  294. if (ConsoleInfo->bFullScreen) {
  295. Console->FullScreenFlags = CONSOLE_FULLSCREEN;
  296. }
  297. }
  298. #endif
  299. if (ConsoleInfo->bQuickEdit) {
  300. Console->Flags |= CONSOLE_QUICK_EDIT_MODE;
  301. }
  302. Console->Flags |= CONSOLE_USE_PRIVATE_FLAGS;
  303. Console->InsertMode = (ConsoleInfo->bInsertMode != FALSE);
  304. Console->CommandHistorySize = (SHORT)ConsoleInfo->uHistoryBufferSize;
  305. Console->MaxCommandHistories = (SHORT)ConsoleInfo->uNumberOfHistoryBuffers;
  306. if (ConsoleInfo->bHistoryNoDup) {
  307. Console->Flags |= CONSOLE_HISTORY_NODUP;
  308. } else {
  309. Console->Flags &= ~CONSOLE_HISTORY_NODUP;
  310. }
  311. RtlCopyMemory(Console->ColorTable, ConsoleInfo->ColorTable, sizeof( Console->ColorTable ));
  312. #if defined(FE_SB)
  313. // for FarEast version, we want get the code page from registry or shell32,
  314. // so we can specify console codepage by console.cpl or shell32
  315. // default codepage is OEMCP. scotthsu
  316. Console->CP = ConsoleInfo->uCodePage;
  317. Console->OutputCP = ConsoleInfo->uCodePage;
  318. Console->fIsDBCSCP = CONSOLE_IS_DBCS_ENABLED() && IsAvailableFarEastCodePage(Console->CP);
  319. Console->fIsDBCSOutputCP = CONSOLE_IS_DBCS_ENABLED() && IsAvailableFarEastCodePage(Console->OutputCP);
  320. #endif
  321. #if defined(FE_IME)
  322. Console->ConsoleIme.ScrollWaitTimeout = guCaretBlinkTime * 2;
  323. #endif
  324. TryNewSize:
  325. Status = CreateScreenBuffer(&Console->ScreenBuffers,
  326. dwWindowSize,
  327. FontIndexWant,
  328. dwScreenBufferSize,
  329. Fill,
  330. PopupFill,
  331. Console,
  332. CONSOLE_TEXTMODE_BUFFER,
  333. NULL,
  334. NULL,
  335. NULL,
  336. ConsoleInfo->uCursorSize,
  337. ConsoleInfo->FaceName
  338. );
  339. if (Status == STATUS_NO_MEMORY) {
  340. //
  341. // If we failed to create a large buffer, try again with a small one.
  342. //
  343. if (dwScreenBufferSize.X > 80 || dwScreenBufferSize.Y > 50) {
  344. dwScreenBufferSize.X = min(dwScreenBufferSize.X, 80);
  345. dwScreenBufferSize.Y = min(dwScreenBufferSize.Y, 50);
  346. dwWindowSize.X = min(dwWindowSize.X, dwScreenBufferSize.X);
  347. dwWindowSize.Y = min(dwWindowSize.Y, dwScreenBufferSize.Y);
  348. Console->Flags |= CONSOLE_DEFAULT_BUFFER_SIZE;
  349. goto TryNewSize;
  350. }
  351. }
  352. return Status;
  353. }
  354. NTSTATUS
  355. CreateScreenBuffer(
  356. OUT PSCREEN_INFORMATION *ScreenInformation,
  357. IN COORD dwWindowSize,
  358. IN DWORD nFont,
  359. IN COORD dwScreenBufferSize,
  360. IN CHAR_INFO Fill,
  361. IN CHAR_INFO PopupFill,
  362. IN PCONSOLE_INFORMATION Console,
  363. IN DWORD Flags,
  364. IN PCONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo OPTIONAL,
  365. OUT PVOID *lpBitmap OPTIONAL,
  366. OUT HANDLE *hMutex OPTIONAL,
  367. IN UINT CursorSize,
  368. IN LPWSTR FaceName
  369. )
  370. /*++
  371. Routine Description:
  372. This routine allocates and initializes the data associated with a screen
  373. buffer. It also creates a window.
  374. Arguments:
  375. ScreenInformation - the new screen buffer.
  376. dwWindowSize - the initial size of screen buffer's window (in rows/columns)
  377. nFont - the initial font to generate text with.
  378. dwScreenBufferSize - the initial size of the screen buffer (in rows/columns).
  379. Return Value:
  380. --*/
  381. {
  382. LONG i,j;
  383. PSCREEN_INFORMATION ScreenInfo;
  384. NTSTATUS Status;
  385. PWCHAR TextRowPtr;
  386. #if defined(FE_SB)
  387. PBYTE AttrRowPtr;
  388. #endif
  389. WINDOW_LIMITS WindowLimits;
  390. /*
  391. * Make sure we have a valid font. Bail if no fonts are available.
  392. */
  393. ASSERT(nFont < NumberOfFonts);
  394. if (NumberOfFonts == 0) {
  395. return STATUS_UNSUCCESSFUL;
  396. }
  397. ScreenInfo = ConsoleHeapAlloc(SCREEN_TAG, sizeof(SCREEN_INFORMATION));
  398. if (ScreenInfo == NULL) {
  399. return STATUS_NO_MEMORY;
  400. }
  401. ScreenInfo->Console = Console;
  402. ScreenInfo->Flags = Flags;
  403. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  404. ASSERT(FontInfo[nFont].FaceName != NULL);
  405. ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont = NULL;
  406. Status = StoreTextBufferFontInfo(ScreenInfo,
  407. nFont,
  408. FontInfo[nFont].Size,
  409. FontInfo[nFont].Family,
  410. FontInfo[nFont].Weight,
  411. FaceName ? FaceName : FontInfo[nFont].FaceName,
  412. Console->OutputCP);
  413. if (!NT_SUCCESS(Status)) {
  414. ConsoleHeapFree(ScreenInfo);
  415. return((ULONG) Status);
  416. }
  417. DBGFONTS(("DoCreateScreenBuffer sets FontSize(%d,%d), FontNumber=%x, Family=%x\n",
  418. SCR_FONTSIZE(ScreenInfo).X,
  419. SCR_FONTSIZE(ScreenInfo).Y,
  420. SCR_FONTNUMBER(ScreenInfo),
  421. SCR_FAMILY(ScreenInfo)));
  422. if (TM_IS_TT_FONT(FontInfo[nFont].Family)) {
  423. ScreenInfo->Flags &= ~CONSOLE_OEMFONT_DISPLAY;
  424. } else {
  425. ScreenInfo->Flags |= CONSOLE_OEMFONT_DISPLAY;
  426. }
  427. ScreenInfo->ScreenBufferSize = dwScreenBufferSize;
  428. GetWindowLimits(ScreenInfo, &WindowLimits);
  429. dwScreenBufferSize.X = max(dwScreenBufferSize.X, WindowLimits.MinimumWindowSize.X);
  430. dwWindowSize.X = max(dwWindowSize.X, WindowLimits.MinimumWindowSize.X);
  431. ScreenInfo->BufferInfo.TextInfo.ModeIndex = (ULONG)-1;
  432. #ifdef i386
  433. if (Console->FullScreenFlags & CONSOLE_FULLSCREEN) {
  434. COORD WindowSize;
  435. ScreenInfo->BufferInfo.TextInfo.WindowedWindowSize = dwWindowSize;
  436. ScreenInfo->BufferInfo.TextInfo.WindowedScreenSize = dwScreenBufferSize;
  437. ScreenInfo->BufferInfo.TextInfo.ModeIndex = MatchWindowSize(Console->OutputCP,dwWindowSize,&WindowSize);
  438. }
  439. #endif
  440. ScreenInfo->BufferInfo.TextInfo.FirstRow = 0;
  441. ScreenInfo->BufferInfo.TextInfo.Rows = ConsoleHeapAlloc(SCREEN_TAG, dwScreenBufferSize.Y * sizeof(ROW));
  442. if (ScreenInfo->BufferInfo.TextInfo.Rows == NULL) {
  443. RemoveTextBufferFontInfo(ScreenInfo);
  444. ConsoleHeapFree(ScreenInfo);
  445. return STATUS_NO_MEMORY;
  446. }
  447. ScreenInfo->BufferInfo.TextInfo.TextRows = ConsoleHeapAlloc(SCREEN_TAG, dwScreenBufferSize.X * dwScreenBufferSize.Y * sizeof(WCHAR));
  448. if (ScreenInfo->BufferInfo.TextInfo.TextRows == NULL) {
  449. ConsoleHeapFree(ScreenInfo->BufferInfo.TextInfo.Rows);
  450. RemoveTextBufferFontInfo(ScreenInfo);
  451. ConsoleHeapFree(ScreenInfo);
  452. return STATUS_NO_MEMORY;
  453. }
  454. #if defined(FE_SB)
  455. if (!CreateDbcsScreenBuffer(Console, dwScreenBufferSize, &ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer)) {
  456. ConsoleHeapFree(ScreenInfo->BufferInfo.TextInfo.TextRows);
  457. ConsoleHeapFree(ScreenInfo->BufferInfo.TextInfo.Rows);
  458. RemoveTextBufferFontInfo(ScreenInfo);
  459. ConsoleHeapFree(ScreenInfo);
  460. return STATUS_NO_MEMORY;
  461. }
  462. AttrRowPtr=ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.KAttrRows;
  463. #endif
  464. for (i=0,TextRowPtr=ScreenInfo->BufferInfo.TextInfo.TextRows;
  465. i<dwScreenBufferSize.Y;
  466. i++,TextRowPtr+=dwScreenBufferSize.X)
  467. {
  468. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.Left = dwScreenBufferSize.X;
  469. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.OldLeft = INVALID_OLD_LENGTH;
  470. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.Right = 0;
  471. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.OldRight = INVALID_OLD_LENGTH;
  472. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.Chars = TextRowPtr;
  473. #if defined(FE_SB)
  474. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.KAttrs = AttrRowPtr;
  475. #endif
  476. for (j=0;j<dwScreenBufferSize.X;j++) {
  477. TextRowPtr[j] = (WCHAR)' ';
  478. }
  479. #if defined(FE_SB)
  480. if (AttrRowPtr) {
  481. RtlZeroMemory(AttrRowPtr, dwScreenBufferSize.X);
  482. AttrRowPtr+=dwScreenBufferSize.X;
  483. }
  484. #endif
  485. ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Length = 1;
  486. ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.AttrPair.Length = dwScreenBufferSize.X;
  487. ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.AttrPair.Attr = Fill.Attributes;
  488. ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs = &ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.AttrPair;
  489. }
  490. ScreenInfo->BufferInfo.TextInfo.CursorSize = CursorSize;
  491. ScreenInfo->BufferInfo.TextInfo.CursorPosition.X = 0;
  492. ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y = 0;
  493. ScreenInfo->BufferInfo.TextInfo.CursorMoved = FALSE;
  494. ScreenInfo->BufferInfo.TextInfo.CursorVisible = TRUE;
  495. ScreenInfo->BufferInfo.TextInfo.CursorOn = FALSE;
  496. ScreenInfo->BufferInfo.TextInfo.CursorYSize = (WORD)CURSOR_SIZE_IN_PIXELS(SCR_FONTSIZE(ScreenInfo).Y,ScreenInfo->BufferInfo.TextInfo.CursorSize);
  497. ScreenInfo->BufferInfo.TextInfo.UpdatingScreen = 0;
  498. ScreenInfo->BufferInfo.TextInfo.DoubleCursor = FALSE;
  499. ScreenInfo->BufferInfo.TextInfo.DelayCursor = FALSE;
  500. ScreenInfo->BufferInfo.TextInfo.Flags = SINGLE_ATTRIBUTES_PER_LINE;
  501. ScreenInfo->ScreenBufferSize = dwScreenBufferSize;
  502. ScreenInfo->Window.Left = 0;
  503. ScreenInfo->Window.Top = 0;
  504. ScreenInfo->Window.Right = dwWindowSize.X - 1;
  505. ScreenInfo->Window.Bottom = dwWindowSize.Y - 1;
  506. if (ScreenInfo->Window.Right >= WindowLimits.MaximumWindowSize.X) {
  507. ScreenInfo->Window.Right = WindowLimits.MaximumWindowSize.X-1;
  508. dwWindowSize.X = CONSOLE_WINDOW_SIZE_X(ScreenInfo);
  509. }
  510. if (ScreenInfo->Window.Bottom >= WindowLimits.MaximumWindowSize.Y) {
  511. ScreenInfo->Window.Bottom = WindowLimits.MaximumWindowSize.Y-1;
  512. dwWindowSize.Y = CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
  513. }
  514. ScreenInfo->WindowMaximizedX = (dwWindowSize.X == dwScreenBufferSize.X);
  515. ScreenInfo->WindowMaximizedY = (dwWindowSize.Y == dwScreenBufferSize.Y);
  516. #if defined(FE_SB)
  517. #if defined(_X86_)
  518. ScreenInfo->BufferInfo.TextInfo.MousePosition.X = 0;
  519. ScreenInfo->BufferInfo.TextInfo.MousePosition.Y = 0;
  520. #endif // i386
  521. ScreenInfo->BufferInfo.TextInfo.CursorBlink = TRUE;
  522. ScreenInfo->BufferInfo.TextInfo.CursorDBEnable = TRUE;
  523. #endif
  524. }
  525. else {
  526. Status = CreateConsoleBitmap(GraphicsBufferInfo,
  527. ScreenInfo,
  528. lpBitmap,
  529. hMutex
  530. );
  531. if (!NT_SUCCESS(Status)) {
  532. ConsoleHeapFree(ScreenInfo);
  533. return Status;
  534. }
  535. ScreenInfo->WindowMaximizedX = TRUE;
  536. ScreenInfo->WindowMaximizedY = TRUE;
  537. }
  538. ScreenInfo->WindowMaximized = FALSE;
  539. ScreenInfo->RefCount = 0;
  540. ScreenInfo->ShareAccess.OpenCount = 0;
  541. ScreenInfo->ShareAccess.Readers = 0;
  542. ScreenInfo->ShareAccess.Writers = 0;
  543. ScreenInfo->ShareAccess.SharedRead = 0;
  544. ScreenInfo->ShareAccess.SharedWrite = 0;
  545. ScreenInfo->CursorHandle = ghNormalCursor;
  546. ScreenInfo->CursorDisplayCount = 0;
  547. ScreenInfo->CommandIdLow = (UINT)-1;
  548. ScreenInfo->CommandIdHigh = (UINT)-1;
  549. ScreenInfo->dwUsage = SYSPAL_STATIC;
  550. ScreenInfo->hPalette = NULL;
  551. ScreenInfo->OutputMode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
  552. ScreenInfo->ResizingWindow = 0;
  553. ScreenInfo->Next = NULL;
  554. ScreenInfo->Attributes = Fill.Attributes;
  555. ScreenInfo->PopupAttributes = PopupFill.Attributes;
  556. ScreenInfo->WheelDelta = 0;
  557. #if defined(FE_SB)
  558. ScreenInfo->WriteConsoleDbcsLeadByte[0] = 0;
  559. ScreenInfo->BisectFlag = 0;
  560. if (Flags & CONSOLE_TEXTMODE_BUFFER) {
  561. SetLineChar(ScreenInfo);
  562. }
  563. ScreenInfo->FillOutDbcsLeadChar = 0;
  564. ScreenInfo->ConvScreenInfo = NULL;
  565. #endif
  566. *ScreenInformation = ScreenInfo;
  567. DBGOUTPUT(("SCREEN at %lx\n", ScreenInfo));
  568. return STATUS_SUCCESS;
  569. }
  570. VOID
  571. PositionConsoleWindow(
  572. IN PCONSOLE_INFORMATION Console,
  573. IN BOOL Initialize
  574. )
  575. {
  576. GetWindowRect(Console->hWnd, &Console->WindowRect);
  577. //
  578. // If this is an autoposition window being initialized, make sure it's
  579. // client area doesn't descend below the tray
  580. //
  581. if (Initialize && (Console->Flags & CONSOLE_AUTO_POSITION)) {
  582. RECT ClientRect;
  583. LONG dx = 0;
  584. LONG dy = 0;
  585. HMONITOR hMonitor;
  586. MONITORINFO MonitorInfo = {sizeof(MonitorInfo)};
  587. hMonitor = MonitorFromRect(&Console->WindowRect, MONITOR_DEFAULTTONULL);
  588. if (hMonitor && GetMonitorInfo(hMonitor, &MonitorInfo)) {
  589. GetClientRect(Console->hWnd, &ClientRect);
  590. ClientToScreen(Console->hWnd, (LPPOINT)&ClientRect.left);
  591. ClientToScreen(Console->hWnd, (LPPOINT)&ClientRect.right);
  592. if (Console->WindowRect.right > MonitorInfo.rcWork.right) {
  593. dx = max(min((Console->WindowRect.right - MonitorInfo.rcWork.right),
  594. (Console->WindowRect.left - MonitorInfo.rcWork.left)),
  595. min((ClientRect.right - MonitorInfo.rcWork.right),
  596. (ClientRect.left - MonitorInfo.rcWork.left)));
  597. }
  598. if (Console->WindowRect.bottom > MonitorInfo.rcWork.bottom) {
  599. dy = max(min((Console->WindowRect.bottom - MonitorInfo.rcWork.bottom),
  600. (Console->WindowRect.top - MonitorInfo.rcWork.top)),
  601. min((ClientRect.bottom - MonitorInfo.rcWork.bottom),
  602. (ClientRect.top - MonitorInfo.rcWork.top)));
  603. }
  604. if (dx || dy) {
  605. SetWindowPos(Console->hWnd,
  606. NULL,
  607. Console->WindowRect.left - dx,
  608. Console->WindowRect.top - dy,
  609. 0,
  610. 0,
  611. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  612. }
  613. }
  614. }
  615. }
  616. /*
  617. * Bug 273518 - joejo
  618. *
  619. * This will allow console windows to set foreground correctly on new
  620. * process' it launches, as opposed it just forcing foreground.
  621. */
  622. NTSTATUS
  623. ConsoleSetActiveWindow(
  624. IN PCONSOLE_INFORMATION Console
  625. )
  626. {
  627. HWND hWnd = Console->hWnd;
  628. HANDLE ConsoleHandle = Console->ConsoleHandle;
  629. UnlockConsole(Console);
  630. SetActiveWindow(hWnd);
  631. return RevalidateConsole(ConsoleHandle, &Console);
  632. }
  633. NTSTATUS
  634. CreateWindowsWindow(
  635. IN PCONSOLE_INFORMATION Console
  636. )
  637. {
  638. PSCREEN_INFORMATION ScreenInfo;
  639. SIZE WindowSize;
  640. DWORD Style;
  641. THREAD_BASIC_INFORMATION ThreadInfo;
  642. HWND hWnd;
  643. ScreenInfo = Console->ScreenBuffers;
  644. //
  645. // figure out how big to make the window, given the desired client area
  646. // size. window is always created in textmode.
  647. //
  648. ASSERT(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER);
  649. WindowSize.cx = CONSOLE_WINDOW_SIZE_X(ScreenInfo)*SCR_FONTSIZE(ScreenInfo).X + VerticalClientToWindow;
  650. WindowSize.cy = CONSOLE_WINDOW_SIZE_Y(ScreenInfo)*SCR_FONTSIZE(ScreenInfo).Y + HorizontalClientToWindow;
  651. Style = CONSOLE_WINDOW_FLAGS & ~WS_VISIBLE;
  652. if (!ScreenInfo->WindowMaximizedX) {
  653. WindowSize.cy += HorizontalScrollSize;
  654. } else {
  655. Style &= ~WS_HSCROLL;
  656. }
  657. if (!ScreenInfo->WindowMaximizedY) {
  658. WindowSize.cx += VerticalScrollSize;
  659. } else {
  660. Style &= ~WS_VSCROLL;
  661. }
  662. //
  663. // create the window.
  664. //
  665. Console->WindowRect.left = Console->dwWindowOriginX;
  666. Console->WindowRect.top = Console->dwWindowOriginY;
  667. Console->WindowRect.right = WindowSize.cx + Console->dwWindowOriginX;
  668. Console->WindowRect.bottom = WindowSize.cy + Console->dwWindowOriginY;
  669. hWnd = CreateWindowEx(CONSOLE_WINDOW_EX_FLAGS,
  670. CONSOLE_WINDOW_CLASS,
  671. Console->Title,
  672. Style,
  673. Console->dwWindowOriginX,
  674. Console->dwWindowOriginY,
  675. WindowSize.cx,
  676. WindowSize.cy,
  677. (Console->Flags & CONSOLE_NO_WINDOW) ? HWND_MESSAGE : HWND_DESKTOP,
  678. NULL,
  679. ghInstance,
  680. NULL);
  681. if (hWnd == NULL) {
  682. NtSetEvent(Console->InitEvents[INITIALIZATION_FAILED],NULL);
  683. return STATUS_NO_MEMORY;
  684. }
  685. Console->hWnd = hWnd;
  686. SetWindowConsole(hWnd, Console);
  687. //
  688. // Stuff the client id into the window so USER can find it.
  689. //
  690. if (NT_SUCCESS(NtQueryInformationThread(Console->ClientThreadHandle,
  691. ThreadBasicInformation, &ThreadInfo,
  692. sizeof(ThreadInfo), NULL))) {
  693. SetConsolePid(Console->hWnd, HandleToUlong(ThreadInfo.ClientId.UniqueProcess));
  694. SetConsoleTid(Console->hWnd, HandleToUlong(ThreadInfo.ClientId.UniqueThread));
  695. }
  696. //
  697. // Get the dc.
  698. //
  699. Console->hDC = GetDC(Console->hWnd);
  700. if (Console->hDC == NULL) {
  701. NtSetEvent(Console->InitEvents[INITIALIZATION_FAILED],NULL);
  702. DestroyWindow(Console->hWnd);
  703. Console->hWnd = NULL;
  704. return STATUS_NO_MEMORY;
  705. }
  706. Console->hMenu = GetSystemMenu(Console->hWnd,FALSE);
  707. //
  708. // modify system menu to our liking.
  709. //
  710. InitSystemMenu(Console);
  711. gnConsoleWindows++;
  712. Console->InputThreadInfo->WindowCount++;
  713. #if defined(FE_IME)
  714. SetUndetermineAttribute(Console);
  715. #endif
  716. #if defined(FE_SB)
  717. RegisterKeisenOfTTFont(ScreenInfo);
  718. #endif
  719. //
  720. // Set up the hot key for this window
  721. //
  722. if ((Console->dwHotKey != 0) && !(Console->Flags & CONSOLE_NO_WINDOW)) {
  723. SendMessage(Console->hWnd, WM_SETHOTKEY, Console->dwHotKey, 0L);
  724. }
  725. //
  726. // create icon
  727. //
  728. if (Console->iIconId) {
  729. // We have no icon, try and get one from progman.
  730. PostMessage(HWND_BROADCAST,
  731. ProgmanHandleMessage,
  732. (WPARAM)Console->hWnd,
  733. 1);
  734. }
  735. if (Console->hIcon == NULL) {
  736. Console->hIcon = ghDefaultIcon;
  737. Console->hSmIcon = ghDefaultSmIcon;
  738. } else if (Console->hIcon != ghDefaultIcon) {
  739. SendMessage(Console->hWnd, WM_SETICON, ICON_BIG, (LPARAM)Console->hIcon);
  740. SendMessage(Console->hWnd, WM_SETICON, ICON_SMALL, (LPARAM)Console->hSmIcon);
  741. }
  742. SetBkMode(Console->hDC,OPAQUE);
  743. SetFont(ScreenInfo);
  744. SelectObject(Console->hDC, GetStockObject(DC_BRUSH));
  745. SetScreenColors(ScreenInfo, ScreenInfo->Attributes,
  746. ScreenInfo->PopupAttributes, FALSE);
  747. if (Console->Flags & CONSOLE_NO_WINDOW) {
  748. ShowWindowAsync(Console->hWnd, SW_HIDE);
  749. #ifdef i386
  750. } else if (Console->FullScreenFlags != 0) {
  751. if (Console->wShowWindow == SW_SHOWMINNOACTIVE) {
  752. ShowWindowAsync(Console->hWnd, Console->wShowWindow);
  753. Console->FullScreenFlags = 0;
  754. Console->Flags |= CONSOLE_IS_ICONIC;
  755. } else {
  756. ConvertToFullScreen(Console);
  757. if (!NT_SUCCESS(ConsoleSetActiveWindow(Console))) {
  758. return STATUS_INVALID_HANDLE;
  759. }
  760. ChangeDispSettings(Console, Console->hWnd,CDS_FULLSCREEN);
  761. }
  762. #endif
  763. } else {
  764. if (Console->wShowWindow != SW_SHOWNOACTIVATE &&
  765. Console->wShowWindow != SW_SHOWMINNOACTIVE &&
  766. Console->wShowWindow != SW_HIDE) {
  767. if (!NT_SUCCESS(ConsoleSetActiveWindow(Console))) {
  768. return STATUS_INVALID_HANDLE;
  769. }
  770. } else if (Console->wShowWindow == SW_SHOWMINNOACTIVE) {
  771. Console->Flags |= CONSOLE_IS_ICONIC;
  772. }
  773. ShowWindowAsync(Console->hWnd, Console->wShowWindow);
  774. }
  775. //UpdateWindow(Console->hWnd);
  776. InternalUpdateScrollBars(ScreenInfo);
  777. if (!(Console->Flags & CONSOLE_IS_ICONIC) &&
  778. (Console->FullScreenFlags == 0) ) {
  779. PositionConsoleWindow(Console, TRUE);
  780. }
  781. #if defined(FE_IME)
  782. if (CONSOLE_IS_IME_ENABLED() && !(Console->Flags & CONSOLE_NO_WINDOW)) {
  783. SetTimer(Console->hWnd, SCROLL_WAIT_TIMER, guCaretBlinkTime, NULL);
  784. }
  785. #endif
  786. NtSetEvent(Console->InitEvents[INITIALIZATION_SUCCEEDED],NULL);
  787. return STATUS_SUCCESS;
  788. }
  789. NTSTATUS
  790. FreeScreenBuffer(
  791. IN PSCREEN_INFORMATION ScreenInfo
  792. )
  793. /*++
  794. Routine Description:
  795. This routine frees the memory associated with a screen buffer.
  796. Arguments:
  797. ScreenInfo - screen buffer data to free.
  798. Return Value:
  799. Note: console handle table lock must be held when calling this routine
  800. --*/
  801. {
  802. SHORT i;
  803. PCONSOLE_INFORMATION Console = ScreenInfo->Console;
  804. ASSERT(ScreenInfo->RefCount == 0);
  805. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  806. for (i=0;i<ScreenInfo->ScreenBufferSize.Y;i++) {
  807. if (ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Length > 1) {
  808. ConsoleHeapFree(ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs);
  809. }
  810. }
  811. ConsoleHeapFree(ScreenInfo->BufferInfo.TextInfo.TextRows);
  812. ConsoleHeapFree(ScreenInfo->BufferInfo.TextInfo.Rows);
  813. #if defined(FE_SB)
  814. DeleteDbcsScreenBuffer(&ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer);
  815. #endif
  816. RemoveTextBufferFontInfo(ScreenInfo);
  817. } else {
  818. if (ScreenInfo->hPalette != NULL) {
  819. if (GetCurrentObject(Console->hDC, OBJ_PAL) == ScreenInfo->hPalette) {
  820. SelectPalette(Console->hDC, Console->hSysPalette, FALSE);
  821. }
  822. DeleteObject(ScreenInfo->hPalette);
  823. }
  824. FreeConsoleBitmap(ScreenInfo);
  825. }
  826. ConsoleHeapFree(ScreenInfo);
  827. return STATUS_SUCCESS;
  828. }
  829. VOID
  830. FindAttrIndex(
  831. IN PATTR_PAIR String,
  832. IN SHORT Index,
  833. OUT PATTR_PAIR *IndexedAttr,
  834. OUT PSHORT CountOfAttr
  835. )
  836. /*++
  837. Routine Description:
  838. This routine finds the nth attribute in a string.
  839. Arguments:
  840. String - attribute string
  841. Index - which attribute to find
  842. IndexedAttr - pointer to attribute within string
  843. CountOfAttr - on output, contains corrected length of indexed attr.
  844. for example, if the attribute string was { 5, BLUE } and the requested
  845. index was 3, CountOfAttr would be 2.
  846. Return Value:
  847. none.
  848. --*/
  849. {
  850. SHORT i;
  851. for (i=0;i<Index;) {
  852. i += String->Length;
  853. String++;
  854. }
  855. if (i>Index) {
  856. String--;
  857. *CountOfAttr = i-Index;
  858. }
  859. else {
  860. *CountOfAttr = String->Length;
  861. }
  862. *IndexedAttr = String;
  863. }
  864. NTSTATUS
  865. MergeAttrStrings(
  866. IN PATTR_PAIR Source,
  867. IN WORD SourceLength,
  868. IN PATTR_PAIR Merge,
  869. IN WORD MergeLength,
  870. OUT PATTR_PAIR *Target,
  871. OUT LPWORD TargetLength,
  872. IN SHORT StartIndex,
  873. IN SHORT EndIndex,
  874. IN PROW Row,
  875. IN PSCREEN_INFORMATION ScreenInfo
  876. )
  877. /*++
  878. Routine Description:
  879. This routine merges two run-length encoded attribute strings into
  880. a third.
  881. for example, if the source string was { 4, BLUE }, the merge string
  882. was { 2, RED }, and the StartIndex and EndIndex were 1 and 2,
  883. respectively, the target string would be { 1, BLUE, 2, RED, 1, BLUE }
  884. and the target length would be 3.
  885. Arguments:
  886. Source - pointer to source attribute string
  887. SourceLength - length of source. for example, the length of
  888. { 4, BLUE } is 1.
  889. Merge - pointer to attribute string to insert into source
  890. MergeLength - length of merge
  891. Target - where to store pointer to resulting attribute string
  892. TargetLength - where to store length of resulting attribute string
  893. StartIndex - index into Source at which to insert Merge String.
  894. EndIndex - index into Source at which to stop insertion of Merge String
  895. Return Value:
  896. none.
  897. --*/
  898. {
  899. PATTR_PAIR SrcAttr,TargetAttr,SrcEnd;
  900. PATTR_PAIR NewString;
  901. SHORT i;
  902. //
  903. // if just changing the attr for the whole row
  904. //
  905. if (MergeLength == 1 && Row->AttrRow.Length == 1) {
  906. if (Row->AttrRow.Attrs->Attr == Merge->Attr) {
  907. *TargetLength = 1;
  908. *Target = &Row->AttrRow.AttrPair;
  909. return STATUS_SUCCESS;
  910. }
  911. if (StartIndex == 0 && EndIndex == (SHORT)(ScreenInfo->ScreenBufferSize.X-1)) {
  912. NewString = &Row->AttrRow.AttrPair;
  913. NewString->Attr = Merge->Attr;
  914. *TargetLength = 1;
  915. *Target = NewString;
  916. return STATUS_SUCCESS;
  917. }
  918. }
  919. NewString = ConsoleHeapAlloc(SCREEN_TAG, (SourceLength + MergeLength + 1) * sizeof(ATTR_PAIR));
  920. if (NewString == NULL) {
  921. return STATUS_NO_MEMORY;
  922. }
  923. //
  924. // copy the source string, up to the start index.
  925. //
  926. SrcAttr = Source;
  927. SrcEnd = Source + SourceLength;
  928. TargetAttr = NewString;
  929. i=0;
  930. if (StartIndex != 0) {
  931. while (i<StartIndex) {
  932. i += SrcAttr->Length;
  933. *TargetAttr++ = *SrcAttr++;
  934. }
  935. //
  936. // back up to the last pair copied, in case the attribute in the first
  937. // pair in the merge string matches. also, adjust TargetAttr->Length
  938. // based on i, the attribute
  939. // counter, back to the StartIndex. i will be larger than the
  940. // StartIndex in the case where the last attribute pair copied had
  941. // a length greater than the number needed to reach StartIndex.
  942. //
  943. TargetAttr--;
  944. if (i>StartIndex) {
  945. TargetAttr->Length -= i-StartIndex;
  946. }
  947. if (Merge->Attr == TargetAttr->Attr) {
  948. TargetAttr->Length += Merge->Length;
  949. MergeLength-=1;
  950. Merge++;
  951. }
  952. TargetAttr++;
  953. }
  954. //
  955. // copy the merge string.
  956. //
  957. RtlCopyMemory(TargetAttr,Merge,MergeLength*sizeof(ATTR_PAIR));
  958. TargetAttr += MergeLength;
  959. //
  960. // figure out where to resume copying the source string.
  961. //
  962. while (i<=EndIndex) {
  963. ASSERT(SrcAttr != SrcEnd);
  964. i += SrcAttr->Length;
  965. SrcAttr++;
  966. }
  967. //
  968. // if not done, copy the rest of the source
  969. //
  970. if (SrcAttr != SrcEnd || i!=(SHORT)(EndIndex+1)) {
  971. //
  972. // see if we've gone past the right attribute. if so, back up and
  973. // copy the attribute and the correct length.
  974. //
  975. TargetAttr--;
  976. if (i>(SHORT)(EndIndex+1)) {
  977. SrcAttr--;
  978. if (TargetAttr->Attr == SrcAttr->Attr) {
  979. TargetAttr->Length += i-(EndIndex+1);
  980. } else {
  981. TargetAttr++;
  982. TargetAttr->Attr = SrcAttr->Attr;
  983. TargetAttr->Length = (SHORT)(i-(EndIndex+1));
  984. }
  985. SrcAttr++;
  986. }
  987. //
  988. // see if we can merge the source and target.
  989. //
  990. else if (TargetAttr->Attr == SrcAttr->Attr) {
  991. TargetAttr->Length += SrcAttr->Length;
  992. i += SrcAttr->Length;
  993. SrcAttr++;
  994. }
  995. TargetAttr++;
  996. //
  997. // copy the rest of the source
  998. //
  999. if (SrcAttr < SrcEnd) {
  1000. RtlCopyMemory(TargetAttr,SrcAttr,(SrcEnd-SrcAttr)*sizeof(ATTR_PAIR));
  1001. TargetAttr += SrcEnd - SrcAttr;
  1002. }
  1003. }
  1004. *TargetLength = (WORD)(TargetAttr - NewString);
  1005. *Target = NewString;
  1006. if (*TargetLength == 1) {
  1007. *Target = &Row->AttrRow.AttrPair;
  1008. **Target = *NewString;
  1009. ConsoleHeapFree(NewString);
  1010. }
  1011. return STATUS_SUCCESS;
  1012. }
  1013. VOID
  1014. ResetTextFlags(
  1015. IN PSCREEN_INFORMATION ScreenInfo,
  1016. IN SHORT StartX,
  1017. IN SHORT StartY,
  1018. IN SHORT EndX,
  1019. IN SHORT EndY
  1020. )
  1021. {
  1022. SHORT RowIndex;
  1023. PROW Row;
  1024. WCHAR Char;
  1025. PATTR_PAIR Attr;
  1026. SHORT CountOfAttr;
  1027. SHORT i;
  1028. //
  1029. // Fire off a winevent to let accessibility apps know what changed.
  1030. //
  1031. if (ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
  1032. ASSERT(EndX < ScreenInfo->ScreenBufferSize.X);
  1033. if (StartX == EndX && StartY == EndY) {
  1034. RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+StartY) % ScreenInfo->ScreenBufferSize.Y;
  1035. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  1036. Char = Row->CharRow.Chars[StartX];
  1037. FindAttrIndex(Row->AttrRow.Attrs, StartX, &Attr, &CountOfAttr);
  1038. ConsoleNotifyWinEvent(ScreenInfo->Console,
  1039. EVENT_CONSOLE_UPDATE_SIMPLE,
  1040. MAKELONG(StartX, StartY),
  1041. MAKELONG(Char, Attr->Attr));
  1042. } else {
  1043. ConsoleNotifyWinEvent(ScreenInfo->Console,
  1044. EVENT_CONSOLE_UPDATE_REGION,
  1045. MAKELONG(StartX, StartY),
  1046. MAKELONG(EndX, EndY));
  1047. }
  1048. }
  1049. //
  1050. // first see whether we wrote any lines with multiple attributes. if
  1051. // we did, set the flags and bail out. also, remember if any of the
  1052. // lines we wrote had attributes different from other lines.
  1053. //
  1054. RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+StartY) % ScreenInfo->ScreenBufferSize.Y;
  1055. for (i=StartY;i<=EndY;i++) {
  1056. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  1057. if (Row->AttrRow.Length != 1) {
  1058. ScreenInfo->BufferInfo.TextInfo.Flags &= ~SINGLE_ATTRIBUTES_PER_LINE;
  1059. return;
  1060. }
  1061. if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
  1062. RowIndex = 0;
  1063. }
  1064. }
  1065. // all of the written lines have the same attribute.
  1066. if (ScreenInfo->BufferInfo.TextInfo.Flags & SINGLE_ATTRIBUTES_PER_LINE) {
  1067. return;
  1068. }
  1069. if (StartY == 0 && EndY == (ScreenInfo->ScreenBufferSize.Y-1)) {
  1070. ScreenInfo->BufferInfo.TextInfo.Flags |= SINGLE_ATTRIBUTES_PER_LINE;
  1071. return;
  1072. }
  1073. RowIndex = ScreenInfo->BufferInfo.TextInfo.FirstRow;
  1074. for (i=0;i<StartY;i++) {
  1075. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  1076. if (Row->AttrRow.Length != 1) {
  1077. return;
  1078. }
  1079. if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
  1080. RowIndex = 0;
  1081. }
  1082. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  1083. }
  1084. RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+EndY+1) % ScreenInfo->ScreenBufferSize.Y;
  1085. for (i=EndY+1;i<ScreenInfo->ScreenBufferSize.Y;i++) {
  1086. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  1087. if (Row->AttrRow.Length != 1) {
  1088. return;
  1089. }
  1090. if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
  1091. RowIndex = 0;
  1092. }
  1093. }
  1094. ScreenInfo->BufferInfo.TextInfo.Flags |= SINGLE_ATTRIBUTES_PER_LINE;
  1095. }
  1096. VOID
  1097. ReadRectFromScreenBuffer(
  1098. IN PSCREEN_INFORMATION ScreenInfo,
  1099. IN COORD SourcePoint,
  1100. IN PCHAR_INFO Target,
  1101. IN COORD TargetSize,
  1102. IN PSMALL_RECT TargetRect
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. This routine copies a rectangular region from the screen buffer.
  1107. no clipping is done.
  1108. Arguments:
  1109. ScreenInfo - pointer to screen info
  1110. SourcePoint - upper left coordinates of source rectangle
  1111. Target - pointer to target buffer
  1112. TargetSize - dimensions of target buffer
  1113. TargetRect - rectangle in source buffer to copy
  1114. Return Value:
  1115. none.
  1116. --*/
  1117. {
  1118. PCHAR_INFO TargetPtr;
  1119. SHORT i,j,k;
  1120. SHORT XSize,YSize;
  1121. BOOLEAN WholeTarget;
  1122. SHORT RowIndex;
  1123. PROW Row;
  1124. PWCHAR Char;
  1125. PATTR_PAIR Attr;
  1126. SHORT CountOfAttr;
  1127. DBGOUTPUT(("ReadRectFromScreenBuffer\n"));
  1128. XSize = (SHORT)(TargetRect->Right - TargetRect->Left + 1);
  1129. YSize = (SHORT)(TargetRect->Bottom - TargetRect->Top + 1);
  1130. TargetPtr = Target;
  1131. WholeTarget = FALSE;
  1132. if (XSize == TargetSize.X) {
  1133. ASSERT (TargetRect->Left == 0);
  1134. if (TargetRect->Top != 0) {
  1135. TargetPtr = (PCHAR_INFO)
  1136. ((PBYTE)Target + SCREEN_BUFFER_POINTER(TargetRect->Left,
  1137. TargetRect->Top,
  1138. TargetSize.X,
  1139. sizeof(CHAR_INFO)));
  1140. }
  1141. WholeTarget = TRUE;
  1142. }
  1143. RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+SourcePoint.Y) % ScreenInfo->ScreenBufferSize.Y;
  1144. for (i=0;i<YSize;i++) {
  1145. if (!WholeTarget) {
  1146. TargetPtr = (PCHAR_INFO)
  1147. ((PBYTE)Target + SCREEN_BUFFER_POINTER(TargetRect->Left,
  1148. TargetRect->Top+i,
  1149. TargetSize.X,
  1150. sizeof(CHAR_INFO)));
  1151. }
  1152. //
  1153. // copy the chars and attrs from their respective arrays
  1154. //
  1155. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  1156. Char = &Row->CharRow.Chars[SourcePoint.X];
  1157. FindAttrIndex(Row->AttrRow.Attrs,
  1158. SourcePoint.X,
  1159. &Attr,
  1160. &CountOfAttr
  1161. );
  1162. k=0;
  1163. #if defined(FE_SB)
  1164. if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console)) {
  1165. PBYTE AttrP = &Row->CharRow.KAttrs[SourcePoint.X];
  1166. for (j=0;j<XSize;TargetPtr++) {
  1167. BYTE AttrR;
  1168. AttrR = *AttrP++;
  1169. if (j==0 && AttrR & ATTR_TRAILING_BYTE)
  1170. {
  1171. TargetPtr->Char.UnicodeChar = UNICODE_SPACE;
  1172. AttrR = 0;
  1173. }
  1174. else if (j+1 >= XSize && AttrR & ATTR_LEADING_BYTE)
  1175. {
  1176. TargetPtr->Char.UnicodeChar = UNICODE_SPACE;
  1177. AttrR = 0;
  1178. }
  1179. else
  1180. TargetPtr->Char.UnicodeChar = *Char;
  1181. Char++;
  1182. TargetPtr->Attributes = Attr->Attr | (WCHAR)(AttrR & ATTR_DBCSSBCS_BYTE) << 8;
  1183. j+=1;
  1184. if (++k==CountOfAttr && j<XSize) {
  1185. Attr++;
  1186. k=0;
  1187. CountOfAttr = Attr->Length;
  1188. }
  1189. }
  1190. }
  1191. else{
  1192. #endif
  1193. for (j=0;j<XSize;TargetPtr++) {
  1194. TargetPtr->Char.UnicodeChar = *Char++;
  1195. TargetPtr->Attributes = Attr->Attr;
  1196. j+=1;
  1197. if (++k==CountOfAttr && j<XSize) {
  1198. Attr++;
  1199. k=0;
  1200. CountOfAttr = Attr->Length;
  1201. }
  1202. }
  1203. #if defined(FE_SB)
  1204. }
  1205. #endif
  1206. if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
  1207. RowIndex = 0;
  1208. }
  1209. }
  1210. }
  1211. VOID
  1212. CopyRectangle(
  1213. IN PSCREEN_INFORMATION ScreenInfo,
  1214. IN PSMALL_RECT SourceRect,
  1215. IN COORD TargetPoint
  1216. )
  1217. /*++
  1218. Routine Description:
  1219. This routine copies a rectangular region from the screen buffer to
  1220. the screen buffer. no clipping is done.
  1221. Arguments:
  1222. ScreenInfo - pointer to screen info
  1223. SourceRect - rectangle in source buffer to copy
  1224. TargetPoint - upper left coordinates of new location rectangle
  1225. Return Value:
  1226. none.
  1227. --*/
  1228. {
  1229. SMALL_RECT Target;
  1230. COORD SourcePoint;
  1231. COORD Size;
  1232. DBGOUTPUT(("CopyRectangle\n"));
  1233. LockScrollBuffer();
  1234. SourcePoint.X = SourceRect->Left;
  1235. SourcePoint.Y = SourceRect->Top;
  1236. Target.Left = 0;
  1237. Target.Top = 0;
  1238. Target.Right = Size.X = SourceRect->Right - SourceRect->Left;
  1239. Target.Bottom = Size.Y = SourceRect->Bottom - SourceRect->Top;
  1240. Size.X++;
  1241. Size.Y++;
  1242. if (ScrollBufferSize < (Size.X * Size.Y * sizeof(CHAR_INFO))) {
  1243. FreeScrollBuffer();
  1244. if (!NT_SUCCESS(AllocateScrollBuffer(Size.X * Size.Y * sizeof(CHAR_INFO)))) {
  1245. UnlockScrollBuffer();
  1246. return;
  1247. }
  1248. }
  1249. ReadRectFromScreenBuffer(ScreenInfo,
  1250. SourcePoint,
  1251. ScrollBuffer,
  1252. Size,
  1253. &Target
  1254. );
  1255. WriteRectToScreenBuffer((PBYTE)ScrollBuffer,
  1256. Size,
  1257. &Target,
  1258. ScreenInfo,
  1259. TargetPoint,
  1260. 0xFFFFFFFF // ScrollBuffer won't need conversion
  1261. );
  1262. UnlockScrollBuffer();
  1263. }
  1264. NTSTATUS
  1265. ReadScreenBuffer(
  1266. IN PSCREEN_INFORMATION ScreenInformation,
  1267. OUT PCHAR_INFO Buffer,
  1268. IN OUT PSMALL_RECT ReadRegion
  1269. )
  1270. /*++
  1271. Routine Description:
  1272. This routine reads a rectangular region from the screen buffer.
  1273. The region is first clipped.
  1274. Arguments:
  1275. ScreenInformation - Screen buffer to read from.
  1276. Buffer - Buffer to read into.
  1277. ReadRegion - Region to read.
  1278. Return Value:
  1279. --*/
  1280. {
  1281. COORD TargetSize;
  1282. COORD TargetPoint,SourcePoint;
  1283. SMALL_RECT Target;
  1284. DBGOUTPUT(("ReadScreenBuffer\n"));
  1285. //
  1286. // calculate dimensions of caller's buffer. have to do this calculation
  1287. // before clipping.
  1288. //
  1289. TargetSize.X = (SHORT)(ReadRegion->Right - ReadRegion->Left + 1);
  1290. TargetSize.Y = (SHORT)(ReadRegion->Bottom - ReadRegion->Top + 1);
  1291. if (TargetSize.X <= 0 || TargetSize.Y <= 0) {
  1292. return STATUS_SUCCESS;
  1293. }
  1294. // do clipping.
  1295. if (ReadRegion->Right > (SHORT)(ScreenInformation->ScreenBufferSize.X-1)) {
  1296. ReadRegion->Right = (SHORT)(ScreenInformation->ScreenBufferSize.X-1);
  1297. }
  1298. if (ReadRegion->Bottom > (SHORT)(ScreenInformation->ScreenBufferSize.Y-1)) {
  1299. ReadRegion->Bottom = (SHORT)(ScreenInformation->ScreenBufferSize.Y-1);
  1300. }
  1301. if (ReadRegion->Left < 0) {
  1302. TargetPoint.X = -ReadRegion->Left;
  1303. ReadRegion->Left = 0;
  1304. } else {
  1305. TargetPoint.X = 0;
  1306. }
  1307. if (ReadRegion->Top < 0) {
  1308. TargetPoint.Y = -ReadRegion->Top;
  1309. ReadRegion->Top = 0;
  1310. }
  1311. else {
  1312. TargetPoint.Y = 0;
  1313. }
  1314. SourcePoint.X = ReadRegion->Left;
  1315. SourcePoint.Y = ReadRegion->Top;
  1316. Target.Left = TargetPoint.X;
  1317. Target.Top = TargetPoint.Y;
  1318. Target.Right = TargetPoint.X + (ReadRegion->Right - ReadRegion->Left);
  1319. Target.Bottom = TargetPoint.Y + (ReadRegion->Bottom - ReadRegion->Top);
  1320. ReadRectFromScreenBuffer(ScreenInformation,
  1321. SourcePoint,
  1322. Buffer,
  1323. TargetSize,
  1324. &Target
  1325. );
  1326. return STATUS_SUCCESS;
  1327. }
  1328. NTSTATUS
  1329. WriteScreenBuffer(
  1330. IN PSCREEN_INFORMATION ScreenInformation,
  1331. IN PCHAR_INFO Buffer,
  1332. IN OUT PSMALL_RECT WriteRegion
  1333. )
  1334. /*++
  1335. Routine Description:
  1336. This routine write a rectangular region to the screen buffer.
  1337. The region is first clipped.
  1338. The region should contain Unicode or UnicodeOem chars.
  1339. Arguments:
  1340. ScreenInformation - Screen buffer to write to.
  1341. Buffer - Buffer to write from.
  1342. ReadRegion - Region to write.
  1343. Return Value:
  1344. --*/
  1345. {
  1346. COORD SourceSize;
  1347. COORD TargetPoint;
  1348. SMALL_RECT SourceRect;
  1349. DBGOUTPUT(("WriteScreenBuffer\n"));
  1350. //
  1351. // Calculate dimensions of caller's buffer; this calculation must be
  1352. // done before clipping.
  1353. //
  1354. SourceSize.X = (SHORT)(WriteRegion->Right - WriteRegion->Left + 1);
  1355. SourceSize.Y = (SHORT)(WriteRegion->Bottom - WriteRegion->Top + 1);
  1356. if (SourceSize.X <= 0 || SourceSize.Y <= 0) {
  1357. return STATUS_SUCCESS;
  1358. }
  1359. //
  1360. // Ensure that the write region is within the constraints of the screen
  1361. // buffer.
  1362. //
  1363. if (WriteRegion->Left >= ScreenInformation->ScreenBufferSize.X ||
  1364. WriteRegion->Top >= ScreenInformation->ScreenBufferSize.Y) {
  1365. return STATUS_SUCCESS;
  1366. }
  1367. //
  1368. // Do clipping.
  1369. //
  1370. if (WriteRegion->Right > (SHORT)(ScreenInformation->ScreenBufferSize.X-1)) {
  1371. WriteRegion->Right = (SHORT)(ScreenInformation->ScreenBufferSize.X-1);
  1372. }
  1373. SourceRect.Right = WriteRegion->Right - WriteRegion->Left;
  1374. if (WriteRegion->Bottom > (SHORT)(ScreenInformation->ScreenBufferSize.Y-1)) {
  1375. WriteRegion->Bottom = (SHORT)(ScreenInformation->ScreenBufferSize.Y-1);
  1376. }
  1377. SourceRect.Bottom = WriteRegion->Bottom - WriteRegion->Top;
  1378. if (WriteRegion->Left < 0) {
  1379. SourceRect.Left = -WriteRegion->Left;
  1380. WriteRegion->Left = 0;
  1381. } else {
  1382. SourceRect.Left = 0;
  1383. }
  1384. if (WriteRegion->Top < 0) {
  1385. SourceRect.Top = -WriteRegion->Top;
  1386. WriteRegion->Top = 0;
  1387. } else {
  1388. SourceRect.Top = 0;
  1389. }
  1390. if (SourceRect.Left > SourceRect.Right ||
  1391. SourceRect.Top > SourceRect.Bottom) {
  1392. return STATUS_INVALID_PARAMETER;
  1393. }
  1394. TargetPoint.X = WriteRegion->Left;
  1395. TargetPoint.Y = WriteRegion->Top;
  1396. WriteRectToScreenBuffer((PBYTE)Buffer,
  1397. SourceSize,
  1398. &SourceRect,
  1399. ScreenInformation,
  1400. TargetPoint,
  1401. 0xFFFFFFFF
  1402. );
  1403. return STATUS_SUCCESS;
  1404. }
  1405. NTSTATUS
  1406. ReadOutputString(
  1407. IN PSCREEN_INFORMATION ScreenInfo,
  1408. OUT PVOID Buffer,
  1409. IN COORD ReadCoord,
  1410. IN ULONG StringType,
  1411. IN OUT PULONG NumRecords // this value is valid even for error cases
  1412. )
  1413. /*++
  1414. Routine Description:
  1415. This routine reads a string of characters or attributes from the
  1416. screen buffer.
  1417. Arguments:
  1418. ScreenInfo - Pointer to screen buffer information.
  1419. Buffer - Buffer to read into.
  1420. ReadCoord - Screen buffer coordinate to begin reading from.
  1421. StringType
  1422. CONSOLE_ASCII - read a string of ASCII characters.
  1423. CONSOLE_REAL_UNICODE - read a string of Real Unicode characters.
  1424. CONSOLE_FALSE_UNICODE - read a string of False Unicode characters.
  1425. CONSOLE_ATTRIBUTE - read a string of attributes.
  1426. NumRecords - On input, the size of the buffer in elements. On output,
  1427. the number of elements read.
  1428. Return Value:
  1429. --*/
  1430. {
  1431. ULONG NumRead;
  1432. SHORT X,Y;
  1433. SHORT RowIndex;
  1434. SHORT CountOfAttr;
  1435. PATTR_PAIR Attr;
  1436. PROW Row;
  1437. PWCHAR Char;
  1438. SHORT j,k;
  1439. PWCHAR TransBuffer = NULL;
  1440. PWCHAR BufPtr;
  1441. #if defined(FE_SB)
  1442. PBYTE AttrP;
  1443. PBYTE TransBufferA,BufPtrA;
  1444. PCONSOLE_INFORMATION Console = ScreenInfo->Console;
  1445. #endif
  1446. DBGOUTPUT(("ReadOutputString\n"));
  1447. if (*NumRecords == 0)
  1448. return STATUS_SUCCESS;
  1449. NumRead = 0;
  1450. X=ReadCoord.X;
  1451. Y=ReadCoord.Y;
  1452. if (X>=ScreenInfo->ScreenBufferSize.X ||
  1453. X<0 ||
  1454. Y>=ScreenInfo->ScreenBufferSize.Y ||
  1455. Y<0) {
  1456. *NumRecords = 0;
  1457. return STATUS_SUCCESS;
  1458. }
  1459. RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+ReadCoord.Y) % ScreenInfo->ScreenBufferSize.Y;
  1460. if (StringType == CONSOLE_ASCII) {
  1461. TransBuffer = ConsoleHeapAlloc(TMP_TAG, *NumRecords * sizeof(WCHAR));
  1462. if (TransBuffer == NULL) {
  1463. return STATUS_NO_MEMORY;
  1464. }
  1465. BufPtr = TransBuffer;
  1466. } else {
  1467. BufPtr = Buffer;
  1468. }
  1469. #if defined(FE_SB)
  1470. if (CONSOLE_IS_DBCS_OUTPUTCP(Console))
  1471. {
  1472. TransBufferA = ConsoleHeapAlloc(TMP_DBCS_TAG, *NumRecords * sizeof(BYTE));
  1473. if (TransBufferA == NULL) {
  1474. if (TransBuffer != NULL)
  1475. ConsoleHeapFree(TransBuffer);
  1476. return STATUS_NO_MEMORY;
  1477. }
  1478. BufPtrA = TransBufferA;
  1479. }
  1480. #endif
  1481. if ((StringType == CONSOLE_ASCII) ||
  1482. (StringType == CONSOLE_REAL_UNICODE) ||
  1483. (StringType == CONSOLE_FALSE_UNICODE)) {
  1484. while (NumRead < *NumRecords) {
  1485. //
  1486. // copy the chars from its array
  1487. //
  1488. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  1489. Char = &Row->CharRow.Chars[X];
  1490. #if defined(FE_SB)
  1491. if (CONSOLE_IS_DBCS_OUTPUTCP(Console))
  1492. AttrP = &Row->CharRow.KAttrs[X];
  1493. #endif
  1494. if ((ULONG)(ScreenInfo->ScreenBufferSize.X - X) > (*NumRecords - NumRead)) {
  1495. RtlCopyMemory(BufPtr,Char,(*NumRecords - NumRead) * sizeof(WCHAR));
  1496. #if defined(FE_SB)
  1497. if (CONSOLE_IS_DBCS_OUTPUTCP(Console))
  1498. RtlCopyMemory(BufPtrA,AttrP,(*NumRecords - NumRead) * sizeof(CHAR));
  1499. #endif
  1500. NumRead += *NumRecords - NumRead;
  1501. break;
  1502. }
  1503. RtlCopyMemory(BufPtr,Char,(ScreenInfo->ScreenBufferSize.X - X) * sizeof(WCHAR));
  1504. BufPtr = (PVOID)((PBYTE)BufPtr + ((ScreenInfo->ScreenBufferSize.X - X) * sizeof(WCHAR)));
  1505. #if defined(FE_SB)
  1506. if (CONSOLE_IS_DBCS_OUTPUTCP(Console)) {
  1507. RtlCopyMemory(BufPtrA,AttrP,(ScreenInfo->ScreenBufferSize.X - X) * sizeof(CHAR));
  1508. BufPtrA = (PVOID)((PBYTE)BufPtrA + ((ScreenInfo->ScreenBufferSize.X - X) * sizeof(CHAR)));
  1509. }
  1510. #endif
  1511. NumRead += ScreenInfo->ScreenBufferSize.X - X;
  1512. if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
  1513. RowIndex = 0;
  1514. }
  1515. X = 0;
  1516. Y++;
  1517. if (Y>=ScreenInfo->ScreenBufferSize.Y) {
  1518. break;
  1519. }
  1520. }
  1521. #if defined(FE_SB)
  1522. if (CONSOLE_IS_DBCS_OUTPUTCP(Console) && (NumRead)) {
  1523. if (StringType == CONSOLE_ASCII) {
  1524. Char = BufPtr = TransBuffer;
  1525. } else {
  1526. Char = BufPtr = Buffer;
  1527. }
  1528. AttrP = BufPtrA = TransBufferA;
  1529. if (*BufPtrA & ATTR_TRAILING_BYTE)
  1530. {
  1531. j = k = (SHORT)(NumRead - 1);
  1532. BufPtr++;
  1533. *Char++ = UNICODE_SPACE;
  1534. BufPtrA++;
  1535. NumRead = 1;
  1536. }
  1537. else {
  1538. j = k = (SHORT)NumRead;
  1539. NumRead = 0;
  1540. }
  1541. while (j--) {
  1542. if (!(*BufPtrA & ATTR_TRAILING_BYTE)) {
  1543. *Char++ = *BufPtr;
  1544. NumRead++;
  1545. }
  1546. BufPtr++;
  1547. BufPtrA++;
  1548. }
  1549. if (k && *(BufPtrA-1) & ATTR_LEADING_BYTE)
  1550. {
  1551. *(Char-1) = UNICODE_SPACE;
  1552. }
  1553. }
  1554. #endif
  1555. } else if (StringType == CONSOLE_ATTRIBUTE) {
  1556. PWORD TargetPtr=BufPtr;
  1557. while (NumRead < *NumRecords) {
  1558. //
  1559. // copy the attrs from its array
  1560. //
  1561. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  1562. #if defined(FE_SB)
  1563. if (CONSOLE_IS_DBCS_OUTPUTCP(Console))
  1564. AttrP = &Row->CharRow.KAttrs[X];
  1565. #endif
  1566. FindAttrIndex(Row->AttrRow.Attrs,
  1567. X,
  1568. &Attr,
  1569. &CountOfAttr
  1570. );
  1571. k=0;
  1572. for (j=X;j<ScreenInfo->ScreenBufferSize.X;TargetPtr++) {
  1573. #if defined(FE_SB)
  1574. if (!CONSOLE_IS_DBCS_OUTPUTCP(Console) )
  1575. *TargetPtr = Attr->Attr;
  1576. else if ((j == X) && (*AttrP & ATTR_TRAILING_BYTE))
  1577. *TargetPtr = Attr->Attr;
  1578. else if (*AttrP & ATTR_LEADING_BYTE){
  1579. if ((NumRead == *NumRecords-1)||(j == ScreenInfo->ScreenBufferSize.X-1))
  1580. *TargetPtr = Attr->Attr;
  1581. else
  1582. *TargetPtr = Attr->Attr | (WCHAR)(*AttrP & ATTR_DBCSSBCS_BYTE) << 8;
  1583. }
  1584. else
  1585. *TargetPtr = Attr->Attr | (WCHAR)(*AttrP & ATTR_DBCSSBCS_BYTE) << 8;
  1586. #else
  1587. *TargetPtr = Attr->Attr;
  1588. #endif
  1589. NumRead++;
  1590. j+=1;
  1591. if (++k==CountOfAttr && j<ScreenInfo->ScreenBufferSize.X) {
  1592. Attr++;
  1593. k=0;
  1594. CountOfAttr = Attr->Length;
  1595. }
  1596. if (NumRead == *NumRecords) {
  1597. #if defined(FE_SB)
  1598. if (CONSOLE_IS_DBCS_OUTPUTCP(Console))
  1599. ConsoleHeapFree(TransBufferA);
  1600. #endif
  1601. return STATUS_SUCCESS;
  1602. }
  1603. #if defined(FE_SB)
  1604. if (CONSOLE_IS_DBCS_OUTPUTCP(Console))
  1605. AttrP++;
  1606. #endif
  1607. }
  1608. if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
  1609. RowIndex = 0;
  1610. }
  1611. X = 0;
  1612. Y++;
  1613. if (Y>=ScreenInfo->ScreenBufferSize.Y) {
  1614. break;
  1615. }
  1616. }
  1617. } else {
  1618. *NumRecords = 0;
  1619. #if defined(FE_SB)
  1620. if (CONSOLE_IS_DBCS_OUTPUTCP(Console))
  1621. ConsoleHeapFree(TransBufferA);
  1622. #endif
  1623. return STATUS_INVALID_PARAMETER;
  1624. }
  1625. if (StringType == CONSOLE_ASCII) {
  1626. UINT Codepage;
  1627. #if defined(FE_SB)
  1628. if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  1629. !(ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
  1630. if (ScreenInfo->Console->OutputCP != WINDOWSCP)
  1631. Codepage = USACP;
  1632. else
  1633. Codepage = WINDOWSCP;
  1634. } else {
  1635. Codepage = ScreenInfo->Console->OutputCP;
  1636. }
  1637. #else
  1638. if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  1639. !(ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
  1640. Codepage = WINDOWSCP;
  1641. } else {
  1642. Codepage = ScreenInfo->Console->OutputCP;
  1643. }
  1644. #endif
  1645. #if defined(FE_SB)
  1646. if ((NumRead == 1) && !CONSOLE_IS_DBCS_OUTPUTCP(Console))
  1647. #else
  1648. if (NumRead == 1)
  1649. #endif
  1650. {
  1651. *((PBYTE)Buffer) = WcharToChar(Codepage, *TransBuffer);
  1652. } else {
  1653. NumRead = ConvertOutputToOem(Codepage, TransBuffer, NumRead, Buffer, *NumRecords);
  1654. }
  1655. ConsoleHeapFree(TransBuffer);
  1656. } else if (StringType == CONSOLE_REAL_UNICODE &&
  1657. (ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  1658. !(ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
  1659. /*
  1660. * Buffer contains false Unicode (UnicodeOem) only in Windowed
  1661. * RasterFont mode, so in this case, convert it to real Unicode.
  1662. */
  1663. FalseUnicodeToRealUnicode(Buffer,
  1664. NumRead,
  1665. ScreenInfo->Console->OutputCP
  1666. );
  1667. }
  1668. #if defined(FE_SB)
  1669. if (CONSOLE_IS_DBCS_OUTPUTCP(Console))
  1670. ConsoleHeapFree(TransBufferA);
  1671. #endif
  1672. *NumRecords = NumRead;
  1673. return STATUS_SUCCESS;
  1674. }
  1675. NTSTATUS
  1676. GetScreenBufferInformation(
  1677. IN PSCREEN_INFORMATION ScreenInfo,
  1678. OUT PCOORD Size,
  1679. OUT PCOORD CursorPosition,
  1680. OUT PCOORD ScrollPosition,
  1681. OUT PWORD Attributes,
  1682. OUT PCOORD CurrentWindowSize,
  1683. OUT PCOORD MaximumWindowSize
  1684. )
  1685. /*++
  1686. Routine Description:
  1687. This routine returns data about the screen buffer.
  1688. Arguments:
  1689. ScreenInfo - Pointer to screen buffer information.
  1690. Size - Pointer to location in which to store screen buffer size.
  1691. CursorPosition - Pointer to location in which to store the cursor position.
  1692. ScrollPosition - Pointer to location in which to store the scroll position.
  1693. Attributes - Pointer to location in which to store the default attributes.
  1694. CurrentWindowSize - Pointer to location in which to store current window size.
  1695. MaximumWindowSize - Pointer to location in which to store maximum window size.
  1696. Return Value:
  1697. --*/
  1698. {
  1699. WINDOW_LIMITS WindowLimits;
  1700. *Size = ScreenInfo->ScreenBufferSize;
  1701. *CursorPosition = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
  1702. ScrollPosition->X = ScreenInfo->Window.Left;
  1703. ScrollPosition->Y = ScreenInfo->Window.Top;
  1704. *Attributes = ScreenInfo->Attributes;
  1705. CurrentWindowSize->X = (SHORT)CONSOLE_WINDOW_SIZE_X(ScreenInfo);
  1706. CurrentWindowSize->Y = (SHORT)CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
  1707. if (ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  1708. MaximumWindowSize->X = min(80,ScreenInfo->ScreenBufferSize.X);
  1709. #if defined(FE_SB)
  1710. if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console)) {
  1711. MaximumWindowSize->Y = min(25,ScreenInfo->ScreenBufferSize.Y);
  1712. } else {
  1713. MaximumWindowSize->Y = min(50,ScreenInfo->ScreenBufferSize.Y);
  1714. }
  1715. #else
  1716. MaximumWindowSize->Y = min(50,ScreenInfo->ScreenBufferSize.Y);
  1717. #endif
  1718. } else {
  1719. GetWindowLimits(ScreenInfo, &WindowLimits);
  1720. *MaximumWindowSize = WindowLimits.MaximumWindowSize;
  1721. }
  1722. return STATUS_SUCCESS;
  1723. }
  1724. VOID
  1725. UpdateScrollBars(
  1726. IN PSCREEN_INFORMATION ScreenInfo
  1727. )
  1728. {
  1729. if (!ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
  1730. return;
  1731. }
  1732. if (ScreenInfo->Console->Flags & CONSOLE_UPDATING_SCROLL_BARS)
  1733. return;
  1734. ScreenInfo->Console->Flags |= CONSOLE_UPDATING_SCROLL_BARS;
  1735. PostMessage(ScreenInfo->Console->hWnd,
  1736. CM_UPDATE_SCROLL_BARS,
  1737. (WPARAM)ScreenInfo,
  1738. 0
  1739. );
  1740. }
  1741. VOID
  1742. InternalUpdateScrollBars(
  1743. IN PSCREEN_INFORMATION ScreenInfo
  1744. )
  1745. {
  1746. SCROLLINFO si;
  1747. ScreenInfo->Console->Flags &= ~CONSOLE_UPDATING_SCROLL_BARS;
  1748. if (!ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
  1749. return;
  1750. }
  1751. ScreenInfo->ResizingWindow++;
  1752. si.cbSize = sizeof(si);
  1753. si.fMask = SIF_ALL;
  1754. si.nPage = CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
  1755. si.nMin = 0;
  1756. si.nMax = ScreenInfo->ScreenBufferSize.Y - 1;
  1757. si.nPos = ScreenInfo->Window.Top;
  1758. SetScrollInfo(ScreenInfo->Console->hWnd, SB_VERT, &si, TRUE);
  1759. si.cbSize = sizeof(si);
  1760. si.fMask = SIF_ALL;
  1761. si.nPage = CONSOLE_WINDOW_SIZE_X(ScreenInfo);
  1762. si.nMin = 0;
  1763. si.nMax = ScreenInfo->ScreenBufferSize.X - 1;
  1764. si.nPos = ScreenInfo->Window.Left;
  1765. SetScrollInfo(ScreenInfo->Console->hWnd, SB_HORZ, &si, TRUE);
  1766. //
  1767. // Fire off an event to let accessibility apps know the layout has changed.
  1768. //
  1769. ConsoleNotifyWinEvent(ScreenInfo->Console,
  1770. EVENT_CONSOLE_LAYOUT,
  1771. 0,
  1772. 0);
  1773. ScreenInfo->ResizingWindow--;
  1774. }
  1775. VOID
  1776. ScreenBufferSizeChange(
  1777. IN PSCREEN_INFORMATION ScreenInfo,
  1778. IN COORD NewSize
  1779. )
  1780. {
  1781. INPUT_RECORD InputEvent;
  1782. InputEvent.EventType = WINDOW_BUFFER_SIZE_EVENT;
  1783. InputEvent.Event.WindowBufferSizeEvent.dwSize = NewSize;
  1784. WriteInputBuffer(ScreenInfo->Console,
  1785. &ScreenInfo->Console->InputBuffer,
  1786. &InputEvent,
  1787. 1
  1788. );
  1789. }
  1790. NTSTATUS
  1791. ResizeScreenBuffer(
  1792. IN PSCREEN_INFORMATION ScreenInfo,
  1793. IN COORD NewScreenSize,
  1794. IN BOOL DoScrollBarUpdate
  1795. )
  1796. /*++
  1797. Routine Description:
  1798. This routine resizes the screen buffer.
  1799. Arguments:
  1800. ScreenInfo - pointer to screen buffer info.
  1801. NewScreenSize - new size of screen.
  1802. Return Value:
  1803. --*/
  1804. {
  1805. SHORT i,j;
  1806. BOOLEAN WindowMaximizedX,WindowMaximizedY;
  1807. SHORT LimitX,LimitY;
  1808. PWCHAR TextRows,TextRowPtr;
  1809. BOOL UpdateWindow;
  1810. SHORT TopRow,TopRowIndex; // new top row of screen buffer
  1811. COORD CursorPosition;
  1812. #if defined(FE_SB)
  1813. DBCS_SCREEN_BUFFER NewDbcsScreenBuffer;
  1814. PBYTE TextRowPtrA;
  1815. #endif
  1816. //
  1817. // Don't allow resize of graphics apps
  1818. //
  1819. if (!(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)) {
  1820. return STATUS_UNSUCCESSFUL;
  1821. }
  1822. TextRows = ConsoleHeapAlloc(SCREEN_TAG,
  1823. NewScreenSize.X * NewScreenSize.Y * sizeof(WCHAR));
  1824. if (TextRows == NULL) {
  1825. return STATUS_NO_MEMORY;
  1826. }
  1827. #if defined(FE_SB)
  1828. if (! CreateDbcsScreenBuffer(ScreenInfo->Console,NewScreenSize,&NewDbcsScreenBuffer))
  1829. {
  1830. ConsoleHeapFree(TextRows);
  1831. return STATUS_NO_MEMORY;
  1832. }
  1833. #endif
  1834. LimitX = (NewScreenSize.X < ScreenInfo->ScreenBufferSize.X) ?
  1835. NewScreenSize.X : ScreenInfo->ScreenBufferSize.X;
  1836. LimitY = (NewScreenSize.Y < ScreenInfo->ScreenBufferSize.Y) ?
  1837. NewScreenSize.Y : ScreenInfo->ScreenBufferSize.Y;
  1838. TopRow = 0;
  1839. if (NewScreenSize.Y <= ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y) {
  1840. TopRow += ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y - NewScreenSize.Y + 1;
  1841. }
  1842. TopRowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TopRow) % ScreenInfo->ScreenBufferSize.Y;
  1843. if (NewScreenSize.Y != ScreenInfo->ScreenBufferSize.Y) {
  1844. PROW Temp;
  1845. SHORT NumToCopy,NumToCopy2;
  1846. //
  1847. // resize ROWs array. first alloc a new ROWs array. then copy the old
  1848. // one over, resetting the FirstRow.
  1849. //
  1850. //
  1851. Temp = ConsoleHeapAlloc(SCREEN_TAG, NewScreenSize.Y * sizeof(ROW));
  1852. if (Temp == NULL) {
  1853. ConsoleHeapFree(TextRows);
  1854. #if defined(FE_SB)
  1855. DeleteDbcsScreenBuffer(&NewDbcsScreenBuffer);
  1856. #endif
  1857. return STATUS_NO_MEMORY;
  1858. }
  1859. NumToCopy = ScreenInfo->ScreenBufferSize.Y-TopRowIndex;
  1860. if (NumToCopy > NewScreenSize.Y)
  1861. NumToCopy = NewScreenSize.Y;
  1862. RtlCopyMemory(Temp,&ScreenInfo->BufferInfo.TextInfo.Rows[TopRowIndex],NumToCopy*sizeof(ROW));
  1863. if (TopRowIndex!=0 && NumToCopy != NewScreenSize.Y) {
  1864. NumToCopy2 = TopRowIndex;
  1865. if (NumToCopy2 > (NewScreenSize.Y-NumToCopy))
  1866. NumToCopy2 = NewScreenSize.Y-NumToCopy;
  1867. RtlCopyMemory(&Temp[NumToCopy],
  1868. ScreenInfo->BufferInfo.TextInfo.Rows,
  1869. NumToCopy2*sizeof(ROW)
  1870. );
  1871. }
  1872. for (i=0;i<LimitY;i++) {
  1873. if (Temp[i].AttrRow.Length == 1) {
  1874. Temp[i].AttrRow.Attrs = &Temp[i].AttrRow.AttrPair;
  1875. }
  1876. }
  1877. //
  1878. // if the new screen buffer has fewer rows than the existing one,
  1879. // free the extra rows. if the new screen buffer has more rows
  1880. // than the existing one, allocate new rows.
  1881. //
  1882. if (NewScreenSize.Y < ScreenInfo->ScreenBufferSize.Y) {
  1883. i = (TopRowIndex+NewScreenSize.Y) % ScreenInfo->ScreenBufferSize.Y;
  1884. for (j=NewScreenSize.Y;j<ScreenInfo->ScreenBufferSize.Y;j++) {
  1885. if (ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Length > 1) {
  1886. ConsoleHeapFree(ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs);
  1887. }
  1888. if (++i == ScreenInfo->ScreenBufferSize.Y) {
  1889. i = 0;
  1890. }
  1891. }
  1892. } else if (NewScreenSize.Y > ScreenInfo->ScreenBufferSize.Y) {
  1893. for (i=ScreenInfo->ScreenBufferSize.Y;i<NewScreenSize.Y;i++) {
  1894. Temp[i].AttrRow.Length = 1;
  1895. Temp[i].AttrRow.AttrPair.Length = NewScreenSize.X;
  1896. Temp[i].AttrRow.AttrPair.Attr = ScreenInfo->Attributes;
  1897. Temp[i].AttrRow.Attrs = &Temp[i].AttrRow.AttrPair;
  1898. }
  1899. }
  1900. ScreenInfo->BufferInfo.TextInfo.FirstRow = 0;
  1901. ConsoleHeapFree(ScreenInfo->BufferInfo.TextInfo.Rows);
  1902. ScreenInfo->BufferInfo.TextInfo.Rows = Temp;
  1903. }
  1904. //
  1905. // Realloc each row. any horizontal growth results in the last
  1906. // attribute in a row getting extended.
  1907. //
  1908. #if defined(FE_SB)
  1909. TextRowPtrA=NewDbcsScreenBuffer.KAttrRows;
  1910. #endif
  1911. for (i=0,TextRowPtr=TextRows;i<LimitY;i++,TextRowPtr+=NewScreenSize.X)
  1912. {
  1913. RtlCopyMemory(TextRowPtr,
  1914. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.Chars,
  1915. LimitX*sizeof(WCHAR));
  1916. #if defined(FE_SB)
  1917. if (TextRowPtrA) {
  1918. RtlCopyMemory(TextRowPtrA,
  1919. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.KAttrs,
  1920. LimitX*sizeof(CHAR));
  1921. }
  1922. #endif
  1923. for (j=ScreenInfo->ScreenBufferSize.X;j<NewScreenSize.X;j++) {
  1924. TextRowPtr[j] = (WCHAR)' ';
  1925. }
  1926. if (ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.Right > NewScreenSize.X) {
  1927. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.OldRight = INVALID_OLD_LENGTH;
  1928. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.Right = NewScreenSize.X;
  1929. }
  1930. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.Chars = TextRowPtr;
  1931. #if defined(FE_SB)
  1932. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.KAttrs = TextRowPtrA;
  1933. if (TextRowPtrA) {
  1934. if (NewScreenSize.X > ScreenInfo->ScreenBufferSize.X)
  1935. RtlZeroMemory(TextRowPtrA+ScreenInfo->ScreenBufferSize.X,
  1936. NewScreenSize.X-ScreenInfo->ScreenBufferSize.X);
  1937. TextRowPtrA+=NewScreenSize.X;
  1938. }
  1939. #endif
  1940. }
  1941. for (;i<NewScreenSize.Y;i++,TextRowPtr+=NewScreenSize.X)
  1942. {
  1943. for (j=0;j<NewScreenSize.X;j++) {
  1944. TextRowPtr[j] = (WCHAR)' ';
  1945. }
  1946. #if defined(FE_SB)
  1947. if (TextRowPtrA) {
  1948. RtlZeroMemory(TextRowPtrA, NewScreenSize.X);
  1949. }
  1950. #endif
  1951. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.Chars = TextRowPtr;
  1952. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.OldLeft = INVALID_OLD_LENGTH;
  1953. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.OldRight = INVALID_OLD_LENGTH;
  1954. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.Left = NewScreenSize.X;
  1955. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.Right = 0;
  1956. #if defined(FE_SB)
  1957. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.KAttrs = TextRowPtrA;
  1958. if (TextRowPtrA) {
  1959. TextRowPtrA+=NewScreenSize.X;
  1960. }
  1961. #endif
  1962. }
  1963. ConsoleHeapFree(ScreenInfo->BufferInfo.TextInfo.TextRows);
  1964. ScreenInfo->BufferInfo.TextInfo.TextRows = TextRows;
  1965. #if defined(FE_SB)
  1966. DeleteDbcsScreenBuffer(&ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer);
  1967. ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer = NewDbcsScreenBuffer;
  1968. #endif
  1969. if (NewScreenSize.X != ScreenInfo->ScreenBufferSize.X) {
  1970. for (i=0;i<LimitY;i++) {
  1971. PATTR_PAIR IndexedAttr;
  1972. SHORT CountOfAttr;
  1973. if (NewScreenSize.X > ScreenInfo->ScreenBufferSize.X) {
  1974. FindAttrIndex(ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs,
  1975. (SHORT)(ScreenInfo->ScreenBufferSize.X-1),
  1976. &IndexedAttr,
  1977. &CountOfAttr
  1978. );
  1979. ASSERT (IndexedAttr <=
  1980. &ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs[ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Length-1]);
  1981. IndexedAttr->Length += NewScreenSize.X - ScreenInfo->ScreenBufferSize.X;
  1982. }
  1983. else {
  1984. FindAttrIndex(ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs,
  1985. (SHORT)(NewScreenSize.X-1),
  1986. &IndexedAttr,
  1987. &CountOfAttr
  1988. );
  1989. IndexedAttr->Length -= CountOfAttr-1;
  1990. if (ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Length != 1) {
  1991. ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Length = (SHORT)(IndexedAttr - ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs + 1);
  1992. if (ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Length != 1) {
  1993. ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs = ConsoleHeapReAlloc(SCREEN_TAG, ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs,
  1994. ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Length * sizeof(ATTR_PAIR));
  1995. }
  1996. else {
  1997. ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.AttrPair = *IndexedAttr;
  1998. ConsoleHeapFree(ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs);
  1999. ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.Attrs = &ScreenInfo->BufferInfo.TextInfo.Rows[i].AttrRow.AttrPair;
  2000. }
  2001. }
  2002. }
  2003. }
  2004. }
  2005. //
  2006. // if the screen buffer is resized smaller than the saved
  2007. // window size, shrink the saved window size.
  2008. //
  2009. #ifdef i386
  2010. if (ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN) {
  2011. if (NewScreenSize.X < ScreenInfo->BufferInfo.TextInfo.WindowedWindowSize.X) {
  2012. ScreenInfo->BufferInfo.TextInfo.WindowedWindowSize.X = NewScreenSize.X;
  2013. }
  2014. if (NewScreenSize.Y < ScreenInfo->BufferInfo.TextInfo.WindowedWindowSize.Y) {
  2015. ScreenInfo->BufferInfo.TextInfo.WindowedWindowSize.Y = NewScreenSize.Y;
  2016. }
  2017. ScreenInfo->BufferInfo.TextInfo.WindowedScreenSize = NewScreenSize;
  2018. }
  2019. #endif
  2020. UpdateWindow = FALSE;
  2021. //
  2022. // if the screen buffer shrunk beyond the boundaries of the window,
  2023. // adjust the window origin.
  2024. //
  2025. if (NewScreenSize.X > CONSOLE_WINDOW_SIZE_X(ScreenInfo)) {
  2026. if (ScreenInfo->Window.Right >= NewScreenSize.X) {
  2027. ScreenInfo->Window.Left -= ScreenInfo->Window.Right - NewScreenSize.X + 1;
  2028. ScreenInfo->Window.Right -= ScreenInfo->Window.Right - NewScreenSize.X + 1;
  2029. UpdateWindow = TRUE;
  2030. }
  2031. } else {
  2032. ScreenInfo->Window.Left = 0;
  2033. ScreenInfo->Window.Right = NewScreenSize.X - 1;
  2034. UpdateWindow = TRUE;
  2035. }
  2036. if (NewScreenSize.Y > CONSOLE_WINDOW_SIZE_Y(ScreenInfo)) {
  2037. if (ScreenInfo->Window.Bottom >= NewScreenSize.Y) {
  2038. ScreenInfo->Window.Top -= ScreenInfo->Window.Bottom - NewScreenSize.Y + 1;
  2039. ScreenInfo->Window.Bottom -= ScreenInfo->Window.Bottom - NewScreenSize.Y + 1;
  2040. UpdateWindow = TRUE;
  2041. }
  2042. } else {
  2043. ScreenInfo->Window.Top = 0;
  2044. ScreenInfo->Window.Bottom = NewScreenSize.Y - 1;
  2045. UpdateWindow = TRUE;
  2046. }
  2047. #if defined(FE_SB)
  2048. // Should be sets ScreenBufferSize before calls SetCursorPosition
  2049. // because SetCursorPosition refer ScreenBufferSize.
  2050. // Also, FE version refer in InvertPixels.
  2051. //
  2052. // kkntbug:11311
  2053. ScreenInfo->ScreenBufferSize = NewScreenSize;
  2054. #endif
  2055. //
  2056. // adjust cursor position if it's no longer with screen buffer
  2057. //
  2058. CursorPosition=ScreenInfo->BufferInfo.TextInfo.CursorPosition;
  2059. if (CursorPosition.X >= NewScreenSize.X) {
  2060. if (ScreenInfo->OutputMode & ENABLE_WRAP_AT_EOL_OUTPUT) {
  2061. CursorPosition.X = 0;
  2062. CursorPosition.Y += 1;
  2063. } else {
  2064. CursorPosition.X = NewScreenSize.X-1;
  2065. }
  2066. }
  2067. if (CursorPosition.Y >= NewScreenSize.Y) {
  2068. CursorPosition.Y = NewScreenSize.Y-1;
  2069. }
  2070. #if defined(FE_SB)
  2071. // set cursor position Y is ZERO when expand screen buffer with IME open mode
  2072. // from screen buffer is one line mode.
  2073. // Because, One line screen buffer mode and IME open mode is set -1 as cursor position Y.
  2074. if (ScreenInfo->Console->InputBuffer.ImeMode.Open && CursorPosition.Y < 0) {
  2075. CursorPosition.Y = 0;
  2076. }
  2077. #endif
  2078. if (CursorPosition.X != ScreenInfo->BufferInfo.TextInfo.CursorPosition.X ||
  2079. CursorPosition.Y != ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y) {
  2080. SetCursorPosition(ScreenInfo,
  2081. CursorPosition,
  2082. FALSE
  2083. );
  2084. }
  2085. ASSERT (ScreenInfo->Window.Left >= 0);
  2086. ASSERT (ScreenInfo->Window.Right < NewScreenSize.X);
  2087. ASSERT (ScreenInfo->Window.Top >= 0);
  2088. ASSERT (ScreenInfo->Window.Bottom < NewScreenSize.Y);
  2089. ScreenInfo->ScreenBufferSize = NewScreenSize;
  2090. ResetTextFlags(ScreenInfo,
  2091. 0,
  2092. 0,
  2093. (SHORT)(ScreenInfo->ScreenBufferSize.X - 1),
  2094. (SHORT)(ScreenInfo->ScreenBufferSize.Y - 1));
  2095. WindowMaximizedX = (CONSOLE_WINDOW_SIZE_X(ScreenInfo) ==
  2096. ScreenInfo->ScreenBufferSize.X);
  2097. WindowMaximizedY = (CONSOLE_WINDOW_SIZE_Y(ScreenInfo) ==
  2098. ScreenInfo->ScreenBufferSize.Y);
  2099. #if defined(FE_IME)
  2100. if (CONSOLE_IS_IME_ENABLED()) {
  2101. if (!NT_SUCCESS(ConsoleImeMessagePump(ScreenInfo->Console,
  2102. CONIME_NOTIFY_SCREENBUFFERSIZE,
  2103. (WPARAM)ScreenInfo->Console->ConsoleHandle,
  2104. (LPARAM)MAKELPARAM(NewScreenSize.X, NewScreenSize.Y)
  2105. ))) {
  2106. return STATUS_INVALID_HANDLE;
  2107. }
  2108. }
  2109. if ( (! ScreenInfo->ConvScreenInfo) &&
  2110. (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console)))
  2111. {
  2112. if (!NT_SUCCESS(ConsoleImeResizeModeSystemScreenBuffer(ScreenInfo->Console,NewScreenSize)) ||
  2113. !NT_SUCCESS(ConsoleImeResizeCompStrScreenBuffer(ScreenInfo->Console,NewScreenSize))) {
  2114. /*
  2115. * If something went wrong, just bail out.
  2116. */
  2117. return STATUS_INVALID_HANDLE;
  2118. }
  2119. }
  2120. #endif // FE_IME
  2121. if (ScreenInfo->WindowMaximizedX != WindowMaximizedX ||
  2122. ScreenInfo->WindowMaximizedY != WindowMaximizedY) {
  2123. ScreenInfo->WindowMaximizedX = WindowMaximizedX;
  2124. ScreenInfo->WindowMaximizedY = WindowMaximizedY;
  2125. UpdateWindow = TRUE;
  2126. }
  2127. if (UpdateWindow) {
  2128. SetWindowSize(ScreenInfo);
  2129. }
  2130. //
  2131. // Fire off an event to let accessibility apps know the layout has changed.
  2132. //
  2133. if (ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
  2134. ConsoleNotifyWinEvent(ScreenInfo->Console,
  2135. EVENT_CONSOLE_LAYOUT,
  2136. 0,
  2137. 0);
  2138. }
  2139. if (DoScrollBarUpdate) {
  2140. UpdateScrollBars(ScreenInfo);
  2141. }
  2142. if (ScreenInfo->Console->InputBuffer.InputMode & ENABLE_WINDOW_INPUT) {
  2143. ScreenBufferSizeChange(ScreenInfo,ScreenInfo->ScreenBufferSize);
  2144. }
  2145. return STATUS_SUCCESS;
  2146. }
  2147. NTSTATUS
  2148. AllocateScrollBuffer(
  2149. DWORD Size
  2150. )
  2151. {
  2152. ScrollBuffer = ConsoleHeapAlloc(SCREEN_TAG, Size);
  2153. if (ScrollBuffer == NULL) {
  2154. ScrollBufferSize = 0;
  2155. return STATUS_NO_MEMORY;
  2156. }
  2157. ScrollBufferSize = Size;
  2158. return STATUS_SUCCESS;
  2159. }
  2160. VOID
  2161. FreeScrollBuffer( VOID )
  2162. {
  2163. ConsoleHeapFree(ScrollBuffer);
  2164. ScrollBuffer = NULL;
  2165. ScrollBufferSize = 0;
  2166. }
  2167. NTSTATUS
  2168. InitializeScrollBuffer(
  2169. VOID)
  2170. {
  2171. NTSTATUS Status;
  2172. /*
  2173. * It's possible for this function to be called multiple times, if, e.g.,
  2174. * console initialization fails the first time *after* this function is
  2175. * called.
  2176. */
  2177. if (ghrgnScroll) {
  2178. return STATUS_SUCCESS;
  2179. }
  2180. ghrgnScroll = CreateRectRgn(0,0,1,1);
  2181. if (ghrgnScroll == NULL) {
  2182. RIPMSGF0(RIP_WARNING, "Cannot allocate ghrgnScroll.");
  2183. return STATUS_UNSUCCESSFUL;
  2184. }
  2185. gprgnData = ConsoleHeapAlloc(SCREEN_TAG, GRGNDATASIZE);
  2186. if (gprgnData == NULL) {
  2187. RIPMSGF0(RIP_WARNING, "Cannot allocate gprgnData.");
  2188. Status = STATUS_NO_MEMORY;
  2189. goto error;
  2190. }
  2191. Status = AllocateScrollBuffer(DefaultRegInfo.ScreenBufferSize.X *
  2192. DefaultRegInfo.ScreenBufferSize.Y *
  2193. sizeof(CHAR_INFO));
  2194. if (!NT_SUCCESS(Status)) {
  2195. goto error;
  2196. }
  2197. Status = RtlInitializeCriticalSectionAndSpinCount(&ScrollBufferLock,
  2198. 0x80000000);
  2199. error:
  2200. if (!NT_SUCCESS(Status)) {
  2201. RIPMSG0(RIP_WARNING, "InitializeScrollBuffer failed, cleaning up");
  2202. if (ghrgnScroll) {
  2203. DeleteObject(ghrgnScroll);
  2204. ghrgnScroll = NULL;
  2205. }
  2206. if (gprgnData) {
  2207. ConsoleHeapFree(gprgnData);
  2208. gprgnData = NULL;
  2209. }
  2210. }
  2211. UserAssert(!NT_SUCCESS(Status) || ghrgnScroll);
  2212. return Status;
  2213. }
  2214. VOID
  2215. UpdateComplexRegion(
  2216. IN PSCREEN_INFORMATION ScreenInfo,
  2217. IN COORD FontSize
  2218. )
  2219. {
  2220. int iSize,i;
  2221. LPRECT pRect;
  2222. SMALL_RECT UpdateRegion;
  2223. LPRGNDATA pRgnData;
  2224. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  2225. ScreenInfo->BufferInfo.TextInfo.Flags &= ~TEXT_VALID_HINT;
  2226. }
  2227. pRgnData = gprgnData;
  2228. /*
  2229. * the dreaded complex region.
  2230. */
  2231. iSize = GetRegionData(ghrgnScroll, 0, NULL);
  2232. if (iSize > GRGNDATASIZE) {
  2233. pRgnData = ConsoleHeapAlloc(TMP_TAG, iSize);
  2234. if (pRgnData == NULL)
  2235. return;
  2236. }
  2237. if (!GetRegionData(ghrgnScroll, iSize, pRgnData)) {
  2238. ASSERT(FALSE);
  2239. if (pRgnData != gprgnData) {
  2240. ConsoleHeapFree(pRgnData);
  2241. }
  2242. return;
  2243. }
  2244. pRect = (PRECT)&pRgnData->Buffer;
  2245. /*
  2246. * Redraw each rectangle
  2247. */
  2248. for(i=0;i<(int)pRgnData->rdh.nCount;i++,pRect++) {
  2249. /*
  2250. * Convert to chars. We know
  2251. * this is only get to get converted back during
  2252. * the textout call.
  2253. */
  2254. UpdateRegion.Left = (SHORT)((pRect->left/FontSize.X)+ \
  2255. ScreenInfo->Window.Left);
  2256. UpdateRegion.Right = (SHORT)(((pRect->right-1)/FontSize.X)+ \
  2257. ScreenInfo->Window.Left);
  2258. UpdateRegion.Top = (SHORT)((pRect->top/FontSize.Y)+ \
  2259. ScreenInfo->Window.Top);
  2260. UpdateRegion.Bottom = (SHORT)(((pRect->bottom-1)/FontSize.Y)+ \
  2261. ScreenInfo->Window.Top);
  2262. /*
  2263. * Fill the rectangle with goodies.
  2264. */
  2265. WriteToScreen(ScreenInfo, &UpdateRegion);
  2266. }
  2267. if (pRgnData != gprgnData) {
  2268. ConsoleHeapFree(pRgnData);
  2269. }
  2270. }
  2271. VOID
  2272. ScrollScreen(
  2273. IN PSCREEN_INFORMATION ScreenInfo,
  2274. IN PSMALL_RECT ScrollRect,
  2275. IN PSMALL_RECT MergeRect,
  2276. IN COORD TargetPoint
  2277. )
  2278. {
  2279. RECT ScrollRectGdi;
  2280. SMALL_RECT UpdateRegion;
  2281. COORD FontSize;
  2282. BOOL Success;
  2283. RECT BoundingBox;
  2284. #if defined(FE_SB)
  2285. BYTE fBisect = 0;
  2286. SMALL_RECT UpdateRect;
  2287. SMALL_RECT TmpBisect;
  2288. #endif
  2289. DBGOUTPUT(("ScrollScreen\n"));
  2290. if (!ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
  2291. return;
  2292. }
  2293. if (ScreenInfo->Console->FullScreenFlags == 0 &&
  2294. !(ScreenInfo->Console->Flags & (CONSOLE_IS_ICONIC | CONSOLE_NO_WINDOW))) {
  2295. #if defined(FE_SB)
  2296. if (ScreenInfo->BisectFlag){
  2297. SMALL_RECT RedrawRect;
  2298. if (ScrollRect->Top < TargetPoint.Y){
  2299. RedrawRect.Top = ScrollRect->Top;
  2300. RedrawRect.Bottom = TargetPoint.Y+(ScrollRect->Bottom-ScrollRect->Top);
  2301. }
  2302. else{
  2303. RedrawRect.Top = TargetPoint.Y;
  2304. RedrawRect.Bottom = ScrollRect->Bottom;
  2305. }
  2306. if (ScrollRect->Left < TargetPoint.X){
  2307. RedrawRect.Left = ScrollRect->Left;
  2308. RedrawRect.Right = TargetPoint.X+(ScrollRect->Right-ScrollRect->Left);
  2309. }
  2310. else{
  2311. RedrawRect.Left = TargetPoint.X;
  2312. RedrawRect.Right = ScrollRect->Right;
  2313. }
  2314. WriteToScreen(ScreenInfo,&RedrawRect);
  2315. }
  2316. else{
  2317. #endif
  2318. ScrollRectGdi.left = ScrollRect->Left-ScreenInfo->Window.Left;
  2319. ScrollRectGdi.right = (ScrollRect->Right-ScreenInfo->Window.Left+1);
  2320. ScrollRectGdi.top = ScrollRect->Top-ScreenInfo->Window.Top;
  2321. ScrollRectGdi.bottom = (ScrollRect->Bottom-ScreenInfo->Window.Top+1);
  2322. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  2323. FontSize = SCR_FONTSIZE(ScreenInfo);
  2324. ScrollRectGdi.left *= FontSize.X;
  2325. ScrollRectGdi.right *= FontSize.X;
  2326. ScrollRectGdi.top *= FontSize.Y;
  2327. ScrollRectGdi.bottom *= FontSize.Y;
  2328. ASSERT (ScreenInfo->BufferInfo.TextInfo.UpdatingScreen>0);
  2329. } else {
  2330. FontSize.X = 1;
  2331. FontSize.Y = 1;
  2332. }
  2333. SCROLLDC_CALL;
  2334. LockScrollBuffer();
  2335. Success = (int)ScrollDC(ScreenInfo->Console->hDC,
  2336. (TargetPoint.X-ScrollRect->Left)*FontSize.X,
  2337. (TargetPoint.Y-ScrollRect->Top)*FontSize.Y,
  2338. &ScrollRectGdi,
  2339. NULL,
  2340. ghrgnScroll,
  2341. NULL);
  2342. //
  2343. // Fire off an event to let accessibility apps know we've scrolled.
  2344. //
  2345. ConsoleNotifyWinEvent(ScreenInfo->Console,
  2346. EVENT_CONSOLE_UPDATE_SCROLL,
  2347. TargetPoint.X - ScrollRect->Left,
  2348. TargetPoint.Y - ScrollRect->Top);
  2349. if (Success) {
  2350. /*
  2351. * Fetch our rectangles. If this is a simple rect then
  2352. * we have already retrieved the rectangle. Otherwise
  2353. * we need to call gdi to get the rectangles. We are
  2354. * optimized for speed rather than size.
  2355. */
  2356. switch (GetRgnBox(ghrgnScroll, &BoundingBox)) {
  2357. case SIMPLEREGION:
  2358. UpdateRegion.Left = (SHORT)((BoundingBox.left / FontSize.X) + \
  2359. ScreenInfo->Window.Left);
  2360. UpdateRegion.Right = (SHORT)(((BoundingBox.right-1) / FontSize.X) + \
  2361. ScreenInfo->Window.Left);
  2362. UpdateRegion.Top = (SHORT)((BoundingBox.top / FontSize.Y) + \
  2363. ScreenInfo->Window.Top);
  2364. UpdateRegion.Bottom = (SHORT)(((BoundingBox.bottom-1) / FontSize.Y) + \
  2365. ScreenInfo->Window.Top);
  2366. #if defined(FE_SB)
  2367. fBisect = ScreenInfo->BisectFlag;
  2368. #endif
  2369. WriteToScreen(ScreenInfo, &UpdateRegion);
  2370. break;
  2371. case COMPLEXREGION:
  2372. UpdateComplexRegion(ScreenInfo, FontSize);
  2373. break;
  2374. }
  2375. if (MergeRect) {
  2376. #if defined(FE_SB)
  2377. if (fBisect)
  2378. ScreenInfo->BisectFlag = fBisect;
  2379. else
  2380. fBisect = ScreenInfo->BisectFlag;
  2381. #endif
  2382. WriteToScreen(ScreenInfo, MergeRect);
  2383. }
  2384. #if defined(FE_SB)
  2385. if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console)) {
  2386. UpdateRect.Left = TargetPoint.X;
  2387. UpdateRect.Right = ScrollRect->Right + (TargetPoint.X-ScrollRect->Left);
  2388. UpdateRect.Top = TargetPoint.Y;
  2389. UpdateRect.Bottom = ScrollRect->Bottom + (TargetPoint.Y-ScrollRect->Top);
  2390. if (UpdateRect.Left &&
  2391. UpdateRect.Right+1 < ScreenInfo->ScreenBufferSize.X &&
  2392. UpdateRect.Right-UpdateRect.Left <= 2) {
  2393. TmpBisect.Left = UpdateRect.Left-1;
  2394. TmpBisect.Right = UpdateRect.Right+1;
  2395. TmpBisect.Top = UpdateRect.Top;
  2396. TmpBisect.Bottom = UpdateRect.Bottom;
  2397. WriteToScreen(ScreenInfo, &TmpBisect);
  2398. }
  2399. else {
  2400. if (UpdateRect.Left) {
  2401. TmpBisect.Left = UpdateRect.Left-1;
  2402. TmpBisect.Right = UpdateRect.Left;
  2403. TmpBisect.Top = UpdateRect.Top;
  2404. TmpBisect.Bottom = UpdateRect.Bottom;
  2405. WriteToScreen(ScreenInfo, &TmpBisect);
  2406. }
  2407. if (UpdateRect.Right+1 < ScreenInfo->ScreenBufferSize.X) {
  2408. TmpBisect.Left = UpdateRect.Right;
  2409. TmpBisect.Right = UpdateRect.Right+1;
  2410. TmpBisect.Top = UpdateRect.Top;
  2411. TmpBisect.Bottom = UpdateRect.Bottom;
  2412. WriteToScreen(ScreenInfo, &TmpBisect);
  2413. }
  2414. }
  2415. }
  2416. #endif
  2417. } else {
  2418. #if defined(FE_SB)
  2419. if (fBisect)
  2420. ScreenInfo->BisectFlag = fBisect;
  2421. else
  2422. fBisect = ScreenInfo->BisectFlag;
  2423. #endif
  2424. WriteToScreen(ScreenInfo, &ScreenInfo->Window);
  2425. }
  2426. UnlockScrollBuffer();
  2427. #if defined(FE_SB)
  2428. }
  2429. #endif
  2430. }
  2431. #ifdef i386
  2432. else if (ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  2433. #if defined(FE_SB)
  2434. if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console)) {
  2435. if (! ScreenInfo->ConvScreenInfo) {
  2436. if (ScreenInfo->Console->CurrentScreenBuffer == ScreenInfo) {
  2437. ScrollHW(ScreenInfo,
  2438. ScrollRect,
  2439. MergeRect,
  2440. TargetPoint
  2441. );
  2442. }
  2443. }
  2444. else if (ScreenInfo->Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER) {
  2445. ScrollHW(ScreenInfo,
  2446. ScrollRect,
  2447. MergeRect,
  2448. TargetPoint
  2449. );
  2450. }
  2451. }
  2452. else
  2453. #endif
  2454. ScrollHW(ScreenInfo,
  2455. ScrollRect,
  2456. MergeRect,
  2457. TargetPoint
  2458. );
  2459. }
  2460. #endif
  2461. }
  2462. void CopyRow(
  2463. PROW Row,
  2464. PROW PrevRow)
  2465. {
  2466. if (PrevRow->AttrRow.Length != 1 ||
  2467. Row->AttrRow.Length != 1 ||
  2468. PrevRow->AttrRow.Attrs->Attr != Row->AttrRow.Attrs->Attr) {
  2469. Row->CharRow.OldRight = INVALID_OLD_LENGTH;
  2470. Row->CharRow.OldLeft = INVALID_OLD_LENGTH;
  2471. } else {
  2472. Row->CharRow.OldRight = PrevRow->CharRow.Right;
  2473. Row->CharRow.OldLeft = PrevRow->CharRow.Left;
  2474. }
  2475. }
  2476. SHORT
  2477. ScrollEntireScreen(
  2478. IN PSCREEN_INFORMATION ScreenInfo,
  2479. IN SHORT ScrollValue,
  2480. IN BOOL UpdateRowIndex
  2481. )
  2482. /**++
  2483. this routine updates FirstRow and all the OldLeft and OldRight
  2484. values when the screen is scrolled up by ScrollValue.
  2485. --*/
  2486. {
  2487. SHORT RowIndex;
  2488. int i;
  2489. int new;
  2490. int old;
  2491. ScreenInfo->BufferInfo.TextInfo.Flags |= TEXT_VALID_HINT;
  2492. //
  2493. // store index of first row
  2494. //
  2495. RowIndex = ScreenInfo->BufferInfo.TextInfo.FirstRow;
  2496. //
  2497. // update the oldright and oldleft values
  2498. //
  2499. new = (RowIndex + ScreenInfo->Window.Bottom + ScrollValue) %
  2500. ScreenInfo->ScreenBufferSize.Y;
  2501. old = (RowIndex + ScreenInfo->Window.Bottom) %
  2502. ScreenInfo->ScreenBufferSize.Y;
  2503. for (i = WINDOW_SIZE_Y(&ScreenInfo->Window) - 1; i >= 0; i--) {
  2504. CopyRow(
  2505. &ScreenInfo->BufferInfo.TextInfo.Rows[new],
  2506. &ScreenInfo->BufferInfo.TextInfo.Rows[old]);
  2507. if (--new < 0)
  2508. new = ScreenInfo->ScreenBufferSize.Y - 1;
  2509. if (--old < 0)
  2510. old = ScreenInfo->ScreenBufferSize.Y - 1;
  2511. }
  2512. //
  2513. // update screen buffer
  2514. //
  2515. if (UpdateRowIndex) {
  2516. ScreenInfo->BufferInfo.TextInfo.FirstRow =
  2517. (SHORT)((RowIndex + ScrollValue) % ScreenInfo->ScreenBufferSize.Y);
  2518. }
  2519. return RowIndex;
  2520. }
  2521. VOID
  2522. StreamScrollRegion(
  2523. IN PSCREEN_INFORMATION ScreenInfo
  2524. )
  2525. /*++
  2526. Routine Description:
  2527. This routine is a special-purpose scroll for use by
  2528. AdjustCursorPosition.
  2529. Arguments:
  2530. ScreenInfo - pointer to screen buffer info.
  2531. Return Value:
  2532. --*/
  2533. {
  2534. SHORT RowIndex;
  2535. PROW Row;
  2536. PWCHAR Char;
  2537. RECT Rect;
  2538. RECT BoundingBox;
  2539. int ScreenWidth,ScrollHeight,ScreenHeight;
  2540. COORD FontSize;
  2541. SMALL_RECT UpdateRegion;
  2542. BOOL Success;
  2543. int i;
  2544. #if defined(FE_SB)
  2545. PBYTE AttrP;
  2546. #endif
  2547. PCONSOLE_INFORMATION Console = ScreenInfo->Console;
  2548. RowIndex = ScrollEntireScreen(ScreenInfo,1,TRUE);
  2549. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  2550. //
  2551. // fill line with blanks
  2552. //
  2553. Char = &Row->CharRow.Chars[Row->CharRow.Left];
  2554. for (i=Row->CharRow.Left;i<Row->CharRow.Right;i++) {
  2555. *Char = (WCHAR)' ';
  2556. Char++;
  2557. }
  2558. #if defined(FE_SB)
  2559. if (CONSOLE_IS_DBCS_OUTPUTCP(Console)){
  2560. int LineWidth = Row->CharRow.Right - Row->CharRow.Left;
  2561. AttrP = &Row->CharRow.KAttrs[Row->CharRow.Left];
  2562. if ( LineWidth > 0 )
  2563. RtlZeroMemory(AttrP, LineWidth);
  2564. AttrP += LineWidth;
  2565. Row->CharRow.OldRight = INVALID_OLD_LENGTH;
  2566. Row->CharRow.OldLeft = INVALID_OLD_LENGTH;
  2567. Console->ConsoleIme.ScrollWaitCountDown = Console->ConsoleIme.ScrollWaitTimeout;
  2568. }
  2569. #endif
  2570. Row->CharRow.Right = 0;
  2571. Row->CharRow.Left = ScreenInfo->ScreenBufferSize.X;
  2572. //
  2573. // set up attributes
  2574. //
  2575. if (Row->AttrRow.Length != 1) {
  2576. ConsoleHeapFree(Row->AttrRow.Attrs);
  2577. Row->AttrRow.Attrs = &Row->AttrRow.AttrPair;
  2578. Row->AttrRow.AttrPair.Length = ScreenInfo->ScreenBufferSize.X;
  2579. Row->AttrRow.Length = 1;
  2580. }
  2581. Row->AttrRow.AttrPair.Attr = ScreenInfo->Attributes;
  2582. //
  2583. // update screen
  2584. //
  2585. if (ACTIVE_SCREEN_BUFFER(ScreenInfo) &&
  2586. Console->FullScreenFlags == 0 &&
  2587. !(Console->Flags & (CONSOLE_IS_ICONIC | CONSOLE_NO_WINDOW))) {
  2588. ConsoleHideCursor(ScreenInfo);
  2589. if (UsePolyTextOut) {
  2590. WriteRegionToScreen(ScreenInfo, &ScreenInfo->Window);
  2591. } else {
  2592. FontSize = SCR_FONTSIZE(ScreenInfo);
  2593. ScreenWidth = WINDOW_SIZE_X(&ScreenInfo->Window) * FontSize.X;
  2594. ScreenHeight = WINDOW_SIZE_Y(&ScreenInfo->Window) * FontSize.Y;
  2595. ScrollHeight = ScreenHeight - FontSize.Y;
  2596. Rect.left = 0;
  2597. Rect.right = ScreenWidth;
  2598. Rect.top = FontSize.Y;
  2599. Rect.bottom = ScreenHeight;
  2600. //
  2601. // find smallest bounding rectangle
  2602. //
  2603. if (ScreenInfo->BufferInfo.TextInfo.Flags & TEXT_VALID_HINT) {
  2604. SHORT MinLeft,MaxRight;
  2605. MinLeft = ScreenInfo->ScreenBufferSize.X;
  2606. MaxRight = 0;
  2607. RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+ScreenInfo->Window.Top) % ScreenInfo->ScreenBufferSize.Y;
  2608. for (i=ScreenInfo->Window.Top+1;i<=ScreenInfo->Window.Bottom;i++) {
  2609. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  2610. if (Row->CharRow.OldLeft == INVALID_OLD_LENGTH) {
  2611. MinLeft = 0;
  2612. } else {
  2613. if (MinLeft > min(Row->CharRow.Left,Row->CharRow.OldLeft)) {
  2614. MinLeft = min(Row->CharRow.Left,Row->CharRow.OldLeft);
  2615. }
  2616. }
  2617. if (Row->CharRow.OldRight == INVALID_OLD_LENGTH) {
  2618. MaxRight = ScreenInfo->ScreenBufferSize.X-1;
  2619. } else {
  2620. if (MaxRight < max(Row->CharRow.Right,Row->CharRow.OldRight)) {
  2621. MaxRight = max(Row->CharRow.Right,Row->CharRow.OldRight);
  2622. }
  2623. }
  2624. if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
  2625. RowIndex = 0;
  2626. }
  2627. }
  2628. Rect.left = MinLeft*FontSize.X;
  2629. Rect.right = (MaxRight+1)*FontSize.X;
  2630. }
  2631. LockScrollBuffer();
  2632. ASSERT (ScreenInfo->BufferInfo.TextInfo.UpdatingScreen>0);
  2633. Success = (int)ScrollDC(Console->hDC,
  2634. 0,
  2635. -FontSize.Y,
  2636. &Rect,
  2637. NULL,
  2638. ghrgnScroll,
  2639. NULL
  2640. );
  2641. //
  2642. // Fire off an event to let accessibility apps know we've scrolled.
  2643. //
  2644. ConsoleNotifyWinEvent(Console,
  2645. EVENT_CONSOLE_UPDATE_SCROLL,
  2646. 0,
  2647. -1);
  2648. if (Success && ScreenInfo->Window.Top!=ScreenInfo->Window.Bottom) {
  2649. #if defined(FE_SB)
  2650. if (CONSOLE_IS_DBCS_OUTPUTCP(Console) &&
  2651. ScreenInfo->Attributes & (COMMON_LVB_GRID_HORIZONTAL +
  2652. COMMON_LVB_GRID_LVERTICAL +
  2653. COMMON_LVB_GRID_RVERTICAL +
  2654. COMMON_LVB_REVERSE_VIDEO +
  2655. COMMON_LVB_UNDERSCORE )){
  2656. UpdateRegion = ScreenInfo->Window;
  2657. UpdateRegion.Top = UpdateRegion.Bottom;
  2658. ScreenInfo->BufferInfo.TextInfo.Flags &= ~TEXT_VALID_HINT;
  2659. WriteToScreen(ScreenInfo,&UpdateRegion);
  2660. }
  2661. else{
  2662. #endif
  2663. switch (GetRgnBox(ghrgnScroll, &BoundingBox)) {
  2664. case SIMPLEREGION:
  2665. if (BoundingBox.left == 0 &&
  2666. BoundingBox.right == ScreenWidth &&
  2667. BoundingBox.top == ScrollHeight &&
  2668. BoundingBox.bottom == ScreenHeight) {
  2669. PatBlt(Console->hDC,0,ScrollHeight,ScreenWidth,FontSize.Y,PATCOPY);
  2670. GdiFlush();
  2671. } else {
  2672. UpdateRegion.Left = (SHORT)((BoundingBox.left/FontSize.X)+ScreenInfo->Window.Left);
  2673. UpdateRegion.Right = (SHORT)(((BoundingBox.right-1)/FontSize.X)+ScreenInfo->Window.Left);
  2674. UpdateRegion.Top = (SHORT)((BoundingBox.top/FontSize.Y)+ScreenInfo->Window.Top);
  2675. UpdateRegion.Bottom = (SHORT)(((BoundingBox.bottom-1)/FontSize.Y)+ScreenInfo->Window.Top);
  2676. WriteToScreen(ScreenInfo,&UpdateRegion);
  2677. }
  2678. break;
  2679. case COMPLEXREGION:
  2680. UpdateComplexRegion(ScreenInfo,FontSize);
  2681. break;
  2682. }
  2683. #if defined(FE_SB)
  2684. }
  2685. #endif
  2686. } else {
  2687. WriteToScreen(ScreenInfo,&ScreenInfo->Window);
  2688. }
  2689. UnlockScrollBuffer();
  2690. }
  2691. ConsoleShowCursor(ScreenInfo);
  2692. }
  2693. #ifdef i386
  2694. else if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  2695. SMALL_RECT ScrollRect;
  2696. COORD TargetPoint;
  2697. ScrollRect = ScreenInfo->Window;
  2698. TargetPoint.Y = ScrollRect.Top;
  2699. ScrollRect.Top += 1;
  2700. TargetPoint.X = 0;
  2701. #if defined(FE_SB)
  2702. if (CONSOLE_IS_DBCS_OUTPUTCP(Console) ) {
  2703. if (! ScreenInfo->ConvScreenInfo) {
  2704. if (ScreenInfo->Console->CurrentScreenBuffer == ScreenInfo) {
  2705. ScrollHW(ScreenInfo,
  2706. &ScrollRect,
  2707. NULL,
  2708. TargetPoint
  2709. );
  2710. }
  2711. }
  2712. else if (ScreenInfo->Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER) {
  2713. ScrollHW(ScreenInfo,
  2714. &ScrollRect,
  2715. NULL,
  2716. TargetPoint
  2717. );
  2718. }
  2719. }
  2720. else
  2721. #endif
  2722. ScrollHW(ScreenInfo,
  2723. &ScrollRect,
  2724. NULL,
  2725. TargetPoint
  2726. );
  2727. ScrollRect.Top = ScrollRect.Bottom - 1;
  2728. WriteRegionToScreenHW(ScreenInfo,&ScrollRect);
  2729. }
  2730. #endif
  2731. }
  2732. NTSTATUS
  2733. ScrollRegion(
  2734. IN PSCREEN_INFORMATION ScreenInfo,
  2735. IN OUT PSMALL_RECT ScrollRectangle,
  2736. IN PSMALL_RECT ClipRectangle OPTIONAL,
  2737. IN COORD DestinationOrigin,
  2738. IN CHAR_INFO Fill
  2739. )
  2740. /*++
  2741. Routine Description:
  2742. This routine copies ScrollRectangle to DestinationOrigin then
  2743. fills in ScrollRectangle with Fill. The scroll region is
  2744. copied to a third buffer, the scroll region is filled, then the
  2745. original contents of the scroll region are copied to the destination.
  2746. Arguments:
  2747. ScreenInfo - pointer to screen buffer info.
  2748. ScrollRectangle - Region to copy
  2749. ClipRectangle - Optional pointer to clip region.
  2750. DestinationOrigin - Upper left corner of target region.
  2751. Fill - Character and attribute to fill source region with.
  2752. Return Value:
  2753. --*/
  2754. {
  2755. SMALL_RECT TargetRectangle, SourceRectangle;
  2756. COORD TargetPoint;
  2757. COORD Size;
  2758. SMALL_RECT OurClipRectangle;
  2759. SMALL_RECT ScrollRectangle2,ScrollRectangle3;
  2760. NTSTATUS Status;
  2761. PCONSOLE_INFORMATION Console = ScreenInfo->Console;
  2762. // here's how we clip:
  2763. //
  2764. // Clip source rectangle to screen buffer => S
  2765. // Create target rectangle based on S => T
  2766. // Clip T to ClipRegion => T
  2767. // Create S2 based on clipped T => S2
  2768. // Clip S to ClipRegion => S3
  2769. //
  2770. // S2 is the region we copy to T
  2771. // S3 is the region to fill
  2772. if (Fill.Char.UnicodeChar == '\0' && Fill.Attributes == 0) {
  2773. Fill.Char.UnicodeChar = (WCHAR)' ';
  2774. Fill.Attributes = ScreenInfo->Attributes;
  2775. }
  2776. //
  2777. // clip the source rectangle to the screen buffer
  2778. //
  2779. if (ScrollRectangle->Left < 0) {
  2780. DestinationOrigin.X += -ScrollRectangle->Left;
  2781. ScrollRectangle->Left = 0;
  2782. }
  2783. if (ScrollRectangle->Top < 0) {
  2784. DestinationOrigin.Y += -ScrollRectangle->Top;
  2785. ScrollRectangle->Top = 0;
  2786. }
  2787. if (ScrollRectangle->Right >= ScreenInfo->ScreenBufferSize.X) {
  2788. ScrollRectangle->Right = (SHORT)(ScreenInfo->ScreenBufferSize.X-1);
  2789. }
  2790. if (ScrollRectangle->Bottom >= ScreenInfo->ScreenBufferSize.Y) {
  2791. ScrollRectangle->Bottom = (SHORT)(ScreenInfo->ScreenBufferSize.Y-1);
  2792. }
  2793. //
  2794. // if source rectangle doesn't intersect screen buffer, return.
  2795. //
  2796. if (ScrollRectangle->Bottom < ScrollRectangle->Top ||
  2797. ScrollRectangle->Right < ScrollRectangle->Left) {
  2798. return STATUS_SUCCESS;
  2799. }
  2800. //
  2801. // clip the target rectangle
  2802. // if a cliprectangle was provided, clip it to the screen buffer.
  2803. // if not, set the cliprectangle to the screen buffer region.
  2804. //
  2805. if (ClipRectangle) {
  2806. //
  2807. // clip the cliprectangle.
  2808. //
  2809. if (ClipRectangle->Left < 0) {
  2810. ClipRectangle->Left = 0;
  2811. }
  2812. if (ClipRectangle->Top < 0) {
  2813. ClipRectangle->Top = 0;
  2814. }
  2815. if (ClipRectangle->Right >= ScreenInfo->ScreenBufferSize.X) {
  2816. ClipRectangle->Right = (SHORT)(ScreenInfo->ScreenBufferSize.X-1);
  2817. }
  2818. if (ClipRectangle->Bottom >= ScreenInfo->ScreenBufferSize.Y) {
  2819. ClipRectangle->Bottom = (SHORT)(ScreenInfo->ScreenBufferSize.Y-1);
  2820. }
  2821. }
  2822. else {
  2823. OurClipRectangle.Left = 0;
  2824. OurClipRectangle.Top = 0;
  2825. OurClipRectangle.Right = (SHORT)(ScreenInfo->ScreenBufferSize.X-1);
  2826. OurClipRectangle.Bottom = (SHORT)(ScreenInfo->ScreenBufferSize.Y-1);
  2827. ClipRectangle = &OurClipRectangle;
  2828. }
  2829. //
  2830. // Create target rectangle based on S => T
  2831. // Clip T to ClipRegion => T
  2832. // Create S2 based on clipped T => S2
  2833. //
  2834. ScrollRectangle2 = *ScrollRectangle;
  2835. TargetRectangle.Left = DestinationOrigin.X;
  2836. TargetRectangle.Top = DestinationOrigin.Y;
  2837. TargetRectangle.Right = (SHORT)(DestinationOrigin.X + (ScrollRectangle2.Right - ScrollRectangle2.Left + 1) - 1);
  2838. TargetRectangle.Bottom = (SHORT)(DestinationOrigin.Y + (ScrollRectangle2.Bottom - ScrollRectangle2.Top + 1) - 1);
  2839. if (TargetRectangle.Left < ClipRectangle->Left) {
  2840. ScrollRectangle2.Left += ClipRectangle->Left - TargetRectangle.Left;
  2841. TargetRectangle.Left = ClipRectangle->Left;
  2842. }
  2843. if (TargetRectangle.Top < ClipRectangle->Top) {
  2844. ScrollRectangle2.Top += ClipRectangle->Top - TargetRectangle.Top;
  2845. TargetRectangle.Top = ClipRectangle->Top;
  2846. }
  2847. if (TargetRectangle.Right > ClipRectangle->Right) {
  2848. ScrollRectangle2.Right -= TargetRectangle.Right - ClipRectangle->Right;
  2849. TargetRectangle.Right = ClipRectangle->Right;
  2850. }
  2851. if (TargetRectangle.Bottom > ClipRectangle->Bottom) {
  2852. ScrollRectangle2.Bottom -= TargetRectangle.Bottom - ClipRectangle->Bottom;
  2853. TargetRectangle.Bottom = ClipRectangle->Bottom;
  2854. }
  2855. //
  2856. // clip scroll rect to clipregion => S3
  2857. //
  2858. ScrollRectangle3 = *ScrollRectangle;
  2859. if (ScrollRectangle3.Left < ClipRectangle->Left) {
  2860. ScrollRectangle3.Left = ClipRectangle->Left;
  2861. }
  2862. if (ScrollRectangle3.Top < ClipRectangle->Top) {
  2863. ScrollRectangle3.Top = ClipRectangle->Top;
  2864. }
  2865. if (ScrollRectangle3.Right > ClipRectangle->Right) {
  2866. ScrollRectangle3.Right = ClipRectangle->Right;
  2867. }
  2868. if (ScrollRectangle3.Bottom > ClipRectangle->Bottom) {
  2869. ScrollRectangle3.Bottom = ClipRectangle->Bottom;
  2870. }
  2871. //
  2872. // if scroll rect doesn't intersect clip region, return.
  2873. //
  2874. if (ScrollRectangle3.Bottom < ScrollRectangle3.Top ||
  2875. ScrollRectangle3.Right < ScrollRectangle3.Left) {
  2876. return STATUS_SUCCESS;
  2877. }
  2878. ConsoleHideCursor(ScreenInfo);
  2879. #if defined(FE_IME)
  2880. Console->ConsoleIme.ScrollWaitCountDown = Console->ConsoleIme.ScrollWaitTimeout;
  2881. #endif // FE_IME
  2882. //
  2883. // if target rectangle doesn't intersect screen buffer, skip scrolling
  2884. // part.
  2885. //
  2886. if (!(TargetRectangle.Bottom < TargetRectangle.Top ||
  2887. TargetRectangle.Right < TargetRectangle.Left)) {
  2888. //
  2889. // if we can, don't use intermediate scroll region buffer. do this
  2890. // by figuring out fill rectangle. NOTE: this code will only work
  2891. // if CopyRectangle copies from low memory to high memory (otherwise
  2892. // we would overwrite the scroll region before reading it).
  2893. //
  2894. if (ScrollRectangle2.Right == TargetRectangle.Right &&
  2895. ScrollRectangle2.Left == TargetRectangle.Left &&
  2896. ScrollRectangle2.Top > TargetRectangle.Top &&
  2897. ScrollRectangle2.Top < TargetRectangle.Bottom) {
  2898. SMALL_RECT FillRect;
  2899. SHORT LastRowIndex,OldRight,OldLeft;
  2900. PROW Row;
  2901. TargetPoint.X = TargetRectangle.Left;
  2902. TargetPoint.Y = TargetRectangle.Top;
  2903. if (ScrollRectangle2.Right == (SHORT)(ScreenInfo->ScreenBufferSize.X-1) &&
  2904. ScrollRectangle2.Left == 0 &&
  2905. ScrollRectangle2.Bottom == (SHORT)(ScreenInfo->ScreenBufferSize.Y-1) &&
  2906. ScrollRectangle2.Top == 1 ) {
  2907. LastRowIndex = ScrollEntireScreen(ScreenInfo,(SHORT)(ScrollRectangle2.Top-TargetRectangle.Top),TRUE);
  2908. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[LastRowIndex];
  2909. OldRight = Row->CharRow.OldRight;
  2910. OldLeft = Row->CharRow.OldLeft;
  2911. } else {
  2912. LastRowIndex = -1;
  2913. CopyRectangle(ScreenInfo,
  2914. &ScrollRectangle2,
  2915. TargetPoint
  2916. );
  2917. }
  2918. FillRect.Left = TargetRectangle.Left;
  2919. FillRect.Right = TargetRectangle.Right;
  2920. FillRect.Top = (SHORT)(TargetRectangle.Bottom+1);
  2921. FillRect.Bottom = ScrollRectangle->Bottom;
  2922. if (FillRect.Top < ClipRectangle->Top) {
  2923. FillRect.Top = ClipRectangle->Top;
  2924. }
  2925. if (FillRect.Bottom > ClipRectangle->Bottom) {
  2926. FillRect.Bottom = ClipRectangle->Bottom;
  2927. }
  2928. FillRectangle(Fill,
  2929. ScreenInfo,
  2930. &FillRect
  2931. );
  2932. //
  2933. // After ScrollEntireScreen, the OldRight and OldLeft values
  2934. // for the last row are set correctly. however, FillRectangle
  2935. // resets them with the previous first row of the screen.
  2936. // reset them here.
  2937. //
  2938. if (LastRowIndex != -1) {
  2939. Row->CharRow.OldRight = OldRight;
  2940. Row->CharRow.OldLeft = OldLeft;
  2941. }
  2942. //
  2943. // update to screen, if we're not iconic. we're marked as
  2944. // iconic if we're fullscreen, so check for fullscreen.
  2945. //
  2946. if (!(Console->Flags & CONSOLE_IS_ICONIC) ||
  2947. Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  2948. ScrollScreen(ScreenInfo,
  2949. &ScrollRectangle2,
  2950. &FillRect,
  2951. TargetPoint
  2952. );
  2953. }
  2954. }
  2955. //
  2956. // if no overlap, don't need intermediate copy
  2957. //
  2958. else if (ScrollRectangle3.Right < TargetRectangle.Left ||
  2959. ScrollRectangle3.Left > TargetRectangle.Right ||
  2960. ScrollRectangle3.Top > TargetRectangle.Bottom ||
  2961. ScrollRectangle3.Bottom < TargetRectangle.Top) {
  2962. TargetPoint.X = TargetRectangle.Left;
  2963. TargetPoint.Y = TargetRectangle.Top;
  2964. CopyRectangle(ScreenInfo,
  2965. &ScrollRectangle2,
  2966. TargetPoint
  2967. );
  2968. FillRectangle(Fill,
  2969. ScreenInfo,
  2970. &ScrollRectangle3
  2971. );
  2972. //
  2973. // update to screen, if we're not iconic. we're marked as
  2974. // iconic if we're fullscreen, so check for fullscreen.
  2975. //
  2976. if (!(Console->Flags & CONSOLE_IS_ICONIC) ||
  2977. Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  2978. ScrollScreen(ScreenInfo,
  2979. &ScrollRectangle2,
  2980. &ScrollRectangle3,
  2981. TargetPoint
  2982. );
  2983. }
  2984. }
  2985. //
  2986. // for the case where the source and target rectangles overlap, we
  2987. // copy the source rectangle, fill it, then copy it to the target.
  2988. //
  2989. else {
  2990. SMALL_RECT TargetRect;
  2991. COORD SourcePoint;
  2992. LockScrollBuffer();
  2993. Size.X = (SHORT)(ScrollRectangle2.Right - ScrollRectangle2.Left + 1);
  2994. Size.Y = (SHORT)(ScrollRectangle2.Bottom - ScrollRectangle2.Top + 1);
  2995. if (ScrollBufferSize < (Size.X * Size.Y * sizeof(CHAR_INFO))) {
  2996. FreeScrollBuffer();
  2997. Status = AllocateScrollBuffer(Size.X * Size.Y * sizeof(CHAR_INFO));
  2998. if (!NT_SUCCESS(Status)) {
  2999. UnlockScrollBuffer();
  3000. ConsoleShowCursor(ScreenInfo);
  3001. return Status;
  3002. }
  3003. }
  3004. TargetRect.Left = 0;
  3005. TargetRect.Top = 0;
  3006. TargetRect.Right = ScrollRectangle2.Right - ScrollRectangle2.Left;
  3007. TargetRect.Bottom = ScrollRectangle2.Bottom - ScrollRectangle2.Top;
  3008. SourcePoint.X = ScrollRectangle2.Left;
  3009. SourcePoint.Y = ScrollRectangle2.Top;
  3010. ReadRectFromScreenBuffer(ScreenInfo,
  3011. SourcePoint,
  3012. ScrollBuffer,
  3013. Size,
  3014. &TargetRect
  3015. );
  3016. FillRectangle(Fill,
  3017. ScreenInfo,
  3018. &ScrollRectangle3
  3019. );
  3020. SourceRectangle.Top = 0;
  3021. SourceRectangle.Left = 0;
  3022. SourceRectangle.Right = (SHORT)(Size.X-1);
  3023. SourceRectangle.Bottom = (SHORT)(Size.Y-1);
  3024. TargetPoint.X = TargetRectangle.Left;
  3025. TargetPoint.Y = TargetRectangle.Top;
  3026. WriteRectToScreenBuffer((PBYTE)ScrollBuffer,
  3027. Size,
  3028. &SourceRectangle,
  3029. ScreenInfo,
  3030. TargetPoint,
  3031. 0xFFFFFFFF
  3032. );
  3033. UnlockScrollBuffer();
  3034. //
  3035. // update to screen, if we're not iconic. we're marked as
  3036. // iconic if we're fullscreen, so check for fullscreen.
  3037. //
  3038. if (!(Console->Flags & CONSOLE_IS_ICONIC) ||
  3039. Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  3040. //
  3041. // update regions on screen.
  3042. //
  3043. ScrollScreen(ScreenInfo,
  3044. &ScrollRectangle2,
  3045. &ScrollRectangle3,
  3046. TargetPoint
  3047. );
  3048. }
  3049. }
  3050. }
  3051. else {
  3052. //
  3053. // do fill
  3054. //
  3055. FillRectangle(Fill,
  3056. ScreenInfo,
  3057. &ScrollRectangle3
  3058. );
  3059. //
  3060. // update to screen, if we're not iconic. we're marked as
  3061. // iconic if we're fullscreen, so check for fullscreen.
  3062. //
  3063. if (ACTIVE_SCREEN_BUFFER(ScreenInfo) &&
  3064. !(Console->Flags & CONSOLE_IS_ICONIC) ||
  3065. Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  3066. WriteToScreen(ScreenInfo,&ScrollRectangle3);
  3067. }
  3068. }
  3069. ConsoleShowCursor(ScreenInfo);
  3070. return STATUS_SUCCESS;
  3071. }
  3072. NTSTATUS
  3073. SetWindowOrigin(
  3074. IN PSCREEN_INFORMATION ScreenInfo,
  3075. IN BOOLEAN Absolute,
  3076. IN COORD WindowOrigin
  3077. )
  3078. /*++
  3079. Routine Description:
  3080. This routine sets the window origin.
  3081. Arguments:
  3082. ScreenInfo - pointer to screen buffer info.
  3083. Absolute - if TRUE, WindowOrigin is specified in absolute screen
  3084. buffer coordinates. if FALSE, WindowOrigin is specified in coordinates
  3085. relative to the current window origin.
  3086. WindowOrigin - New window origin.
  3087. Return Value:
  3088. --*/
  3089. {
  3090. SMALL_RECT NewWindow;
  3091. COORD WindowSize;
  3092. RECT BoundingBox;
  3093. BOOL Success;
  3094. RECT ScrollRect;
  3095. SMALL_RECT UpdateRegion;
  3096. COORD FontSize;
  3097. PCONSOLE_INFORMATION Console = ScreenInfo->Console;
  3098. //
  3099. // calculate window size
  3100. //
  3101. WindowSize.X = (SHORT)CONSOLE_WINDOW_SIZE_X(ScreenInfo);
  3102. WindowSize.Y = (SHORT)CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
  3103. //
  3104. // if relative coordinates, figure out absolute coords.
  3105. //
  3106. if (!Absolute) {
  3107. if (WindowOrigin.X == 0 && WindowOrigin.Y == 0) {
  3108. return STATUS_SUCCESS;
  3109. }
  3110. NewWindow.Left = ScreenInfo->Window.Left + WindowOrigin.X;
  3111. NewWindow.Top = ScreenInfo->Window.Top + WindowOrigin.Y;
  3112. }
  3113. else {
  3114. if (WindowOrigin.X == ScreenInfo->Window.Left &&
  3115. WindowOrigin.Y == ScreenInfo->Window.Top) {
  3116. return STATUS_SUCCESS;
  3117. }
  3118. NewWindow.Left = WindowOrigin.X;
  3119. NewWindow.Top = WindowOrigin.Y;
  3120. }
  3121. NewWindow.Right = (SHORT)(NewWindow.Left + WindowSize.X - 1);
  3122. NewWindow.Bottom = (SHORT)(NewWindow.Top + WindowSize.Y - 1);
  3123. //
  3124. // see if new window origin would extend window beyond extent of screen
  3125. // buffer
  3126. //
  3127. if (NewWindow.Left < 0 || NewWindow.Top < 0 ||
  3128. NewWindow.Right < 0 || NewWindow.Bottom < 0 ||
  3129. NewWindow.Right >= ScreenInfo->ScreenBufferSize.X ||
  3130. NewWindow.Bottom >= ScreenInfo->ScreenBufferSize.Y) {
  3131. return STATUS_INVALID_PARAMETER;
  3132. }
  3133. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  3134. FontSize = SCR_FONTSIZE(ScreenInfo);
  3135. ScreenInfo->BufferInfo.TextInfo.Flags &= ~TEXT_VALID_HINT;
  3136. } else {
  3137. FontSize.X = 1;
  3138. FontSize.Y = 1;
  3139. }
  3140. ConsoleHideCursor(ScreenInfo);
  3141. if (ACTIVE_SCREEN_BUFFER(ScreenInfo) &&
  3142. Console->FullScreenFlags == 0 &&
  3143. !(Console->Flags & (CONSOLE_IS_ICONIC | CONSOLE_NO_WINDOW))) {
  3144. InvertSelection(Console, TRUE);
  3145. #if defined(FE_SB)
  3146. if (CONSOLE_IS_DBCS_OUTPUTCP(Console) &&
  3147. !(Console->ConsoleIme.ScrollFlag & HIDE_FOR_SCROLL)) {
  3148. ConsoleImeBottomLineUse(ScreenInfo,0);
  3149. }
  3150. #endif
  3151. if ( ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER
  3152. && UsePolyTextOut
  3153. && NewWindow.Left == ScreenInfo->Window.Left
  3154. ) {
  3155. ScrollEntireScreen(ScreenInfo,
  3156. (SHORT)(NewWindow.Top - ScreenInfo->Window.Top),
  3157. FALSE);
  3158. ScreenInfo->Window = NewWindow;
  3159. WriteRegionToScreen(ScreenInfo, &NewWindow);
  3160. } else {
  3161. #if defined(FE_SB)
  3162. RECT ClipRect;
  3163. #endif
  3164. ScrollRect.left = 0;
  3165. ScrollRect.right = CONSOLE_WINDOW_SIZE_X(ScreenInfo)*FontSize.X;
  3166. ScrollRect.top = 0;
  3167. #if defined(FE_SB)
  3168. if (CONSOLE_IS_DBCS_OUTPUTCP(Console) &&
  3169. Console->InputBuffer.ImeMode.Open )
  3170. {
  3171. if (ScreenInfo->Window.Top <= NewWindow.Top)
  3172. ScrollRect.bottom = (CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-1)*FontSize.Y;
  3173. else
  3174. ScrollRect.bottom = (CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-2)*FontSize.Y;
  3175. ClipRect = ScrollRect;
  3176. ClipRect.bottom = (CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-1)*FontSize.Y;
  3177. }
  3178. else
  3179. #endif
  3180. ScrollRect.bottom = CONSOLE_WINDOW_SIZE_Y(ScreenInfo)*FontSize.Y;
  3181. #if defined(FE_SB)
  3182. if (CONSOLE_IS_DBCS_OUTPUTCP(Console) &&
  3183. ScrollRect.bottom == 0) {
  3184. UpdateRegion.Left = 0;
  3185. UpdateRegion.Top = 0;
  3186. UpdateRegion.Right = CONSOLE_WINDOW_SIZE_X(ScreenInfo);
  3187. UpdateRegion.Bottom = 0;
  3188. WriteToScreen(ScreenInfo,&UpdateRegion);
  3189. }
  3190. else {
  3191. #endif
  3192. SCROLLDC_CALL;
  3193. #if defined(FE_SB)
  3194. if (CONSOLE_IS_DBCS_OUTPUTCP(Console) &&
  3195. Console->InputBuffer.ImeMode.Open )
  3196. {
  3197. Success = ScrollDC(Console->hDC,
  3198. (ScreenInfo->Window.Left-NewWindow.Left)*FontSize.X,
  3199. (ScreenInfo->Window.Top-NewWindow.Top)*FontSize.Y,
  3200. &ScrollRect,
  3201. &ClipRect,
  3202. NULL,
  3203. &BoundingBox
  3204. );
  3205. }
  3206. else
  3207. #endif
  3208. Success = ScrollDC(Console->hDC,
  3209. (ScreenInfo->Window.Left-NewWindow.Left)*FontSize.X,
  3210. (ScreenInfo->Window.Top-NewWindow.Top)*FontSize.Y,
  3211. &ScrollRect,
  3212. NULL,
  3213. NULL,
  3214. &BoundingBox
  3215. );
  3216. //
  3217. // Fire off an event to let accessibility apps know we've scrolled.
  3218. //
  3219. ConsoleNotifyWinEvent(Console,
  3220. EVENT_CONSOLE_UPDATE_SCROLL,
  3221. ScreenInfo->Window.Left - NewWindow.Left,
  3222. ScreenInfo->Window.Top - NewWindow.Top);
  3223. if (Success) {
  3224. UpdateRegion.Left = (SHORT)((BoundingBox.left/FontSize.X)+NewWindow.Left);
  3225. UpdateRegion.Right = (SHORT)(((BoundingBox.right-1)/FontSize.X)+NewWindow.Left);
  3226. UpdateRegion.Top = (SHORT)((BoundingBox.top/FontSize.Y)+NewWindow.Top);
  3227. UpdateRegion.Bottom = (SHORT)(((BoundingBox.bottom-1)/FontSize.Y)+NewWindow.Top);
  3228. }
  3229. else {
  3230. UpdateRegion = NewWindow;
  3231. }
  3232. //
  3233. // new window is ok. store it in screeninfo and refresh screen.
  3234. //
  3235. ScreenInfo->Window = NewWindow;
  3236. WriteToScreen(ScreenInfo,&UpdateRegion);
  3237. #if defined(FE_SB)
  3238. }
  3239. #endif
  3240. }
  3241. InvertSelection(Console, FALSE);
  3242. }
  3243. #ifdef i386
  3244. else if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE &&
  3245. ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  3246. //
  3247. // keep mouse pointer on screen
  3248. //
  3249. if (ScreenInfo->BufferInfo.TextInfo.MousePosition.X < NewWindow.Left) {
  3250. ScreenInfo->BufferInfo.TextInfo.MousePosition.X = NewWindow.Left;
  3251. } else if (ScreenInfo->BufferInfo.TextInfo.MousePosition.X > NewWindow.Right) {
  3252. ScreenInfo->BufferInfo.TextInfo.MousePosition.X = NewWindow.Right;
  3253. }
  3254. if (ScreenInfo->BufferInfo.TextInfo.MousePosition.Y < NewWindow.Top) {
  3255. ScreenInfo->BufferInfo.TextInfo.MousePosition.Y = NewWindow.Top;
  3256. } else if (ScreenInfo->BufferInfo.TextInfo.MousePosition.Y > NewWindow.Bottom) {
  3257. ScreenInfo->BufferInfo.TextInfo.MousePosition.Y = NewWindow.Bottom;
  3258. }
  3259. ScreenInfo->Window = NewWindow;
  3260. WriteToScreen(ScreenInfo,&ScreenInfo->Window);
  3261. }
  3262. #endif
  3263. else {
  3264. // we're iconic
  3265. ScreenInfo->Window = NewWindow;
  3266. }
  3267. #if defined(FE_SB)
  3268. if (CONSOLE_IS_DBCS_OUTPUTCP(Console) ) {
  3269. ConsoleImeResizeModeSystemView(Console,ScreenInfo->Window);
  3270. ConsoleImeResizeCompStrView(Console,ScreenInfo->Window);
  3271. }
  3272. #endif
  3273. ConsoleShowCursor(ScreenInfo);
  3274. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  3275. ScreenInfo->BufferInfo.TextInfo.Flags |= TEXT_VALID_HINT;
  3276. }
  3277. UpdateScrollBars(ScreenInfo);
  3278. return STATUS_SUCCESS;
  3279. }
  3280. NTSTATUS
  3281. ResizeWindow(
  3282. IN PSCREEN_INFORMATION ScreenInfo,
  3283. IN PSMALL_RECT WindowDimensions,
  3284. IN BOOL DoScrollBarUpdate
  3285. )
  3286. /*++
  3287. Routine Description:
  3288. This routine changes the console data structures to reflect the specified
  3289. window size change. it does not call the user component to update
  3290. the screen.
  3291. Arguments:
  3292. ScreenInformation - the new screen buffer.
  3293. dwWindowSize - the initial size of screen buffer's window.
  3294. nFont - the initial font to generate text with.
  3295. dwScreenBufferSize - the initial size of the screen buffer.
  3296. Return Value:
  3297. --*/
  3298. {
  3299. //
  3300. // make sure there's something to do
  3301. //
  3302. if (RtlEqualMemory(&ScreenInfo->Window, WindowDimensions, sizeof(SMALL_RECT))) {
  3303. return STATUS_SUCCESS;
  3304. }
  3305. if (WindowDimensions->Left < 0) {
  3306. WindowDimensions->Right -= WindowDimensions->Left;
  3307. WindowDimensions->Left = 0;
  3308. }
  3309. if (WindowDimensions->Top < 0) {
  3310. WindowDimensions->Bottom -= WindowDimensions->Top;
  3311. WindowDimensions->Top = 0;
  3312. }
  3313. if (WindowDimensions->Right >= ScreenInfo->ScreenBufferSize.X) {
  3314. WindowDimensions->Right = ScreenInfo->ScreenBufferSize.X;
  3315. }
  3316. if (WindowDimensions->Bottom >= ScreenInfo->ScreenBufferSize.Y) {
  3317. WindowDimensions->Bottom = ScreenInfo->ScreenBufferSize.Y;
  3318. }
  3319. ScreenInfo->Window = *WindowDimensions;
  3320. ScreenInfo->WindowMaximizedX = (CONSOLE_WINDOW_SIZE_X(ScreenInfo) == ScreenInfo->ScreenBufferSize.X);
  3321. ScreenInfo->WindowMaximizedY = (CONSOLE_WINDOW_SIZE_Y(ScreenInfo) == ScreenInfo->ScreenBufferSize.Y);
  3322. if (DoScrollBarUpdate) {
  3323. UpdateScrollBars(ScreenInfo);
  3324. }
  3325. if (!(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)) {
  3326. return STATUS_SUCCESS;
  3327. }
  3328. if (ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
  3329. ScreenInfo->BufferInfo.TextInfo.Flags &= ~TEXT_VALID_HINT;
  3330. }
  3331. #ifdef i386
  3332. if (ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  3333. //
  3334. // keep mouse pointer on screen
  3335. //
  3336. if (ScreenInfo->BufferInfo.TextInfo.MousePosition.X < WindowDimensions->Left) {
  3337. ScreenInfo->BufferInfo.TextInfo.MousePosition.X = WindowDimensions->Left;
  3338. } else if (ScreenInfo->BufferInfo.TextInfo.MousePosition.X > WindowDimensions->Right) {
  3339. ScreenInfo->BufferInfo.TextInfo.MousePosition.X = WindowDimensions->Right;
  3340. }
  3341. if (ScreenInfo->BufferInfo.TextInfo.MousePosition.Y < WindowDimensions->Top) {
  3342. ScreenInfo->BufferInfo.TextInfo.MousePosition.Y = WindowDimensions->Top;
  3343. } else if (ScreenInfo->BufferInfo.TextInfo.MousePosition.Y > WindowDimensions->Bottom) {
  3344. ScreenInfo->BufferInfo.TextInfo.MousePosition.Y = WindowDimensions->Bottom;
  3345. }
  3346. }
  3347. #endif
  3348. return(STATUS_SUCCESS);
  3349. }
  3350. VOID
  3351. SetWindowSize(
  3352. IN PSCREEN_INFORMATION ScreenInfo
  3353. )
  3354. {
  3355. #if defined(FE_IME)
  3356. if (ScreenInfo->ConvScreenInfo != NULL)
  3357. return;
  3358. #endif
  3359. if (ScreenInfo->Console->Flags & CONSOLE_SETTING_WINDOW_SIZE)
  3360. return;
  3361. ScreenInfo->Console->Flags |= CONSOLE_SETTING_WINDOW_SIZE;
  3362. PostMessage(ScreenInfo->Console->hWnd,
  3363. CM_SET_WINDOW_SIZE,
  3364. (WPARAM)ScreenInfo,
  3365. 0x47474747
  3366. );
  3367. }
  3368. VOID
  3369. UpdateWindowSize(
  3370. IN PCONSOLE_INFORMATION Console,
  3371. IN PSCREEN_INFORMATION ScreenInfo
  3372. )
  3373. {
  3374. LONG WindowStyle;
  3375. if (!(Console->Flags & CONSOLE_IS_ICONIC)) {
  3376. InternalUpdateScrollBars(ScreenInfo);
  3377. WindowStyle = GetWindowLong(Console->hWnd, GWL_STYLE);
  3378. if (ScreenInfo->WindowMaximized) {
  3379. WindowStyle |= WS_MAXIMIZE;
  3380. } else {
  3381. WindowStyle &= ~WS_MAXIMIZE;
  3382. }
  3383. SetWindowLong(Console->hWnd, GWL_STYLE, WindowStyle);
  3384. SetWindowPos(Console->hWnd, NULL,
  3385. 0,
  3386. 0,
  3387. Console->WindowRect.right-Console->WindowRect.left,
  3388. Console->WindowRect.bottom-Console->WindowRect.top,
  3389. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME
  3390. );
  3391. Console->ResizeFlags &= ~SCREEN_BUFFER_CHANGE;
  3392. } else {
  3393. Console->ResizeFlags |= SCREEN_BUFFER_CHANGE;
  3394. }
  3395. }
  3396. NTSTATUS
  3397. InternalSetWindowSize(
  3398. IN PCONSOLE_INFORMATION Console,
  3399. IN PSCREEN_INFORMATION ScreenInfo,
  3400. IN PSMALL_RECT Window
  3401. )
  3402. {
  3403. SIZE WindowSize;
  3404. WORD WindowSizeX, WindowSizeY;
  3405. Console->Flags &= ~CONSOLE_SETTING_WINDOW_SIZE;
  3406. if (Console->CurrentScreenBuffer == ScreenInfo) {
  3407. if (Console->FullScreenFlags == 0) {
  3408. //
  3409. // Make sure our max screen sizes reflect reality
  3410. //
  3411. if (gfInitSystemMetrics) {
  3412. InitializeSystemMetrics();
  3413. }
  3414. //
  3415. // figure out how big to make the window, given the desired client area
  3416. // size.
  3417. //
  3418. ScreenInfo->ResizingWindow++;
  3419. WindowSizeX = WINDOW_SIZE_X(Window);
  3420. WindowSizeY = WINDOW_SIZE_Y(Window);
  3421. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  3422. WindowSize.cx = WindowSizeX*SCR_FONTSIZE(ScreenInfo).X;
  3423. WindowSize.cy = WindowSizeY*SCR_FONTSIZE(ScreenInfo).Y;
  3424. } else {
  3425. WindowSize.cx = WindowSizeX;
  3426. WindowSize.cy = WindowSizeY;
  3427. }
  3428. WindowSize.cx += VerticalClientToWindow;
  3429. WindowSize.cy += HorizontalClientToWindow;
  3430. if (WindowSizeY != 0) {
  3431. if (!ScreenInfo->WindowMaximizedX) {
  3432. WindowSize.cy += HorizontalScrollSize;
  3433. }
  3434. if (!ScreenInfo->WindowMaximizedY) {
  3435. WindowSize.cx += VerticalScrollSize;
  3436. }
  3437. }
  3438. Console->WindowRect.right = Console->WindowRect.left + WindowSize.cx;
  3439. Console->WindowRect.bottom = Console->WindowRect.top + WindowSize.cy;
  3440. UpdateWindowSize(Console,ScreenInfo);
  3441. ScreenInfo->ResizingWindow--;
  3442. } else if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  3443. WriteToScreen(ScreenInfo,&ScreenInfo->Window);
  3444. }
  3445. #if defined(FE_IME)
  3446. if ( (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) &&
  3447. (CONSOLE_IS_DBCS_OUTPUTCP(Console)))
  3448. {
  3449. ConsoleImeResizeModeSystemView(Console,Console->CurrentScreenBuffer->Window);
  3450. ConsoleImeResizeCompStrView(Console,Console->CurrentScreenBuffer->Window);
  3451. }
  3452. #endif // FE_IME
  3453. }
  3454. return STATUS_SUCCESS;
  3455. }
  3456. NTSTATUS
  3457. SetActiveScreenBuffer(
  3458. IN PSCREEN_INFORMATION ScreenInfo
  3459. )
  3460. {
  3461. PSCREEN_INFORMATION OldScreenInfo;
  3462. PCONSOLE_INFORMATION Console = ScreenInfo->Console;
  3463. OldScreenInfo = Console->CurrentScreenBuffer;
  3464. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  3465. #if !defined(_X86_)
  3466. if (Console->FullScreenFlags & CONSOLE_FULLSCREEN) {
  3467. return STATUS_INVALID_PARAMETER;
  3468. }
  3469. #endif
  3470. Console->CurrentScreenBuffer = ScreenInfo;
  3471. if (Console->FullScreenFlags == 0) {
  3472. //
  3473. // initialize cursor
  3474. //
  3475. ScreenInfo->BufferInfo.TextInfo.CursorOn = FALSE;
  3476. //
  3477. // set font
  3478. //
  3479. SetFont(ScreenInfo);
  3480. }
  3481. #if defined(_X86_)
  3482. else if (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  3483. if (!(Console->Flags & CONSOLE_VDM_REGISTERED)) {
  3484. if ( (!(OldScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)) ||
  3485. (OldScreenInfo->BufferInfo.TextInfo.ModeIndex!=ScreenInfo->BufferInfo.TextInfo.ModeIndex)) {
  3486. // set video mode and font
  3487. SetVideoMode(ScreenInfo);
  3488. }
  3489. //set up cursor
  3490. SetCursorInformationHW(ScreenInfo,
  3491. ScreenInfo->BufferInfo.TextInfo.CursorSize,
  3492. ScreenInfo->BufferInfo.TextInfo.CursorVisible);
  3493. SetCursorPositionHW(ScreenInfo,
  3494. ScreenInfo->BufferInfo.TextInfo.CursorPosition);
  3495. }
  3496. }
  3497. #endif
  3498. }
  3499. else {
  3500. Console->CurrentScreenBuffer = ScreenInfo;
  3501. }
  3502. //
  3503. // empty input buffer
  3504. //
  3505. FlushAllButKeys(&Console->InputBuffer);
  3506. if (Console->FullScreenFlags == 0) {
  3507. SetScreenColors(ScreenInfo, ScreenInfo->Attributes,
  3508. ScreenInfo->PopupAttributes, FALSE);
  3509. //
  3510. // set window size
  3511. //
  3512. SetWindowSize(ScreenInfo);
  3513. //
  3514. // initialize the palette, if we have the focus and we're not fullscreen
  3515. //
  3516. if (!(Console->Flags & CONSOLE_IS_ICONIC) &&
  3517. Console->FullScreenFlags == 0) {
  3518. if (ScreenInfo->hPalette != NULL || OldScreenInfo->hPalette != NULL) {
  3519. HPALETTE hPalette;
  3520. BOOL bReset = FALSE;
  3521. USERTHREAD_USEDESKTOPINFO utudi;
  3522. if (GetCurrentThreadId() != Console->InputThreadInfo->ThreadId) {
  3523. bReset = TRUE;
  3524. utudi.hThread = Console->InputThreadInfo->ThreadHandle;
  3525. utudi.drdRestore.pdeskRestore = NULL;
  3526. NtUserSetInformationThread(NtCurrentThread(),
  3527. UserThreadUseDesktop,
  3528. &utudi, sizeof(utudi));
  3529. }
  3530. if (ScreenInfo->hPalette == NULL) {
  3531. hPalette = Console->hSysPalette;
  3532. } else {
  3533. hPalette = ScreenInfo->hPalette;
  3534. }
  3535. SelectPalette(Console->hDC,
  3536. hPalette,
  3537. FALSE);
  3538. SetActivePalette(ScreenInfo);
  3539. if (bReset == TRUE) {
  3540. utudi.hThread = NULL;
  3541. NtUserSetInformationThread(NtCurrentThread(),
  3542. UserThreadUseDesktop, &utudi, sizeof(utudi));
  3543. }
  3544. }
  3545. }
  3546. }
  3547. #if defined(FE_IME)
  3548. SetUndetermineAttribute(Console);
  3549. #endif
  3550. //
  3551. // write data to screen
  3552. //
  3553. ScreenInfo->BufferInfo.TextInfo.Flags &= ~TEXT_VALID_HINT;
  3554. WriteToScreen(ScreenInfo,&ScreenInfo->Window);
  3555. return STATUS_SUCCESS;
  3556. }
  3557. VOID
  3558. SetProcessFocus(
  3559. IN PCSR_PROCESS Process,
  3560. IN BOOL Foreground
  3561. )
  3562. {
  3563. if (Foreground) {
  3564. CsrSetForegroundPriority(Process);
  3565. } else {
  3566. CsrSetBackgroundPriority(Process);
  3567. }
  3568. }
  3569. VOID
  3570. SetProcessForegroundRights(
  3571. IN PCSR_PROCESS Process,
  3572. IN BOOL Foreground
  3573. )
  3574. {
  3575. USERTHREAD_FLAGS Flags;
  3576. Flags.dwMask = (W32PF_ALLOWSETFOREGROUND | W32PF_CONSOLEHASFOCUS);
  3577. Flags.dwFlags = (Foreground ? (W32PF_ALLOWSETFOREGROUND | W32PF_CONSOLEHASFOCUS) : 0);
  3578. NtUserSetInformationProcess(Process->ProcessHandle, UserProcessFlags, &Flags, sizeof(Flags));
  3579. }
  3580. VOID
  3581. ModifyConsoleProcessFocus(
  3582. IN PCONSOLE_INFORMATION Console,
  3583. IN BOOL Foreground
  3584. )
  3585. {
  3586. PCONSOLE_PROCESS_HANDLE ProcessHandleRecord;
  3587. PLIST_ENTRY ListHead, ListNext;
  3588. ListHead = &Console->ProcessHandleList;
  3589. ListNext = ListHead->Flink;
  3590. while (ListNext != ListHead) {
  3591. ProcessHandleRecord = CONTAINING_RECORD( ListNext, CONSOLE_PROCESS_HANDLE, ListLink );
  3592. ListNext = ListNext->Flink;
  3593. SetProcessFocus(ProcessHandleRecord->Process, Foreground);
  3594. SetProcessForegroundRights(ProcessHandleRecord->Process, Foreground);
  3595. }
  3596. }
  3597. VOID
  3598. TrimConsoleWorkingSet(
  3599. IN PCONSOLE_INFORMATION Console
  3600. )
  3601. {
  3602. PCONSOLE_PROCESS_HANDLE ProcessHandleRecord;
  3603. PLIST_ENTRY ListHead, ListNext;
  3604. ListHead = &Console->ProcessHandleList;
  3605. ListNext = ListHead->Flink;
  3606. while (ListNext != ListHead) {
  3607. ProcessHandleRecord = CONTAINING_RECORD( ListNext, CONSOLE_PROCESS_HANDLE, ListLink );
  3608. ListNext = ListNext->Flink;
  3609. SetProcessWorkingSetSize(ProcessHandleRecord->Process->ProcessHandle, (SIZE_T)-1, (SIZE_T)-1);
  3610. }
  3611. }
  3612. NTSTATUS
  3613. QueueConsoleMessage(
  3614. PCONSOLE_INFORMATION Console,
  3615. UINT Message,
  3616. WPARAM wParam,
  3617. LPARAM lParam
  3618. )
  3619. /*++
  3620. Routine Description:
  3621. This inserts a message into the console's message queue and wakes up
  3622. the console input thread to process it.
  3623. Arguments:
  3624. Console - Pointer to console information structure.
  3625. Message - Message to store in queue.
  3626. wParam - wParam to store in queue.
  3627. lParam - lParam to store in queue.
  3628. Return Value:
  3629. NTSTATUS - STATUS_SUCCESS if everything is OK.
  3630. --*/
  3631. {
  3632. PCONSOLE_MSG pConMsg;
  3633. ASSERT(ConsoleLocked(Console));
  3634. pConMsg = ConsoleHeapAlloc(TMP_TAG, sizeof(CONSOLE_MSG));
  3635. if (pConMsg == NULL) {
  3636. return STATUS_NO_MEMORY;
  3637. }
  3638. pConMsg->Message = Message;
  3639. pConMsg->wParam = wParam;
  3640. pConMsg->lParam = lParam;
  3641. InsertHeadList(&Console->MessageQueue, &pConMsg->ListLink);
  3642. if (!PostMessage(Console->hWnd, CM_CONSOLE_MSG, 0, 0)) {
  3643. RemoveEntryList(&pConMsg->ListLink);
  3644. ConsoleHeapFree(pConMsg);
  3645. return STATUS_UNSUCCESSFUL;
  3646. }
  3647. return STATUS_SUCCESS;
  3648. }
  3649. BOOL
  3650. UnqueueConsoleMessage(
  3651. PCONSOLE_INFORMATION Console,
  3652. UINT *pMessage,
  3653. WPARAM *pwParam,
  3654. LPARAM *plParam
  3655. )
  3656. /*++
  3657. Routine Description:
  3658. This routine removes a message from the console's message queue.
  3659. Arguments:
  3660. Console - Pointer to console information structure.
  3661. pMessage - Pointer in which to return Message.
  3662. pwParam - Pointer in which to return wParam.
  3663. plParam - Pointer in which to return lParam.
  3664. Return Value:
  3665. BOOL - TRUE if message was found and FALSE otherwise.
  3666. --*/
  3667. {
  3668. PLIST_ENTRY pEntry;
  3669. PCONSOLE_MSG pConMsg = NULL;
  3670. ASSERT(ConsoleLocked(Console));
  3671. if (IsListEmpty(&Console->MessageQueue)) {
  3672. return FALSE;
  3673. }
  3674. pEntry = RemoveTailList(&Console->MessageQueue);
  3675. pConMsg = CONTAINING_RECORD(pEntry, CONSOLE_MSG, ListLink);
  3676. *pMessage = pConMsg->Message;
  3677. *pwParam = pConMsg->wParam;
  3678. *plParam = pConMsg->lParam;
  3679. ConsoleHeapFree(pConMsg);
  3680. return TRUE;
  3681. }
  3682. VOID
  3683. CleanupConsoleMessages(
  3684. PCONSOLE_INFORMATION Console
  3685. )
  3686. /*++
  3687. Routine Description:
  3688. This routine cleans up any console messages still in the queue.
  3689. Arguments:
  3690. Console - Pointer to console information structure.
  3691. Return Value:
  3692. none.
  3693. --*/
  3694. {
  3695. UINT Message;
  3696. WPARAM wParam;
  3697. LPARAM lParam;
  3698. while (UnqueueConsoleMessage(Console, &Message, &wParam, &lParam)) {
  3699. switch (Message) {
  3700. case CM_MODE_TRANSITION:
  3701. NtSetEvent((HANDLE)lParam, NULL);
  3702. NtClose((HANDLE)lParam);
  3703. break;
  3704. case CM_SET_IME_CODEPAGE:
  3705. case CM_SET_NLSMODE:
  3706. case CM_GET_NLSMODE:
  3707. if (wParam) {
  3708. NtSetEvent((HANDLE)wParam, NULL);
  3709. NtClose((HANDLE)wParam);
  3710. }
  3711. break;
  3712. case EVENT_CONSOLE_CARET:
  3713. case EVENT_CONSOLE_UPDATE_REGION:
  3714. case EVENT_CONSOLE_UPDATE_SIMPLE:
  3715. case EVENT_CONSOLE_UPDATE_SCROLL:
  3716. case EVENT_CONSOLE_LAYOUT:
  3717. case EVENT_CONSOLE_START_APPLICATION:
  3718. case EVENT_CONSOLE_END_APPLICATION:
  3719. break;
  3720. default:
  3721. RIPMSG1(RIP_ERROR,
  3722. "CleanupConsoleMessages - unknown message 0x%x",
  3723. Message);
  3724. break;
  3725. }
  3726. }
  3727. }
  3728. VOID
  3729. ConsoleNotifyWinEvent(
  3730. IN PCONSOLE_INFORMATION Console,
  3731. IN DWORD Event,
  3732. IN LONG idObjectType,
  3733. IN LONG idObject
  3734. )
  3735. /*++
  3736. Routine Description:
  3737. If this routine is called by the console input thread, it can notify the
  3738. system about the event by calling NotifyWinEvent directly. Otherwise, it
  3739. queues the event up for the input thread to deal with.
  3740. Arguments:
  3741. Console - Pointer to console information structure.
  3742. Event - Event that occurred.
  3743. idObjectType - Additional data about the event.
  3744. idObject - Additional data about the event.
  3745. Return Value:
  3746. none.
  3747. --*/
  3748. {
  3749. //
  3750. // If no one's listening then there's no reason to send the winevent.
  3751. //
  3752. if (!IsWinEventHookInstalled(Event)) {
  3753. return;
  3754. }
  3755. //
  3756. // Due to the asynchronous nature of console creation, it's possible we'll get
  3757. // here but the InputThreadInfo pointer hasn't been set yet. If that's the case,
  3758. // we're certainly not the ConsoleInputThread, so conceptually we'd want to queue
  3759. // up the winevent anyway.
  3760. //
  3761. if (Console->InputThreadInfo != NULL &&
  3762. HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) == Console->InputThreadInfo->ThreadId) {
  3763. NotifyWinEvent(Event, Console->hWnd, idObjectType, idObject);
  3764. } else {
  3765. QueueConsoleMessage(Console, Event, idObjectType, idObject);
  3766. }
  3767. }
  3768. VOID
  3769. AbortCreateConsole(
  3770. IN PCONSOLE_INFORMATION Console
  3771. )
  3772. {
  3773. //
  3774. // Signal any process waiting for us that initialization failed
  3775. //
  3776. NtSetEvent(Console->InitEvents[INITIALIZATION_FAILED], NULL);
  3777. //
  3778. // Now clean up the console structure
  3779. //
  3780. CloseHandle(Console->ClientThreadHandle);
  3781. FreeInputBuffer(&Console->InputBuffer);
  3782. ConsoleHeapFree(Console->Title);
  3783. ConsoleHeapFree(Console->OriginalTitle);
  3784. NtClose(Console->InitEvents[INITIALIZATION_SUCCEEDED]);
  3785. NtClose(Console->InitEvents[INITIALIZATION_FAILED]);
  3786. NtClose(Console->TerminationEvent);
  3787. FreeAliasBuffers(Console);
  3788. FreeCommandHistoryBuffers(Console);
  3789. #if defined(FE_SB)
  3790. FreeLocalEUDC(Console);
  3791. DestroyFontCache(Console->FontCacheInformation);
  3792. #endif
  3793. DestroyConsole(Console);
  3794. }
  3795. VOID
  3796. DestroyWindowsWindow(
  3797. IN PCONSOLE_INFORMATION Console
  3798. )
  3799. {
  3800. PSCREEN_INFORMATION Cur,Next;
  3801. HWND hWnd = Console->hWnd;
  3802. gnConsoleWindows--;
  3803. Console->InputThreadInfo->WindowCount--;
  3804. SetWindowConsole(hWnd, NULL);
  3805. KillTimer(Console->hWnd, CURSOR_TIMER);
  3806. if (Console->hWndProperties) {
  3807. SendMessage(Console->hWndProperties, WM_CLOSE, 0, 0);
  3808. }
  3809. // FE_SB
  3810. if (Console->FonthDC) {
  3811. ReleaseDC(NULL, Console->FonthDC);
  3812. DeleteObject(Console->hBitmap);
  3813. }
  3814. DeleteEUDC(Console);
  3815. // FE_IME
  3816. if (CONSOLE_IS_IME_ENABLED()) {
  3817. if (!(Console->Flags & CONSOLE_NO_WINDOW)) {
  3818. KillTimer(Console->hWnd, SCROLL_WAIT_TIMER);
  3819. }
  3820. ConsoleImeMessagePump(Console,
  3821. CONIME_DESTROY,
  3822. (WPARAM)Console->ConsoleHandle,
  3823. (LPARAM)NULL
  3824. );
  3825. }
  3826. CleanupConsoleMessages(Console);
  3827. ReleaseDC(NULL, Console->hDC);
  3828. Console->hDC = NULL;
  3829. DestroyWindow(Console->hWnd);
  3830. Console->hWnd = NULL;
  3831. //
  3832. // Tell the worker thread that the window is destroyed.
  3833. //
  3834. ReplyMessage(0);
  3835. //
  3836. // Clear out any keyboard messages we have stored away.
  3837. //
  3838. ClearKeyInfo(hWnd);
  3839. if (Console->hIcon != NULL && Console->hIcon != ghDefaultIcon) {
  3840. DestroyIcon(Console->hIcon);
  3841. }
  3842. if (Console->hSmIcon != NULL && Console->hSmIcon != ghDefaultSmIcon) {
  3843. DestroyIcon(Console->hSmIcon);
  3844. }
  3845. //
  3846. // must keep this thread handle around until after the destroywindow
  3847. // call so that impersonation will work.
  3848. //
  3849. CloseHandle(Console->ClientThreadHandle);
  3850. //
  3851. // once the sendmessage returns, there will be no more input to
  3852. // the console so we don't need to lock it.
  3853. // also, we've freed the console handle, so no apis may access the console.
  3854. //
  3855. //
  3856. // free screen buffers
  3857. //
  3858. for (Cur=Console->ScreenBuffers;Cur!=NULL;Cur=Next) {
  3859. Next = Cur->Next;
  3860. FreeScreenBuffer(Cur);
  3861. }
  3862. FreeAliasBuffers(Console);
  3863. FreeCommandHistoryBuffers(Console);
  3864. //
  3865. // free input buffer
  3866. //
  3867. FreeInputBuffer(&Console->InputBuffer);
  3868. ConsoleHeapFree(Console->Title);
  3869. ConsoleHeapFree(Console->OriginalTitle);
  3870. NtClose(Console->InitEvents[INITIALIZATION_SUCCEEDED]);
  3871. NtClose(Console->InitEvents[INITIALIZATION_FAILED]);
  3872. NtClose(Console->TerminationEvent);
  3873. if (Console->hWinSta != NULL) {
  3874. CloseDesktop(Console->hDesk);
  3875. CloseWindowStation(Console->hWinSta);
  3876. }
  3877. if (Console->VDMProcessHandle) {
  3878. CloseHandle(Console->VDMProcessHandle);
  3879. }
  3880. ASSERT(!(Console->Flags & CONSOLE_VDM_REGISTERED));
  3881. #if defined(FE_SB)
  3882. FreeLocalEUDC(Console);
  3883. DestroyFontCache(Console->FontCacheInformation);
  3884. #endif
  3885. DestroyConsole(Console);
  3886. }
  3887. VOID
  3888. VerticalScroll(
  3889. IN PCONSOLE_INFORMATION Console,
  3890. IN PSCREEN_INFORMATION ScreenInfo,
  3891. IN WORD ScrollCommand,
  3892. IN WORD AbsoluteChange
  3893. )
  3894. {
  3895. COORD NewOrigin;
  3896. NewOrigin.X = ScreenInfo->Window.Left;
  3897. NewOrigin.Y = ScreenInfo->Window.Top;
  3898. switch (ScrollCommand) {
  3899. case SB_LINEUP:
  3900. NewOrigin.Y--;
  3901. break;
  3902. case SB_LINEDOWN:
  3903. NewOrigin.Y++;
  3904. break;
  3905. case SB_PAGEUP:
  3906. #if defined(FE_IME)
  3907. // MSKK July.22.1993 KazuM
  3908. // Plan of bottom line reservation for console IME.
  3909. if (ScreenInfo->Console->InputBuffer.ImeMode.Open) {
  3910. ASSERT(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER);
  3911. if (!(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)) {
  3912. return;
  3913. }
  3914. NewOrigin.Y-=CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-2;
  3915. ScreenInfo->BufferInfo.TextInfo.Flags &= ~TEXT_VALID_HINT;
  3916. ScreenInfo->BufferInfo.TextInfo.Flags |= CONSOLE_CONVERSION_AREA_REDRAW;
  3917. }
  3918. else
  3919. #endif // FE_IME
  3920. NewOrigin.Y-=CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-1;
  3921. break;
  3922. case SB_PAGEDOWN:
  3923. #if defined(FE_IME)
  3924. // MSKK July.22.1993 KazuM
  3925. // Plan of bottom line reservation for console IME.
  3926. if ( ScreenInfo->Console->InputBuffer.ImeMode.Open )
  3927. {
  3928. NewOrigin.Y+=CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-2;
  3929. ScreenInfo->BufferInfo.TextInfo.Flags &= ~TEXT_VALID_HINT;
  3930. ScreenInfo->BufferInfo.TextInfo.Flags |= CONSOLE_CONVERSION_AREA_REDRAW;
  3931. }
  3932. else
  3933. #endif // FE_IME
  3934. NewOrigin.Y+=CONSOLE_WINDOW_SIZE_Y(ScreenInfo)-1;
  3935. break;
  3936. case SB_THUMBTRACK:
  3937. Console->Flags |= CONSOLE_SCROLLBAR_TRACKING;
  3938. NewOrigin.Y= AbsoluteChange;
  3939. break;
  3940. case SB_THUMBPOSITION:
  3941. UnblockWriteConsole(Console, CONSOLE_SCROLLBAR_TRACKING);
  3942. NewOrigin.Y= AbsoluteChange;
  3943. break;
  3944. case SB_TOP:
  3945. NewOrigin.Y=0;
  3946. break;
  3947. case SB_BOTTOM:
  3948. NewOrigin.Y=(WORD)(ScreenInfo->ScreenBufferSize.Y-CONSOLE_WINDOW_SIZE_Y(ScreenInfo));
  3949. break;
  3950. default:
  3951. return;
  3952. }
  3953. NewOrigin.Y = (WORD)(max(0,min((SHORT)NewOrigin.Y,
  3954. (SHORT)ScreenInfo->ScreenBufferSize.Y-(SHORT)CONSOLE_WINDOW_SIZE_Y(ScreenInfo))));
  3955. SetWindowOrigin(ScreenInfo,
  3956. (BOOLEAN)TRUE,
  3957. NewOrigin
  3958. );
  3959. }
  3960. VOID
  3961. HorizontalScroll(
  3962. IN PSCREEN_INFORMATION ScreenInfo,
  3963. IN WORD ScrollCommand,
  3964. IN WORD AbsoluteChange
  3965. )
  3966. {
  3967. COORD NewOrigin;
  3968. NewOrigin.X = ScreenInfo->Window.Left;
  3969. NewOrigin.Y = ScreenInfo->Window.Top;
  3970. switch (ScrollCommand) {
  3971. case SB_LINEUP:
  3972. NewOrigin.X--;
  3973. break;
  3974. case SB_LINEDOWN:
  3975. NewOrigin.X++;
  3976. break;
  3977. case SB_PAGEUP:
  3978. NewOrigin.X-=CONSOLE_WINDOW_SIZE_X(ScreenInfo)-1;
  3979. break;
  3980. case SB_PAGEDOWN:
  3981. NewOrigin.X+=CONSOLE_WINDOW_SIZE_X(ScreenInfo)-1;
  3982. break;
  3983. case SB_THUMBTRACK:
  3984. case SB_THUMBPOSITION:
  3985. NewOrigin.X= AbsoluteChange;
  3986. break;
  3987. case SB_TOP:
  3988. NewOrigin.X=0;
  3989. break;
  3990. case SB_BOTTOM:
  3991. NewOrigin.X=(WORD)(ScreenInfo->ScreenBufferSize.X-CONSOLE_WINDOW_SIZE_X(ScreenInfo));
  3992. break;
  3993. default:
  3994. return;
  3995. }
  3996. NewOrigin.X = (WORD)(max(0,min((SHORT)NewOrigin.X,
  3997. (SHORT)ScreenInfo->ScreenBufferSize.X-(SHORT)CONSOLE_WINDOW_SIZE_X(ScreenInfo))));
  3998. SetWindowOrigin(ScreenInfo,
  3999. (BOOLEAN)TRUE,
  4000. NewOrigin
  4001. );
  4002. }
  4003. /*
  4004. * If guCaretBlinkTime is -1, we don't want to blink the caret. However, we
  4005. * need to make sure it gets drawn, so we'll set a short timer. When that
  4006. * goes off, we'll hit CursorTimerRoutine, and it'll do the right thing if
  4007. * guCaretBlinkTime is -1.
  4008. */
  4009. VOID SetCaretTimer(
  4010. HWND hWnd)
  4011. {
  4012. static CONST DWORD dwDefTimeout = 0x212;
  4013. SetTimer(hWnd,
  4014. CURSOR_TIMER,
  4015. guCaretBlinkTime == -1 ? dwDefTimeout : guCaretBlinkTime,
  4016. NULL);
  4017. }
  4018. LRESULT APIENTRY
  4019. ConsoleWindowProc(
  4020. HWND hWnd,
  4021. UINT Message,
  4022. WPARAM wParam,
  4023. LPARAM lParam)
  4024. {
  4025. HDC hDC;
  4026. PAINTSTRUCT ps;
  4027. PCONSOLE_INFORMATION Console;
  4028. PSCREEN_INFORMATION ScreenInfo;
  4029. SMALL_RECT PaintRect;
  4030. LRESULT Status = 0;
  4031. BOOL Unlock = TRUE;
  4032. Console = GetWindowConsole(hWnd);
  4033. if (Console != NULL) {
  4034. //
  4035. // Set up our thread so we can impersonate the client
  4036. // while processing the message.
  4037. //
  4038. CSR_SERVER_QUERYCLIENTTHREAD()->ThreadHandle =
  4039. Console->ClientThreadHandle;
  4040. //
  4041. // If the console is terminating, don't bother processing messages
  4042. // other than CM_DESTROY_WINDOW.
  4043. //
  4044. if (Console->Flags & CONSOLE_TERMINATING) {
  4045. LockConsole(Console);
  4046. DestroyWindowsWindow(Console);
  4047. return 0;
  4048. }
  4049. //
  4050. // Make sure the console pointer is still valid
  4051. //
  4052. ASSERT(NT_SUCCESS(ValidateConsole(Console)));
  4053. LockConsole(Console);
  4054. ScreenInfo = Console->CurrentScreenBuffer;
  4055. }
  4056. try {
  4057. if (Console == NULL || ScreenInfo == NULL) {
  4058. switch (Message) {
  4059. case WM_GETMINMAXINFO:
  4060. {
  4061. //
  4062. // createwindow issues a WM_GETMINMAXINFO
  4063. // message before we have the windowlong set up
  4064. // with the console pointer. we need to allow
  4065. // the created window to be bigger than the
  4066. // default size by the scroll size.
  4067. //
  4068. LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam;
  4069. lpmmi->ptMaxTrackSize.y += HorizontalScrollSize;
  4070. lpmmi->ptMaxTrackSize.x += VerticalScrollSize;
  4071. }
  4072. break;
  4073. default:
  4074. goto CallDefWin;
  4075. }
  4076. } else if (Message == ProgmanHandleMessage && lParam == 0) {
  4077. //
  4078. // NOTE: lParam will be 0 if progman is sending it and
  4079. // 1 if console is sending it. This is a workaround for
  4080. // a progman bug. progman sends a progmanhandlemessage
  4081. // twice for each window in the system each time one is
  4082. // requested (for one window).
  4083. //
  4084. if ((HWND)wParam != hWnd && Console->bIconInit) {
  4085. ATOM App,Topic;
  4086. CHAR szItem[ITEM_MAX_SIZE+1];
  4087. PCHAR lpItem;
  4088. ATOM aItem;
  4089. HANDLE ConsoleHandle;
  4090. if (!(Console->Flags & CONSOLE_TERMINATING)) {
  4091. ConsoleHandle = Console->ConsoleHandle;
  4092. Console->hWndProgMan = (HWND)wParam;
  4093. UnlockConsole(Console);
  4094. App = GlobalAddAtomA("Shell");
  4095. Topic = GlobalAddAtomA("AppIcon");
  4096. SendMessage(Console->hWndProgMan,
  4097. WM_DDE_INITIATE,
  4098. (WPARAM)hWnd,
  4099. MAKELONG(App, Topic)
  4100. );
  4101. // If the console is still valid, continue getting icon.
  4102. Status = RevalidateConsole(ConsoleHandle, &Console);
  4103. if (NT_SUCCESS(Status)) {
  4104. Console->bIconInit = FALSE;
  4105. lpItem = _itoa((int)Console->iIconId, szItem, 10);
  4106. aItem = GlobalAddAtomA(lpItem);
  4107. PostMessage(Console->hWndProgMan,
  4108. WM_DDE_REQUEST,
  4109. (WPARAM)hWnd,
  4110. MAKELONG(CF_TEXT, aItem));
  4111. }
  4112. }
  4113. }
  4114. } else {
  4115. switch (Message) {
  4116. case WM_DROPFILES:
  4117. DoDrop (wParam,Console);
  4118. break;
  4119. case WM_MOVE:
  4120. if (!IsIconic(hWnd)) {
  4121. PositionConsoleWindow(Console, (Console->WindowRect.left == CW_USEDEFAULT));
  4122. #if defined(FE_IME)
  4123. if (CONSOLE_IS_DBCS_OUTPUTCP(Console)) {
  4124. ConsoleImeResizeModeSystemView(Console,ScreenInfo->Window);
  4125. ConsoleImeResizeCompStrView(Console,ScreenInfo->Window);
  4126. }
  4127. #endif // FE_IME
  4128. }
  4129. break;
  4130. case WM_SIZE:
  4131. if (wParam != SIZE_MINIMIZED) {
  4132. //
  4133. // both SetWindowPos and SetScrollRange cause WM_SIZE
  4134. // messages to be issued. ignore them if we have already
  4135. // figured out what size the window should be.
  4136. //
  4137. if (!ScreenInfo->ResizingWindow) {
  4138. ScreenInfo->WindowMaximized = (wParam == SIZE_MAXIMIZED);
  4139. if (Console->ResizeFlags & SCREEN_BUFFER_CHANGE) {
  4140. UpdateWindowSize(Console,ScreenInfo);
  4141. }
  4142. PositionConsoleWindow(Console, (Console->WindowRect.left == CW_USEDEFAULT));
  4143. #if defined(FE_IME)
  4144. if (CONSOLE_IS_DBCS_OUTPUTCP(Console)) {
  4145. ConsoleImeResizeModeSystemView(Console,ScreenInfo->Window);
  4146. ConsoleImeResizeCompStrView(Console,ScreenInfo->Window);
  4147. }
  4148. #endif // FE_IME
  4149. if (Console->ResizeFlags & SCROLL_BAR_CHANGE) {
  4150. InternalUpdateScrollBars(ScreenInfo);
  4151. Console->ResizeFlags &= ~SCROLL_BAR_CHANGE;
  4152. }
  4153. }
  4154. } else {
  4155. //
  4156. // Console is going iconic. Trim working set of all
  4157. // processes in the console
  4158. //
  4159. TrimConsoleWorkingSet(Console);
  4160. }
  4161. break;
  4162. case WM_DDE_ACK:
  4163. if (Console->bIconInit) {
  4164. Console->hWndProgMan = (HWND)wParam;
  4165. }
  4166. break;
  4167. case WM_DDE_DATA:
  4168. {
  4169. DDEDATA *lpDDEData;
  4170. LPPMICONDATA lpIconData;
  4171. HICON hIcon;
  4172. HANDLE hDdeData;
  4173. BOOL bRelease;
  4174. WPARAM atomTemp;
  4175. UnpackDDElParam(WM_DDE_DATA, lParam, (WPARAM *)&hDdeData, &atomTemp);
  4176. if (hDdeData == NULL) {
  4177. break;
  4178. }
  4179. lpDDEData = (DDEDATA *)GlobalLock(hDdeData);
  4180. ASSERT(lpDDEData->cfFormat == CF_TEXT);
  4181. lpIconData = (LPPMICONDATA)lpDDEData->Value;
  4182. hIcon = CreateIconFromResourceEx(&lpIconData->iResource,
  4183. 0, TRUE, 0x30000, 0, 0, LR_DEFAULTSIZE);
  4184. if (hIcon) {
  4185. if (Console->hIcon != NULL && Console->hIcon != ghDefaultIcon) {
  4186. DestroyIcon(Console->hIcon);
  4187. }
  4188. Console->hIcon = hIcon;
  4189. SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
  4190. if (Console->hSmIcon != NULL) {
  4191. if (Console->hSmIcon != ghDefaultSmIcon) {
  4192. DestroyIcon(Console->hSmIcon);
  4193. }
  4194. Console->hSmIcon = NULL;
  4195. SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)NULL);
  4196. }
  4197. }
  4198. if (lpDDEData->fAckReq) {
  4199. PostMessage(Console->hWndProgMan,
  4200. WM_DDE_ACK,
  4201. (WPARAM)hWnd,
  4202. ReuseDDElParam(lParam, WM_DDE_DATA, WM_DDE_ACK, 0x8000, atomTemp));
  4203. }
  4204. bRelease = lpDDEData->fRelease;
  4205. GlobalUnlock(hDdeData);
  4206. if (bRelease){
  4207. GlobalFree(hDdeData);
  4208. }
  4209. PostMessage(Console->hWndProgMan,
  4210. WM_DDE_TERMINATE,
  4211. (WPARAM)hWnd,
  4212. 0
  4213. );
  4214. if (Console->Flags & CONSOLE_IS_ICONIC) {
  4215. // force repaint of icon
  4216. InvalidateRect(hWnd, NULL, TRUE);
  4217. }
  4218. }
  4219. break;
  4220. case WM_ACTIVATE:
  4221. //
  4222. // if we're activated by a mouse click, remember it so
  4223. // we don't pass the click on to the app.
  4224. //
  4225. if (LOWORD(wParam) == WA_CLICKACTIVE) {
  4226. Console->Flags |= CONSOLE_IGNORE_NEXT_MOUSE_INPUT;
  4227. }
  4228. goto CallDefWin;
  4229. break;
  4230. case WM_DDE_TERMINATE:
  4231. break;
  4232. // FE_IME
  4233. case CM_CONIME_KL_ACTIVATE:
  4234. ActivateKeyboardLayout((HKL)wParam, KLF_SETFORPROCESS);
  4235. break;
  4236. case WM_INPUTLANGCHANGEREQUEST:
  4237. if (CONSOLE_IS_IME_ENABLED()) {
  4238. ULONG ConimeMessage;
  4239. LRESULT lResult;
  4240. if (wParam & INPUTLANGCHANGE_BACKWARD) {
  4241. ConimeMessage = CONIME_INPUTLANGCHANGEREQUESTBACKWARD;
  4242. } else if (wParam & INPUTLANGCHANGE_FORWARD) {
  4243. ConimeMessage = CONIME_INPUTLANGCHANGEREQUESTFORWARD;
  4244. } else {
  4245. ConimeMessage = CONIME_INPUTLANGCHANGEREQUEST;
  4246. }
  4247. if (!NT_SUCCESS(ConsoleImeMessagePumpWorker(Console,
  4248. ConimeMessage,
  4249. (WPARAM)Console->ConsoleHandle,
  4250. (LPARAM)lParam,
  4251. &lResult)) ||
  4252. !lResult) {
  4253. break;
  4254. }
  4255. }
  4256. #ifdef LATER
  4257. else if (IS_IME_KBDLAYOUT(lParam)) {
  4258. // IME keyboard layout should be avoided
  4259. // if the console is not IME enabled.
  4260. break;
  4261. }
  4262. // Call the default window proc and let it handle
  4263. // the keyboard layout activation.
  4264. #endif
  4265. goto CallDefWin;
  4266. break;
  4267. // end FE_IME
  4268. case WM_INPUTLANGCHANGE:
  4269. Console->hklActive = (HKL)lParam;
  4270. // FE_IME
  4271. if (CONSOLE_IS_IME_ENABLED()) {
  4272. if (!NT_SUCCESS(ConsoleImeMessagePump(Console,
  4273. CONIME_INPUTLANGCHANGE,
  4274. (WPARAM)Console->ConsoleHandle,
  4275. (LPARAM)Console->hklActive
  4276. ))) {
  4277. break;
  4278. } else{
  4279. GetImeKeyState(Console, NULL) ;
  4280. }
  4281. }
  4282. // end FE_IME
  4283. goto CallDefWin;
  4284. break;
  4285. case WM_SETFOCUS:
  4286. ModifyConsoleProcessFocus(Console, TRUE);
  4287. SetConsoleReserveKeys(hWnd, Console->ReserveKeys);
  4288. Console->Flags |= CONSOLE_HAS_FOCUS;
  4289. SetCaretTimer(hWnd);
  4290. HandleFocusEvent(Console, TRUE);
  4291. if (!Console->hklActive) {
  4292. SystemParametersInfo(SPI_GETDEFAULTINPUTLANG, 0, &Console->hklActive, FALSE);
  4293. GetNonBiDiKeyboardLayout(&Console->hklActive);
  4294. }
  4295. ActivateKeyboardLayout(Console->hklActive, 0);
  4296. // FE_IME
  4297. if (CONSOLE_IS_IME_ENABLED()) {
  4298. // v-HirShi Sep.15.1995 Support Console IME
  4299. if (!NT_SUCCESS(ConsoleImeMessagePump(Console,
  4300. CONIME_SETFOCUS,
  4301. (WPARAM)Console->ConsoleHandle,
  4302. (LPARAM)Console->hklActive
  4303. ))) {
  4304. break;
  4305. }
  4306. if (Console->InputBuffer.hWndConsoleIME) {
  4307. /*
  4308. * Open property window by ImmConfigureIME.
  4309. * Never set focus on console window
  4310. * so, set focus to property window.
  4311. */
  4312. HWND hwnd = GetLastActivePopup(Console->InputBuffer.hWndConsoleIME);
  4313. if (hwnd != NULL)
  4314. SetForegroundWindow(hwnd);
  4315. }
  4316. }
  4317. // FE_IME
  4318. break;
  4319. case WM_KILLFOCUS:
  4320. ModifyConsoleProcessFocus(Console, FALSE);
  4321. SetConsoleReserveKeys(hWnd, CONSOLE_NOSHORTCUTKEY);
  4322. Console->Flags &= ~CONSOLE_HAS_FOCUS;
  4323. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  4324. ConsoleHideCursor(ScreenInfo);
  4325. ScreenInfo->BufferInfo.TextInfo.UpdatingScreen -= 1; // counteract HideCursor
  4326. }
  4327. KillTimer(hWnd, CURSOR_TIMER);
  4328. HandleFocusEvent(Console,FALSE);
  4329. // FE_IME
  4330. if (CONSOLE_IS_IME_ENABLED()) {
  4331. // v-HirShi Sep.16.1995 Support Console IME
  4332. if (!NT_SUCCESS(ConsoleImeMessagePump(Console,
  4333. CONIME_KILLFOCUS,
  4334. (WPARAM)Console->ConsoleHandle,
  4335. (LPARAM)NULL
  4336. ))) {
  4337. break;
  4338. }
  4339. }
  4340. // end FE_IME
  4341. break;
  4342. case WM_PAINT:
  4343. // ICONIC bit is not set if we're fullscreen and don't
  4344. // have the hardware
  4345. ConsoleHideCursor(ScreenInfo);
  4346. hDC = BeginPaint(hWnd, &ps);
  4347. if (Console->Flags & CONSOLE_IS_ICONIC ||
  4348. Console->FullScreenFlags == CONSOLE_FULLSCREEN) {
  4349. RECT rc;
  4350. UINT cxIcon, cyIcon;
  4351. GetClientRect(hWnd, &rc);
  4352. cxIcon = GetSystemMetrics(SM_CXICON);
  4353. cyIcon = GetSystemMetrics(SM_CYICON);
  4354. rc.left = (rc.right - cxIcon) >> 1;
  4355. rc.top = (rc.bottom - cyIcon) >> 1;
  4356. DrawIcon(hDC, rc.left, rc.top, Console->hIcon);
  4357. } else {
  4358. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  4359. PaintRect.Left = (SHORT)((ps.rcPaint.left/SCR_FONTSIZE(ScreenInfo).X)+ScreenInfo->Window.Left);
  4360. PaintRect.Right = (SHORT)((ps.rcPaint.right/SCR_FONTSIZE(ScreenInfo).X)+ScreenInfo->Window.Left);
  4361. PaintRect.Top = (SHORT)((ps.rcPaint.top/SCR_FONTSIZE(ScreenInfo).Y)+ScreenInfo->Window.Top);
  4362. PaintRect.Bottom = (SHORT)((ps.rcPaint.bottom/SCR_FONTSIZE(ScreenInfo).Y)+ScreenInfo->Window.Top);
  4363. } else {
  4364. PaintRect.Left = (SHORT)(ps.rcPaint.left+ScreenInfo->Window.Left);
  4365. PaintRect.Right = (SHORT)(ps.rcPaint.right+ScreenInfo->Window.Left);
  4366. PaintRect.Top = (SHORT)(ps.rcPaint.top+ScreenInfo->Window.Top);
  4367. PaintRect.Bottom = (SHORT)(ps.rcPaint.bottom+ScreenInfo->Window.Top);
  4368. }
  4369. ScreenInfo->BufferInfo.TextInfo.Flags &= ~TEXT_VALID_HINT;
  4370. WriteToScreen(ScreenInfo,&PaintRect);
  4371. }
  4372. EndPaint(hWnd,&ps);
  4373. ConsoleShowCursor(ScreenInfo);
  4374. break;
  4375. case WM_CLOSE:
  4376. if (!(Console->Flags & CONSOLE_NO_WINDOW) ||
  4377. !(Console->Flags & CONSOLE_WOW_REGISTERED)) {
  4378. HandleCtrlEvent(Console,CTRL_CLOSE_EVENT);
  4379. }
  4380. break;
  4381. case WM_ERASEBKGND:
  4382. // ICONIC bit is not set if we're fullscreen and don't
  4383. // have the hardware
  4384. if (Console->Flags & CONSOLE_IS_ICONIC ||
  4385. Console->FullScreenFlags == CONSOLE_FULLSCREEN) {
  4386. Message = WM_ICONERASEBKGND;
  4387. goto CallDefWin;
  4388. }
  4389. break;
  4390. case WM_SETTINGCHANGE:
  4391. {
  4392. DWORD dwCaretBlinkTime = GetCaretBlinkTime();
  4393. if (dwCaretBlinkTime != guCaretBlinkTime) {
  4394. KillTimer(hWnd, CURSOR_TIMER);
  4395. guCaretBlinkTime = dwCaretBlinkTime;
  4396. SetCaretTimer(hWnd);
  4397. }
  4398. }
  4399. /* Fall through */
  4400. case WM_DISPLAYCHANGE:
  4401. gfInitSystemMetrics = TRUE;
  4402. break;
  4403. case WM_SETCURSOR:
  4404. if (lParam == -1) {
  4405. //
  4406. // the app changed the cursor visibility or shape.
  4407. // see if the cursor is in the client area.
  4408. //
  4409. POINT Point;
  4410. HWND hWndTmp;
  4411. GetCursorPos(&Point);
  4412. hWndTmp = WindowFromPoint(Point);
  4413. if (hWndTmp == hWnd) {
  4414. lParam = DefWindowProc(hWnd,WM_NCHITTEST,0,MAKELONG((WORD)Point.x, (WORD)Point.y));
  4415. }
  4416. }
  4417. if ((WORD)lParam == HTCLIENT) {
  4418. if (ScreenInfo->CursorDisplayCount < 0) {
  4419. SetCursor(NULL);
  4420. } else {
  4421. SetCursor(ScreenInfo->CursorHandle);
  4422. }
  4423. } else {
  4424. goto CallDefWin;
  4425. }
  4426. break;
  4427. case WM_GETMINMAXINFO:
  4428. {
  4429. LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam;
  4430. COORD FontSize;
  4431. WINDOW_LIMITS WindowLimits;
  4432. GetWindowLimits(ScreenInfo, &WindowLimits);
  4433. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  4434. FontSize = SCR_FONTSIZE(ScreenInfo);
  4435. } else {
  4436. FontSize.X = 1;
  4437. FontSize.Y = 1;
  4438. }
  4439. lpmmi->ptMaxSize.x = lpmmi->ptMaxTrackSize.x = WindowLimits.MaxWindow.X;
  4440. if (!ScreenInfo->WindowMaximizedY) {
  4441. lpmmi->ptMaxTrackSize.x += VerticalScrollSize;
  4442. lpmmi->ptMaxSize.x += VerticalScrollSize;
  4443. }
  4444. while (lpmmi->ptMaxSize.x > WindowLimits.FullScreenSize.X + VerticalClientToWindow) {
  4445. lpmmi->ptMaxSize.x -= FontSize.X;
  4446. }
  4447. lpmmi->ptMaxSize.y = lpmmi->ptMaxTrackSize.y = WindowLimits.MaxWindow.Y;
  4448. if (!ScreenInfo->WindowMaximizedX) {
  4449. lpmmi->ptMaxTrackSize.y += HorizontalScrollSize;
  4450. lpmmi->ptMaxSize.y += HorizontalScrollSize;
  4451. }
  4452. while (lpmmi->ptMaxSize.y > WindowLimits.FullScreenSize.Y + HorizontalClientToWindow) {
  4453. lpmmi->ptMaxSize.y -= FontSize.Y;
  4454. }
  4455. lpmmi->ptMinTrackSize.x = WindowLimits.MinimumWindowSize.X * FontSize.X + VerticalClientToWindow;
  4456. lpmmi->ptMinTrackSize.y = HorizontalClientToWindow;
  4457. }
  4458. break;
  4459. case WM_QUERYDRAGICON:
  4460. Status = (LRESULT)Console->hIcon;
  4461. break;
  4462. case WM_WINDOWPOSCHANGING:
  4463. {
  4464. LPWINDOWPOS WindowPos = (LPWINDOWPOS)lParam;
  4465. DWORD fMinimized;
  4466. /*
  4467. * This message is sent before a SetWindowPos() operation
  4468. * occurs. We use it here to set/clear the CONSOLE_IS_ICONIC
  4469. * bit appropriately... doing so in the WM_SIZE handler
  4470. * is incorrect because the WM_SIZE comes after the
  4471. * WM_ERASEBKGND during SetWindowPos() processing, and the
  4472. * WM_ERASEBKGND needs to know if the console window is
  4473. * iconic or not.
  4474. */
  4475. fMinimized = IsIconic(hWnd);
  4476. if (fMinimized) {
  4477. if (!(Console->Flags & CONSOLE_IS_ICONIC)) {
  4478. Console->Flags |= CONSOLE_IS_ICONIC;
  4479. //
  4480. // If the palette is something other than default,
  4481. // select the default palette in. Otherwise, the
  4482. // screen will repaint twice each time the icon
  4483. // is painted.
  4484. //
  4485. if (ScreenInfo->hPalette != NULL &&
  4486. Console->FullScreenFlags == 0) {
  4487. SelectPalette(Console->hDC,
  4488. Console->hSysPalette,
  4489. FALSE);
  4490. UnsetActivePalette(ScreenInfo);
  4491. }
  4492. }
  4493. } else {
  4494. if (Console->Flags & CONSOLE_IS_ICONIC) {
  4495. Console->Flags &= ~CONSOLE_IS_ICONIC;
  4496. //
  4497. // If the palette is something other than default,
  4498. // select the default palette in. Otherwise, the
  4499. // screen will repaint twice each time the icon
  4500. // is painted.
  4501. //
  4502. if (ScreenInfo->hPalette != NULL &&
  4503. Console->FullScreenFlags == 0) {
  4504. SelectPalette(Console->hDC,
  4505. ScreenInfo->hPalette,
  4506. FALSE);
  4507. SetActivePalette(ScreenInfo);
  4508. }
  4509. }
  4510. }
  4511. if (!ScreenInfo->ResizingWindow &&
  4512. (WindowPos->cx || WindowPos->cy) &&
  4513. !fMinimized) {
  4514. ProcessResizeWindow(ScreenInfo,Console,WindowPos);
  4515. }
  4516. }
  4517. break;
  4518. case WM_CONTEXTMENU:
  4519. if (DefWindowProc(hWnd, WM_NCHITTEST, 0, lParam) == HTCLIENT) {
  4520. TrackPopupMenuEx(Console->hHeirMenu,
  4521. TPM_RIGHTBUTTON,
  4522. GET_X_LPARAM(lParam),
  4523. GET_Y_LPARAM(lParam),
  4524. hWnd,
  4525. NULL);
  4526. } else {
  4527. goto CallDefWin;
  4528. }
  4529. break;
  4530. case WM_NCLBUTTONDOWN:
  4531. // allow user to move window even when bigger than the screen
  4532. switch (wParam & 0x00FF) {
  4533. case HTCAPTION:
  4534. UnlockConsole(Console);
  4535. Unlock = FALSE;
  4536. SetActiveWindow(hWnd);
  4537. SendMessage(hWnd, WM_SYSCOMMAND,
  4538. SC_MOVE | wParam, lParam);
  4539. break;
  4540. default:
  4541. goto CallDefWin;
  4542. }
  4543. break;
  4544. #if defined (FE_IME)
  4545. // Sep.16.1995 Support Console IME
  4546. case WM_KEYDOWN +CONIME_KEYDATA:
  4547. case WM_KEYUP +CONIME_KEYDATA:
  4548. case WM_CHAR +CONIME_KEYDATA:
  4549. case WM_DEADCHAR +CONIME_KEYDATA:
  4550. case WM_SYSKEYDOWN +CONIME_KEYDATA:
  4551. case WM_SYSKEYUP +CONIME_KEYDATA:
  4552. case WM_SYSCHAR +CONIME_KEYDATA:
  4553. case WM_SYSDEADCHAR+CONIME_KEYDATA:
  4554. #endif
  4555. case WM_KEYDOWN:
  4556. case WM_KEYUP:
  4557. case WM_CHAR:
  4558. case WM_DEADCHAR:
  4559. HandleKeyEvent(Console,hWnd,Message,wParam,lParam);
  4560. break;
  4561. case WM_SYSKEYDOWN:
  4562. case WM_SYSKEYUP:
  4563. case WM_SYSCHAR:
  4564. case WM_SYSDEADCHAR:
  4565. if (HandleSysKeyEvent(Console, hWnd, Message, wParam, lParam, &Unlock)) {
  4566. goto CallDefWin;
  4567. }
  4568. break;
  4569. case WM_COMMAND:
  4570. //
  4571. // If this is an edit command from the context menu, treat
  4572. // it like a sys command.
  4573. //
  4574. if ((wParam < cmCopy) || (wParam > cmSelectAll)) {
  4575. break;
  4576. }
  4577. // FALL THRU
  4578. case WM_SYSCOMMAND:
  4579. if (wParam >= ScreenInfo->CommandIdLow &&
  4580. wParam <= ScreenInfo->CommandIdHigh) {
  4581. HandleMenuEvent(Console, (DWORD)wParam);
  4582. } else if (wParam == cmMark) {
  4583. DoMark(Console);
  4584. } else if (wParam == cmCopy) {
  4585. DoCopy(Console);
  4586. } else if (wParam == cmPaste) {
  4587. DoPaste(Console);
  4588. } else if (wParam == cmScroll) {
  4589. DoScroll(Console);
  4590. } else if (wParam == cmFind) {
  4591. DoFind(Console);
  4592. } else if (wParam == cmSelectAll) {
  4593. DoSelectAll(Console);
  4594. } else if (wParam == cmControl) {
  4595. PropertiesDlgShow(Console, TRUE);
  4596. } else if (wParam == cmDefaults) {
  4597. PropertiesDlgShow(Console, FALSE);
  4598. } else if ((wParam == SC_RESTORE || wParam == SC_MAXIMIZE) &&
  4599. Console->Flags & CONSOLE_VDM_HIDDEN_WINDOW) {
  4600. Console->Flags &= ~CONSOLE_VDM_HIDDEN_WINDOW;
  4601. SendMessage(Console->hWnd, CM_MODE_TRANSITION, FULLSCREEN, 0L);
  4602. } else {
  4603. goto CallDefWin;
  4604. }
  4605. break;
  4606. case WM_TIMER:
  4607. #if defined(FE_IME)
  4608. if (wParam == SCROLL_WAIT_TIMER) {
  4609. ASSERT(CONSOLE_IS_IME_ENABLED());
  4610. if ((ScreenInfo->Console->ConsoleIme.ScrollFlag & (HIDE_FOR_SCROLL)) &&
  4611. (ScreenInfo->Console->ConsoleIme.ScrollWaitCountDown > 0)
  4612. ) {
  4613. if ((ScreenInfo->Console->ConsoleIme.ScrollWaitCountDown -= guCaretBlinkTime) <= 0) {
  4614. ConsoleImeBottomLineInUse(ScreenInfo);
  4615. }
  4616. }
  4617. break;
  4618. }
  4619. #endif
  4620. CursorTimerRoutine(ScreenInfo);
  4621. ScrollIfNecessary(Console, ScreenInfo);
  4622. break;
  4623. case WM_HSCROLL:
  4624. HorizontalScroll(ScreenInfo, LOWORD(wParam), HIWORD(wParam));
  4625. break;
  4626. case WM_VSCROLL:
  4627. VerticalScroll(Console, ScreenInfo, LOWORD(wParam), HIWORD(wParam));
  4628. break;
  4629. case WM_INITMENU:
  4630. HandleMenuEvent(Console, WM_INITMENU);
  4631. InitializeMenu(Console);
  4632. break;
  4633. case WM_MENUSELECT:
  4634. if (HIWORD(wParam) == 0xffff) {
  4635. HandleMenuEvent(Console, WM_MENUSELECT);
  4636. }
  4637. break;
  4638. case WM_MOUSEMOVE:
  4639. case WM_LBUTTONDOWN:
  4640. case WM_LBUTTONUP:
  4641. case WM_LBUTTONDBLCLK:
  4642. case WM_RBUTTONDOWN:
  4643. case WM_RBUTTONUP:
  4644. case WM_RBUTTONDBLCLK:
  4645. case WM_MBUTTONDOWN:
  4646. case WM_MBUTTONUP:
  4647. case WM_MBUTTONDBLCLK:
  4648. case WM_MOUSEWHEEL:
  4649. if (HandleMouseEvent(Console, ScreenInfo, Message, wParam, lParam)) {
  4650. if (Message != WM_MOUSEWHEEL) {
  4651. goto CallDefWin;
  4652. }
  4653. } else {
  4654. break;
  4655. }
  4656. /*
  4657. * Don't handle zoom.
  4658. */
  4659. if (wParam & MK_CONTROL) {
  4660. goto CallDefWin;
  4661. }
  4662. Status = 1;
  4663. if (gfInitSystemMetrics) {
  4664. InitializeSystemMetrics();
  4665. }
  4666. ScreenInfo->WheelDelta -= (short)HIWORD(wParam);
  4667. if (abs(ScreenInfo->WheelDelta) >= WHEEL_DELTA &&
  4668. gucWheelScrollLines > 0) {
  4669. COORD NewOrigin;
  4670. SHORT dy;
  4671. NewOrigin.X = ScreenInfo->Window.Left;
  4672. NewOrigin.Y = ScreenInfo->Window.Top;
  4673. /*
  4674. * Limit a roll of one (1) WHEEL_DELTA to scroll one (1)
  4675. * page. If in shift scroll mode then scroll one page at
  4676. * a time regardless.
  4677. */
  4678. if (!(wParam & MK_SHIFT)) {
  4679. dy = (int) min(
  4680. (UINT) CONSOLE_WINDOW_SIZE_Y(ScreenInfo) - 1,
  4681. gucWheelScrollLines);
  4682. } else {
  4683. dy = CONSOLE_WINDOW_SIZE_Y(ScreenInfo) - 1;
  4684. }
  4685. if (dy == 0) {
  4686. dy++;
  4687. }
  4688. dy *= (ScreenInfo->WheelDelta / WHEEL_DELTA);
  4689. ScreenInfo->WheelDelta %= WHEEL_DELTA;
  4690. NewOrigin.Y += dy;
  4691. if (NewOrigin.Y < 0) {
  4692. NewOrigin.Y = 0;
  4693. } else if (NewOrigin.Y + CONSOLE_WINDOW_SIZE_Y(ScreenInfo) >
  4694. ScreenInfo->ScreenBufferSize.Y) {
  4695. NewOrigin.Y = ScreenInfo->ScreenBufferSize.Y -
  4696. CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
  4697. }
  4698. SetWindowOrigin(ScreenInfo, TRUE, NewOrigin);
  4699. }
  4700. break;
  4701. case WM_PALETTECHANGED:
  4702. if (Console->FullScreenFlags == 0) {
  4703. if (ScreenInfo->hPalette != NULL) {
  4704. SetActivePalette(ScreenInfo);
  4705. if (ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER) {
  4706. WriteRegionToScreenBitMap(ScreenInfo,
  4707. &ScreenInfo->Window);
  4708. }
  4709. } else {
  4710. SetScreenColors(ScreenInfo, ScreenInfo->Attributes,
  4711. ScreenInfo->PopupAttributes, TRUE);
  4712. }
  4713. }
  4714. break;
  4715. #if defined(_X86_)
  4716. case WM_FULLSCREEN:
  4717. //
  4718. // This message is sent by the system to tell console that
  4719. // the fullscreen state of a window has changed.
  4720. // In some cases, this message will be sent in response to
  4721. // a call from console to change to fullscreen (Atl-Enter)
  4722. // or may also come directly from the system (switch of
  4723. // focus from a windowed app to a fullscreen app).
  4724. //
  4725. RIPMSG0(RIP_WARNING, "WindowProc - WM_FULLSCREEN");
  4726. Status = DisplayModeTransition(wParam,Console,ScreenInfo);
  4727. #if defined(FE_IME)
  4728. if (NT_SUCCESS(Status)) {
  4729. Status = ImeWmFullScreen(wParam,Console,ScreenInfo);
  4730. }
  4731. #endif // FE_IME
  4732. break;
  4733. #endif
  4734. case CM_SET_WINDOW_SIZE:
  4735. if (lParam == 0x47474747) {
  4736. Status = InternalSetWindowSize(Console,
  4737. (PSCREEN_INFORMATION)wParam,
  4738. &ScreenInfo->Window
  4739. );
  4740. }
  4741. break;
  4742. case CM_BEEP:
  4743. if (lParam == 0x47474747) {
  4744. Beep(800, 200);
  4745. }
  4746. break;
  4747. case CM_UPDATE_SCROLL_BARS:
  4748. InternalUpdateScrollBars(ScreenInfo);
  4749. break;
  4750. case CM_UPDATE_TITLE:
  4751. SetWindowText(hWnd, Console->Title);
  4752. break;
  4753. case CM_CONSOLE_MSG:
  4754. if (!UnqueueConsoleMessage(Console, &Message, &wParam, &lParam)) {
  4755. break;
  4756. }
  4757. switch (Message) {
  4758. #if defined(_X86_)
  4759. case CM_MODE_TRANSITION:
  4760. RIPMSG0(RIP_WARNING, "WindowProc - CM_MODE_TRANSITION");
  4761. if (wParam == FULLSCREEN) {
  4762. if (Console->FullScreenFlags == 0) {
  4763. ConvertToFullScreen(Console);
  4764. Console->FullScreenFlags |= CONSOLE_FULLSCREEN;
  4765. ChangeDispSettings(Console, hWnd, CDS_FULLSCREEN);
  4766. }
  4767. } else {
  4768. if (Console->FullScreenFlags & CONSOLE_FULLSCREEN) {
  4769. ConvertToWindowed(Console);
  4770. Console->FullScreenFlags &= ~CONSOLE_FULLSCREEN;
  4771. ChangeDispSettings(Console, hWnd, 0);
  4772. ShowWindow(hWnd, SW_RESTORE);
  4773. }
  4774. }
  4775. UnlockConsole(Console);
  4776. Unlock = FALSE;
  4777. NtSetEvent((HANDLE)lParam, NULL);
  4778. NtClose((HANDLE)lParam);
  4779. break;
  4780. #endif
  4781. #if defined (FE_IME)
  4782. case CM_SET_IME_CODEPAGE: {
  4783. if (!LOWORD(lParam)) {
  4784. // Input code page
  4785. Status = SetImeCodePage(Console);
  4786. } else {
  4787. // Output code page
  4788. Status = SetImeOutputCodePage(Console, ScreenInfo, HIWORD(lParam));
  4789. }
  4790. if (wParam) {
  4791. NtSetEvent((HANDLE)wParam, NULL);
  4792. NtClose((HANDLE)wParam);
  4793. }
  4794. break;
  4795. }
  4796. case CM_SET_NLSMODE:
  4797. Status = SetImeKeyState(Console, ImmConversionFromConsole((DWORD)lParam));
  4798. if (wParam) {
  4799. NtSetEvent((HANDLE)wParam, NULL);
  4800. NtClose((HANDLE)wParam);
  4801. }
  4802. break;
  4803. case CM_GET_NLSMODE:
  4804. if (Console->InputThreadInfo->hWndConsoleIME) {
  4805. ASSERT(CONSOLE_IS_IME_ENABLED());
  4806. if (!NT_SUCCESS(GetImeKeyState(Console, NULL))) {
  4807. if (wParam) {
  4808. NtSetEvent((HANDLE)wParam, NULL);
  4809. NtClose((HANDLE)wParam);
  4810. }
  4811. break;
  4812. }
  4813. if (wParam) {
  4814. NtSetEvent((HANDLE)wParam, NULL);
  4815. NtClose((HANDLE)wParam);
  4816. }
  4817. } else if (lParam < 10) {
  4818. /*
  4819. * try get conversion mode until ready ConIME.
  4820. */
  4821. Status = QueueConsoleMessage(Console,
  4822. CM_GET_NLSMODE,
  4823. wParam,
  4824. lParam+1
  4825. );
  4826. if (!NT_SUCCESS(Status)) {
  4827. if (wParam) {
  4828. NtSetEvent((HANDLE)wParam, NULL);
  4829. NtClose((HANDLE)wParam);
  4830. }
  4831. }
  4832. } else {
  4833. if (wParam) {
  4834. NtSetEvent((HANDLE)wParam, NULL);
  4835. NtClose((HANDLE)wParam);
  4836. }
  4837. }
  4838. break;
  4839. #endif // FE_IME
  4840. case EVENT_CONSOLE_CARET:
  4841. case EVENT_CONSOLE_UPDATE_REGION:
  4842. case EVENT_CONSOLE_UPDATE_SIMPLE:
  4843. case EVENT_CONSOLE_UPDATE_SCROLL:
  4844. case EVENT_CONSOLE_LAYOUT:
  4845. case EVENT_CONSOLE_START_APPLICATION:
  4846. case EVENT_CONSOLE_END_APPLICATION:
  4847. NotifyWinEvent(Message, hWnd, (LONG)wParam, (LONG)lParam);
  4848. break;
  4849. default:
  4850. RIPMSG1(RIP_WARNING, "Unknown console message 0x%x", Message);
  4851. break;
  4852. }
  4853. break;
  4854. #if defined(_X86_)
  4855. case CM_MODE_TRANSITION:
  4856. /*
  4857. * This is called by win32k.sys to request a display mode
  4858. * transition.
  4859. */
  4860. RIPMSG0(RIP_WARNING, "WindowProc - CM_MODE_TRANSITION");
  4861. if (wParam == FULLSCREEN) {
  4862. if (Console->FullScreenFlags == 0) {
  4863. ConvertToFullScreen(Console);
  4864. Console->FullScreenFlags |= CONSOLE_FULLSCREEN;
  4865. ChangeDispSettings(Console, hWnd, CDS_FULLSCREEN);
  4866. }
  4867. } else {
  4868. if (Console->FullScreenFlags & CONSOLE_FULLSCREEN) {
  4869. ConvertToWindowed(Console);
  4870. Console->FullScreenFlags &= ~CONSOLE_FULLSCREEN;
  4871. ChangeDispSettings(Console, hWnd, 0);
  4872. ShowWindow(hWnd, SW_RESTORE);
  4873. }
  4874. }
  4875. UnlockConsole(Console);
  4876. Unlock = FALSE;
  4877. break;
  4878. #endif // _X86_
  4879. case CM_HIDE_WINDOW:
  4880. ShowWindowAsync(hWnd, SW_MINIMIZE);
  4881. break;
  4882. case CM_PROPERTIES_START:
  4883. Console->hWndProperties = (HWND)wParam;
  4884. break;
  4885. case CM_PROPERTIES_UPDATE:
  4886. PropertiesUpdate(Console, (HANDLE)wParam);
  4887. break;
  4888. case CM_PROPERTIES_END:
  4889. Console->hWndProperties = NULL;
  4890. break;
  4891. #if defined(FE_IME)
  4892. case WM_COPYDATA:
  4893. if (CONSOLE_IS_IME_ENABLED() && CONSOLE_IS_DBCS_OUTPUTCP(Console)) {
  4894. Status = ImeControl(Console,(HWND)wParam,(PCOPYDATASTRUCT)lParam);
  4895. }
  4896. break;
  4897. // v-HirShi Sep.18.1995 Support Console IME
  4898. case WM_ENTERMENULOOP:
  4899. if (Console->Flags & CONSOLE_HAS_FOCUS) {
  4900. Console->InputBuffer.ImeMode.Unavailable = TRUE;
  4901. if (CONSOLE_IS_IME_ENABLED()) {
  4902. if (!NT_SUCCESS(ConsoleImeMessagePump(Console,
  4903. CONIME_KILLFOCUS,
  4904. (WPARAM)Console->ConsoleHandle,
  4905. (LPARAM)NULL
  4906. ))) {
  4907. break;
  4908. }
  4909. }
  4910. }
  4911. break;
  4912. case WM_EXITMENULOOP:
  4913. if (Console->Flags & CONSOLE_HAS_FOCUS) {
  4914. if (CONSOLE_IS_IME_ENABLED()) {
  4915. if (!NT_SUCCESS(ConsoleImeMessagePump(Console,
  4916. CONIME_SETFOCUS,
  4917. (WPARAM)Console->ConsoleHandle,
  4918. (LPARAM)Console->hklActive
  4919. ))) {
  4920. break;
  4921. }
  4922. }
  4923. Console->InputBuffer.ImeMode.Unavailable = FALSE;
  4924. }
  4925. break;
  4926. case WM_ENTERSIZEMOVE:
  4927. if (Console->Flags & CONSOLE_HAS_FOCUS) {
  4928. Console->InputBuffer.ImeMode.Unavailable = TRUE;
  4929. }
  4930. break;
  4931. case WM_EXITSIZEMOVE:
  4932. if (Console->Flags & CONSOLE_HAS_FOCUS) {
  4933. Console->InputBuffer.ImeMode.Unavailable = FALSE;
  4934. }
  4935. break;
  4936. #endif // FE_IME
  4937. CallDefWin:
  4938. default:
  4939. if (Unlock && Console != NULL) {
  4940. UnlockConsole(Console);
  4941. Unlock = FALSE;
  4942. }
  4943. Status = DefWindowProc(hWnd,Message,wParam,lParam);
  4944. break;
  4945. }
  4946. }
  4947. } finally {
  4948. if (Unlock && Console != NULL) {
  4949. UnlockConsole(Console);
  4950. }
  4951. }
  4952. return Status;
  4953. }
  4954. /*
  4955. * Drag and Drop support functions for console window
  4956. */
  4957. /*++
  4958. Routine Description:
  4959. This routine retrieves the filenames of dropped files. It was copied from
  4960. shelldll API DragQueryFile. We didn't use DragQueryFile () because we don't
  4961. want to load Shell32.dll in CSR
  4962. Arguments:
  4963. Same as DragQueryFile
  4964. Return Value:
  4965. --*/
  4966. UINT ConsoleDragQueryFile(
  4967. IN HANDLE hDrop,
  4968. IN PVOID lpFile,
  4969. IN UINT cb)
  4970. {
  4971. UINT i = 0;
  4972. LPDROPFILESTRUCT lpdfs;
  4973. BOOL fWide;
  4974. lpdfs = (LPDROPFILESTRUCT)GlobalLock(hDrop);
  4975. if (lpdfs && lpdfs != hDrop) {
  4976. try {
  4977. fWide = (LOWORD(lpdfs->pFiles) == sizeof(DROPFILES));
  4978. if (fWide) {
  4979. //
  4980. // This is a new (NT-compatible) HDROP
  4981. //
  4982. fWide = lpdfs->fWide; // Redetermine fWide from struct
  4983. // since it is present.
  4984. }
  4985. if (fWide) {
  4986. LPWSTR lpList;
  4987. //
  4988. // UNICODE HDROP
  4989. //
  4990. lpList = (LPWSTR)((LPBYTE)lpdfs + lpdfs->pFiles);
  4991. i = lstrlenW(lpList);
  4992. if (!i)
  4993. goto Exit;
  4994. cb--;
  4995. if (cb < i)
  4996. i = cb;
  4997. lstrcpynW((LPWSTR)lpFile, lpList, i + 1);
  4998. } else {
  4999. LPSTR lpList;
  5000. //
  5001. // This is Win31-style HDROP or an ANSI NT Style HDROP
  5002. //
  5003. lpList = (LPSTR)((LPBYTE)lpdfs + lpdfs->pFiles);
  5004. i = lstrlenA(lpList);
  5005. if (!i) {
  5006. goto Exit;
  5007. }
  5008. cb--;
  5009. if (cb < i) {
  5010. i = cb;
  5011. }
  5012. MultiByteToWideChar(CP_ACP, 0, lpList, -1, (LPWSTR)lpFile, cb);
  5013. }
  5014. } except( EXCEPTION_EXECUTE_HANDLER ) {
  5015. RIPMSG1(RIP_WARNING, "CONSRV: WM_DROPFILES raised exception 0x%x", GetExceptionCode());
  5016. i = 0;
  5017. }
  5018. Exit:
  5019. GlobalUnlock(hDrop);
  5020. GlobalFree(hDrop);
  5021. }
  5022. return i;
  5023. }
  5024. /*++
  5025. Routine Description:
  5026. This routine is called when ConsoleWindowProc receives a WM_DROPFILES
  5027. message. It initially calls ConsoleDragQueryFile() to calculate the number
  5028. of files dropped and then ConsoleDragQueryFile() is called
  5029. to retrieve the filename. DoStringPaste() pastes the filename to the console
  5030. window
  5031. Arguments:
  5032. wParam - Identifies the structure containing the filenames of the
  5033. dropped files.
  5034. Console - Pointer to CONSOLE_INFORMATION structure
  5035. Return Value:
  5036. None
  5037. --*/
  5038. VOID
  5039. DoDrop(
  5040. WPARAM wParam,
  5041. PCONSOLE_INFORMATION Console)
  5042. {
  5043. WCHAR szPath[MAX_PATH];
  5044. BOOL fAddQuotes;
  5045. if (ConsoleDragQueryFile((HANDLE)wParam, szPath, ARRAY_SIZE(szPath))) {
  5046. fAddQuotes = (wcschr(szPath, L' ') != NULL);
  5047. if (fAddQuotes) {
  5048. DoStringPaste(Console, L"\"", 1);
  5049. }
  5050. DoStringPaste(Console, szPath, wcslen(szPath));
  5051. if (fAddQuotes) {
  5052. DoStringPaste(Console, L"\"", 1);
  5053. }
  5054. }
  5055. }
  5056. BOOL
  5057. CreateDbcsScreenBuffer(
  5058. IN PCONSOLE_INFORMATION Console,
  5059. IN COORD dwScreenBufferSize,
  5060. OUT PDBCS_SCREEN_BUFFER DbcsScreenBuffer)
  5061. {
  5062. if (CONSOLE_IS_DBCS_OUTPUTCP(Console)) {
  5063. DbcsScreenBuffer->TransBufferCharacter =
  5064. ConsoleHeapAlloc(SCREEN_DBCS_TAG,
  5065. (dwScreenBufferSize.X * dwScreenBufferSize.Y * sizeof(WCHAR)) + sizeof(WCHAR));
  5066. if (DbcsScreenBuffer->TransBufferCharacter == NULL) {
  5067. return FALSE;
  5068. }
  5069. DbcsScreenBuffer->TransBufferAttribute =
  5070. ConsoleHeapAlloc(SCREEN_DBCS_TAG,
  5071. (dwScreenBufferSize.X * dwScreenBufferSize.Y * sizeof(BYTE)) + sizeof(BYTE));
  5072. if (DbcsScreenBuffer->TransBufferAttribute == NULL) {
  5073. ConsoleHeapFree(DbcsScreenBuffer->TransBufferCharacter);
  5074. return FALSE;
  5075. }
  5076. DbcsScreenBuffer->TransWriteConsole =
  5077. ConsoleHeapAlloc(SCREEN_DBCS_TAG,
  5078. (dwScreenBufferSize.X * dwScreenBufferSize.Y * sizeof(WCHAR)) + sizeof(WCHAR));
  5079. if (DbcsScreenBuffer->TransWriteConsole == NULL) {
  5080. ConsoleHeapFree(DbcsScreenBuffer->TransBufferAttribute);
  5081. ConsoleHeapFree(DbcsScreenBuffer->TransBufferCharacter);
  5082. return FALSE;
  5083. }
  5084. DbcsScreenBuffer->KAttrRows =
  5085. ConsoleHeapAlloc(SCREEN_DBCS_TAG,
  5086. dwScreenBufferSize.X * dwScreenBufferSize.Y * sizeof(BYTE));
  5087. if (DbcsScreenBuffer->KAttrRows == NULL) {
  5088. ConsoleHeapFree(DbcsScreenBuffer->TransWriteConsole);
  5089. ConsoleHeapFree(DbcsScreenBuffer->TransBufferAttribute);
  5090. ConsoleHeapFree(DbcsScreenBuffer->TransBufferCharacter);
  5091. return FALSE;
  5092. }
  5093. } else {
  5094. DbcsScreenBuffer->TransBufferCharacter = NULL;
  5095. DbcsScreenBuffer->TransBufferAttribute = NULL;
  5096. DbcsScreenBuffer->TransWriteConsole = NULL;
  5097. DbcsScreenBuffer->KAttrRows = NULL;
  5098. }
  5099. return TRUE;
  5100. }
  5101. BOOL
  5102. DeleteDbcsScreenBuffer(
  5103. IN PDBCS_SCREEN_BUFFER DbcsScreenBuffer
  5104. )
  5105. {
  5106. if (DbcsScreenBuffer->KAttrRows) {
  5107. ConsoleHeapFree(DbcsScreenBuffer->TransBufferCharacter);
  5108. ConsoleHeapFree(DbcsScreenBuffer->TransBufferAttribute);
  5109. ConsoleHeapFree(DbcsScreenBuffer->TransWriteConsole);
  5110. ConsoleHeapFree(DbcsScreenBuffer->KAttrRows);
  5111. }
  5112. return TRUE;
  5113. }
  5114. BOOL
  5115. ReCreateDbcsScreenBufferWorker(
  5116. IN PCONSOLE_INFORMATION Console,
  5117. IN PSCREEN_INFORMATION ScreenInfo
  5118. )
  5119. {
  5120. SHORT i;
  5121. PBYTE KAttrRowPtr;
  5122. COORD dwScreenBufferSize;
  5123. DBCS_SCREEN_BUFFER NewDbcsScreenBuffer;
  5124. ASSERT(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER);
  5125. if (!(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)) {
  5126. return FALSE;
  5127. }
  5128. dwScreenBufferSize = ScreenInfo->ScreenBufferSize;
  5129. if (!CreateDbcsScreenBuffer(Console,
  5130. dwScreenBufferSize,
  5131. &NewDbcsScreenBuffer)) {
  5132. return FALSE;
  5133. }
  5134. KAttrRowPtr = NewDbcsScreenBuffer.KAttrRows;
  5135. for (i = 0; i < dwScreenBufferSize.Y; i++) {
  5136. ScreenInfo->BufferInfo.TextInfo.Rows[i].CharRow.KAttrs = KAttrRowPtr;
  5137. if (KAttrRowPtr) {
  5138. RtlZeroMemory(KAttrRowPtr, dwScreenBufferSize.X);
  5139. KAttrRowPtr += dwScreenBufferSize.X;
  5140. }
  5141. }
  5142. ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer = NewDbcsScreenBuffer;
  5143. return TRUE;
  5144. }
  5145. typedef struct _DBCS_SCREEN_BUFFER_TRACKER {
  5146. DBCS_SCREEN_BUFFER data;
  5147. #if DBG
  5148. PSCREEN_INFORMATION pScreenInfo;
  5149. #endif
  5150. } DBCS_SCREEN_BUFFER_TRACKER, *PDBCS_SCREEN_BUFFER_TRACKER;
  5151. BOOL
  5152. ReCreateDbcsScreenBuffer(
  5153. IN PCONSOLE_INFORMATION pConsole,
  5154. IN UINT OldCodePage)
  5155. {
  5156. BOOL fResult = FALSE;
  5157. PDBCS_SCREEN_BUFFER_TRACKER pDbcsScreenBuffer;
  5158. PSCREEN_INFORMATION pScreenInfo;
  5159. UINT nScreen;
  5160. UINT i;
  5161. #if DBG
  5162. UINT nScreenSave;
  5163. #endif
  5164. //
  5165. // If DbcsBuffers don't need to be modified, just bail out.
  5166. //
  5167. if (!IsAvailableFarEastCodePage(OldCodePage) == !CONSOLE_IS_DBCS_OUTPUTCP(pConsole) )
  5168. return TRUE;
  5169. //
  5170. // Count the number of screens allocated.
  5171. //
  5172. for (nScreen = 0, pScreenInfo = pConsole->ScreenBuffers; pScreenInfo; pScreenInfo = pScreenInfo->Next) {
  5173. //
  5174. // Ignore graphic mode buffer.
  5175. //
  5176. if (pScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  5177. ++nScreen;
  5178. }
  5179. }
  5180. #if DBG
  5181. nScreenSave = nScreen;
  5182. #endif
  5183. //
  5184. // Allocate the temporary buffer to store the old values
  5185. //
  5186. pDbcsScreenBuffer = ConsoleHeapAlloc(TMP_DBCS_TAG, sizeof(*pDbcsScreenBuffer) * nScreen);
  5187. if (pDbcsScreenBuffer == NULL) {
  5188. RIPMSG0(RIP_WARNING, "ReCreateDbcsScreenBuffer: not enough memory.");
  5189. return FALSE;
  5190. }
  5191. //
  5192. // Try to allocate or de-allocate the necessary DBCS buffers
  5193. //
  5194. for (nScreen = 0, pScreenInfo = pConsole->ScreenBuffers; pScreenInfo; pScreenInfo = pScreenInfo->Next) {
  5195. ASSERT(nScreen < nScreenSave); // make sure ScreenBuffers are not changed
  5196. //
  5197. // We only handle the text mode screen buffer.
  5198. //
  5199. if (pScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  5200. //
  5201. // Save the previous value just in case something goes bad.
  5202. //
  5203. #if DBG
  5204. pDbcsScreenBuffer[nScreen].pScreenInfo = pScreenInfo;
  5205. #endif
  5206. pDbcsScreenBuffer[nScreen++].data = pScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer;
  5207. if (!ReCreateDbcsScreenBufferWorker(pConsole, pScreenInfo)) {
  5208. //
  5209. // If we fail to ReCreate the DbcsScreenBuffer,
  5210. // free all allocation to this point, and restore the orginal.
  5211. //
  5212. RIPMSG0(RIP_WARNING, "ReCreateDbcsScreenBuffer: failed to recreate dbcs screen buffer.");
  5213. for (i = 0, pScreenInfo = pConsole->ScreenBuffers; i < nScreen; pScreenInfo = pScreenInfo->Next) {
  5214. ASSERT(pScreenInfo);
  5215. if (pScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  5216. ASSERT(pDbcsScreenBuffer[i].pScreenInfo == pScreenInfo);
  5217. if (i < nScreen - 1) {
  5218. ASSERT(pScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.KAttrRows != pDbcsScreenBuffer[i].data.KAttrRows);
  5219. DeleteDbcsScreenBuffer(&pScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer);
  5220. }
  5221. pScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer = pDbcsScreenBuffer[i++].data;
  5222. }
  5223. }
  5224. goto exit;
  5225. }
  5226. }
  5227. }
  5228. //
  5229. // All allocation succeeded. Now we can delete the old allocation.
  5230. //
  5231. for (i = 0; i < nScreen; ++i) {
  5232. DeleteDbcsScreenBuffer(&pDbcsScreenBuffer[i].data);
  5233. }
  5234. fResult = TRUE;
  5235. exit:
  5236. ConsoleHeapFree(pDbcsScreenBuffer);
  5237. return fResult;
  5238. }
  5239. // Checks if the primary language of this keyborad layout is BiDi or not.
  5240. BOOL
  5241. IsNotBiDILayout(
  5242. HKL hkl)
  5243. {
  5244. BOOL bRet = TRUE;
  5245. LANGID LangID = PRIMARYLANGID(HandleToUlong(hkl));
  5246. if (LangID == LANG_ARABIC || LangID == LANG_HEBREW) {
  5247. bRet = FALSE;
  5248. }
  5249. return bRet;
  5250. }
  5251. VOID
  5252. GetNonBiDiKeyboardLayout(
  5253. HKL *phklActive)
  5254. {
  5255. HKL hkl = *phklActive;
  5256. HKL hklActive = *phklActive;
  5257. if (IsNotBiDILayout(hkl)) {
  5258. return;
  5259. }
  5260. // Start with the default one.
  5261. ActivateKeyboardLayout(hkl, 0);
  5262. // We know that the default is not good, activate the next.
  5263. ActivateKeyboardLayout((HKL)HKL_NEXT, 0);
  5264. // Loop until you find a none BiDi one or endof list.
  5265. while (hkl = GetKeyboardLayout(0)) {
  5266. if ((hkl == hklActive) || IsNotBiDILayout(hkl)) {
  5267. *phklActive = hkl;
  5268. break;
  5269. }
  5270. ActivateKeyboardLayout((HKL)HKL_NEXT, 0);
  5271. }
  5272. }
  5273. #if defined(FE_SB)
  5274. #define WWSB_NOFE
  5275. #include "_output.h"
  5276. #undef WWSB_NOFE
  5277. #define WWSB_FE
  5278. #include "_output.h"
  5279. #undef WWSB_FE
  5280. #endif // FE_SB