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.

1368 lines
42 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. clipbrd.c
  5. Abstract:
  6. This file implements the clipboard functions.
  7. Author:
  8. Therese Stowell (thereses) Jan-24-1992
  9. --*/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. /*++
  13. Here's the pseudocode for various clipboard operations
  14. init keyboard select (mark)
  15. ---------------------------
  16. if (already selecting)
  17. cancel selection
  18. init flags
  19. hidecursor
  20. createcursor
  21. init select rect
  22. set win text
  23. convert to mouse select (select)
  24. --------------------------------
  25. set flags
  26. destroy cursor
  27. showcursor
  28. invert old select rect
  29. init select rect
  30. invert select rect
  31. set win text
  32. re-init mouse select
  33. --------------------
  34. invert old select rect
  35. init select rect
  36. invert select rect
  37. cancel mouse select
  38. -------------------
  39. set flags
  40. reset win text
  41. invert old select rect
  42. cancel key select
  43. -----------------
  44. set flags
  45. reset win text
  46. destroy cursor
  47. showcursor
  48. invert old select rect
  49. --*/
  50. BOOL
  51. MyInvert(
  52. IN PCONSOLE_INFORMATION Console,
  53. IN PSMALL_RECT SmallRect
  54. )
  55. /*++
  56. invert a rect
  57. --*/
  58. {
  59. RECT Rect;
  60. PSCREEN_INFORMATION ScreenInfo;
  61. #ifdef FE_SB
  62. SMALL_RECT SmallRect2;
  63. COORD TargetPoint;
  64. SHORT StringLength;
  65. #endif // FE_SB
  66. ScreenInfo = Console->CurrentScreenBuffer;
  67. #ifdef FE_SB
  68. if (CONSOLE_IS_DBCS_OUTPUTCP(Console) &&
  69. ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  70. for (SmallRect2.Top=SmallRect->Top; SmallRect2.Top <= SmallRect->Bottom;SmallRect2.Top++) {
  71. SmallRect2.Bottom = SmallRect2.Top;
  72. SmallRect2.Left = SmallRect->Left;
  73. SmallRect2.Right = SmallRect->Right;
  74. TargetPoint.X = SmallRect2.Left;
  75. TargetPoint.Y = SmallRect2.Top;
  76. StringLength = SmallRect2.Right - SmallRect2.Left + 1;
  77. BisectClipbrd(StringLength,TargetPoint,ScreenInfo,&SmallRect2);
  78. if (SmallRect2.Left <= SmallRect2.Right) {
  79. Rect.left = SmallRect2.Left-ScreenInfo->Window.Left;
  80. Rect.top = SmallRect2.Top-ScreenInfo->Window.Top;
  81. Rect.right = SmallRect2.Right+1-ScreenInfo->Window.Left;
  82. Rect.bottom = SmallRect2.Bottom+1-ScreenInfo->Window.Top;
  83. Rect.left *= SCR_FONTSIZE(ScreenInfo).X;
  84. Rect.top *= SCR_FONTSIZE(ScreenInfo).Y;
  85. Rect.right *= SCR_FONTSIZE(ScreenInfo).X;
  86. Rect.bottom *= SCR_FONTSIZE(ScreenInfo).Y;
  87. PatBlt(Console->hDC,
  88. Rect.left,
  89. Rect.top,
  90. Rect.right - Rect.left,
  91. Rect.bottom - Rect.top,
  92. DSTINVERT
  93. );
  94. }
  95. }
  96. } else
  97. #endif // FE_SB
  98. {
  99. Rect.left = SmallRect->Left-ScreenInfo->Window.Left;
  100. Rect.top = SmallRect->Top-ScreenInfo->Window.Top;
  101. Rect.right = SmallRect->Right+1-ScreenInfo->Window.Left;
  102. Rect.bottom = SmallRect->Bottom+1-ScreenInfo->Window.Top;
  103. #ifdef FE_SB
  104. if (!CONSOLE_IS_DBCS_OUTPUTCP(Console) &&
  105. ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)
  106. #else
  107. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)
  108. #endif
  109. {
  110. Rect.left *= SCR_FONTSIZE(ScreenInfo).X;
  111. Rect.top *= SCR_FONTSIZE(ScreenInfo).Y;
  112. Rect.right *= SCR_FONTSIZE(ScreenInfo).X;
  113. Rect.bottom *= SCR_FONTSIZE(ScreenInfo).Y;
  114. }
  115. PatBlt(Console->hDC,
  116. Rect.left,
  117. Rect.top,
  118. Rect.right - Rect.left,
  119. Rect.bottom - Rect.top,
  120. DSTINVERT
  121. );
  122. }
  123. return(TRUE);
  124. }
  125. VOID
  126. InvertSelection(
  127. IN PCONSOLE_INFORMATION Console,
  128. BOOL Inverting
  129. )
  130. {
  131. BOOL Inverted;
  132. if (Console->Flags & CONSOLE_SELECTING &&
  133. Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY) {
  134. Inverted = (Console->SelectionFlags & CONSOLE_SELECTION_INVERTED) ? TRUE : FALSE;
  135. if (Inverting == Inverted) {
  136. return;
  137. }
  138. if (Inverting) {
  139. Console->SelectionFlags |= CONSOLE_SELECTION_INVERTED;
  140. } else {
  141. Console->SelectionFlags &= ~CONSOLE_SELECTION_INVERTED;
  142. }
  143. MyInvert(Console,&Console->SelectionRect);
  144. }
  145. }
  146. VOID
  147. InitializeMouseSelection(
  148. IN PCONSOLE_INFORMATION Console,
  149. IN COORD CursorPosition
  150. )
  151. /*++
  152. This routine initializes a selection region.
  153. --*/
  154. {
  155. Console->SelectionAnchor = CursorPosition;
  156. Console->SelectionRect.Left = Console->SelectionRect.Right = CursorPosition.X;
  157. Console->SelectionRect.Top = Console->SelectionRect.Bottom = CursorPosition.Y;
  158. //
  159. // Fire off an event to let accessibility apps know the selection has changed.
  160. //
  161. ConsoleNotifyWinEvent(Console,
  162. EVENT_CONSOLE_CARET,
  163. CONSOLE_CARET_SELECTION,
  164. PACKCOORD(CursorPosition));
  165. }
  166. VOID
  167. ExtendSelection(
  168. IN PCONSOLE_INFORMATION Console,
  169. IN COORD CursorPosition
  170. )
  171. /*++
  172. This routine extends a selection region.
  173. --*/
  174. {
  175. SMALL_RECT OldSelectionRect;
  176. HRGN OldRegion,NewRegion,CombineRegion;
  177. COORD FontSize;
  178. PSCREEN_INFORMATION ScreenInfo = Console->CurrentScreenBuffer;
  179. if (CursorPosition.X < 0) {
  180. CursorPosition.X = 0;
  181. } else if (CursorPosition.X >= ScreenInfo->ScreenBufferSize.X) {
  182. CursorPosition.X = ScreenInfo->ScreenBufferSize.X-1;
  183. }
  184. if (CursorPosition.Y < 0) {
  185. CursorPosition.Y = 0;
  186. } else if (CursorPosition.Y >= ScreenInfo->ScreenBufferSize.Y) {
  187. CursorPosition.Y = ScreenInfo->ScreenBufferSize.Y-1;
  188. }
  189. if (!(Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY)) {
  190. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  191. // scroll if necessary to make cursor visible.
  192. MakeCursorVisible(ScreenInfo, CursorPosition);
  193. ASSERT(!(Console->SelectionFlags & CONSOLE_MOUSE_SELECTION));
  194. //
  195. // if the selection rect hasn't actually been started,
  196. // the selection cursor is still blinking. turn it off.
  197. //
  198. ConsoleHideCursor(ScreenInfo);
  199. }
  200. Console->SelectionFlags |= CONSOLE_SELECTION_NOT_EMPTY;
  201. Console->SelectionRect.Left =Console->SelectionRect.Right = Console->SelectionAnchor.X;
  202. Console->SelectionRect.Top = Console->SelectionRect.Bottom = Console->SelectionAnchor.Y;
  203. // invert the cursor corner
  204. #ifdef FE_SB
  205. if (!CONSOLE_IS_DBCS_OUTPUTCP(Console) &&
  206. ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)
  207. #else
  208. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)
  209. #endif
  210. {
  211. MyInvert(Console,&Console->SelectionRect);
  212. }
  213. } else {
  214. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  215. // scroll if necessary to make cursor visible.
  216. MakeCursorVisible(ScreenInfo,CursorPosition);
  217. }
  218. #ifdef FE_SB
  219. //
  220. // uninvert old selection
  221. //
  222. if (CONSOLE_IS_DBCS_OUTPUTCP(Console)) {
  223. MyInvert(Console, &Console->SelectionRect);
  224. }
  225. #endif // FE_SB
  226. }
  227. //
  228. // update selection rect
  229. //
  230. OldSelectionRect = Console->SelectionRect;
  231. if (CursorPosition.X <= Console->SelectionAnchor.X) {
  232. Console->SelectionRect.Left = CursorPosition.X;
  233. Console->SelectionRect.Right = Console->SelectionAnchor.X;
  234. } else if (CursorPosition.X > Console->SelectionAnchor.X) {
  235. Console->SelectionRect.Right = CursorPosition.X;
  236. Console->SelectionRect.Left = Console->SelectionAnchor.X;
  237. }
  238. if (CursorPosition.Y <= Console->SelectionAnchor.Y) {
  239. Console->SelectionRect.Top = CursorPosition.Y;
  240. Console->SelectionRect.Bottom = Console->SelectionAnchor.Y;
  241. } else if (CursorPosition.Y > Console->SelectionAnchor.Y) {
  242. Console->SelectionRect.Bottom = CursorPosition.Y;
  243. Console->SelectionRect.Top = Console->SelectionAnchor.Y;
  244. }
  245. //
  246. // change inverted selection
  247. //
  248. #ifdef FE_SB
  249. if (CONSOLE_IS_DBCS_OUTPUTCP(Console)) {
  250. MyInvert(Console, &Console->SelectionRect);
  251. } else
  252. #endif
  253. {
  254. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  255. FontSize = CON_FONTSIZE(Console);
  256. } else {
  257. FontSize.X = 1;
  258. FontSize.Y = 1;
  259. }
  260. CombineRegion = CreateRectRgn(0,0,0,0);
  261. OldRegion = CreateRectRgn((OldSelectionRect.Left-ScreenInfo->Window.Left)*FontSize.X,
  262. (OldSelectionRect.Top-ScreenInfo->Window.Top)*FontSize.Y,
  263. (OldSelectionRect.Right-ScreenInfo->Window.Left+1)*FontSize.X,
  264. (OldSelectionRect.Bottom-ScreenInfo->Window.Top+1)*FontSize.Y
  265. );
  266. NewRegion = CreateRectRgn((Console->SelectionRect.Left-ScreenInfo->Window.Left)*FontSize.X,
  267. (Console->SelectionRect.Top-ScreenInfo->Window.Top)*FontSize.Y,
  268. (Console->SelectionRect.Right-ScreenInfo->Window.Left+1)*FontSize.X,
  269. (Console->SelectionRect.Bottom-ScreenInfo->Window.Top+1)*FontSize.Y
  270. );
  271. CombineRgn(CombineRegion,OldRegion,NewRegion,RGN_XOR);
  272. InvertRgn(Console->hDC,CombineRegion);
  273. DeleteObject(OldRegion);
  274. DeleteObject(NewRegion);
  275. DeleteObject(CombineRegion);
  276. }
  277. //
  278. // Fire off an event to let accessibility apps know the selection has changed.
  279. //
  280. ConsoleNotifyWinEvent(Console,
  281. EVENT_CONSOLE_CARET,
  282. CONSOLE_CARET_SELECTION,
  283. PACKCOORD(CursorPosition));
  284. }
  285. VOID
  286. CancelMouseSelection(
  287. IN PCONSOLE_INFORMATION Console
  288. )
  289. /*++
  290. This routine terminates a mouse selection.
  291. --*/
  292. {
  293. PSCREEN_INFORMATION ScreenInfo = Console->CurrentScreenBuffer;
  294. //
  295. // turn off selection flag
  296. //
  297. Console->Flags &= ~CONSOLE_SELECTING;
  298. SetWinText(Console,msgSelectMode,FALSE);
  299. //
  300. // invert old select rect. if we're selecting by mouse, we
  301. // always have a selection rect.
  302. //
  303. MyInvert(Console,&Console->SelectionRect);
  304. ReleaseCapture();
  305. //
  306. // Mark the cursor position as changed so we'll fire off a win event.
  307. //
  308. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  309. ScreenInfo->BufferInfo.TextInfo.CursorMoved = TRUE;
  310. }
  311. }
  312. VOID
  313. CancelKeySelection(
  314. IN PCONSOLE_INFORMATION Console,
  315. IN BOOL JustCursor
  316. )
  317. /*++
  318. This routine terminates a key selection.
  319. --*/
  320. {
  321. PSCREEN_INFORMATION ScreenInfo;
  322. if (!JustCursor) {
  323. //
  324. // turn off selection flag
  325. //
  326. Console->Flags &= ~CONSOLE_SELECTING;
  327. SetWinText(Console,msgMarkMode,FALSE);
  328. }
  329. //
  330. // invert old select rect, if we have one.
  331. //
  332. ScreenInfo = Console->CurrentScreenBuffer;
  333. if (Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY) {
  334. MyInvert(Console,&Console->SelectionRect);
  335. } else {
  336. ConsoleHideCursor(ScreenInfo);
  337. }
  338. // restore text cursor
  339. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  340. SetCursorInformation(ScreenInfo,
  341. Console->TextCursorSize,
  342. Console->TextCursorVisible
  343. );
  344. SetCursorPosition(ScreenInfo,
  345. Console->TextCursorPosition,
  346. TRUE
  347. );
  348. }
  349. ConsoleShowCursor(ScreenInfo);
  350. }
  351. VOID
  352. ConvertToMouseSelect(
  353. IN PCONSOLE_INFORMATION Console,
  354. IN COORD MousePosition
  355. )
  356. /*++
  357. This routine converts to a mouse selection from a key selection.
  358. --*/
  359. {
  360. Console->SelectionFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
  361. //
  362. // undo key selection
  363. //
  364. CancelKeySelection(Console,TRUE);
  365. Console->SelectionFlags |= CONSOLE_SELECTION_NOT_EMPTY;
  366. //
  367. // invert new selection
  368. //
  369. InitializeMouseSelection(Console, MousePosition);
  370. MyInvert(Console,&Console->SelectionRect);
  371. //
  372. // update title bar
  373. //
  374. SetWinText(Console,msgMarkMode,FALSE);
  375. SetWinText(Console,msgSelectMode,TRUE);
  376. //
  377. // capture mouse movement
  378. //
  379. SetCapture(Console->hWnd);
  380. }
  381. VOID
  382. ClearSelection(
  383. IN PCONSOLE_INFORMATION Console
  384. )
  385. {
  386. if (Console->Flags & CONSOLE_SELECTING) {
  387. if (Console->SelectionFlags & CONSOLE_MOUSE_SELECTION) {
  388. CancelMouseSelection(Console);
  389. } else {
  390. CancelKeySelection(Console,FALSE);
  391. }
  392. UnblockWriteConsole(Console, CONSOLE_SELECTING);
  393. }
  394. }
  395. VOID
  396. StoreSelection(
  397. IN PCONSOLE_INFORMATION Console
  398. )
  399. /*++
  400. StoreSelection - Store selection (if present) into the Clipboard
  401. --*/
  402. {
  403. PCHAR_INFO Selection,CurCharInfo;
  404. COORD SourcePoint;
  405. COORD TargetSize;
  406. SMALL_RECT TargetRect;
  407. PWCHAR CurChar,CharBuf;
  408. HANDLE ClipboardDataHandle;
  409. SHORT i,j;
  410. BOOL Success;
  411. PSCREEN_INFORMATION ScreenInfo;
  412. BOOL bFalseUnicode;
  413. BOOL bMungeData;
  414. #if defined(FE_SB)
  415. COORD TargetSize2;
  416. PWCHAR TmpClipboardData;
  417. SMALL_RECT SmallRect2;
  418. COORD TargetPoint;
  419. SHORT StringLength;
  420. WCHAR wchCARRIAGERETURN;
  421. WCHAR wchLINEFEED;
  422. int iExtra = 0;
  423. int iFeReserve = 1;
  424. #endif
  425. //
  426. // See if there is a selection to get
  427. //
  428. if (!(Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY)) {
  429. return;
  430. }
  431. //
  432. // read selection rectangle. clip it first.
  433. //
  434. ScreenInfo = Console->CurrentScreenBuffer;
  435. if (Console->SelectionRect.Left < 0) {
  436. Console->SelectionRect.Left = 0;
  437. }
  438. if (Console->SelectionRect.Top < 0) {
  439. Console->SelectionRect.Top = 0;
  440. }
  441. if (Console->SelectionRect.Right >= ScreenInfo->ScreenBufferSize.X) {
  442. Console->SelectionRect.Right = (SHORT)(ScreenInfo->ScreenBufferSize.X-1);
  443. }
  444. if (Console->SelectionRect.Bottom >= ScreenInfo->ScreenBufferSize.Y) {
  445. Console->SelectionRect.Bottom = (SHORT)(ScreenInfo->ScreenBufferSize.Y-1);
  446. }
  447. TargetSize.X = WINDOW_SIZE_X(&Console->SelectionRect);
  448. TargetSize.Y = WINDOW_SIZE_Y(&Console->SelectionRect);
  449. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  450. #if defined(FE_SB)
  451. if (CONSOLE_IS_DBCS_CP(Console)) {
  452. iExtra = 4 ; // 4 is for DBCS lead or tail extra
  453. iFeReserve = 2 ; // FE does this for safety
  454. TmpClipboardData = ConsoleHeapAlloc(TMP_DBCS_TAG, (sizeof(WCHAR) * TargetSize.Y * (TargetSize.X + iExtra) + sizeof(WCHAR)));
  455. if (TmpClipboardData == NULL) {
  456. return;
  457. }
  458. } else {
  459. TmpClipboardData = NULL;
  460. }
  461. Selection = ConsoleHeapAlloc(TMP_TAG, sizeof(CHAR_INFO) * (TargetSize.X + iExtra) * TargetSize.Y * iFeReserve);
  462. if (Selection == NULL)
  463. {
  464. if (TmpClipboardData)
  465. ConsoleHeapFree(TmpClipboardData);
  466. return;
  467. }
  468. #else
  469. Selection = ConsoleHeapAlloc(TMP_TAG, sizeof(CHAR_INFO) * TargetSize.X * TargetSize.Y);
  470. if (Selection == NULL)
  471. return;
  472. #endif
  473. #if defined(FE_SB)
  474. if (!CONSOLE_IS_DBCS_CP(Console)) {
  475. #endif
  476. #ifdef i386
  477. if ((Console->FullScreenFlags & CONSOLE_FULLSCREEN) &&
  478. (Console->Flags & CONSOLE_VDM_REGISTERED)) {
  479. ReadRegionFromScreenHW(ScreenInfo,
  480. &Console->SelectionRect,
  481. Selection);
  482. CurCharInfo = Selection;
  483. for (i=0; i<TargetSize.Y; i++) {
  484. for (j=0; j<TargetSize.X; j++,CurCharInfo++) {
  485. CurCharInfo->Char.UnicodeChar = SB_CharToWcharGlyph(Console->OutputCP, CurCharInfo->Char.AsciiChar);
  486. }
  487. }
  488. } else {
  489. #endif
  490. SourcePoint.X = Console->SelectionRect.Left;
  491. SourcePoint.Y = Console->SelectionRect.Top;
  492. TargetRect.Left = TargetRect.Top = 0;
  493. TargetRect.Right = (SHORT)(TargetSize.X-1);
  494. TargetRect.Bottom = (SHORT)(TargetSize.Y-1);
  495. ReadRectFromScreenBuffer(ScreenInfo,
  496. SourcePoint,
  497. Selection,
  498. TargetSize,
  499. &TargetRect);
  500. #ifdef i386
  501. }
  502. #endif
  503. // extra 2 per line is for CRLF, extra 1 is for null
  504. ClipboardDataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
  505. (TargetSize.Y * (TargetSize.X + 2) + 1) * sizeof(WCHAR));
  506. if (ClipboardDataHandle == NULL) {
  507. ConsoleHeapFree(Selection);
  508. return;
  509. }
  510. #if defined(FE_SB)
  511. }
  512. #endif
  513. //
  514. // convert to clipboard form
  515. //
  516. #if defined(FE_SB)
  517. if (CONSOLE_IS_DBCS_CP(Console)) {
  518. if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  519. !(Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
  520. /*
  521. * False Unicode is obtained, so we will have to convert it to
  522. * Real Unicode, in which case we can't put CR or LF in now, since
  523. * they will be converted into 0x266A and 0x25d9. Temporarily
  524. * mark the CR/LF positions with 0x0000 instead.
  525. */
  526. wchCARRIAGERETURN = 0x0000;
  527. wchLINEFEED = 0x0000;
  528. } else {
  529. wchCARRIAGERETURN = UNICODE_CARRIAGERETURN;
  530. wchLINEFEED = UNICODE_LINEFEED;
  531. }
  532. CurChar = TmpClipboardData;
  533. bMungeData = (GetKeyState(VK_SHIFT) & KEY_PRESSED) == 0;
  534. for (i=0;i<TargetSize.Y;i++) {
  535. PWCHAR pwchLineStart = CurChar;
  536. SourcePoint.X = Console->SelectionRect.Left;
  537. SourcePoint.Y = Console->SelectionRect.Top + i;
  538. TargetSize2.X = TargetSize.X;
  539. TargetSize2.Y = 1;
  540. SmallRect2.Left = SourcePoint.X;
  541. SmallRect2.Top = SourcePoint.Y;
  542. SmallRect2.Right = SourcePoint.X + TargetSize2.X - 1;
  543. SmallRect2.Bottom = SourcePoint.Y;
  544. TargetPoint = SourcePoint;
  545. StringLength = TargetSize2.X;
  546. BisectClipbrd(StringLength,TargetPoint,ScreenInfo,&SmallRect2);
  547. SourcePoint.X = SmallRect2.Left;
  548. SourcePoint.Y = SmallRect2.Top;
  549. TargetSize2.X = SmallRect2.Right - SmallRect2.Left + 1;
  550. TargetSize2.Y = 1;
  551. TargetRect.Left = TargetRect.Top = TargetRect.Bottom = 0;
  552. TargetRect.Right = (SHORT)(TargetSize2.X-1);
  553. ReadRectFromScreenBuffer(ScreenInfo,
  554. SourcePoint,
  555. Selection,
  556. TargetSize2,
  557. &TargetRect);
  558. CurCharInfo = Selection;
  559. for (j=0;j<TargetSize2.X;j++,CurCharInfo++) {
  560. if (!(CurCharInfo->Attributes & COMMON_LVB_TRAILING_BYTE))
  561. *CurChar++ = CurCharInfo->Char.UnicodeChar;
  562. }
  563. // trim trailing spaces
  564. if (bMungeData) {
  565. CurChar--;
  566. while ((CurChar >= pwchLineStart) && (*CurChar == UNICODE_SPACE))
  567. CurChar--;
  568. CurChar++;
  569. *CurChar++ = wchCARRIAGERETURN;
  570. *CurChar++ = wchLINEFEED;
  571. }
  572. }
  573. }
  574. else {
  575. #endif
  576. CurCharInfo = Selection;
  577. CurChar = CharBuf = GlobalLock(ClipboardDataHandle);
  578. bFalseUnicode = ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  579. !(Console->FullScreenFlags & CONSOLE_FULLSCREEN));
  580. bMungeData = (GetKeyState(VK_SHIFT) & KEY_PRESSED) == 0;
  581. for (i=0;i<TargetSize.Y;i++) {
  582. PWCHAR pwchLineStart = CurChar;
  583. for (j=0;j<TargetSize.X;j++,CurCharInfo++,CurChar++) {
  584. *CurChar = CurCharInfo->Char.UnicodeChar;
  585. if (*CurChar == 0) {
  586. *CurChar = UNICODE_SPACE;
  587. }
  588. }
  589. // trim trailing spaces
  590. if (bMungeData) {
  591. CurChar--;
  592. while ((CurChar >= pwchLineStart) && (*CurChar == UNICODE_SPACE))
  593. CurChar--;
  594. CurChar++;
  595. }
  596. if (bFalseUnicode) {
  597. FalseUnicodeToRealUnicode(pwchLineStart,
  598. (ULONG)(CurChar - pwchLineStart), Console->OutputCP);
  599. }
  600. if (bMungeData) {
  601. *CurChar++ = UNICODE_CARRIAGERETURN;
  602. *CurChar++ = UNICODE_LINEFEED;
  603. }
  604. }
  605. #if defined(FE_SB)
  606. }
  607. #endif
  608. if (bMungeData) {
  609. if (TargetSize.Y)
  610. CurChar -= 2; // don't put CRLF on last line
  611. }
  612. *CurChar = '\0'; // null terminate
  613. #if defined(FE_SB)
  614. if (CONSOLE_IS_DBCS_CP(Console)) {
  615. // extra 4 is for CRLF and DBCS Reserved, extra 1 is for null
  616. ClipboardDataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
  617. (sizeof(WCHAR) * TargetSize.Y * (TargetSize.X+(4*sizeof(WCHAR)))) +
  618. (1*sizeof(WCHAR)));
  619. if (ClipboardDataHandle == NULL) {
  620. ConsoleHeapFree(Selection);
  621. ConsoleHeapFree(TmpClipboardData);
  622. return;
  623. }
  624. CharBuf = GlobalLock(ClipboardDataHandle);
  625. RtlCopyMemory(CharBuf,TmpClipboardData,ConsoleHeapSize(TmpClipboardData));
  626. CurChar = CharBuf + (CurChar - TmpClipboardData);
  627. if (wchCARRIAGERETURN == 0x0000) {
  628. /*
  629. * We have False Unicode, so we temporarily represented CRLFs with
  630. * 0x0000s to avoid undesirable conversions (above).
  631. * Convert to Real Unicode and restore real CRLFs.
  632. */
  633. PWCHAR pwch;
  634. FalseUnicodeToRealUnicode(CharBuf,
  635. (ULONG)(CurChar - CharBuf),
  636. Console->OutputCP
  637. );
  638. for (pwch = CharBuf; pwch < CurChar; pwch++) {
  639. if ((*pwch == 0x0000) && (pwch[1] == 0x0000)) {
  640. *pwch++ = UNICODE_CARRIAGERETURN;
  641. *pwch = UNICODE_LINEFEED;
  642. }
  643. }
  644. }
  645. }
  646. #endif
  647. GlobalUnlock(ClipboardDataHandle);
  648. #if defined(FE_SB)
  649. if (TmpClipboardData)
  650. ConsoleHeapFree(TmpClipboardData);
  651. #endif
  652. ConsoleHeapFree(Selection);
  653. Success = OpenClipboard(Console->hWnd);
  654. if (!Success) {
  655. GlobalFree(ClipboardDataHandle);
  656. return;
  657. }
  658. Success = EmptyClipboard();
  659. if (!Success) {
  660. GlobalFree(ClipboardDataHandle);
  661. return;
  662. }
  663. SetClipboardData(CF_UNICODETEXT,ClipboardDataHandle);
  664. CloseClipboard(); // Close clipboard
  665. } else {
  666. HBITMAP hBitmapTarget, hBitmapOld;
  667. HDC hDCMem;
  668. HPALETTE hPaletteOld;
  669. int Height;
  670. NtWaitForSingleObject(ScreenInfo->BufferInfo.GraphicsInfo.hMutex,
  671. FALSE, NULL);
  672. hDCMem = CreateCompatibleDC(Console->hDC);
  673. hBitmapTarget = CreateCompatibleBitmap(Console->hDC,
  674. TargetSize.X,
  675. TargetSize.Y);
  676. if (hBitmapTarget) {
  677. hBitmapOld = SelectObject(hDCMem, hBitmapTarget);
  678. if (ScreenInfo->hPalette) {
  679. hPaletteOld = SelectPalette(hDCMem,
  680. ScreenInfo->hPalette,
  681. FALSE);
  682. }
  683. MyInvert(Console,&Console->SelectionRect);
  684. // if (DIB is a top-down)
  685. // ySrc = abs(height) - rect.bottom - 1;
  686. // else
  687. // ySrc = rect.Bottom.
  688. //
  689. Height = ScreenInfo->BufferInfo.GraphicsInfo.lpBitMapInfo->bmiHeader.biHeight;
  690. StretchDIBits(hDCMem, 0, 0,
  691. TargetSize.X, TargetSize.Y,
  692. Console->SelectionRect.Left + ScreenInfo->Window.Left,
  693. (Height < 0) ? -Height - (Console->SelectionRect.Bottom + ScreenInfo->Window.Top) - 1
  694. : Console->SelectionRect.Bottom + ScreenInfo->Window.Top,
  695. TargetSize.X, TargetSize.Y,
  696. ScreenInfo->BufferInfo.GraphicsInfo.BitMap,
  697. ScreenInfo->BufferInfo.GraphicsInfo.lpBitMapInfo,
  698. ScreenInfo->BufferInfo.GraphicsInfo.dwUsage,
  699. SRCCOPY);
  700. MyInvert(Console,&Console->SelectionRect);
  701. if (ScreenInfo->hPalette) {
  702. SelectPalette(hDCMem, hPaletteOld, FALSE);
  703. }
  704. SelectObject(hDCMem, hBitmapOld);
  705. OpenClipboard(Console->hWnd);
  706. EmptyClipboard();
  707. SetClipboardData(CF_BITMAP,hBitmapTarget);
  708. CloseClipboard();
  709. }
  710. DeleteDC(hDCMem);
  711. NtReleaseMutant(ScreenInfo->BufferInfo.GraphicsInfo.hMutex, NULL);
  712. }
  713. }
  714. VOID
  715. DoCopy(
  716. IN PCONSOLE_INFORMATION Console
  717. )
  718. {
  719. StoreSelection(Console); // store selection in clipboard
  720. ClearSelection(Console); // clear selection in console
  721. }
  722. VOID
  723. ColorSelection(
  724. IN PCONSOLE_INFORMATION Console,
  725. IN PSMALL_RECT Rect,
  726. IN ULONG Attr
  727. )
  728. {
  729. PSCREEN_INFORMATION ScreenInfo;
  730. COORD TargetSize, Target;
  731. DWORD Written;
  732. ASSERT( Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER);
  733. ASSERT( Attr <= 0xff);
  734. //
  735. // See if there is a selection to get
  736. //
  737. if (!(Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY)) {
  738. return;
  739. }
  740. //
  741. // read selection rectangle, assumed already clipped to buffer.
  742. //
  743. ScreenInfo = Console->CurrentScreenBuffer;
  744. TargetSize.X = WINDOW_SIZE_X(&Console->SelectionRect);
  745. TargetSize.Y = WINDOW_SIZE_Y(&Console->SelectionRect);
  746. //
  747. // Now color the selection a line at a time, since this seems to be
  748. // the only way to do it?
  749. //
  750. Target.X = Rect->Left;
  751. Target.Y = Rect->Top;
  752. for ( ; (Target.Y < Rect->Top + TargetSize.Y); ++Target.Y) {
  753. Written = TargetSize.X;
  754. (VOID)FillOutput( Console->CurrentScreenBuffer,
  755. (USHORT)Attr,
  756. Target,
  757. CONSOLE_ATTRIBUTE,
  758. &Written);
  759. }
  760. }
  761. /*++
  762. Routine Description:
  763. This routine pastes given Unicode string into the console window.
  764. Arguments:
  765. Console - Pointer to CONSOLE_INFORMATION structure
  766. pwStr - Unicode string that is pasted to the console window
  767. DataSize - Size of the Unicode String in characters
  768. Return Value:
  769. None
  770. --*/
  771. VOID
  772. DoStringPaste(
  773. IN PCONSOLE_INFORMATION Console,
  774. IN PWCHAR pwStr,
  775. IN UINT DataSize
  776. )
  777. {
  778. PINPUT_RECORD StringData,CurRecord;
  779. PWCHAR CurChar;
  780. WCHAR Char;
  781. DWORD i;
  782. DWORD ChunkSize,j;
  783. ULONG EventsWritten;
  784. if(!pwStr) {
  785. return;
  786. }
  787. if (DataSize > DATA_CHUNK_SIZE) {
  788. ChunkSize = DATA_CHUNK_SIZE;
  789. } else {
  790. ChunkSize = DataSize;
  791. }
  792. //
  793. // allocate space to copy data.
  794. //
  795. StringData = ConsoleHeapAlloc(TMP_TAG, ChunkSize * sizeof(INPUT_RECORD) * 8); // 8 is maximum number of events per char
  796. if (StringData == NULL) {
  797. return;
  798. }
  799. //
  800. // transfer data to the input buffer in chunks
  801. //
  802. CurChar = pwStr; // LATER remove this
  803. for (j = 0; j < DataSize; j += ChunkSize) {
  804. if (ChunkSize > DataSize - j) {
  805. ChunkSize = DataSize - j;
  806. }
  807. CurRecord = StringData;
  808. for (i = 0, EventsWritten = 0; i < ChunkSize; i++) {
  809. // filter out LF if not first char and preceded by CR
  810. Char = *CurChar;
  811. if (Char != UNICODE_LINEFEED || (i==0 && j==0) || (*(CurChar-1)) != UNICODE_CARRIAGERETURN) {
  812. SHORT KeyState;
  813. BYTE KeyFlags;
  814. BOOL AltGr=FALSE;
  815. BOOL Shift=FALSE;
  816. if (Char == 0) {
  817. j = DataSize;
  818. break;
  819. }
  820. KeyState = VkKeyScan(Char);
  821. #if defined(FE_SB)
  822. if (CONSOLE_IS_DBCS_ENABLED() &&
  823. (KeyState == -1)) {
  824. WORD CharType;
  825. //
  826. // Determine DBCS character because these character doesn't know by VkKeyScan.
  827. // GetStringTypeW(CT_CTYPE3) & C3_ALPHA can determine all linguistic characters.
  828. // However, this is not include symbolic character for DBCS.
  829. // IsConsoleFullWidth can help for DBCS symbolic character.
  830. //
  831. GetStringTypeW(CT_CTYPE3,&Char,1,&CharType);
  832. if ((CharType & C3_ALPHA) ||
  833. IsConsoleFullWidth(Console->hDC,Console->OutputCP,Char)) {
  834. KeyState = 0;
  835. }
  836. }
  837. #endif
  838. // if VkKeyScanW fails (char is not in kbd layout), we must
  839. // emulate the key being input through the numpad
  840. if (KeyState == -1) {
  841. CHAR CharString[4];
  842. UCHAR OemChar;
  843. PCHAR pCharString;
  844. ConvertToOem(Console->OutputCP,
  845. &Char,
  846. 1,
  847. &OemChar,
  848. 1
  849. );
  850. _itoa(OemChar, CharString, 10);
  851. EventsWritten++;
  852. LoadKeyEvent(CurRecord,TRUE,0,VK_MENU,0x38,LEFT_ALT_PRESSED);
  853. CurRecord++;
  854. for (pCharString=CharString;*pCharString;pCharString++) {
  855. WORD wVirtualKey, wScancode;
  856. EventsWritten++;
  857. wVirtualKey = *pCharString-'0'+VK_NUMPAD0;
  858. wScancode = (WORD)MapVirtualKey(wVirtualKey, 0);
  859. LoadKeyEvent(CurRecord,TRUE,0,wVirtualKey,wScancode,LEFT_ALT_PRESSED);
  860. CurRecord++;
  861. EventsWritten++;
  862. LoadKeyEvent(CurRecord,FALSE,0,wVirtualKey,wScancode,LEFT_ALT_PRESSED);
  863. CurRecord++;
  864. }
  865. EventsWritten++;
  866. LoadKeyEvent(CurRecord,FALSE,Char,VK_MENU,0x38,0);
  867. CurRecord++;
  868. } else {
  869. KeyFlags = HIBYTE(KeyState);
  870. // handle yucky alt-gr keys
  871. if ((KeyFlags & 6) == 6) {
  872. AltGr=TRUE;
  873. EventsWritten++;
  874. LoadKeyEvent(CurRecord,TRUE,0,VK_MENU,0x38,ENHANCED_KEY | LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
  875. CurRecord++;
  876. } else if (KeyFlags & 1) {
  877. Shift=TRUE;
  878. EventsWritten++;
  879. LoadKeyEvent(CurRecord,TRUE,0,VK_SHIFT,0x2a,SHIFT_PRESSED);
  880. CurRecord++;
  881. }
  882. EventsWritten++;
  883. LoadKeyEvent(CurRecord,
  884. TRUE,
  885. Char,
  886. LOBYTE(KeyState),
  887. (WORD)MapVirtualKey(CurRecord->Event.KeyEvent.wVirtualKeyCode,0),
  888. 0);
  889. if (KeyFlags & 1)
  890. CurRecord->Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
  891. if (KeyFlags & 2)
  892. CurRecord->Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED;
  893. if (KeyFlags & 4)
  894. CurRecord->Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
  895. CurRecord++;
  896. EventsWritten++;
  897. *CurRecord = *(CurRecord-1);
  898. CurRecord->Event.KeyEvent.bKeyDown = FALSE;
  899. CurRecord++;
  900. // handle yucky alt-gr keys
  901. if (AltGr) {
  902. EventsWritten++;
  903. LoadKeyEvent(CurRecord,FALSE,0,VK_MENU,0x38,ENHANCED_KEY);
  904. CurRecord++;
  905. } else if (Shift) {
  906. EventsWritten++;
  907. LoadKeyEvent(CurRecord,FALSE,0,VK_SHIFT,0x2a,0);
  908. CurRecord++;
  909. }
  910. }
  911. }
  912. CurChar++;
  913. }
  914. EventsWritten = WriteInputBuffer(Console,
  915. &Console->InputBuffer,
  916. StringData,
  917. EventsWritten
  918. );
  919. }
  920. ConsoleHeapFree(StringData);
  921. return;
  922. }
  923. VOID
  924. DoPaste(
  925. IN PCONSOLE_INFORMATION Console
  926. )
  927. /*++
  928. Perform paste request into old app by pulling out clipboard
  929. contents and writing them to the console's input buffer
  930. --*/
  931. {
  932. BOOL Success;
  933. HANDLE ClipboardDataHandle;
  934. if (Console->Flags & CONSOLE_SCROLLING) {
  935. return;
  936. }
  937. //
  938. // Get paste data from clipboard
  939. //
  940. Success = OpenClipboard(Console->hWnd);
  941. if (!Success)
  942. return;
  943. if (Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER) {
  944. PWCHAR pwstr;
  945. ClipboardDataHandle = GetClipboardData(CF_UNICODETEXT);
  946. if (ClipboardDataHandle == NULL) {
  947. CloseClipboard(); // Close clipboard
  948. return;
  949. }
  950. pwstr = GlobalLock(ClipboardDataHandle);
  951. DoStringPaste(Console,pwstr,(ULONG)GlobalSize(ClipboardDataHandle)/sizeof(WCHAR));
  952. GlobalUnlock(ClipboardDataHandle);
  953. } else {
  954. HBITMAP hBitmapSource,hBitmapTarget;
  955. HDC hDCMemSource,hDCMemTarget;
  956. BITMAP bm;
  957. PSCREEN_INFORMATION ScreenInfo;
  958. hBitmapSource = GetClipboardData(CF_BITMAP);
  959. if (hBitmapSource) {
  960. ScreenInfo = Console->CurrentScreenBuffer;
  961. NtWaitForSingleObject(ScreenInfo->BufferInfo.GraphicsInfo.hMutex,
  962. FALSE, NULL);
  963. hBitmapTarget = CreateDIBitmap(Console->hDC,
  964. &ScreenInfo->BufferInfo.GraphicsInfo.lpBitMapInfo->bmiHeader,
  965. CBM_INIT,
  966. ScreenInfo->BufferInfo.GraphicsInfo.BitMap,
  967. ScreenInfo->BufferInfo.GraphicsInfo.lpBitMapInfo,
  968. ScreenInfo->BufferInfo.GraphicsInfo.dwUsage
  969. );
  970. if (hBitmapTarget) {
  971. hDCMemTarget = CreateCompatibleDC ( Console->hDC );
  972. if (hDCMemTarget != NULL) {
  973. hDCMemSource = CreateCompatibleDC ( Console->hDC );
  974. if (hDCMemSource != NULL) {
  975. SelectObject( hDCMemTarget, hBitmapTarget );
  976. SelectObject( hDCMemSource, hBitmapSource );
  977. GetObjectW(hBitmapSource, sizeof (BITMAP), (LPSTR) &bm);
  978. BitBlt ( hDCMemTarget, 0, 0, bm.bmWidth, bm.bmHeight,
  979. hDCMemSource, 0, 0, SRCCOPY);
  980. GetObjectW(hBitmapTarget, sizeof (BITMAP), (LPSTR) &bm);
  981. // copy the bits from the DC to memory
  982. GetDIBits(hDCMemTarget, hBitmapTarget, 0, bm.bmHeight,
  983. ScreenInfo->BufferInfo.GraphicsInfo.BitMap,
  984. ScreenInfo->BufferInfo.GraphicsInfo.lpBitMapInfo,
  985. ScreenInfo->BufferInfo.GraphicsInfo.dwUsage);
  986. DeleteDC(hDCMemSource);
  987. }
  988. DeleteDC(hDCMemTarget);
  989. }
  990. DeleteObject(hBitmapTarget);
  991. InvalidateRect(Console->hWnd,NULL,FALSE); // force repaint
  992. }
  993. NtReleaseMutant(ScreenInfo->BufferInfo.GraphicsInfo.hMutex, NULL);
  994. }
  995. }
  996. CloseClipboard();
  997. return;
  998. }
  999. VOID
  1000. InitSelection(
  1001. IN PCONSOLE_INFORMATION Console
  1002. )
  1003. /*++
  1004. This routine initializes the selection process. It is called
  1005. when the user selects the Mark option from the system menu.
  1006. --*/
  1007. {
  1008. COORD Position;
  1009. PSCREEN_INFORMATION ScreenInfo;
  1010. //
  1011. // if already selecting, cancel selection.
  1012. //
  1013. if (Console->Flags & CONSOLE_SELECTING) {
  1014. if (Console->SelectionFlags & CONSOLE_MOUSE_SELECTION) {
  1015. CancelMouseSelection(Console);
  1016. } else {
  1017. CancelKeySelection(Console,FALSE);
  1018. }
  1019. }
  1020. //
  1021. // set flags
  1022. //
  1023. Console->Flags |= CONSOLE_SELECTING;
  1024. Console->SelectionFlags = 0;
  1025. //
  1026. // save old cursor position and
  1027. // make console cursor into selection cursor.
  1028. //
  1029. ScreenInfo = Console->CurrentScreenBuffer;
  1030. Console->TextCursorPosition = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
  1031. Console->TextCursorVisible = (BOOLEAN)ScreenInfo->BufferInfo.TextInfo.CursorVisible;
  1032. Console->TextCursorSize = ScreenInfo->BufferInfo.TextInfo.CursorSize;
  1033. ConsoleHideCursor(ScreenInfo);
  1034. SetCursorInformation(ScreenInfo,
  1035. 100,
  1036. TRUE
  1037. );
  1038. Position.X = ScreenInfo->Window.Left;
  1039. Position.Y = ScreenInfo->Window.Top;
  1040. SetCursorPosition(ScreenInfo,
  1041. Position,
  1042. TRUE
  1043. );
  1044. ConsoleShowCursor(ScreenInfo);
  1045. //
  1046. // init select rect
  1047. //
  1048. Console->SelectionAnchor = Position;
  1049. //
  1050. // set win text
  1051. //
  1052. SetWinText(Console,msgMarkMode,TRUE);
  1053. }
  1054. VOID
  1055. DoMark(
  1056. IN PCONSOLE_INFORMATION Console
  1057. )
  1058. {
  1059. InitSelection(Console); // initialize selection
  1060. }
  1061. VOID
  1062. DoSelectAll(
  1063. IN PCONSOLE_INFORMATION Console
  1064. )
  1065. {
  1066. COORD Position;
  1067. COORD WindowOrigin;
  1068. PSCREEN_INFORMATION ScreenInfo;
  1069. // clear any old selections
  1070. if (Console->Flags & CONSOLE_SELECTING) {
  1071. ClearSelection(Console);
  1072. }
  1073. // save the old window position
  1074. ScreenInfo = Console->CurrentScreenBuffer;
  1075. WindowOrigin.X = ScreenInfo->Window.Left;
  1076. WindowOrigin.Y = ScreenInfo->Window.Top;
  1077. // initialize selection
  1078. Console->Flags |= CONSOLE_SELECTING;
  1079. Console->SelectionFlags = CONSOLE_MOUSE_SELECTION | CONSOLE_SELECTION_NOT_EMPTY;
  1080. Position.X = Position.Y = 0;
  1081. InitializeMouseSelection(Console, Position);
  1082. MyInvert(Console,&Console->SelectionRect);
  1083. SetWinText(Console,msgSelectMode,TRUE);
  1084. // extend selection
  1085. Position.X = ScreenInfo->ScreenBufferSize.X - 1;
  1086. Position.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  1087. ExtendSelection(Console, Position);
  1088. // restore the old window position
  1089. SetWindowOrigin(ScreenInfo, TRUE, WindowOrigin);
  1090. }
  1091. VOID
  1092. DoScroll(
  1093. IN PCONSOLE_INFORMATION Console
  1094. )
  1095. {
  1096. if (!(Console->Flags & CONSOLE_SCROLLING)) {
  1097. SetWinText(Console,msgScrollMode,TRUE);
  1098. Console->Flags |= CONSOLE_SCROLLING;
  1099. }
  1100. }
  1101. VOID
  1102. ClearScroll(
  1103. IN PCONSOLE_INFORMATION Console
  1104. )
  1105. {
  1106. SetWinText(Console,msgScrollMode,FALSE);
  1107. Console->Flags &= ~CONSOLE_SCROLLING;
  1108. }
  1109. VOID
  1110. ScrollIfNecessary(
  1111. IN PCONSOLE_INFORMATION Console,
  1112. IN PSCREEN_INFORMATION ScreenInfo
  1113. )
  1114. {
  1115. POINT CursorPos;
  1116. RECT ClientRect;
  1117. COORD MousePosition;
  1118. if (Console->Flags & CONSOLE_SELECTING &&
  1119. Console->SelectionFlags & CONSOLE_MOUSE_DOWN) {
  1120. if (!GetCursorPos(&CursorPos)) {
  1121. return;
  1122. }
  1123. if (!GetClientRect(Console->hWnd,&ClientRect)) {
  1124. return;
  1125. }
  1126. MapWindowPoints(Console->hWnd,NULL,(LPPOINT)&ClientRect,2);
  1127. if (!(PtInRect(&ClientRect,CursorPos))) {
  1128. ScreenToClient(Console->hWnd,&CursorPos);
  1129. MousePosition.X = (SHORT)CursorPos.x;
  1130. MousePosition.Y = (SHORT)CursorPos.y;
  1131. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  1132. MousePosition.X /= SCR_FONTSIZE(ScreenInfo).X;
  1133. MousePosition.Y /= SCR_FONTSIZE(ScreenInfo).Y;
  1134. }
  1135. MousePosition.X += ScreenInfo->Window.Left;
  1136. MousePosition.Y += ScreenInfo->Window.Top;
  1137. ExtendSelection(Console,
  1138. MousePosition
  1139. );
  1140. }
  1141. }
  1142. }