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.

585 lines
17 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. cursor.c
  5. Abstract:
  6. This file implements the NT console server cursor routines.
  7. Author:
  8. Therese Stowell (thereses) 5-Dec-1990
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //#define PROFILE_GDI
  14. #ifdef PROFILE_GDI
  15. LONG InvertCount;
  16. #define INVERT_CALL InvertCount++
  17. #else
  18. #define INVERT_CALL
  19. #endif
  20. extern UINT guCaretBlinkTime;
  21. VOID
  22. InvertPixels(
  23. IN PSCREEN_INFORMATION ScreenInfo
  24. )
  25. /*++
  26. Routine Description:
  27. This routine inverts the cursor pixels, making it either visible or
  28. invisible.
  29. Arguments:
  30. ScreenInfo - pointer to screen info structure.
  31. Return Value:
  32. none.
  33. --*/
  34. {
  35. #ifdef FE_SB
  36. if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console)) {
  37. PCONVERSIONAREA_INFORMATION ConvAreaInfo;
  38. SMALL_RECT Region;
  39. SMALL_RECT CursorRegion;
  40. SMALL_RECT ClippedRegion;
  41. #ifdef DBG_KATTR
  42. // BeginKAttrCheck(ScreenInfo);
  43. #endif
  44. ConvAreaInfo = ScreenInfo->Console->ConsoleIme.ConvAreaRoot;
  45. CursorRegion.Left = CursorRegion.Right = ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
  46. CursorRegion.Top = CursorRegion.Bottom = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  47. while (ConvAreaInfo) {
  48. if ((ConvAreaInfo->ConversionAreaMode & (CA_HIDDEN+CA_HIDE_FOR_SCROLL))==0) {
  49. //
  50. // Do clipping region
  51. //
  52. Region.Left = ScreenInfo->Window.Left +
  53. ConvAreaInfo->CaInfo.rcViewCaWindow.Left +
  54. ConvAreaInfo->CaInfo.coordConView.X;
  55. Region.Right = Region.Left +
  56. (ConvAreaInfo->CaInfo.rcViewCaWindow.Right -
  57. ConvAreaInfo->CaInfo.rcViewCaWindow.Left);
  58. Region.Top = ScreenInfo->Window.Top +
  59. ConvAreaInfo->CaInfo.rcViewCaWindow.Top +
  60. ConvAreaInfo->CaInfo.coordConView.Y;
  61. Region.Bottom = Region.Top +
  62. (ConvAreaInfo->CaInfo.rcViewCaWindow.Bottom -
  63. ConvAreaInfo->CaInfo.rcViewCaWindow.Top);
  64. ClippedRegion.Left = max(Region.Left, ScreenInfo->Window.Left);
  65. ClippedRegion.Top = max(Region.Top, ScreenInfo->Window.Top);
  66. ClippedRegion.Right = min(Region.Right, ScreenInfo->Window.Right);
  67. ClippedRegion.Bottom = min(Region.Bottom, ScreenInfo->Window.Bottom);
  68. if (ClippedRegion.Right < ClippedRegion.Left ||
  69. ClippedRegion.Bottom < ClippedRegion.Top) {
  70. ;
  71. }
  72. else {
  73. Region = ClippedRegion;
  74. ClippedRegion.Left = max(Region.Left, CursorRegion.Left);
  75. ClippedRegion.Top = max(Region.Top, CursorRegion.Top);
  76. ClippedRegion.Right = min(Region.Right, CursorRegion.Right);
  77. ClippedRegion.Bottom = min(Region.Bottom, CursorRegion.Bottom);
  78. if (ClippedRegion.Right < ClippedRegion.Left ||
  79. ClippedRegion.Bottom < ClippedRegion.Top) {
  80. ;
  81. }
  82. else {
  83. return;
  84. }
  85. }
  86. }
  87. ConvAreaInfo = ConvAreaInfo->ConvAreaNext;
  88. }
  89. }
  90. #endif // FE_SB
  91. {
  92. ULONG CursorYSize;
  93. POLYPATBLT PolyData;
  94. #ifdef FE_SB
  95. SHORT RowIndex;
  96. PROW Row;
  97. COORD TargetPoint;
  98. int iTrailing = 0;
  99. int iDBCursor = 1;
  100. #endif
  101. INVERT_CALL;
  102. CursorYSize = ScreenInfo->BufferInfo.TextInfo.CursorYSize;
  103. if (ScreenInfo->BufferInfo.TextInfo.DoubleCursor) {
  104. if (ScreenInfo->BufferInfo.TextInfo.CursorSize > 50)
  105. CursorYSize = CursorYSize >> 1;
  106. else
  107. CursorYSize = CursorYSize << 1;
  108. }
  109. #ifdef FE_SB
  110. if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console))
  111. {
  112. TargetPoint = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
  113. RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
  114. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  115. ASSERT(Row);
  116. if ((Row->CharRow.KAttrs[TargetPoint.X] & ATTR_TRAILING_BYTE) &&
  117. ScreenInfo->BufferInfo.TextInfo.CursorDBEnable) {
  118. iTrailing = 1;
  119. iDBCursor = 2;
  120. } else if ((Row->CharRow.KAttrs[TargetPoint.X] & ATTR_LEADING_BYTE) &&
  121. ScreenInfo->BufferInfo.TextInfo.CursorDBEnable) {
  122. iDBCursor = 2;
  123. }
  124. }
  125. PolyData.x = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X -
  126. ScreenInfo->Window.Left - iTrailing) * SCR_FONTSIZE(ScreenInfo).X;
  127. PolyData.y = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y -
  128. ScreenInfo->Window.Top) * SCR_FONTSIZE(ScreenInfo).Y +
  129. (CURSOR_Y_OFFSET_IN_PIXELS(SCR_FONTSIZE(ScreenInfo).Y,CursorYSize));
  130. PolyData.cx = SCR_FONTSIZE(ScreenInfo).X * iDBCursor;
  131. PolyData.cy = CursorYSize;
  132. #else
  133. PolyData.x = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X-ScreenInfo->Window.Left)*SCR_FONTSIZE(ScreenInfo).X;
  134. PolyData.y = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y-ScreenInfo->Window.Top)*SCR_FONTSIZE(ScreenInfo).Y+(CURSOR_Y_OFFSET_IN_PIXELS(SCR_FONTSIZE(ScreenInfo).Y,CursorYSize));
  135. PolyData.cx = SCR_FONTSIZE(ScreenInfo).X;
  136. PolyData.cy = CursorYSize;
  137. #endif
  138. PolyData.BrClr.hbr = GetStockObject(LTGRAY_BRUSH);
  139. PolyPatBlt(ScreenInfo->Console->hDC, PATINVERT, &PolyData, 1, PPB_BRUSH);
  140. GdiFlush();
  141. }
  142. }
  143. VOID
  144. ConsoleShowCursor(
  145. IN PSCREEN_INFORMATION ScreenInfo
  146. )
  147. /*++
  148. Routine Description:
  149. This routine makes the cursor visible both in the data structures
  150. and on the screen.
  151. Arguments:
  152. ScreenInfo - pointer to screen info structure.
  153. Return Value:
  154. none.
  155. --*/
  156. {
  157. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  158. ASSERT (ScreenInfo->BufferInfo.TextInfo.UpdatingScreen>0);
  159. if (--ScreenInfo->BufferInfo.TextInfo.UpdatingScreen == 0) {
  160. ScreenInfo->BufferInfo.TextInfo.CursorOn = FALSE;
  161. }
  162. }
  163. }
  164. VOID
  165. ConsoleHideCursor(
  166. IN PSCREEN_INFORMATION ScreenInfo
  167. )
  168. /*++
  169. Routine Description:
  170. This routine makes the cursor invisible both in the data structures
  171. and on the screen.
  172. Arguments:
  173. ScreenInfo - pointer to screen info structure.
  174. Return Value:
  175. none.
  176. --*/
  177. {
  178. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  179. if (++ScreenInfo->BufferInfo.TextInfo.UpdatingScreen == 1) {
  180. if (ScreenInfo->BufferInfo.TextInfo.CursorVisible &&
  181. ScreenInfo->BufferInfo.TextInfo.CursorOn &&
  182. ScreenInfo->Console->CurrentScreenBuffer == ScreenInfo &&
  183. !(ScreenInfo->Console->Flags & CONSOLE_IS_ICONIC)) {
  184. InvertPixels(ScreenInfo);
  185. ScreenInfo->BufferInfo.TextInfo.CursorOn = FALSE;
  186. }
  187. }
  188. }
  189. }
  190. NTSTATUS
  191. SetCursorInformation(
  192. IN PSCREEN_INFORMATION ScreenInfo,
  193. ULONG Size,
  194. BOOLEAN Visible
  195. )
  196. /*++
  197. Routine Description:
  198. This routine sets the cursor size and visibility both in the data structures
  199. and on the screen.
  200. Arguments:
  201. ScreenInfo - pointer to screen info structure.
  202. Size - cursor size
  203. Visible - cursor visibility
  204. Return Value:
  205. Status
  206. --*/
  207. {
  208. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  209. ConsoleHideCursor(ScreenInfo);
  210. ScreenInfo->BufferInfo.TextInfo.CursorSize = Size;
  211. ScreenInfo->BufferInfo.TextInfo.CursorVisible = Visible;
  212. ScreenInfo->BufferInfo.TextInfo.CursorYSize = (WORD)CURSOR_SIZE_IN_PIXELS(SCR_FONTSIZE(ScreenInfo).Y,ScreenInfo->BufferInfo.TextInfo.CursorSize);
  213. #ifdef i386
  214. if ((!(ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED)) &&
  215. ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  216. SetCursorInformationHW(ScreenInfo,Size,Visible);
  217. }
  218. #endif
  219. ConsoleShowCursor(ScreenInfo);
  220. }
  221. return STATUS_SUCCESS;
  222. }
  223. NTSTATUS
  224. SetCursorMode(
  225. IN PSCREEN_INFORMATION ScreenInfo,
  226. BOOLEAN DoubleCursor
  227. )
  228. /*++
  229. Routine Description:
  230. This routine sets a flag saying whether the cursor should be displayed
  231. with it's default size or it should be modified to indicate the
  232. insert/overtype mode has changed.
  233. Arguments:
  234. ScreenInfo - pointer to screen info structure.
  235. DoubleCursor - should we indicated non-normal mode
  236. Return Value:
  237. Status
  238. --*/
  239. {
  240. if ((ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) &&
  241. (ScreenInfo->BufferInfo.TextInfo.DoubleCursor != DoubleCursor)) {
  242. ConsoleHideCursor(ScreenInfo);
  243. ScreenInfo->BufferInfo.TextInfo.DoubleCursor = DoubleCursor;
  244. #ifdef i386
  245. if ((!(ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED)) &&
  246. ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  247. SetCursorInformationHW(ScreenInfo,
  248. ScreenInfo->BufferInfo.TextInfo.CursorSize,
  249. ScreenInfo->BufferInfo.TextInfo.CursorVisible);
  250. }
  251. #endif
  252. ConsoleShowCursor(ScreenInfo);
  253. }
  254. return STATUS_SUCCESS;
  255. }
  256. VOID
  257. CursorTimerRoutine(
  258. IN PSCREEN_INFORMATION ScreenInfo
  259. )
  260. /*++
  261. Routine Description:
  262. This routine is called when the timer in the console with the focus
  263. goes off. It blinks the cursor.
  264. Arguments:
  265. ScreenInfo - pointer to screen info structure.
  266. Return Value:
  267. none.
  268. --*/
  269. {
  270. if (!(ScreenInfo->Console->Flags & CONSOLE_HAS_FOCUS))
  271. return;
  272. if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) {
  273. //
  274. // Update the cursor pos in USER so accessibility will work
  275. //
  276. if (ScreenInfo->BufferInfo.TextInfo.CursorMoved) {
  277. CONSOLE_CARET_INFO ConsoleCaretInfo;
  278. DWORD dwFlags = 0;
  279. ScreenInfo->BufferInfo.TextInfo.CursorMoved = FALSE;
  280. ConsoleCaretInfo.hwnd = ScreenInfo->Console->hWnd;
  281. ConsoleCaretInfo.rc.left = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X - ScreenInfo->Window.Left) * SCR_FONTSIZE(ScreenInfo).X;
  282. ConsoleCaretInfo.rc.top = (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y - ScreenInfo->Window.Top) * SCR_FONTSIZE(ScreenInfo).Y;
  283. ConsoleCaretInfo.rc.right = ConsoleCaretInfo.rc.left + SCR_FONTSIZE(ScreenInfo).X;
  284. ConsoleCaretInfo.rc.bottom = ConsoleCaretInfo.rc.top + SCR_FONTSIZE(ScreenInfo).Y;
  285. NtUserConsoleControl(ConsoleSetCaretInfo,
  286. &ConsoleCaretInfo,
  287. sizeof(ConsoleCaretInfo));
  288. if (ScreenInfo->BufferInfo.TextInfo.CursorVisible) {
  289. dwFlags |= CONSOLE_CARET_VISIBLE;
  290. }
  291. if (ScreenInfo->Console->Flags & CONSOLE_SELECTING) {
  292. dwFlags |= CONSOLE_CARET_SELECTION;
  293. }
  294. ConsoleNotifyWinEvent(ScreenInfo->Console,
  295. EVENT_CONSOLE_CARET,
  296. dwFlags,
  297. PACKCOORD(ScreenInfo->BufferInfo.TextInfo.CursorPosition));
  298. }
  299. // if the DelayCursor flag has been set, wait one more tick before toggle.
  300. // This is used to guarantee the cursor is on for a finite period of time
  301. // after a move and off for a finite period of time after a WriteString
  302. if (ScreenInfo->BufferInfo.TextInfo.DelayCursor) {
  303. ScreenInfo->BufferInfo.TextInfo.DelayCursor = FALSE;
  304. return;
  305. }
  306. //
  307. // Don't blink the cursor for remote sessions.
  308. //
  309. if ((NtCurrentPeb()->SessionId != WTSGetActiveConsoleSessionId() ||
  310. (guCaretBlinkTime == (UINT)-1)) &&
  311. ScreenInfo->BufferInfo.TextInfo.CursorOn) {
  312. return;
  313. }
  314. if (ScreenInfo->BufferInfo.TextInfo.CursorVisible &&
  315. !ScreenInfo->BufferInfo.TextInfo.UpdatingScreen) {
  316. InvertPixels(ScreenInfo);
  317. ScreenInfo->BufferInfo.TextInfo.CursorOn = !ScreenInfo->BufferInfo.TextInfo.CursorOn;
  318. }
  319. }
  320. }
  321. #ifdef i386
  322. NTSTATUS
  323. SetCursorPositionHW(
  324. IN OUT PSCREEN_INFORMATION ScreenInfo,
  325. IN COORD Position
  326. )
  327. /*++
  328. Routine Description:
  329. This routine moves the cursor.
  330. Arguments:
  331. ScreenInfo - Pointer to screen buffer information.
  332. Position - Contains the new position of the cursor in screen buffer
  333. coordinates.
  334. Return Value:
  335. none.
  336. --*/
  337. {
  338. #if defined(FE_SB)
  339. FSVIDEO_CURSOR_POSITION CursorPosition;
  340. SHORT RowIndex;
  341. PROW Row;
  342. COORD TargetPoint;
  343. if (ScreenInfo->ConvScreenInfo)
  344. return STATUS_SUCCESS;
  345. TargetPoint.X = Position.X;
  346. TargetPoint.Y = Position.Y;
  347. RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
  348. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  349. if (!CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console))
  350. CursorPosition.dwType = CHAR_TYPE_SBCS;
  351. else if (Row->CharRow.KAttrs[TargetPoint.X] & ATTR_TRAILING_BYTE)
  352. CursorPosition.dwType = CHAR_TYPE_TRAILING;
  353. else if (Row->CharRow.KAttrs[TargetPoint.X] & ATTR_LEADING_BYTE)
  354. CursorPosition.dwType = CHAR_TYPE_LEADING;
  355. else
  356. CursorPosition.dwType = CHAR_TYPE_SBCS;
  357. // set cursor position
  358. CursorPosition.Coord.Column = Position.X - ScreenInfo->Window.Left;
  359. CursorPosition.Coord.Row = Position.Y - ScreenInfo->Window.Top;
  360. #else
  361. VIDEO_CURSOR_POSITION CursorPosition;
  362. // set cursor position
  363. CursorPosition.Column = Position.X - ScreenInfo->Window.Left;
  364. CursorPosition.Row = Position.Y - ScreenInfo->Window.Top;
  365. #endif
  366. return GdiFullscreenControl(FullscreenControlSetCursorPosition,
  367. (PVOID)&CursorPosition,
  368. sizeof(CursorPosition),
  369. NULL,
  370. 0);
  371. }
  372. #endif
  373. NTSTATUS
  374. SetCursorPosition(
  375. IN OUT PSCREEN_INFORMATION ScreenInfo,
  376. IN COORD Position,
  377. IN BOOL TurnOn
  378. )
  379. /*++
  380. Routine Description:
  381. This routine sets the cursor position in the data structures and on
  382. the screen.
  383. Arguments:
  384. ScreenInfo - pointer to screen info structure.
  385. Position - new position of cursor
  386. TurnOn - true if cursor should be left on, false if should be left off
  387. Return Value:
  388. Status
  389. --*/
  390. {
  391. //
  392. // Ensure that the cursor position is within the constraints of the screen
  393. // buffer.
  394. //
  395. if (Position.X >= ScreenInfo->ScreenBufferSize.X ||
  396. Position.Y >= ScreenInfo->ScreenBufferSize.Y ||
  397. Position.X < 0 || Position.Y < 0) {
  398. return STATUS_INVALID_PARAMETER;
  399. }
  400. ConsoleHideCursor(ScreenInfo);
  401. ScreenInfo->BufferInfo.TextInfo.CursorPosition = Position;
  402. #ifdef i386
  403. if ((!(ScreenInfo->Console->Flags & CONSOLE_VDM_REGISTERED)) &&
  404. ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) {
  405. SetCursorPositionHW(ScreenInfo,Position);
  406. }
  407. #endif
  408. ConsoleShowCursor(ScreenInfo);
  409. // if we have the focus, adjust the cursor state
  410. if (ScreenInfo->Console->Flags & CONSOLE_HAS_FOCUS) {
  411. if (TurnOn) {
  412. ScreenInfo->BufferInfo.TextInfo.DelayCursor = FALSE;
  413. CursorTimerRoutine(ScreenInfo);
  414. } else {
  415. ScreenInfo->BufferInfo.TextInfo.DelayCursor = TRUE;
  416. }
  417. ScreenInfo->BufferInfo.TextInfo.CursorMoved = TRUE;
  418. }
  419. return STATUS_SUCCESS;
  420. }
  421. #ifdef i386
  422. NTSTATUS
  423. SetCursorInformationHW(
  424. PSCREEN_INFORMATION ScreenInfo,
  425. ULONG Size,
  426. BOOLEAN Visible
  427. )
  428. {
  429. VIDEO_CURSOR_ATTRIBUTES CursorAttr;
  430. ULONG FontSizeY;
  431. if (ScreenInfo->BufferInfo.TextInfo.DoubleCursor) {
  432. if (Size > 50)
  433. Size = Size >> 1;
  434. else
  435. Size = Size << 1;
  436. }
  437. ASSERT (Size <= 100 && Size > 0);
  438. FontSizeY = CONSOLE_WINDOW_SIZE_Y(ScreenInfo) > 25 ? 8 : 16;
  439. CursorAttr.Height = (USHORT)CURSOR_PERCENTAGE_TO_TOP_SCAN_LINE(FontSizeY,Size);
  440. CursorAttr.Width = 31;
  441. CursorAttr.Enable = Visible;
  442. return GdiFullscreenControl(FullscreenControlSetCursorAttributes,
  443. (PVOID)&CursorAttr,
  444. sizeof(CursorAttr),
  445. NULL,
  446. 0);
  447. }
  448. #endif