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.

737 lines
23 KiB

  1. /****************************Module*Header***********************************\
  2. * Module Name: SCICOMM.C
  3. *
  4. * Module Descripton:
  5. *
  6. * Warnings:
  7. *
  8. * Created:
  9. *
  10. * Author:
  11. \****************************************************************************/
  12. #include "scicalc.h"
  13. #include "calchelp.h"
  14. #include "unifunc.h"
  15. #include "input.h"
  16. #include "strsafe.h"
  17. extern HWND hStatBox;
  18. extern HNUMOBJ ghnoNum, ghnoLastNum, ghnoMem;
  19. extern HNUMOBJ ghnoParNum[25], ghnoPrecNum[25];
  20. extern eNUMOBJ_FMT nFE;
  21. extern INT nTempCom, nParNum, nPrecNum, gcIntDigits,
  22. nOpCode, nOp[25], nPrecOp[25];
  23. extern BOOL bError;
  24. extern TCHAR szBlank[6];
  25. extern TCHAR *rgpsz[CSTRINGS];
  26. int nLastCom; // Last command entered.
  27. CALCINPUTOBJ gcio; // Global calc input object for decimal strings
  28. BOOL gbRecord; // Global mode: recording or displaying
  29. /* Puts up the wait cursor if the calc will take a long time */
  30. HCURSOR ghcurOld = NULL;
  31. BOOL SetWaitCursor( BOOL fOn ) {
  32. if (fOn && ghcurOld == NULL) {
  33. ghcurOld = SetCursor( LoadCursor(NULL, IDC_WAIT) );
  34. } else if (!fOn && ghcurOld != NULL) {
  35. SetCursor( ghcurOld );
  36. ghcurOld = NULL;
  37. }
  38. return (fOn && ghcurOld != NULL);
  39. }
  40. /* Process all keyclicks whether by mouse or accelerator. */
  41. VOID NEAR RealProcessCommands(WPARAM wParam);
  42. VOID NEAR ProcessCommands(WPARAM wParam)
  43. {
  44. if (wParam != IDM_ABOUT)
  45. {
  46. TimeCalc(TRUE);
  47. }
  48. try
  49. {
  50. RealProcessCommands( wParam );
  51. }
  52. catch( ... )
  53. {
  54. // note: it should be impossible for a throw to reach this level, this is put here as an
  55. // emergency backup only. Throws are normally caught at the boundry between calc and ratpak.
  56. ASSERT( 0 );
  57. MessageBox( g_hwndDlg, TEXT("An unknown error has occured."), TEXT("Error"), MB_OK );
  58. }
  59. if (wParam != IDM_ABOUT)
  60. {
  61. TimeCalc(FALSE);
  62. }
  63. }
  64. VOID NEAR RealProcessCommands(WPARAM wParam)
  65. {
  66. static BOOL bNoPrevEqu=TRUE, /* Flag for previous equals. */
  67. bChangeOp=FALSE; /* Flag for changing operation. */
  68. INT nx, ni;
  69. TCHAR szJunk[50], szTemp[50];
  70. static BYTE rgbPrec[24]={ 0,0, IDC_OR,0, IDC_XOR,0, IDC_AND,1,
  71. IDC_ADD,2, IDC_SUB,2, RSHF,3, IDC_LSHF,3,
  72. IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, IDC_PWR,4};
  73. // Make sure we're only getting commands we understand.
  74. ASSERT( xwParam(IDC_FIRSTCONTROL, IDC_LASTCONTROL) || // Is it a button?
  75. xwParam(IDM_FIRSTMENU, IDM_LASTMENU) ); // or a menu command?
  76. // Save the last command. Some commands are not saved in this manor, these
  77. // commands are:
  78. // Inv, Hyp, Deg, Rad, Grad, Stat, FE, MClear, Back, and Exp. The excluded
  79. // commands are not
  80. // really mathematical operations, rather they are GUI mode settings.
  81. if ( !xwParam(IDC_INV, IDC_HYP) && !xwParam(IDM_HEX, IDM_BIN) &&
  82. !xwParam(IDM_QWORD, IDM_BYTE) && !xwParam(IDM_DEG, IDM_GRAD) &&
  83. wParam!=IDC_STAT && wParam!=IDC_FE &&
  84. wParam!=IDC_MCLEAR && wParam!=IDC_BACK && wParam!=IDC_EXP)
  85. {
  86. nLastCom=nTempCom;
  87. nTempCom=(INT)wParam;
  88. }
  89. // If error and not a clear key or help key, BEEP.
  90. if (bError && (wParam !=IDC_CLEAR) && (wParam !=IDC_CENTR) &&
  91. (wParam != IDM_HELPTOPICS))
  92. {
  93. MessageBeep(0);
  94. return;
  95. }
  96. // Toggle Record/Display mode if appropriate.
  97. if (gbRecord)
  98. {
  99. if (xwParam(IDC_AND, IDC_MPLUS) ||
  100. xwParam(IDC_AVE, IDC_CLOSEP) ||
  101. xwParam(IDC_INV, IDC_HYP) ||
  102. xwParam(IDM_HEX, IDM_BIN) ||
  103. xwParam(IDM_QWORD, IDM_BYTE) ||
  104. xwParam(IDM_DEG, IDM_GRAD) ||
  105. wParam == IDM_PASTE)
  106. {
  107. gbRecord = FALSE;
  108. SetWaitCursor(TRUE);
  109. CIO_vConvertToNumObj(&ghnoNum, &gcio);
  110. DisplayNum(); // Causes 3.000 to shrink to 3. on first op.
  111. SetWaitCursor(FALSE);
  112. }
  113. }
  114. else
  115. {
  116. if ( xwParam(IDC_0, IDC_F) || wParam == IDC_PNT)
  117. {
  118. gbRecord = TRUE;
  119. CIO_vClear(&gcio);
  120. }
  121. }
  122. // Interpret digit keys.
  123. if (xwParam(IDC_0, IDC_F))
  124. {
  125. int iValue = (int)(wParam-IDC_0);
  126. // this is redundant, illegal keys are disabled
  127. if (iValue >= nRadix)
  128. {
  129. //ASSERT( 0 );
  130. MessageBeep(0);
  131. return;
  132. }
  133. if (!CIO_bAddDigit(&gcio, iValue))
  134. {
  135. MessageBeep(0);
  136. return;
  137. }
  138. DisplayNum();
  139. return;
  140. }
  141. // STATISTICAL FUNCTIONS:
  142. if (xwParam(IDC_AVE,IDC_DATA))
  143. {
  144. /* Do statistics functions on data in fpStatNum array. */
  145. if (hStatBox)
  146. {
  147. DisplayNum(); // Make sure gpszNum has the correct string
  148. try
  149. {
  150. StatFunctions (wParam);
  151. }
  152. catch ( ... )
  153. {
  154. ASSERT( 0 ); // the only thing stat box should be able to throw is out of memory
  155. // which in previous versions of calc caused a program crash
  156. }
  157. if (!bError)
  158. DisplayNum ();
  159. }
  160. else
  161. /* Beep if the stat box is not active. */
  162. MessageBeep(0);
  163. /* Reset the inverse flag since some functions use it. */
  164. SetBox (IDC_INV, bInv=FALSE);
  165. return;
  166. }
  167. // BINARY OPERATORS:
  168. if (xwParam(IDC_AND,IDC_PWR))
  169. {
  170. if (bInv && wParam==IDC_LSHF)
  171. {
  172. SetBox (IDC_INV, bInv=FALSE);
  173. wParam=RSHF;
  174. }
  175. /* Change the operation if last input was operation. */
  176. if (nLastCom >=IDC_AND && nLastCom <=IDC_PWR)
  177. {
  178. nOpCode=(INT)wParam;
  179. return;
  180. }
  181. /* bChangeOp is true if there was an operation done and the */
  182. /* current ghnoNum is the result of that operation. This is so */
  183. /* entering 3+4+5= gives 7 after the first + and 12 after the */
  184. /* the =. The rest of this stuff attempts to do precedence in*/
  185. /* Scientific mode. */
  186. if (bChangeOp)
  187. {
  188. DoPrecedenceCheckAgain:
  189. nx=0;
  190. while (wParam!=rgbPrec[nx*2] && nx <12)
  191. nx++;
  192. ni=0;
  193. while (nOpCode!=rgbPrec[ni*2] && ni <12)
  194. ni++;
  195. if (nx==12) nx=0;
  196. if (ni==12) ni=0;
  197. if (rgbPrec[nx*2+1] > rgbPrec[ni*2+1] && nCalc==0)
  198. {
  199. if (nPrecNum <25)
  200. {
  201. NumObjAssign( &ghnoPrecNum[nPrecNum], ghnoLastNum );
  202. nPrecOp[nPrecNum]=nOpCode;
  203. }
  204. else
  205. {
  206. nPrecNum=24;
  207. MessageBeep(0);
  208. }
  209. nPrecNum++;
  210. }
  211. else
  212. {
  213. /* do the last operation and then if the precedence array is not
  214. * empty or the top is not the '(' demarcator then pop the top
  215. * of the array and recheck precedence against the new operator
  216. */
  217. SetWaitCursor(TRUE);
  218. DoOperation(nOpCode, &ghnoNum, ghnoLastNum);
  219. SetWaitCursor(FALSE);
  220. if ((nPrecNum !=0) && (nPrecOp[nPrecNum-1]))
  221. {
  222. nPrecNum--;
  223. nOpCode=nPrecOp[nPrecNum] ;
  224. if (NumObjOK( ghnoPrecNum[nPrecNum] ))
  225. NumObjAssign(&ghnoLastNum , ghnoPrecNum[nPrecNum]);
  226. else
  227. NumObjAssign(&ghnoLastNum, HNO_ZERO);
  228. goto DoPrecedenceCheckAgain ;
  229. }
  230. if (!bError)
  231. DisplayNum ();
  232. }
  233. }
  234. NumObjAssign(&ghnoLastNum, ghnoNum);
  235. NumObjAssign(&ghnoNum, HNO_ZERO);
  236. nOpCode=(INT)wParam;
  237. bNoPrevEqu=bChangeOp=TRUE;
  238. return;
  239. }
  240. // UNARY OPERATORS:
  241. if (xwParam(IDC_CHOP,IDC_PERCENT))
  242. {
  243. /* Functions are unary operations. */
  244. /* If the last thing done was an operator, ghnoNum was cleared. */
  245. /* In that case we better use the number before the operator */
  246. /* was entered, otherwise, things like 5+ 1/x give Divide By */
  247. /* zero. This way 5+=gives 10 like most calculators do. */
  248. if (nLastCom >= IDC_AND && nLastCom <= IDC_PWR)
  249. NumObjAssign( &ghnoNum, ghnoLastNum );
  250. SetWaitCursor(TRUE);
  251. SciCalcFunctions ( &ghnoNum, (DWORD)wParam);
  252. SetWaitCursor(FALSE);
  253. if (bError)
  254. return;
  255. /* Display the result, reset flags, and reset indicators. */
  256. DisplayNum ();
  257. /* reset the bInv and bHyp flags and indicators if they are set
  258. and have been used */
  259. if (bInv &&
  260. (wParam == IDC_CHOP || wParam == IDC_SIN || wParam == IDC_COS ||
  261. wParam == IDC_TAN || wParam == IDC_SQR || wParam == IDC_CUB ||
  262. wParam == IDC_LOG || wParam == IDC_LN || wParam == IDC_DMS))
  263. {
  264. bInv=FALSE;
  265. SetBox (IDC_INV, FALSE);
  266. }
  267. if (bHyp &&
  268. (wParam == IDC_SIN || wParam == IDC_COS || wParam == IDC_TAN))
  269. {
  270. bHyp = FALSE;
  271. SetBox (IDC_HYP, FALSE);
  272. }
  273. bNoPrevEqu=TRUE;
  274. return;
  275. }
  276. // BASE CHANGES:
  277. if (xwParam(IDM_HEX, IDM_BIN))
  278. {
  279. // Change radix and update display.
  280. if (nCalc==1)
  281. {
  282. wParam=IDM_DEC;
  283. }
  284. SetRadix((DWORD)wParam);
  285. return;
  286. }
  287. SetWaitCursor(TRUE);
  288. /* Now branch off to do other commands and functions. */
  289. switch(wParam)
  290. {
  291. case IDM_COPY:
  292. case IDM_PASTE:
  293. case IDM_ABOUT:
  294. case IDM_SC:
  295. case IDM_SSC:
  296. case IDM_USE_SEPARATOR:
  297. case IDM_HELPTOPICS:
  298. // Jump to menu command handler in scimenu.c.
  299. MenuFunctions((DWORD)wParam);
  300. DisplayNum();
  301. break;
  302. case IDC_CLEAR: /* Total clear. */
  303. NumObjAssign( &ghnoLastNum, HNO_ZERO );
  304. nPrecNum=nTempCom=nLastCom=nOpCode=nParNum=bChangeOp=FALSE;
  305. nFE = FMT_FLOAT; // back to the default number format
  306. bNoPrevEqu=TRUE;
  307. /* clear the paranthesis status box indicator, this will not be
  308. cleared for CENTR */
  309. SetDlgItemText(g_hwndDlg, IDC_PARTEXT, szBlank);
  310. /* fall through */
  311. case IDC_CENTR: /* Clear only temporary values. */
  312. NumObjAssign( &ghnoNum, HNO_ZERO );
  313. if (!nCalc)
  314. {
  315. // Clear the INV, HYP indicators & leave (=xx indicator active
  316. SetBox (IDC_INV, bInv=FALSE);
  317. SetBox (IDC_HYP, bHyp=FALSE);
  318. }
  319. bError=FALSE;
  320. CIO_vClear(&gcio);
  321. gbRecord = TRUE;
  322. DisplayNum ();
  323. break;
  324. case IDC_STAT: /* Shift focus to Statistix Box if it's active. */
  325. if (hStatBox)
  326. SetFocus(hStatBox);
  327. else
  328. SetStat (TRUE);
  329. break;
  330. case IDC_BACK:
  331. // Divide number by the current radix and truncate.
  332. // Only allow backspace if we're recording.
  333. if (gbRecord)
  334. {
  335. if (!CIO_bBackspace(&gcio))
  336. MessageBeep(0);
  337. DisplayNum();
  338. }
  339. else
  340. MessageBeep(0);
  341. break;
  342. /* EQU enables the user to press it multiple times after and */
  343. /* operation to enable repeats of the last operation. I don't */
  344. /* know if I can explain what the [censored] I did here... */
  345. case IDC_EQU:
  346. do {
  347. // NOTE: the number pointed to by hnoHold won't get freed until process termination.
  348. static HNUMOBJ hnoHold;
  349. /* Last thing keyed in was an operator. Lets do the op on*/
  350. /* a duplicate of the last entry. */
  351. if ((nLastCom >= IDC_AND) && (nLastCom <= IDC_PWR))
  352. NumObjAssign( &ghnoNum, ghnoLastNum );
  353. if (nOpCode) /* Is there a valid operation around? */
  354. {
  355. /* If this is the first EQU in a string, set hnoHold=ghnoNum */
  356. /* Otherwise let ghnoNum=hnoTemp. This keeps ghnoNum constant */
  357. /* through all EQUs in a row. */
  358. if (bNoPrevEqu)
  359. NumObjAssign(&hnoHold, ghnoNum);
  360. else
  361. NumObjAssign(&ghnoNum, hnoHold);
  362. /* Do the current or last operation. */
  363. DoOperation (nOpCode, &ghnoNum, ghnoLastNum);
  364. NumObjAssign(&ghnoLastNum, ghnoNum );
  365. /* Check for errors. If this wasn't done, DisplayNum */
  366. /* would immediately overwrite any error message. */
  367. if (!bError)
  368. DisplayNum ();
  369. /* No longer the first EQU. */
  370. bNoPrevEqu=FALSE;
  371. }
  372. else if (!bError)
  373. DisplayNum();
  374. if (nPrecNum==0 || nCalc==1)
  375. break;
  376. nOpCode=nPrecOp[--nPrecNum];
  377. if (NumObjOK( ghnoPrecNum[nPrecNum] ))
  378. NumObjAssign(&ghnoLastNum , ghnoPrecNum[nPrecNum]);
  379. else
  380. NumObjAssign(&ghnoLastNum, HNO_ZERO);
  381. bNoPrevEqu=TRUE;
  382. } while (nPrecNum >= 0);
  383. bChangeOp=FALSE;
  384. break;
  385. case IDC_OPENP:
  386. case IDC_CLOSEP:
  387. nx=0;
  388. if (wParam==IDC_OPENP)
  389. nx=1;
  390. // -IF- the Paren holding array is full and we try to add a paren
  391. // -OR- the paren holding array is empty and we try to remove a
  392. // paren
  393. // -OR- the the precidence holding array is full
  394. if ((nParNum >= 25 && nx) || (!nParNum && !nx)
  395. || ( (nPrecNum >= 25 && nPrecOp[nPrecNum-1]!=0) ) )
  396. {
  397. MessageBeep(0);
  398. break;
  399. }
  400. if (nx)
  401. {
  402. /* Open level of parentheses, save number and operation. */
  403. NumObjAssign( &ghnoParNum[nParNum], ghnoLastNum);
  404. nOp[nParNum++]=nOpCode;
  405. /* save a special marker on the precedence array */
  406. nPrecOp[nPrecNum++]=0 ;
  407. NumObjAssign( &ghnoLastNum, HNO_ZERO );
  408. nTempCom=0;
  409. nOpCode=IDC_ADD;
  410. }
  411. else
  412. {
  413. /* Get the operation and number and return result. */
  414. DoOperation (nOpCode, &ghnoNum, ghnoLastNum);
  415. /* now process the precedence stack till we get to an
  416. opcode which is zero. */
  417. while (nOpCode = nPrecOp[--nPrecNum])
  418. {
  419. if (NumObjOK( ghnoPrecNum[nPrecNum] ))
  420. NumObjAssign(&ghnoLastNum , ghnoPrecNum[nPrecNum]);
  421. else
  422. NumObjAssign(&ghnoLastNum, HNO_ZERO);
  423. DoOperation (nOpCode, &ghnoNum, ghnoLastNum);
  424. }
  425. /* now get back the operation and opcode at the begining
  426. of this paranthesis pair */
  427. nParNum -= 1;
  428. NumObjAssign( &ghnoLastNum, ghnoParNum[nParNum] );
  429. nOpCode=nOp[nParNum];
  430. /* if nOpCode is a valid operator then set bChangeOp to
  431. be true else set it false */
  432. if (nOpCode)
  433. bChangeOp=TRUE;
  434. else
  435. bChangeOp=FALSE ;
  436. }
  437. /* Set the "(=xx" indicator. */
  438. StringCchCopy(szJunk, ARRAYSIZE(szJunk), TEXT("(="));
  439. StringCchCat(szJunk, ARRAYSIZE(szJunk), UToDecT(nParNum, szTemp));
  440. SetDlgItemText(g_hwndDlg, IDC_PARTEXT,
  441. (nParNum) ? (szJunk) : (szBlank));
  442. if (bError)
  443. break;
  444. if (nx)
  445. {
  446. /* Build a display string of nParNum "("'s. */
  447. for (nx=0; nx < nParNum; nx++)
  448. szJunk[nx]=TEXT('(');
  449. szJunk[nx]=0; /* Null-terminate. */
  450. SetDisplayText(g_hwndDlg, szJunk);
  451. bChangeOp=FALSE;
  452. }
  453. else
  454. DisplayNum ();
  455. break;
  456. case IDM_QWORD:
  457. case IDM_DWORD:
  458. case IDM_WORD:
  459. case IDM_BYTE:
  460. case IDM_DEG:
  461. case IDM_RAD:
  462. case IDM_GRAD:
  463. if (!F_INTMATH())
  464. {
  465. // in decimal mode, these buttons simply set a flag which is
  466. // passed to the ratpak to handle angle conversions
  467. if (xwParam(IDM_DEG, IDM_GRAD))
  468. {
  469. nDecMode = (ANGLE_TYPE)(wParam - IDM_DEG);
  470. CheckMenuRadioItem(GetSubMenu(GetMenu(g_hwndDlg), 1),
  471. IDM_DEG, IDM_GRAD, IDM_DEG+nDecMode,
  472. MF_BYCOMMAND);
  473. CheckRadioButton(g_hwndDlg, IDC_DEG, IDC_GRAD,
  474. IDC_DEG+nDecMode);
  475. }
  476. }
  477. else
  478. {
  479. if (xwParam(IDM_DEG, IDM_GRAD))
  480. {
  481. // if in hex mode, but we got a decimal key press this
  482. // likely is the accelorator. map this to the correct key
  483. wParam=IDM_DWORD+(wParam-IDM_DEG);
  484. }
  485. if ( gbRecord )
  486. {
  487. CIO_vConvertToNumObj(&ghnoNum, &gcio);
  488. gbRecord = FALSE;
  489. }
  490. // Compat. mode BaseX: Qword, Dword, Word, Byte
  491. nHexMode = (int)(wParam - IDM_QWORD);
  492. switch (nHexMode)
  493. {
  494. case 0: dwWordBitWidth = 64; break;
  495. case 1: dwWordBitWidth = 32; break;
  496. case 2: dwWordBitWidth = 16; break;
  497. case 3: dwWordBitWidth = 8; break;
  498. default:
  499. ASSERT( 0 ); // Invalid Word Size
  500. break;
  501. }
  502. // different wordsize means the new wordsize determines
  503. // the precision
  504. BaseOrPrecisionChanged();
  505. CheckMenuRadioItem(GetSubMenu(GetMenu(g_hwndDlg), 1),
  506. IDM_QWORD, IDM_BYTE, IDM_QWORD+nHexMode,
  507. MF_BYCOMMAND);
  508. CheckRadioButton(g_hwndDlg, IDC_QWORD, IDC_BYTE,
  509. IDC_QWORD+nHexMode);
  510. }
  511. // REARCHITECT: the call to display number is what actually does the
  512. // chop. it would make more sense to do the chop here when the
  513. // wordsize changes. the chop must be done when a different
  514. // wordsize is selected AND when the base is changed to non-decimal
  515. DisplayNum();
  516. break;
  517. case IDC_SIGN:
  518. // Change the sign.
  519. if (gbRecord)
  520. CIO_vToggleSign(&gcio);
  521. else {
  522. NumObjNegate( &ghnoNum );
  523. }
  524. DisplayNum();
  525. break;
  526. case IDC_RECALL:
  527. /* Recall immediate memory value. */
  528. NumObjAssign( &ghnoNum, ghnoMem );
  529. DisplayNum ();
  530. break;
  531. case IDC_MPLUS:
  532. /* MPLUS adds ghnoNum to immediate memory and kills the "mem" */
  533. /* indicator if the result is zero. */
  534. addrat( &ghnoMem, ghnoNum);
  535. SetDlgItemText(g_hwndDlg,IDC_MEMTEXT,
  536. !NumObjIsZero(ghnoMem) ? (TEXT(" M")):(szBlank));
  537. break;
  538. case IDC_STORE:
  539. case IDC_MCLEAR:
  540. if (wParam==IDC_STORE)
  541. {
  542. NumObjAssign( &ghnoMem, ghnoNum );
  543. }
  544. else
  545. {
  546. NumObjAssign( &ghnoMem, HNO_ZERO );
  547. }
  548. SetDlgItemText(g_hwndDlg,IDC_MEMTEXT,
  549. !NumObjIsZero(ghnoMem) ? (TEXT(" M")):(szBlank));
  550. break;
  551. case IDC_PI:
  552. if (!F_INTMATH())
  553. {
  554. /* Return PI if bInv==FALSE, or 2PI if bInv==TRUE. */
  555. if (bInv)
  556. NumObjAssign( &ghnoNum, HNO_2PI );
  557. else
  558. NumObjAssign( &ghnoNum, HNO_PI );
  559. DisplayNum();
  560. SetBox(IDC_INV, bInv=FALSE);
  561. }
  562. else
  563. MessageBeep(0);
  564. break;
  565. case IDC_FE:
  566. // Toggle exponential notation display.
  567. nFE = NUMOBJ_FMT(!(int)nFE);
  568. DisplayNum();
  569. break;
  570. case IDC_EXP:
  571. if (gbRecord && !F_INTMATH())
  572. if (CIO_bExponent(&gcio))
  573. {
  574. DisplayNum();
  575. break;
  576. }
  577. MessageBeep(0);
  578. break;
  579. case IDC_PNT:
  580. if (gbRecord && !F_INTMATH()) {
  581. if (CIO_bAddDecimalPt(&gcio)) {
  582. DisplayNum();
  583. break;
  584. }
  585. }
  586. MessageBeep(0);
  587. break;
  588. case IDC_INV:
  589. SetBox((int)wParam, bInv=!bInv);
  590. break;
  591. case IDC_HYP:
  592. SetBox((int)wParam, bHyp=!bHyp);
  593. break;
  594. }
  595. SetWaitCursor(FALSE);
  596. }
  597. // change the display area from a static text to an editbox, which has the focus can make
  598. // Magnifer (Accessibility tool) work
  599. BOOL SetDisplayText(HWND hDlg, LPCTSTR szText)
  600. {
  601. HWND hDispEdit = GetDlgItem(hDlg, IDC_DISPLAY);
  602. int nLen = lstrlen(szText);
  603. SetWindowText(hDispEdit, szText);
  604. SetFocus(hDispEdit);
  605. // make sure the number just typed is shown at the center of Magnifier
  606. SendMessage(hDispEdit, EM_SETSEL, nLen, nLen);
  607. return TRUE;
  608. }