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.

1061 lines
27 KiB

  1. /* File: D:\WACKER\tdll\termutil.c (Created: 23-Dec-1993)
  2. *
  3. * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 4 $
  7. * $Date: 3/26/02 8:46a $
  8. */
  9. #include <windows.h>
  10. #pragma hdrstop
  11. //#define DEBUGSTR 1
  12. #include <stdlib.h>
  13. #include <limits.h>
  14. #include "stdtyp.h"
  15. #include "session.h"
  16. #include "assert.h"
  17. #include "timers.h"
  18. #include "chars.h"
  19. #include <emu\emu.h>
  20. #include "term.h"
  21. #include "term.hh"
  22. #include "statusbr.h"
  23. #include <term\res.h>
  24. static int InMiddleofWideChar(ECHAR *pszRow, int iCol);
  25. //
  26. // The following function is from code mofified slightly
  27. // from MSDN for determining if you are currently running as a
  28. // remote session (Terminal Service). REV: 10/03/2001
  29. //
  30. BOOL ValidateProductSuite ( LPSTR SuiteName );
  31. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  32. * FUNCTION:
  33. * termQuerySnapRect
  34. *
  35. * DESCRIPTION:
  36. * Returns the minimum rectangle that will encompass a full terminal.
  37. *
  38. * ARGUMENTS:
  39. * hhTerm - internal terminal handle.
  40. * prc - pointer to rect
  41. *
  42. * RETURNS:
  43. * void
  44. *
  45. */
  46. void termQuerySnapRect(const HHTERM hhTerm, LPRECT prc)
  47. {
  48. prc->left = prc->top = 0;
  49. prc->right = (hhTerm->iCols * hhTerm->xChar) +
  50. (2 * (hhTerm->xIndent + hhTerm->xBezel)) +
  51. (2 * GetSystemMetrics(SM_CXEDGE)) +
  52. GetSystemMetrics(SM_CXVSCROLL);
  53. prc->bottom = ((hhTerm->iRows + 2) * hhTerm->yChar) +
  54. (2 * GetSystemMetrics(SM_CYEDGE));
  55. }
  56. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  57. * FUNCTION:
  58. * MarkText
  59. *
  60. * DESCRIPTION:
  61. * Work horse routine that marks and unmarks text on the terminal screen.
  62. * It has two methods for marking, ABSOLUTE and XOR. ABSOLUTE sets the
  63. * range of cells given by ptBeg and ptEnd to the given setting (fMark)
  64. * while XOR will perform an exclusive or on the cell range. ABSOLUTE
  65. * is used to unmark cells mostly.
  66. *
  67. * ARGUMENTS:
  68. * HTERM hTerm - handle to a terminal
  69. * LPPOINT ptBeg - one end of the marking range
  70. * LPPOINT ptEnd - the other end of the marking range
  71. * BOOL fMark - new marking state of cells
  72. * SHORT fMarkingMethod - MARK_ABS or MARK_XOR
  73. *
  74. *
  75. * RETURNS:
  76. * VOID
  77. *
  78. */
  79. void MarkText(const HHTERM hhTerm,
  80. const LPPOINT ptBeg,
  81. const LPPOINT ptEnd,
  82. const BOOL fMark,
  83. const int sMarkingMethod)
  84. {
  85. int iOffsetBeg,
  86. iOffsetEnd,
  87. sTermBeg,
  88. sTermEnd,
  89. i, j;
  90. RECT rc;
  91. long yBeg, yEnd;
  92. //const int iMaxCells = hhTerm->iRows * TERM_COLS;
  93. //
  94. const int iMaxCells = MAX_EMUROWS * MAX_EMUCOLS;
  95. //iOffsetBeg = ((ptBeg->y - 1) * TERM_COLS) + ptBeg->x;
  96. //iOffsetEnd = ((ptEnd->y - 1) * TERM_COLS) + ptEnd->x;
  97. //
  98. iOffsetBeg = ((ptBeg->y - 1) * MAX_EMUCOLS) + ptBeg->x;
  99. iOffsetEnd = ((ptEnd->y - 1) * MAX_EMUCOLS) + ptEnd->x;
  100. // Check if we moved enough to actually mark something.
  101. if (iOffsetBeg == iOffsetEnd)
  102. return;
  103. // Determine offsets for terminal area.
  104. sTermBeg = min(max(iOffsetBeg, 0), iMaxCells);
  105. sTermEnd = min(max(iOffsetEnd, 0), iMaxCells);
  106. // This routine use to reference the text and attribute buffers as
  107. // a continous buffer. When switching over to pointer arrays, I
  108. // introduced the [i/sCols][i%sCols] notation to keep from having
  109. // to change the entire routine.
  110. if (sTermBeg != sTermEnd)
  111. {
  112. //i = (min(sTermBeg, sTermEnd)
  113. // + (hhTerm->iTopline * TERM_COLS)) % iMaxCells;
  114. //
  115. i = (min(sTermBeg, sTermEnd)
  116. + (hhTerm->iTopline * MAX_EMUCOLS)) % iMaxCells;
  117. j = abs(sTermEnd - sTermBeg);
  118. switch (sMarkingMethod)
  119. {
  120. case MARK_XOR:
  121. while (j-- > 0)
  122. {
  123. if (i >= iMaxCells)
  124. i = 0;
  125. //hhTerm->fppstAttr[i/TERM_COLS][i%TERM_COLS].txtmrk
  126. // ^= (unsigned)fMark;
  127. //
  128. hhTerm->fppstAttr[i/MAX_EMUCOLS][i%MAX_EMUCOLS].txtmrk
  129. ^= (unsigned)fMark;
  130. i += 1;
  131. }
  132. break;
  133. case MARK_ABS:
  134. while (j-- > 0)
  135. {
  136. if (i >= iMaxCells)
  137. i = 0;
  138. //hhTerm->fppstAttr[i/TERM_COLS][i%TERM_COLS].txtmrk
  139. // = (unsigned)fMark;
  140. //
  141. hhTerm->fppstAttr[i/MAX_EMUCOLS][i%MAX_EMUCOLS].txtmrk
  142. = (unsigned)fMark;
  143. i += 1;
  144. }
  145. break;
  146. default:
  147. assert(0);
  148. break;
  149. }
  150. }
  151. TestForMarkingLock(hhTerm);
  152. // Invalidate the rectangle covering the marked region
  153. yBeg = min(ptBeg->y, ptEnd->y);
  154. yEnd = max(ptBeg->y, ptEnd->y);
  155. rc.left = hhTerm->xIndent + (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel);
  156. //rc.right = min((hhTerm->xChar * hhTerm->iCols) + hhTerm->xIndent +
  157. // (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel), hhTerm->cx);
  158. //
  159. rc.right = min((hhTerm->xChar * MAX_EMUCOLS) + hhTerm->xIndent +
  160. (hhTerm->iHScrlPos ? 0 : hhTerm->xBezel), hhTerm->cx);
  161. rc.top = (yBeg - hhTerm->iVScrlPos) * hhTerm->yChar;
  162. rc.bottom = (yEnd + 1 - hhTerm->iVScrlPos) * hhTerm->yChar;
  163. InvalidateRect(hhTerm->hwnd, &rc, FALSE);
  164. return;
  165. }
  166. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  167. * FUNCTION:
  168. * MarkTextAll
  169. *
  170. * DESCRIPTION:
  171. * Marks all of the text on the terminal screen and backscroll buffer.
  172. *
  173. * ARGUMENTS:
  174. * hhTerm - private terminal handle
  175. *
  176. * RETURNS:
  177. * void
  178. *
  179. */
  180. void MarkTextAll(HHTERM hhTerm)
  181. {
  182. MarkText(hhTerm, &hhTerm->ptBeg, &hhTerm->ptEnd, FALSE, MARK_ABS);
  183. hhTerm->ptBeg.x = 0;
  184. hhTerm->ptBeg.y = hhTerm->iVScrlMin;
  185. //iEmuId = EmuQ(sessQueryEmuHdl(hhTerm->hSession)
  186. hhTerm->ptEnd.x = hhTerm->iCols;
  187. hhTerm->ptEnd.y = hhTerm->iRows;
  188. MarkText(hhTerm, &hhTerm->ptBeg, &hhTerm->ptEnd, TRUE, MARK_ABS);
  189. return;
  190. }
  191. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  192. * FUNCTION:
  193. * UnmarkText
  194. *
  195. * DESCRIPTION:
  196. * Unmarks all text on the terminal screen
  197. *
  198. * ARGUMENTS:
  199. * hhTerm - private terminal handle
  200. *
  201. * RETURNS:
  202. * void
  203. *
  204. */
  205. void UnmarkText(const HHTERM hhTerm)
  206. {
  207. MarkText(hhTerm, &hhTerm->ptBeg, &hhTerm->ptEnd, FALSE, MARK_ABS);
  208. hhTerm->ptBeg = hhTerm->ptEnd;
  209. TestForMarkingLock(hhTerm);
  210. return;
  211. }
  212. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  213. * FUNCTION:
  214. * TestForMarkingLock
  215. *
  216. * DESCRIPTION:
  217. * Checks to seek if hTerm->fMarkingLock should be on or off.
  218. *
  219. * ARGUMENTS:
  220. * HTERM hTerm - handle to a terminal
  221. *
  222. * RETURNS:
  223. * VOID
  224. *
  225. */
  226. void TestForMarkingLock(const HHTERM hhTerm)
  227. {
  228. hhTerm->fMarkingLock = (memcmp(&hhTerm->ptBeg, &hhTerm->ptEnd,
  229. sizeof(POINT)) == 0) ? FALSE : TRUE;
  230. if (hhTerm->fMarkingLock)
  231. sessSetSuspend(hhTerm->hSession, SUSPEND_TERMINAL_MARKING);
  232. else
  233. sessClearSuspend(hhTerm->hSession, SUSPEND_TERMINAL_MARKING);
  234. return;
  235. }
  236. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  237. * FUNCTION:
  238. * PointInSelectionRange
  239. *
  240. * DESCRIPTION:
  241. * Tests if given point is within the range of the given beginning and
  242. * ending points. Note, pptBeg does not have to be less the pptEnd.
  243. *
  244. * ARGUMENTS:
  245. * const PPOINT ppt - point to test.
  246. * const PPOINT pptBeg - one end of the range.
  247. * const PPOINT pptEnd - other end of the range.
  248. * const int iCols - number of columns in current emulator.
  249. *
  250. * RETURNS:
  251. * TRUE if in range, else FALSE
  252. *
  253. */
  254. BOOL PointInSelectionRange(const PPOINT ppt,
  255. const PPOINT pptBeg,
  256. const PPOINT pptEnd,
  257. const int iCols)
  258. {
  259. long l, lBeg, lEnd;
  260. l = (ppt->y * iCols) + ppt->x;
  261. lBeg = (pptBeg->y * iCols) + pptBeg->x;
  262. lEnd = (pptEnd->y * iCols) + pptEnd->x;
  263. if (l >= min(lBeg, lEnd) && l < max(lBeg, lEnd))
  264. return TRUE;
  265. return FALSE;
  266. }
  267. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  268. * FUNCTION:
  269. * termTranslateKey
  270. *
  271. * DESCRIPTION:
  272. * Does the dirty work of translate accelator keys.
  273. *
  274. * ARGUMENTS:
  275. * HTERM hTerm - terminal handle.
  276. * HWND hwnd - terminal window handle.
  277. * USHORT usKey - key code from utilGetCharacter().
  278. *
  279. * RETURNS:
  280. * TRUE if it processed char, else FALSE
  281. *
  282. */
  283. BOOL termTranslateKey(const HHTERM hhTerm, const HWND hwnd, const KEY_T Key)
  284. {
  285. POINT ptTmp;
  286. INT x = 0;
  287. STEMUSET stEmuSet;
  288. BOOL fShiftKey,
  289. fScrlLk;
  290. if (Key == 0)
  291. return TRUE;
  292. fScrlLk = GetKeyState(VK_SCROLL) & 1;
  293. fShiftKey = (Key & SHIFT_KEY) ? TRUE : FALSE;
  294. // Check to see if we use it.
  295. switch (Key)
  296. {
  297. /* -------------- VK_HOME ------------- */
  298. case VK_HOME | VIRTUAL_KEY:
  299. case VK_HOME | VIRTUAL_KEY | SHIFT_KEY:
  300. case VK_HOME | VIRTUAL_KEY | EXTENDED_KEY:
  301. case VK_HOME | VIRTUAL_KEY | EXTENDED_KEY | SHIFT_KEY:
  302. MoveSelectionCursor(hhTerm, hwnd, -hhTerm->iCols, 0, fShiftKey);
  303. break;
  304. case VK_HOME | VIRTUAL_KEY | CTRL_KEY:
  305. case VK_HOME | VIRTUAL_KEY | CTRL_KEY | SHIFT_KEY:
  306. case VK_HOME | VIRTUAL_KEY | CTRL_KEY | EXTENDED_KEY:
  307. case VK_HOME | VIRTUAL_KEY | CTRL_KEY | EXTENDED_KEY | SHIFT_KEY:
  308. MoveSelectionCursor(hhTerm, hwnd, -hhTerm->iCols,
  309. hhTerm->iVScrlMin - hhTerm->iRows, fShiftKey);
  310. break;
  311. case VK_HOME | VIRTUAL_KEY | ALT_KEY:
  312. case VK_HOME | VIRTUAL_KEY | ALT_KEY | SHIFT_KEY:
  313. case VK_HOME | VIRTUAL_KEY | ALT_KEY | SHIFT_KEY | CTRL_KEY:
  314. case VK_HOME | VIRTUAL_KEY | ALT_KEY | SHIFT_KEY | CTRL_KEY | EXTENDED_KEY:
  315. break;
  316. /* -------------- VK_END ------------- */
  317. case VK_END | VIRTUAL_KEY:
  318. case VK_END | VIRTUAL_KEY | SHIFT_KEY:
  319. case VK_END | VIRTUAL_KEY | EXTENDED_KEY:
  320. case VK_END | VIRTUAL_KEY | SHIFT_KEY | EXTENDED_KEY:
  321. MoveSelectionCursor(hhTerm, hwnd, hhTerm->iCols - hhTerm->ptEnd.x,
  322. 0, fShiftKey);
  323. break;
  324. case VK_END | VIRTUAL_KEY | CTRL_KEY:
  325. case VK_END | VIRTUAL_KEY | CTRL_KEY | SHIFT_KEY:
  326. case VK_END | VIRTUAL_KEY | CTRL_KEY | EXTENDED_KEY:
  327. case VK_END | VIRTUAL_KEY | CTRL_KEY | SHIFT_KEY | EXTENDED_KEY:
  328. MoveSelectionCursor(hhTerm, hwnd, hhTerm->iCols, INT_MAX/2, fShiftKey);
  329. break;
  330. /* -------------- VK_PRIOR & VK_NEXT ------------- */
  331. case VK_PRIOR | VIRTUAL_KEY:
  332. case VK_NEXT | VIRTUAL_KEY:
  333. case VK_PRIOR | VIRTUAL_KEY | SHIFT_KEY:
  334. case VK_NEXT | VIRTUAL_KEY | SHIFT_KEY:
  335. case VK_PRIOR | VIRTUAL_KEY | EXTENDED_KEY:
  336. case VK_NEXT | VIRTUAL_KEY | EXTENDED_KEY:
  337. case VK_PRIOR | VIRTUAL_KEY | EXTENDED_KEY| SHIFT_KEY:
  338. case VK_NEXT | VIRTUAL_KEY | EXTENDED_KEY| SHIFT_KEY:
  339. ptTmp = hhTerm->ptEnd;
  340. if (fShiftKey == 0)
  341. UnmarkText(hhTerm);
  342. if (hhTerm->ptEnd.y < hhTerm->iVScrlPos ||
  343. (hhTerm->ptEnd.y - hhTerm->iTermHite + 1) > hhTerm->iVScrlPos
  344. || !hhTerm->fLclCurOn)
  345. {
  346. x = 1; // means it is out of view.
  347. }
  348. SendMessage(hwnd, WM_VSCROLL, ((UCHAR)Key == VK_NEXT) ?
  349. SB_PAGEDOWN : SB_PAGEUP, 0);
  350. if (x)
  351. {
  352. hhTerm->ptEnd.y = hhTerm->iVScrlPos;
  353. if (hhTerm->fLclCurOn)
  354. SetLclCurPos(hhTerm, &hhTerm->ptEnd);
  355. }
  356. else
  357. {
  358. if ((UCHAR)Key == VK_NEXT)
  359. {
  360. hhTerm->ptEnd.y += hhTerm->iTermHite;
  361. hhTerm->ptEnd.y = min(hhTerm->iRows, hhTerm->ptEnd.y);
  362. }
  363. else
  364. {
  365. hhTerm->ptEnd.y -= hhTerm->iTermHite;
  366. hhTerm->ptEnd.y = max(hhTerm->iVScrlMin, hhTerm->ptEnd.y);
  367. }
  368. if (hhTerm->fLclCurOn)
  369. SetLclCurPos(hhTerm, &hhTerm->ptEnd);
  370. }
  371. if (!fShiftKey)
  372. hhTerm->ptBeg = hhTerm->ptEnd;
  373. if (fShiftKey)
  374. MarkText(hhTerm, &ptTmp, &hhTerm->ptEnd, TRUE, MARK_XOR);
  375. break;
  376. case VK_PRIOR | VIRTUAL_KEY | CTRL_KEY:
  377. case VK_NEXT | VIRTUAL_KEY | CTRL_KEY:
  378. case VK_PRIOR | VIRTUAL_KEY | CTRL_KEY | EXTENDED_KEY:
  379. case VK_NEXT | VIRTUAL_KEY | CTRL_KEY | EXTENDED_KEY:
  380. UnmarkText(hhTerm);
  381. SendMessage(hwnd, WM_HSCROLL, ((UCHAR)Key == VK_NEXT) ?
  382. SB_PAGEDOWN : SB_PAGEUP, 0);
  383. break;
  384. /* -------------- VK_UP ------------- */
  385. case VK_UP | VIRTUAL_KEY:
  386. case VK_UP | VIRTUAL_KEY | SHIFT_KEY:
  387. case VK_UP | VIRTUAL_KEY | EXTENDED_KEY:
  388. case VK_UP | VIRTUAL_KEY | EXTENDED_KEY | SHIFT_KEY:
  389. MoveSelectionCursor(hhTerm, hwnd, 0, -1, fShiftKey);
  390. break;
  391. /* -------------- VK_DOWN ------------- */
  392. case VK_DOWN | VIRTUAL_KEY:
  393. case VK_DOWN | VIRTUAL_KEY | SHIFT_KEY:
  394. case VK_DOWN | VIRTUAL_KEY | EXTENDED_KEY:
  395. case VK_DOWN | VIRTUAL_KEY | EXTENDED_KEY | SHIFT_KEY:
  396. MoveSelectionCursor(hhTerm, hwnd, 0, 1, fShiftKey);
  397. break;
  398. /* -------------- VK_LEFT ------------- */
  399. case VK_LEFT | VIRTUAL_KEY:
  400. case VK_LEFT | VIRTUAL_KEY | SHIFT_KEY:
  401. case VK_LEFT | VIRTUAL_KEY | EXTENDED_KEY:
  402. case VK_LEFT | VIRTUAL_KEY | EXTENDED_KEY | SHIFT_KEY:
  403. MoveSelectionCursor(hhTerm, hwnd, -1, 0, fShiftKey);
  404. break;
  405. /* -------------- VK_RIGHT ------------- */
  406. case VK_RIGHT | VIRTUAL_KEY:
  407. case VK_RIGHT | VIRTUAL_KEY | SHIFT_KEY:
  408. case VK_RIGHT | VIRTUAL_KEY | EXTENDED_KEY:
  409. case VK_RIGHT | VIRTUAL_KEY | EXTENDED_KEY | SHIFT_KEY:
  410. MoveSelectionCursor(hhTerm, hwnd, 1, 0, fShiftKey);
  411. break;
  412. /* -------------- VK_F4 ------------- */
  413. case VK_F4 | CTRL_KEY | VIRTUAL_KEY:
  414. PostMessage(sessQueryHwnd(hhTerm->hSession), WM_CLOSE, 0, 0L);
  415. break;
  416. /* -------------- VK_F8 ------------- */
  417. case VK_F8 | VIRTUAL_KEY:
  418. if (fScrlLk || hhTerm->fMarkingLock)
  419. {
  420. hhTerm->fExtSelect = !hhTerm->fExtSelect;
  421. break;
  422. }
  423. return FALSE;
  424. /* -------------- CTRL-C ------------- */
  425. case 0x03:
  426. case VK_INSERT | VIRTUAL_KEY | CTRL_KEY:
  427. case VK_INSERT | VIRTUAL_KEY | CTRL_KEY | EXTENDED_KEY:
  428. if (fScrlLk || hhTerm->fMarkingLock)
  429. {
  430. PostMessage(sessQueryHwnd(hhTerm->hSession), WM_COMMAND, IDM_COPY, 0);
  431. break;
  432. }
  433. return FALSE;
  434. /* -------------- CTRL-V ------------- */
  435. case 0x16:
  436. case VK_INSERT | VIRTUAL_KEY | SHIFT_KEY:
  437. case VK_INSERT | VIRTUAL_KEY | SHIFT_KEY | EXTENDED_KEY:
  438. if (emuQuerySettings(sessQueryEmuHdl(hhTerm->hSession),
  439. &stEmuSet) == 0 && stEmuSet.nTermKeys != EMU_KEYS_TERM)
  440. {
  441. PostMessage(sessQueryHwnd(hhTerm->hSession), WM_COMMAND,
  442. IDM_PASTE, 0);
  443. break;
  444. }
  445. return FALSE;
  446. /* -------------- CTRL-X ------------- */
  447. /* -------------- CTRL-Z ------------- */
  448. case 0x18:
  449. case 0x1A:
  450. if (fScrlLk || hhTerm->fMarkingLock)
  451. return TRUE;
  452. return FALSE;
  453. /* -------------- Scroll Lock ------------- */
  454. case VIRTUAL_KEY | VK_SCROLL:
  455. case VIRTUAL_KEY | SHIFT_KEY | VK_SCROLL:
  456. case VIRTUAL_KEY | ALT_KEY | VK_SCROLL:
  457. case VIRTUAL_KEY | ALT_KEY | SHIFT_KEY | VK_SCROLL:
  458. if (fScrlLk)
  459. sessSetSuspend(hhTerm->hSession, SUSPEND_SCRLCK);
  460. else
  461. sessClearSuspend(hhTerm->hSession, SUSPEND_SCRLCK);
  462. PostMessage(sessQueryHwndStatusbar(hhTerm->hSession),
  463. SBR_NTFY_REFRESH, (WPARAM)SBR_SCRL_PART_NO, 0);
  464. return TRUE;
  465. /* -------------- Num Lock ------------- */
  466. case VIRTUAL_KEY | EXTENDED_KEY | VK_NUMLOCK:
  467. case VIRTUAL_KEY | EXTENDED_KEY | SHIFT_KEY | VK_NUMLOCK:
  468. case VIRTUAL_KEY | EXTENDED_KEY | ALT_KEY | VK_NUMLOCK:
  469. case VIRTUAL_KEY | EXTENDED_KEY | ALT_KEY | SHIFT_KEY | VK_NUMLOCK:
  470. PostMessage(sessQueryHwndStatusbar(hhTerm->hSession),
  471. SBR_NTFY_REFRESH, (WPARAM)SBR_NUML_PART_NO, 0);
  472. return TRUE;
  473. /* -------------- Caps Lock ------------- */
  474. case VIRTUAL_KEY | VK_CAPITAL:
  475. case VIRTUAL_KEY | SHIFT_KEY | VK_CAPITAL:
  476. case VIRTUAL_KEY | ALT_KEY | VK_CAPITAL:
  477. case VIRTUAL_KEY | ALT_KEY | SHIFT_KEY | VK_CAPITAL:
  478. PostMessage(sessQueryHwndStatusbar(hhTerm->hSession),
  479. SBR_NTFY_REFRESH, (WPARAM)SBR_CAPL_PART_NO, 0);
  480. return TRUE;
  481. /* -------------- Let it through based on scroll lock ------------- */
  482. default:
  483. return fScrlLk;
  484. }
  485. return TRUE;
  486. }
  487. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  488. * FUNCTION:
  489. * MarkingTimerProc
  490. *
  491. * DESCRIPTION:
  492. * Multiplex timer callback routine used for text marking
  493. *
  494. * ARGUMENTS:
  495. * pvhWnd - terminal window.
  496. * lTime - contains time elapsed.
  497. *
  498. * RETURNS:
  499. * void
  500. *
  501. */
  502. void CALLBACK MarkingTimerProc(void *pvhWnd, long lTime)
  503. {
  504. const HWND hwnd = (HWND)pvhWnd;
  505. const HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  506. MSG msg;
  507. POINT ptTemp;
  508. if (hhTerm->fCapture == FALSE)
  509. return;
  510. // This is TRUE if timer went off after we posted ourselves a message.
  511. //
  512. PeekMessage(&msg, hwnd, WM_TERM_SCRLMARK, WM_TERM_SCRLMARK, PM_REMOVE);
  513. // Because mouse messages go in the system queue and don't get put in
  514. // our application queue until its empty, we need to check.
  515. //
  516. if (PeekMessage(&msg, hwnd, WM_LBUTTONUP, WM_LBUTTONUP, PM_NOREMOVE) == TRUE)
  517. return;
  518. // The scrolling routines set this whenever they actually perform
  519. // a scroll. So we set it FALSE here. Then if any of the SendMessage()
  520. // calls below actually scroll, we know to post a message back to
  521. // ourselves to continue scrolling.
  522. hhTerm->fScrolled = FALSE;
  523. GetCursorPos(&ptTemp);
  524. MapWindowPoints(GetDesktopWindow(), hwnd, &ptTemp, 1);
  525. /* -------------- We control the horizontal ------------- */
  526. if (ptTemp.x > hhTerm->cx)
  527. SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, 0);
  528. else if (ptTemp.x < 0)
  529. SendMessage(hwnd, WM_HSCROLL, SB_LINEUP, 0);
  530. /* -------------- We control the vertical ------------- */
  531. if (ptTemp.y > hhTerm->cy)
  532. SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
  533. else if (ptTemp.y < 0)
  534. SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
  535. // If we scrolled, post a message back to ourselves. Do this because
  536. // the timer resolution is not short enough to produce a fast, smooth
  537. // scrolling effect. Ideally, it would be better to drive this
  538. // entirely from timer intervals, but its too slow compared to other
  539. // apps.
  540. if (hhTerm->fScrolled)
  541. {
  542. SendMessage(hwnd, WM_MOUSEMOVE, MK_LBUTTON, MAKELPARAM(ptTemp.x, ptTemp.y));
  543. UpdateWindow(hwnd);
  544. //Sleep(10); // so we don't scroll too fast on fast machines.
  545. PostMessage(hwnd, WM_TERM_SCRLMARK, 0, 0);
  546. }
  547. return;
  548. }
  549. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  550. * FUNCTION:
  551. * termSetClrAttr
  552. *
  553. * DESCRIPTION:
  554. * Called as a result of the emulator notifying the terminal that
  555. * it's clear attribute has changed. This function calls the
  556. * appropriate emulator call to get the attribute and then
  557. * sets appropriate terminal variables.
  558. *
  559. * ARGUMENTS:
  560. * hhTerm - private terminal handle.
  561. *
  562. * RETURNS:
  563. * void
  564. *
  565. */
  566. void termSetClrAttr(const HHTERM hhTerm)
  567. {
  568. HBRUSH hBrush;
  569. STATTR stAttr;
  570. emuQueryClearAttr(sessQueryEmuHdl(hhTerm->hSession), &stAttr);
  571. hhTerm->crTerm = hhTerm->pacrEmuColors[(stAttr.revvid) ?
  572. stAttr.txtclr : stAttr.bkclr];
  573. if ((hBrush = CreateSolidBrush(hhTerm->crTerm)) == 0)
  574. return;
  575. if (hhTerm->hbrushTerminal)
  576. DeleteObject(hhTerm->hbrushTerminal);
  577. hhTerm->hbrushTerminal = hBrush;
  578. InvalidateRect(hhTerm->hwnd, 0, FALSE);
  579. return;
  580. }
  581. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  582. * FUNCTION:
  583. * BlinkText
  584. *
  585. * DESCRIPTION:
  586. * Routine to toggle blinking-attribute cells on and off.
  587. *
  588. * ARGUMENTS:
  589. * HWND hwnd - terminal window handle.
  590. *
  591. * RETURNS:
  592. * VOID
  593. *
  594. */
  595. void BlinkText(const HHTERM hhTerm)
  596. {
  597. int i, j, k;
  598. DWORD dwTime;
  599. RECT rc;
  600. BOOL fUpdate,
  601. fBlinks = FALSE;
  602. const int m = hhTerm->iRows; // for speed
  603. const int n = hhTerm->iCols; // for speed
  604. // hhTerm->iBlink is a tristate variable. If it is zero,
  605. // there are no blink attributes in the image and we can exit
  606. // immediately (this is an optimization). Otherwise, we toggle
  607. // hhTerm->iBlink between -1 and 1, invalidate only those areas
  608. // that have blinks, and paint.
  609. if (hhTerm->iBlink == 0)
  610. return;
  611. hhTerm->iBlink = (hhTerm->iBlink == -1) ? 1 : -1;
  612. dwTime = GetTickCount();
  613. for (i = 0 ; i < m ; ++i)
  614. {
  615. const int r = (i + hhTerm->iTopline) % MAX_EMUROWS;
  616. if (hhTerm->abBlink[r] == 0)
  617. continue;
  618. // Don't let this routine gobble-up to much time. If we can't
  619. // paint all the blinks, we can't paint all the blinks.
  620. if ((GetTickCount() - dwTime) >= (DWORD)(hhTerm->uBlinkRate/2))
  621. return;
  622. for (j = 0, fUpdate = FALSE ; j < n ; ++j)
  623. {
  624. if (hhTerm->fppstAttr[r][j].blink)
  625. {
  626. for (k = j, j += 1 ; j < n ; ++j)
  627. {
  628. if (hhTerm->fppstAttr[r][j].blink == 0)
  629. break;
  630. }
  631. rc.left = ((k - hhTerm->iHScrlPos) * hhTerm->xChar) + hhTerm->xIndent + hhTerm->xBezel;
  632. rc.right = rc.left + ((j - k) * hhTerm->xChar);
  633. rc.top = (i + 1 - hhTerm->iVScrlPos) * hhTerm->yChar;
  634. //rc.top = ((((i + m - hhTerm->iTopline) % m) + 1)
  635. // - hhTerm->iVScrlPos) * hhTerm->yChar;
  636. rc.bottom = rc.top + hhTerm->yChar;
  637. //
  638. // Currently we are blinking the text in the terminal
  639. // emulator screen. If we don't want the text to blink
  640. // when running in a Terminal Service session (Remote
  641. // Desktop Connection) then uncomment the following
  642. // line. REV: 10/4/2001
  643. //
  644. // if (!IsTerminalServicesEnabled()) // REMOVE:REV 10/4/2001
  645. {
  646. InvalidateRect(hhTerm->hwnd, &rc, FALSE);
  647. fUpdate = TRUE;
  648. }
  649. fBlinks = TRUE;
  650. }
  651. }
  652. // Should draw here. Reason: if line 1 had a blinker and line 24
  653. // had a blinker, we would have to repaint the whole terminal window
  654. // since windows combines invalid regions.
  655. if (fUpdate)
  656. UpdateWindow(hhTerm->hwnd);
  657. hhTerm->abBlink[r] = (BYTE)fUpdate;
  658. }
  659. if (fBlinks == FALSE)
  660. hhTerm->iBlink = 0;
  661. return;
  662. }
  663. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  664. * FUNCTION:
  665. * RefreshTernWindow
  666. *
  667. * DESCRIPTION:
  668. * Calls the WM_SIZE code for terminal window
  669. *
  670. * ARGUMENTS:
  671. * hwnd - Terminal Window to refresh
  672. *
  673. * RETURNS:
  674. * void
  675. *
  676. */
  677. void RefreshTermWindow(const HWND hwndTerm)
  678. {
  679. RECT rc;
  680. const HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwndTerm, GWLP_USERDATA);
  681. if (hhTerm) // need to check validatity of handle. mrw:3/1/95
  682. {
  683. TP_WM_SIZE(hhTerm->hwnd, 0, 0, 0); // mrw:11/3/95
  684. GetClientRect(hwndTerm, &rc);
  685. TP_WM_SIZE(hhTerm->hwnd, 0, rc.right, rc.bottom);
  686. InvalidateRect(hwndTerm, 0, FALSE);
  687. }
  688. return;
  689. }
  690. //mpt:1-23-98 attempt to re-enable DBCS code
  691. //#if 0
  692. #ifndef CHAR_NARROW
  693. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  694. * FUNCTION:
  695. * termValidatePosition
  696. *
  697. * DESCRIPTION:
  698. * Checks the marking cursor position information in the HHTERM struct and
  699. * determines if it is valid by checking the underlying characters to see if
  700. * the cursor would split a double byte character. It optionally adjusts
  701. * the position to a valid position.
  702. *
  703. * ARGUMENTS:
  704. * hhTerm -- internal terminal data structure
  705. * nAdjustmentMode -- one of the following values:
  706. * VP_NO_ADJUSTMENT
  707. * VP_ADJUST_RIGHT
  708. * VP_ADJUST_LEFT
  709. *
  710. * RETURNS:
  711. * TRUE if the input values are OK, otherwise FALSE. Note that the adjust
  712. * parameter and any actions performed do not alter the return value.
  713. *
  714. */
  715. BOOL termValidatePosition(const HHTERM hhTerm,
  716. const int nAdjustmentMode,
  717. POINT *pLocation)
  718. {
  719. BOOL bRet = TRUE;
  720. if (pLocation->y <= 0)
  721. return TRUE;
  722. if ( hhTerm->fppstAttr[pLocation->y - 1][pLocation->x].wirt == TRUE )
  723. {
  724. switch (nAdjustmentMode)
  725. {
  726. case VP_ADJUST_RIGHT:
  727. if ( pLocation->x < hhTerm->iCols )
  728. {
  729. DbgOutStr("incrementing %d\r\n", pLocation->x, 0,0,0,0);
  730. pLocation->x++;
  731. bRet = FALSE;
  732. }
  733. break;
  734. case VP_ADJUST_LEFT:
  735. if (pLocation->x > 0)
  736. {
  737. DbgOutStr("decrementing %d\r\n", pLocation->x, 0,0,0,0);
  738. pLocation->x--;
  739. bRet = FALSE;
  740. }
  741. break;
  742. default:
  743. break;
  744. }
  745. }
  746. return bRet;
  747. }
  748. #endif // !CHAR_NARROW
  749. #if 0 //DEADWOOD
  750. BOOL bRet = TRUE;
  751. int bLeadByteSeen;
  752. int nOffset;
  753. LONG lIndx;
  754. LPTSTR pszStr = (LPTSTR)NULL;
  755. /*
  756. * This function just doesn't work correctly. The reason for that is
  757. * that I don't understand how the lines are organized and indexed in
  758. * the terminal. For now, this works OK if you just have a few lines
  759. * on the terminal screen for testing. Nothing in the backscroll. I
  760. * have no idea what other problems it has.
  761. *
  762. * DLW (17-Aug-1994)
  763. *
  764. * OK, I have made some attempt to get this stuff working correctly.
  765. * At least it doesn't seg anymore and seems to work most of the time.
  766. * I know that it still screws up when the scroll numbers are not just
  767. * right, so it is pretty obvious that it still is not what it should
  768. * be. So, it still needs to be checked by someone who knows what they
  769. * are doing (which leaves me out).
  770. *
  771. * DLW (18-Aug-1994)
  772. */
  773. nOffset = 0;
  774. if (pLocation->y <= 0)
  775. {
  776. nOffset = hhTerm->iPhysicalBkRows + hhTerm->iNextBkLn + pLocation->y;
  777. nOffset %= hhTerm->iPhysicalBkRows;
  778. pszStr = (LPTSTR)hhTerm->fplpstrBkTxt[nOffset];
  779. }
  780. else if (pLocation->y > 0)
  781. {
  782. nOffset = pLocation->y - 1;
  783. pszStr = (LPTSTR)hhTerm->fplpstrTxt[nOffset];
  784. }
  785. assert(pszStr);
  786. if (pszStr == (LPTSTR)NULL)
  787. return FALSE;
  788. /*
  789. * We need to loop thru the string and check if the last character before
  790. * the specified character is a DBCS lead byte. If it is, we return FALSE
  791. * and perform any requested adjustment.
  792. */
  793. bLeadByteSeen = FALSE;
  794. for (lIndx = 0; lIndx < pLocation->x; lIndx += 1)
  795. {
  796. if (bLeadByteSeen)
  797. {
  798. /* The rule is that a lead byte can NEVER follow a lead byte */
  799. bLeadByteSeen = FALSE;
  800. }
  801. else
  802. {
  803. bLeadByteSeen = IsDBCSLeadByte(pszStr[lIndx]);
  804. }
  805. }
  806. if (lIndx == pLocation->x)
  807. {
  808. bRet = !bLeadByteSeen;
  809. }
  810. if (!bRet)
  811. {
  812. switch (nAdjustmentMode)
  813. {
  814. case VP_ADJUST_RIGHT:
  815. DbgOutStr("incrementing %d\r\n", pLocation->x, 0,0,0,0);
  816. /* TODO: range check this first */
  817. pLocation->x += 1;
  818. break;
  819. case VP_ADJUST_LEFT:
  820. DbgOutStr("decrementing %d\r\n", pLocation->x, 0,0,0,0);
  821. /* TODO: range check this first */
  822. pLocation->x -= 1;
  823. break;
  824. default:
  825. break;
  826. }
  827. }
  828. return bRet;
  829. }
  830. #endif
  831. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  832. * FUNCTION:
  833. * termGetLogFont
  834. *
  835. * DESCRIPTION:
  836. * This is here to handle a problem with calling send message in
  837. * the minitel load routines.
  838. *
  839. * ARGUMENTS:
  840. * hwndTerm - Terminal Window
  841. *
  842. * RETURNS:
  843. * 0=OK
  844. *
  845. * AUTHOR: mrw,2/21/95
  846. *
  847. */
  848. int termGetLogFont(const HWND hwndTerm, LPLOGFONT plf)
  849. {
  850. HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwndTerm, GWLP_USERDATA);
  851. assert(plf != 0);
  852. if (hhTerm == 0)
  853. return -1; // mrw:6/15/95
  854. *plf = hhTerm->lf;
  855. return 0;
  856. }
  857. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  858. * FUNCTION:
  859. * termSetLogFont
  860. *
  861. * DESCRIPTION:
  862. * This is here to handle a problem with calling send message in
  863. * the minitel load routines.
  864. *
  865. * ARGUMENTS:
  866. * hwndTerm - Terminal Window
  867. *
  868. * RETURNS:
  869. * 0=OK
  870. *
  871. * AUTHOR: mrw,2/21/95
  872. *
  873. */
  874. int termSetLogFont(const HWND hwndTerm, LPLOGFONT plf)
  875. {
  876. HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwndTerm, GWLP_USERDATA);
  877. assert(plf != 0);
  878. if (hhTerm == 0) // mrw,3/2/95
  879. return -1;
  880. hhTerm->lfHold = *plf;
  881. PostMessage(hwndTerm, WM_TERM_KLUDGE_FONT, 0, 0);
  882. return 0;
  883. }