Source code of Windows XP (NT5)
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.

1314 lines
34 KiB

  1. /*
  2. * mouse - Dialog box property sheet for "mouse ui tweaks"
  3. */
  4. #include "tweakui.h"
  5. #pragma BEGIN_CONST_DATA
  6. KL const c_klDelay = { &c_hkCU, c_tszRegPathDesktop, c_tszDelay };
  7. const char CODESEG c_szUser[] = "USER"; /* Must be ANSI */
  8. const static DWORD CODESEG rgdwHelp[] = {
  9. IDC_SPEEDTEXT, IDH_SPEEDHELP,
  10. IDC_SPEEDFAST, IDH_SPEEDHELP,
  11. IDC_SPEEDSLOW, IDH_SPEEDHELP,
  12. IDC_SPEEDTRACK, IDH_SPEEDHELP,
  13. IDC_SPEEDHELP, IDH_SPEEDHELP,
  14. IDC_SENSGROUP, IDH_GROUP,
  15. IDC_DBLCLKTEXT, IDH_DBLCLK,
  16. IDC_DBLCLK, IDH_DBLCLK,
  17. IDC_DBLCLKUD, IDH_DBLCLK,
  18. IDC_DRAGTEXT, IDH_DRAG,
  19. IDC_DRAG, IDH_DRAG,
  20. IDC_DRAGUD, IDH_DRAG,
  21. IDC_SENSHELP, IDH_GROUP,
  22. IDC_EFFECTGROUP, IDH_GROUP,
  23. IDC_BEEP, IDH_BEEP,
  24. /* SOMEDAY - SPI_GETMOUSEHOVERHEIGHT/WIDTH */
  25. IDC_WHEELGROUP, IDH_GROUP,
  26. IDC_WHEELENABLE, IDH_WHEEL,
  27. IDC_WHEELPAGE, IDH_WHEEL,
  28. IDC_WHEELLINE, IDH_WHEEL,
  29. IDC_WHEELLINENO, IDH_WHEEL,
  30. IDC_TESTGROUP, IDH_TEST,
  31. IDC_TEST, IDH_TEST,
  32. IDC_XMOUSE, IDH_XMOUSE,
  33. IDC_XMOUSERAISE, IDH_XMOUSERAISE,
  34. IDC_XMOUSEDELAYTXT, IDH_XMOUSEDELAY,
  35. IDC_XMOUSEDELAY, IDH_XMOUSEDELAY,
  36. IDC_TIPS, IDH_TIPSTIP,
  37. IDC_RESET, IDH_RESET,
  38. 0, 0,
  39. };
  40. #pragma END_CONST_DATA
  41. typedef WORD DT, FAR *LPDT; /* typeof(dtMNDropDown) */
  42. #ifdef WIN32
  43. #define fLpdt (lpdt != &dtScratch)
  44. #else
  45. #define fLpdt (SELECTOROF(lpdt) != SELECTOROF((LPDT)&dtScratch))
  46. #endif
  47. /*
  48. * Globals
  49. */
  50. DT dtScratch; /* Point lpdt here if we are stuck */
  51. DT dtNT; /* Point lpdt here if we are on NT */
  52. LPDT lpdt; /* Where to tweak to adjust the actual dt */
  53. /*
  54. * Instanced. We're a cpl so have only one instance, but I declare
  55. * all the instance stuff in one place so it's easy to convert this
  56. * code to multiple-instance if ever we need to.
  57. */
  58. typedef struct MDII { /* Mouse_dialog instance info */
  59. BOOL fDrag; /* Potential drag in progress? */
  60. DT dtOrig; /* Original dt when we started */
  61. RECT rcTest; /* Test area */
  62. RECT rcDrag; /* Drag test rectangle */
  63. RECT rcDblClk; /* Double click rectangle */
  64. LONG tmClick; /* Time of previous lbutton down */
  65. HCURSOR hcurDrag; /* What is being dragged? */
  66. BOOL fFactory; /* Factory defaults? */
  67. POINT ptDblClk; /* Double click values pending */
  68. POINT ptDrag; /* Drag values pending */
  69. POINT ptDragStart; /* Where the start click went down */
  70. int cxAspect; /* Screen aspect ratio */
  71. int cyAspect; /* Screen aspect ratio */
  72. int idi; /* Which icon to use? */
  73. } MDII, *PMDII;
  74. MDII mdii;
  75. #define pmdii (&mdii)
  76. #define DestroyCursor(hcur) SafeDestroyIcon((HICON)(hcur))
  77. /*****************************************************************************
  78. *
  79. * Grovelling to find the dropmenu variable.
  80. *
  81. *****************************************************************************/
  82. /*****************************************************************************
  83. *
  84. * dtDefault
  85. *
  86. * Return the default dropmenu time, which is DoubleClickTime * 4 / 5.
  87. *
  88. *****************************************************************************/
  89. DT PASCAL
  90. dtDefault(void)
  91. {
  92. return GetDoubleClickTime() * 4 / 5;
  93. }
  94. /*****************************************************************************
  95. *
  96. * dtCur
  97. *
  98. * Determine what the dropmenu time is, by external means.
  99. *
  100. * It ought to be DoubleClickTime * 4 / 5, or the value in the registry.
  101. *
  102. *****************************************************************************/
  103. INLINE DT
  104. dtCur(void)
  105. {
  106. return (DT)GetIntPkl(dtDefault(), &c_klDelay);
  107. }
  108. /*****************************************************************************
  109. *
  110. * GetProcOrd
  111. *
  112. * Win95 does not allow GetProcAddress to work on Kernel32, so we must
  113. * implement it by hand.
  114. *
  115. *****************************************************************************/
  116. /*
  117. * winnt.h uses these strange structure names.
  118. * Does anybody speak Hungarian over there?
  119. */
  120. typedef IMAGE_DOS_HEADER IDH, *PIDH;
  121. typedef IMAGE_NT_HEADERS NTH, *PINTH; /* I like how this is "HEADERS" plural */
  122. typedef IMAGE_EXPORT_DIRECTORY EDT, *PEDT;
  123. typedef DWORD EAT, *PEAT;
  124. typedef IMAGE_DATA_DIRECTORY OTE, *POTE;
  125. #define pvAdd(pv, cb) ((LPVOID)((LPSTR)(pv) + (DWORD)(cb)))
  126. #define pvSub(pv1, pv2) (DWORD)((LPSTR)(pv1) - (LPSTR)(pv2))
  127. #define poteExp(pinth) (&(pinth)->OptionalHeader. \
  128. DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT])
  129. FARPROC PASCAL
  130. GetProcOrd(LPVOID lpv, UINT ord)
  131. {
  132. PIDH pidh = (PIDH)lpv;
  133. if (!IsBadReadPtr(pidh, sizeof(*pidh)) &&
  134. pidh->e_magic == IMAGE_DOS_SIGNATURE) {
  135. PINTH pinth = (PINTH)pvAdd(pidh, pidh->e_lfanew);
  136. if (!IsBadReadPtr(pinth, sizeof(*pinth)) &&
  137. pinth->Signature == IMAGE_NT_SIGNATURE) {
  138. PEDT pedt = (PEDT)pvAdd(pidh, poteExp(pinth)->VirtualAddress);
  139. if (!IsBadReadPtr(pedt, sizeof(*pedt)) &&
  140. (ord - pedt->Base) < pedt->NumberOfFunctions) {
  141. PEAT peat = (PEAT)pvAdd(pidh, pedt->AddressOfFunctions);
  142. FARPROC fp = (FARPROC)pvAdd(pidh, peat[ord - pedt->Base]);
  143. if (pvSub(fp, peat) >= poteExp(pinth)->Size) {
  144. return fp;
  145. } else { /* Forwarded!? */
  146. return 0;
  147. }
  148. } else {
  149. return 0;
  150. }
  151. } else {
  152. return 0;
  153. }
  154. } else {
  155. return 0;
  156. }
  157. }
  158. /*****************************************************************************
  159. *
  160. * fGrovel
  161. *
  162. * Grovel into USER's DS to find the dropmenu time.
  163. * The problem is that there is no documented way of getting and setting
  164. * the dropmenu time without rebooting. So we find it by (trust me)
  165. * disassembling the SetDoubleClickTime function and knowing that the
  166. * last instructions are
  167. *
  168. * mov [xxxx], ax ; set drop menu time
  169. * pop ds
  170. * leave
  171. * retf 2
  172. *
  173. * Good news! On Windows NT, there is a new SPI to do this.
  174. *
  175. *****************************************************************************/
  176. typedef HINSTANCE (*LL16)(LPCSTR);
  177. typedef FARPROC (*GPA16)(HINSTANCE, LPCSTR);
  178. typedef BOOL (*FL16)(HINSTANCE);
  179. typedef LPVOID (*MSL)(DWORD);
  180. BOOL PASCAL
  181. fGrovel(void)
  182. {
  183. OSVERSIONINFO ovi;
  184. if (SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &dtNT, 0)) {
  185. lpdt = &dtNT;
  186. return 1;
  187. }
  188. #ifdef _X86_
  189. /* Else win95 - must grovel */
  190. ovi.dwOSVersionInfoSize = sizeof(ovi);
  191. if (GetVersionEx(&ovi) &&
  192. ovi.dwMajorVersion == 4 &&
  193. ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
  194. HINSTANCE hinstK32 = GetModuleHandle(c_tszKernel32);
  195. if (hinstK32) {
  196. LL16 LoadLibrary16 = (LL16)GetProcOrd(hinstK32, 35);
  197. FL16 FreeLibrary16 = (FL16)GetProcOrd(hinstK32, 36);
  198. GPA16 GetProcAddress16 = (GPA16)GetProcOrd(hinstK32, 37);
  199. MSL MapSL = (MSL)GetProcAddress(hinstK32, c_tszMapSL);
  200. if ((DWORD)LoadLibrary16 & (DWORD)FreeLibrary16 &
  201. (DWORD)GetProcAddress16 & (DWORD)MapSL) {
  202. HINSTANCE hinst16 = LoadLibrary16(c_szUser);
  203. if ((UINT)hinst16 > 32) {
  204. FARPROC fp = GetProcAddress16(hinst16,
  205. MAKEINTRESOURCE(20));
  206. if (fp) {
  207. LPBYTE lpSDCT;
  208. GetDoubleClickTime(); /* Force segment present */
  209. lpSDCT = (LPBYTE)MapSL((DWORD)fp);
  210. if (!IsBadReadPtr(lpSDCT, 84)) {
  211. int i;
  212. for (i = 0; i < 80; i++, lpSDCT++) {
  213. if (*(LPDWORD)lpSDCT == 0x02CAC91F) {
  214. lpdt = (LPDT)MapSL(MAKELONG(
  215. *(LPWORD)(lpSDCT - 2),
  216. hinst16));
  217. return *lpdt == dtCur();
  218. }
  219. }
  220. }
  221. }
  222. FreeLibrary16(hinst16);
  223. }
  224. }
  225. }
  226. }
  227. #endif
  228. return 0;
  229. }
  230. /*****************************************************************************
  231. *
  232. * msDt
  233. *
  234. * Get the actual drop time if possible. Don't all this unless
  235. * you know it'll work.
  236. *
  237. *****************************************************************************/
  238. DT PASCAL
  239. msDt(void)
  240. {
  241. if (lpdt == &dtNT) {
  242. SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &dtNT, 0);
  243. }
  244. return (DT)*lpdt;
  245. }
  246. /*****************************************************************************
  247. *
  248. * SetDt
  249. *
  250. * Set the drop time, returning TRUE if we need a reboot.
  251. *
  252. *****************************************************************************/
  253. BOOL PASCAL
  254. SetDt(UINT ms, DWORD spif)
  255. {
  256. #ifdef _X86_
  257. if (lpdt == &dtNT) {
  258. #endif
  259. SystemParametersInfo(SPI_SETMENUSHOWDELAY, ms, 0, spif);
  260. return 0;
  261. #ifdef _X86_
  262. } else {
  263. if (spif & SPIF_UPDATEINIFILE) {
  264. SetIntPkl(pmdii->dtOrig, &c_klDelay);
  265. }
  266. if (fLpdt) {
  267. *lpdt = (WORD)ms;
  268. return 0;
  269. } else {
  270. return 1;
  271. }
  272. }
  273. #endif
  274. }
  275. /*****************************************************************************
  276. *
  277. * fXMouse
  278. *
  279. * Determine whether XMouse is enabled.
  280. *
  281. * Returns 0 if disabled, 1 if enabled, or -1 if not supported.
  282. *
  283. * Note that there are *two* ways of getting this information,
  284. * depending on which flavor of NT/Win9x we are running. So
  285. * try all of them until one of them works.
  286. *
  287. *****************************************************************************/
  288. BOOL PASCAL
  289. fXMouse(void)
  290. {
  291. BOOL fX;
  292. if (SystemParametersInfo(SPI_GETUSERPREFERENCE,
  293. SPI_UP_ACTIVEWINDOWTRACKING, &fX, 0)) {
  294. return fX != 0;
  295. } else if (SystemParametersInfo(SPI_GETACTIVEWINDOWTRACKING,
  296. 0, &fX, 0)) {
  297. return fX != 0;
  298. } else {
  299. return -1;
  300. }
  301. }
  302. /*****************************************************************************
  303. *
  304. * SetXMouse
  305. *
  306. * Set the XMouse feature.
  307. *
  308. *****************************************************************************/
  309. INLINE void
  310. SetXMouse(BOOL f)
  311. {
  312. if (SystemParametersInfo(SPI_SETUSERPREFERENCE,
  313. SPI_UP_ACTIVEWINDOWTRACKING, IntToPtr(f),
  314. SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)) {
  315. } else {
  316. SystemParametersInfo(SPI_SETACTIVEWINDOWTRACKING,
  317. 0, IntToPtr(f), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
  318. }
  319. }
  320. /*****************************************************************************
  321. *
  322. * msXMouseDelay
  323. *
  324. * Returns the XMouse hover delay, or -1 if not supported.
  325. *
  326. *****************************************************************************/
  327. int
  328. msXMouseDelay(void)
  329. {
  330. DWORD dw;
  331. if (SystemParametersInfo(SPI_GETACTIVEWNDTRKTIMEOUT, 0, &dw, 0)) {
  332. return (int)dw;
  333. }
  334. return -1;
  335. }
  336. /*****************************************************************************
  337. *
  338. * SetXMouseDelay
  339. *
  340. *****************************************************************************/
  341. INLINE void
  342. SetXMouseDelay(int msDelay)
  343. {
  344. SystemParametersInfo(SPI_SETACTIVEWNDTRKTIMEOUT, 0, IntToPtr(msDelay),
  345. SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
  346. }
  347. /*****************************************************************************
  348. *
  349. * fXMouseRaise
  350. *
  351. * Returns 0 if autoraise disabled, 1 if enabled, or -1 if not supported.
  352. *
  353. *****************************************************************************/
  354. BOOL PASCAL
  355. fXMouseRaise(void)
  356. {
  357. BOOL f;
  358. if (SystemParametersInfo(SPI_GETACTIVEWNDTRKZORDER, 0, &f, 0)) {
  359. return f != 0;
  360. } else {
  361. return -1;
  362. }
  363. }
  364. /*****************************************************************************
  365. *
  366. * SetXMouseRaise
  367. *
  368. * Set the XMouse autoraise feature.
  369. *
  370. *****************************************************************************/
  371. INLINE void
  372. SetXMouseRaise(BOOL f)
  373. {
  374. SystemParametersInfo(SPI_SETACTIVEWNDTRKZORDER, 0, IntToPtr(f),
  375. SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
  376. }
  377. /*****************************************************************************
  378. *
  379. * cxDragCur
  380. *
  381. * Return the current horizontal drag sensitivity.
  382. *
  383. *****************************************************************************/
  384. INLINE int
  385. cxDragCur(void)
  386. {
  387. return GetSystemMetrics(SM_CXDRAG);
  388. }
  389. /*****************************************************************************
  390. *
  391. * SetCxCyDrag
  392. *
  393. * Set the new horizontal and vertical drag tolerances.
  394. *
  395. *****************************************************************************/
  396. INLINE void
  397. SetCxCyDrag(int cxDrag, int cyDrag)
  398. {
  399. SystemParametersInfo(SPI_SETDRAGWIDTH, (UINT)cxDrag, 0L,
  400. SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
  401. SystemParametersInfo(SPI_SETDRAGHEIGHT, (UINT)cyDrag, 0L,
  402. SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
  403. }
  404. /*****************************************************************************
  405. *
  406. * cxDblClkCur
  407. *
  408. * Return the current horizontal double click sensitivity.
  409. * Note that GetSystemMetrics records the total width, so we
  410. * need to divide by two to get the half-wit half-width.
  411. *
  412. *****************************************************************************/
  413. INLINE int
  414. cxDblClkCur(void)
  415. {
  416. return GetSystemMetrics(SM_CXDOUBLECLK) / 2;
  417. }
  418. /*****************************************************************************
  419. *
  420. * SetCxCyDblClk
  421. *
  422. * Set the current horizontal double click sensitivity.
  423. * Note that GetSystemMetrics records the total width, so we
  424. * need to multiply the half-width and half-height by two.
  425. *
  426. *****************************************************************************/
  427. INLINE void
  428. SetCxCyDblClk(int cxDblClk, int cyDblClk)
  429. {
  430. SystemParametersInfo(SPI_SETDOUBLECLKWIDTH, (UINT)cxDblClk * 2, 0L,
  431. SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
  432. SystemParametersInfo(SPI_SETDOUBLECLKHEIGHT, (UINT)cyDblClk * 2, 0L,
  433. SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
  434. }
  435. /*****************************************************************************
  436. *
  437. * Mouse_ReloadDlgInt
  438. *
  439. * Reload values from an edit control.
  440. *
  441. * hdlg is the dialog box itself.
  442. *
  443. * idc is the edit control identifier.
  444. *
  445. * ppt -> a POINT structure which will contain the current value
  446. * in the x, and an aspect-ratio-corrected value in the y.
  447. *
  448. * We allow the value to exceed the range, in case you
  449. * really want it.
  450. *
  451. *
  452. *****************************************************************************/
  453. void PASCAL
  454. Mouse_ReloadDlgInt(HWND hdlg, UINT idc, PPOINT ppt)
  455. {
  456. BOOL f;
  457. LRESULT lr;
  458. HWND hwnd;
  459. int x;
  460. hwnd = GetDlgItem(hdlg, idc+didcUd);
  461. if (hwnd) {
  462. lr = SendMessage(hwnd, UDM_GETRANGE, 0, 0L);
  463. x = (int)GetDlgItemInt(hdlg, idc+didcEdit, &f, 0);
  464. x = max((UINT)x, HIWORD(lr)); /* Force to lower limit of range */
  465. ppt->x = x;
  466. ppt->y = MulDiv(x, pmdii->cyAspect, pmdii->cxAspect);
  467. }
  468. }
  469. /*****************************************************************************
  470. *
  471. * Mouse_InitDlgInt
  472. *
  473. * Initialize a paired edit control / updown control.
  474. *
  475. * hdlg is the dialog box itself.
  476. *
  477. * idc is the edit control identifier. It is assumed that idc+didcUd is
  478. * the identifier for the updown control.
  479. *
  480. * xMin and xMax are the limits of the control.
  481. *
  482. * x = initial value
  483. *
  484. * ppt -> a POINT structure which will contain the current value
  485. * in the x, and an aspect-ratio-corrected value in the y.
  486. *
  487. *
  488. *****************************************************************************/
  489. void PASCAL
  490. Mouse_InitDlgInt(HWND hdlg, UINT idc, int xMin, int xMax, int xVal, PPOINT ppt)
  491. {
  492. SendDlgItemMessage(hdlg, idc+didcEdit, EM_LIMITTEXT, 2, 0L);
  493. SetDlgItemInt(hdlg, idc+didcEdit, xVal, 0);
  494. SendDlgItemMessage(hdlg, idc+didcUd,
  495. UDM_SETRANGE, 0, MAKELPARAM(xMax, xMin));
  496. Mouse_ReloadDlgInt(hdlg, idc, ppt);
  497. }
  498. /*****************************************************************************
  499. *
  500. * The trackbar
  501. *
  502. * The trackbar slider is piecewise linear. It really should be
  503. * exponential, but it's hard to write exp() and log() for integers.
  504. *
  505. * Given two parallel arrays which describe the domain and range,
  506. * with
  507. *
  508. * x[N] <= x <= x[N+1] mapping to y[N] <= y <= y[N+1],
  509. *
  510. * then
  511. *
  512. * x[N] <= x <= x[N+1] maps to
  513. *
  514. * y = y[N] + (x - x[N]) * (y[N+1] - y[N]) / (x[N+1] - x[N]).
  515. *
  516. *****************************************************************************/
  517. /* tbt = trackbar tick */
  518. #define tbtMax 120
  519. #define tbtFreq 15
  520. #define dtMax 65534 /* Don't use 65535; that's uiErr */
  521. const static UINT CODESEG rgtbt[] =
  522. { 0, tbtMax/2, tbtMax*3/4, tbtMax*7/8, tbtMax };
  523. const static UINT CODESEG rgdt[] =
  524. { 0, 500, 2000, 5000, dtMax };
  525. /*****************************************************************************
  526. *
  527. * Mouse_Interpolate
  528. *
  529. * Perform piecewise linear interpolation. See the formulas above.
  530. *
  531. *****************************************************************************/
  532. UINT PASCAL
  533. Mouse_Interpolate(UINT x, const UINT CODESEG *px, const UINT CODESEG *py)
  534. {
  535. while (x > px[1]) px++, py++;
  536. return py[0] + MulDiv(x - px[0], py[1] - py[0], px[1] - px[0]);
  537. }
  538. /*****************************************************************************
  539. *
  540. * Mouse_GetDt
  541. *
  542. * Get the setting that the user has selected.
  543. *
  544. * hdlg = dialog handle
  545. *
  546. * dtMax maps to dtInfinite.
  547. *
  548. *****************************************************************************/
  549. DT PASCAL
  550. Mouse_GetDt(HWND hdlg)
  551. {
  552. return (DT)Mouse_Interpolate(
  553. (UINT)SendDlgItemMessage(hdlg, IDC_SPEEDTRACK,
  554. TBM_GETPOS, 0, 0L), rgtbt, rgdt);
  555. }
  556. /*****************************************************************************
  557. *
  558. * Mouse_SetDt
  559. *
  560. * Set the setting into the trackbar.
  561. *
  562. * hdlg = dialog handle
  563. *
  564. *****************************************************************************/
  565. void PASCAL
  566. Mouse_SetDt(HWND hdlg, DT dt)
  567. {
  568. SendDlgItemMessage(hdlg, IDC_SPEEDTRACK, TBM_SETPOS, 1,
  569. Mouse_Interpolate(dt, rgdt, rgtbt));
  570. }
  571. /*****************************************************************************
  572. *
  573. * Mouse_SetDirty
  574. *
  575. * Make a control dirty.
  576. *
  577. *****************************************************************************/
  578. void NEAR PASCAL
  579. Mouse_SetDirty(HWND hdlg)
  580. {
  581. pmdii->fFactory = 0;
  582. PropSheet_Changed(GetParent(hdlg), hdlg);
  583. }
  584. /*****************************************************************************
  585. *
  586. * Mouse_UpdateWheel
  587. *
  588. * Update all the wheel control controls.
  589. *
  590. * If "Use wheel" is unchecked, then disable all the insides.
  591. *
  592. *****************************************************************************/
  593. void PASCAL
  594. Mouse_UpdateWheel(HWND hdlg)
  595. {
  596. HWND hwnd = GetDlgItem(hdlg, IDC_WHEELENABLE);
  597. if (hwnd) {
  598. BOOL f = IsWindowEnabled(hwnd) &&
  599. IsDlgButtonChecked(hdlg, IDC_WHEELENABLE);
  600. AdjustDlgItems(hdlg, IDC_WHEELPAGE, IDC_WHEELLAST, f ? ADI_ENABLE : ADI_DISABLE);
  601. }
  602. }
  603. /*****************************************************************************
  604. *
  605. * Mouse_Reset
  606. *
  607. * Reset all controls to initial values. This also marks
  608. * the control as clean.
  609. *
  610. *****************************************************************************/
  611. BOOL PASCAL
  612. Mouse_Reset(HWND hdlg)
  613. {
  614. HWND hwnd = GetDlgItem(hdlg, IDC_SPEEDTRACK);
  615. BOOL f;
  616. SendMessage(hwnd, TBM_SETRANGE, 0, MAKELPARAM(0, tbtMax));
  617. SendMessage(hwnd, TBM_SETTICFREQ, tbtFreq, 0L);
  618. if (fLpdt) {
  619. pmdii->dtOrig = msDt(); /* Save for revert */
  620. if (pmdii->dtOrig > dtMax) { /* Max out here */
  621. pmdii->dtOrig = dtMax;
  622. }
  623. } else {
  624. /* just use what seems to be the current setting */
  625. pmdii->dtOrig = dtCur();
  626. }
  627. Mouse_SetDt(hdlg, pmdii->dtOrig);
  628. f = fXMouse();
  629. if (f >= 0) {
  630. CheckDlgButton(hdlg, IDC_XMOUSE, f);
  631. f = fXMouseRaise();
  632. if (f >= 0) {
  633. CheckDlgButton(hdlg, IDC_XMOUSERAISE, f);
  634. }
  635. int ms = msXMouseDelay();
  636. if (ms >= 0) {
  637. SetDlgItemInt(hdlg, IDC_XMOUSEDELAY, ms, FALSE);
  638. }
  639. }
  640. Mouse_UpdateWheel(hdlg);
  641. Mouse_InitDlgInt(hdlg, IDC_DBLCLK, 1, 32, cxDblClkCur(), &pmdii->ptDblClk);
  642. Mouse_InitDlgInt(hdlg, IDC_DRAG, 1, 32, cxDragCur(), &pmdii->ptDrag);
  643. return 1;
  644. }
  645. /*****************************************************************************
  646. *
  647. * Mouse_Apply
  648. *
  649. * Write the changes to the registry and into USER's DS.
  650. *
  651. *****************************************************************************/
  652. BOOL NEAR PASCAL
  653. Mouse_Apply(HWND hdlg)
  654. {
  655. BOOL f;
  656. BOOL fNow;
  657. DWORD dwNow;
  658. DT dt;
  659. dt = Mouse_GetDt(hdlg);
  660. if (dt != pmdii->dtOrig) {
  661. pmdii->dtOrig = dt;
  662. if (pmdii->fFactory) {
  663. /* DelPkl(&c_klDelay); */
  664. dt = dtDefault();
  665. }
  666. if (SetDt(pmdii->dtOrig, SPIF_UPDATEINIFILE)) {
  667. Common_NeedLogoff(hdlg);
  668. }
  669. SendNotifyMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
  670. (LPARAM)(LPCTSTR)c_tszWindows);
  671. }
  672. if (cxDragCur() != pmdii->ptDrag.x) {
  673. /* This will send WM_WININICHANGE as necessary */
  674. SetCxCyDrag(pmdii->ptDrag.x, pmdii->ptDrag.y);
  675. }
  676. if (cxDblClkCur() != pmdii->ptDblClk.x) {
  677. /* This will send WM_WININICHANGE as necessary */
  678. SetCxCyDblClk(pmdii->ptDblClk.x, pmdii->ptDblClk.y);
  679. }
  680. fNow = fXMouse();
  681. if (fNow >= 0) {
  682. f = IsDlgButtonChecked(hdlg, IDC_XMOUSE);
  683. if (fNow != f) {
  684. /* This will send WM_WININICHANGE as necessary */
  685. SetXMouse(f);
  686. }
  687. fNow = fXMouseRaise();
  688. f = IsDlgButtonChecked(hdlg, IDC_XMOUSERAISE);
  689. if (fNow != f) {
  690. SetXMouseRaise(f);
  691. }
  692. int msDelay = (int)GetDlgItemInt(hdlg, IDC_XMOUSEDELAY, &f, FALSE);
  693. int msDelayNow = msXMouseDelay();
  694. if (msDelay != msDelayNow) {
  695. SetXMouseDelay(msDelay);
  696. }
  697. }
  698. if (SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &dwNow, 0)) {
  699. if (IsWindowEnabled(GetDlgItem(hdlg, IDC_WHEELENABLE))) {
  700. DWORD dw;
  701. if (!IsDlgButtonChecked(hdlg, IDC_WHEELENABLE)) {
  702. dw = 0;
  703. } else if (IsDlgButtonChecked(hdlg, IDC_WHEELPAGE)) {
  704. dw = WHEEL_PAGESCROLL;
  705. } else {
  706. dw = GetDlgItemInt(hdlg, IDC_WHEELLINENO, &f, 0);
  707. }
  708. if (dw != dwNow) {
  709. SystemParametersInfo(SPI_SETWHEELSCROLLLINES, dw, 0,
  710. SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
  711. }
  712. }
  713. }
  714. return Mouse_Reset(hdlg);
  715. }
  716. /*****************************************************************************
  717. *
  718. * Mouse_ReloadUpdowns
  719. *
  720. * Reload the values from the updown controls and update our
  721. * internals accordingly.
  722. *
  723. *****************************************************************************/
  724. BOOL PASCAL
  725. Mouse_ReloadUpdowns(HWND hdlg)
  726. {
  727. Mouse_ReloadDlgInt(hdlg, IDC_DBLCLK, &pmdii->ptDblClk);
  728. Mouse_ReloadDlgInt(hdlg, IDC_DRAG, &pmdii->ptDrag);
  729. Mouse_SetDirty(hdlg);
  730. return 1;
  731. }
  732. /*****************************************************************************
  733. *
  734. * Mouse_FactoryReset
  735. *
  736. * Restore to original factory settings.
  737. *
  738. * Droptime = DoubleClickTime * 4 / 5.
  739. * Animation = !((GetSystemMetrics(SM_SLOWMACHINE) & 0x0004) &&
  740. * (GetSystemMetrics(SM_SLOWMACHINE) & 0x0001))
  741. * cxDrag = 2
  742. * cxDblClk = 2
  743. *
  744. *****************************************************************************/
  745. BOOL PASCAL
  746. Mouse_FactoryReset(HWND hdlg)
  747. {
  748. Mouse_SetDirty(hdlg);
  749. Mouse_SetDt(hdlg, dtDefault());
  750. if (fXMouse() >= 0) {
  751. CheckDlgButton(hdlg, IDC_XMOUSE, 0);
  752. }
  753. SetDlgItemInt(hdlg, IDC_DRAG, 2, 0);
  754. SetDlgItemInt(hdlg, IDC_DBLCLK, 2, 0);
  755. Mouse_ReloadUpdowns(hdlg);
  756. if (GetDlgItem(hdlg, IDC_WHEELENABLE)) {
  757. CheckDlgButton(hdlg, IDC_WHEELENABLE, TRUE);
  758. CheckRadioButton(hdlg, IDC_WHEELPAGE, IDC_WHEELLINE, IDC_WHEELLINE);
  759. SetDlgItemInt(hdlg, IDC_WHEELLINENO, 3, 0);
  760. }
  761. pmdii->fFactory = 1;
  762. return 1;
  763. }
  764. /*****************************************************************************
  765. *
  766. * Mouse_OnTips
  767. *
  768. *****************************************************************************/
  769. void PASCAL
  770. Mouse_OnTips(HWND hdlg)
  771. {
  772. WinHelp(hdlg, c_tszMyHelp, HELP_FINDER, 0);
  773. }
  774. #ifdef IDC_BUGREPORT
  775. /*****************************************************************************
  776. *
  777. * Mouse_OnBugReport
  778. *
  779. *****************************************************************************/
  780. void PASCAL
  781. Mouse_OnBugReport(HWND hdlg)
  782. {
  783. ShellExecute(hdlg, "open", "http://abject/tweakui/", "", "",
  784. SW_NORMAL);
  785. }
  786. #endif
  787. /*****************************************************************************
  788. *
  789. * Mouse_OnCommand
  790. *
  791. * Ooh, we got a command.
  792. *
  793. *****************************************************************************/
  794. BOOL PASCAL
  795. Mouse_OnCommand(HWND hdlg, int id, UINT codeNotify)
  796. {
  797. switch (id) {
  798. case IDC_RESET: /* Reset to factory default */
  799. if (codeNotify == BN_CLICKED) return Mouse_FactoryReset(hdlg);
  800. break;
  801. case IDC_TIPS: /* Call up help */
  802. if (codeNotify == BN_CLICKED) Mouse_OnTips(hdlg);
  803. break;
  804. #ifdef IDC_BUGREPORT
  805. case IDC_BUGREPORT:
  806. if (codeNotify == BN_CLICKED) Mouse_OnBugReport(hdlg);
  807. break;
  808. #endif
  809. case IDC_XMOUSE:
  810. case IDC_XMOUSERAISE:
  811. case IDC_WHEELPAGE:
  812. case IDC_WHEELLINE:
  813. if (codeNotify == BN_CLICKED) Mouse_SetDirty(hdlg);
  814. break;
  815. case IDC_DRAG:
  816. case IDC_DBLCLK:
  817. case IDC_WHEELLINENO:
  818. case IDC_XMOUSEDELAY:
  819. if (codeNotify == EN_CHANGE) {
  820. Mouse_ReloadUpdowns(hdlg);
  821. Mouse_SetDirty(hdlg);
  822. }
  823. break;
  824. case IDC_WHEELENABLE:
  825. if (codeNotify == BN_CLICKED) {
  826. Mouse_UpdateWheel(hdlg);
  827. Mouse_SetDirty(hdlg);
  828. }
  829. break;
  830. }
  831. return 0;
  832. }
  833. /*****************************************************************************
  834. *
  835. * Mouse_SetTestIcon
  836. *
  837. * Set a new test icon, returning the previous one.
  838. *
  839. *****************************************************************************/
  840. HCURSOR PASCAL
  841. Mouse_SetTestIcon(HWND hdlg, UINT idi)
  842. {
  843. return (HCURSOR)
  844. SendDlgItemMessage(hdlg, IDC_TEST, STM_SETICON,
  845. (WPARAM)LoadIconId(idi), 0L);
  846. }
  847. /*****************************************************************************
  848. *
  849. * Mouse_StopDrag
  850. *
  851. * Stop any drag operation in progress.
  852. *
  853. * We must release the capture unconditionally, or a double-click
  854. * will result in the mouse capture being stuck!
  855. *
  856. *****************************************************************************/
  857. void PASCAL
  858. Mouse_StopDrag(HWND hdlg)
  859. {
  860. ReleaseCapture(); /* Always do this! */
  861. if (pmdii->hcurDrag) {
  862. SetCursor(0); /* We're about to destroy the current cursor */
  863. DestroyCursor(pmdii->hcurDrag);
  864. pmdii->hcurDrag = 0;
  865. DestroyCursor(Mouse_SetTestIcon(hdlg, pmdii->idi));
  866. }
  867. pmdii->fDrag = 0; /* not dragging */
  868. }
  869. /*****************************************************************************
  870. *
  871. * Mouse_OnNotify
  872. *
  873. * Ooh, we got a notification.
  874. *
  875. *****************************************************************************/
  876. BOOL PASCAL
  877. Mouse_OnNotify(HWND hdlg, NMHDR FAR *pnm)
  878. {
  879. switch (pnm->code) {
  880. case PSN_APPLY:
  881. Mouse_Apply(hdlg);
  882. break;
  883. /*
  884. * If we are dragging, then ESC cancels the drag, not the prsht.
  885. * Note that we must set the message result *last*, because
  886. * ReleaseCapture will recursively call the dialog procedure,
  887. * smashing whatever used to be in the message result.
  888. */
  889. case PSN_QUERYCANCEL:
  890. if (pmdii->fDrag) {
  891. Mouse_StopDrag(hdlg);
  892. SetDlgMsgResult(hdlg, WM_NOTIFY, 1);
  893. }
  894. return 1;
  895. }
  896. return 0;
  897. }
  898. /*****************************************************************************
  899. *
  900. * Mouse_OnInitDialog
  901. *
  902. * Initialize the controls.
  903. *
  904. *****************************************************************************/
  905. BOOL NEAR PASCAL
  906. Mouse_OnInitDialog(HWND hdlg)
  907. {
  908. UINT idc;
  909. DWORD dw;
  910. pmdii->idi = IDI_GEAR1; /* Start with the first gear */
  911. pmdii->fDrag = 0; /* not dragging */
  912. /* Make sure first click isn't counted as a double */
  913. pmdii->tmClick = 0;
  914. pmdii->fFactory = 0;
  915. pmdii->hcurDrag = 0;
  916. GetDlgItemRect(hdlg, IDC_TEST, &pmdii->rcTest);
  917. {
  918. HDC hdc = GetDC(0);
  919. if (hdc) {
  920. pmdii->cxAspect = GetDeviceCaps(hdc, ASPECTX);
  921. pmdii->cyAspect = GetDeviceCaps(hdc, ASPECTY);
  922. ReleaseDC(0, hdc);
  923. if (pmdii->cxAspect == 0) { /* Buggy display driver */
  924. goto Fallback;
  925. }
  926. } else { /* Assume 1:1 aspect ratio */
  927. Fallback:
  928. pmdii->cxAspect = pmdii->cyAspect = 1;
  929. }
  930. }
  931. SendDlgItemMessage(hdlg, IDC_WHEELLINENO, EM_LIMITTEXT, 3, 0L);
  932. SetDlgItemInt(hdlg, IDC_WHEELLINENO, 3, 0);
  933. SendDlgItemMessage(hdlg, IDC_WHEELLINEUD,
  934. UDM_SETRANGE, 0, MAKELPARAM(999, 1));
  935. if (SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &dw, 0)) {
  936. if (GetSystemMetrics(SM_MOUSEWHEELPRESENT)) {
  937. CheckDlgButton(hdlg, IDC_WHEELENABLE, dw != 0);
  938. if (dw == WHEEL_PAGESCROLL) {
  939. CheckDlgButton(hdlg, IDC_WHEELPAGE, TRUE);
  940. } else {
  941. CheckDlgButton(hdlg, IDC_WHEELLINE, TRUE);
  942. if (dw) {
  943. SetDlgItemInt(hdlg, IDC_WHEELLINENO, dw, 0);
  944. }
  945. }
  946. } else {
  947. EnableDlgItem(hdlg, IDC_WHEELENABLE, 0);
  948. }
  949. } else {
  950. DestroyDlgItems(hdlg, IDC_WHEELFIRST, IDC_WHEELLAST);
  951. }
  952. if (fXMouse() < 0) {
  953. DestroyDlgItems(hdlg, IDC_XMOUSEFIRST, IDC_XMOUSELAST);
  954. } else {
  955. if (fXMouseRaise() < 0) {
  956. EnableDlgItem(hdlg, IDC_XMOUSERAISE, FALSE);
  957. }
  958. if (msXMouseDelay() < 0) {
  959. EnableDlgItem(hdlg, IDC_XMOUSEDELAY, FALSE);
  960. EnableDlgItem(hdlg, IDC_XMOUSEDELAYTXT, FALSE);
  961. }
  962. }
  963. if (fGrovel()) {
  964. Mouse_Reset(hdlg);
  965. return 1; /* Allow focus to travel normally */
  966. } else {
  967. lpdt = &dtScratch;
  968. *lpdt = dtCur(); /* Gotta give it something */
  969. Mouse_Reset(hdlg);
  970. ShowWindow(GetDlgItem(hdlg, IDC_SPEEDHELP), SW_HIDE);
  971. return 0;
  972. }
  973. }
  974. /*****************************************************************************
  975. *
  976. * Mouse_OnLButtonDown
  977. *
  978. * If the left button went down in the test area, begin capturing.
  979. * Also record the time the button went down, so we can do double-click
  980. * fuzz testing.
  981. *
  982. *****************************************************************************/
  983. BOOL PASCAL
  984. Mouse_OnLButtonDown(HWND hdlg, int x, int y)
  985. {
  986. POINT pt = { x, y };
  987. LONG tm = GetMessageTime();
  988. if (PtInRect(&pmdii->rcTest, pt)) {
  989. /*
  990. * Is this a double-click?
  991. */
  992. if (pmdii->tmClick &&
  993. (DWORD)(tm - pmdii->tmClick) < GetDoubleClickTime() &&
  994. PtInRect(&pmdii->rcDblClk, pt)) {
  995. pmdii->idi ^= IDI_GEAR1 ^ IDI_GEAR2;
  996. DestroyCursor(Mouse_SetTestIcon(hdlg, pmdii->idi));
  997. tm = 0;
  998. }
  999. SetRectPoint(&pmdii->rcDrag, pt);
  1000. SetRectPoint(&pmdii->rcDblClk, pt);
  1001. InflateRect(&pmdii->rcDrag, pmdii->ptDrag.x, pmdii->ptDrag.y);
  1002. InflateRect(&pmdii->rcDblClk, pmdii->ptDblClk.x, pmdii->ptDblClk.y);
  1003. pmdii->fDrag = 1; /* Drag in progress */
  1004. SetCapture(hdlg);
  1005. }
  1006. pmdii->tmClick = tm;
  1007. return 1;
  1008. }
  1009. /*****************************************************************************
  1010. *
  1011. * Mouse_OnMouseMove
  1012. *
  1013. * If we are captured, see if we've moved far enough to act as
  1014. * if a drag is in progress.
  1015. *
  1016. *****************************************************************************/
  1017. BOOL PASCAL
  1018. Mouse_OnMouseMove(HWND hdlg, int x, int y)
  1019. {
  1020. if (pmdii->fDrag && !pmdii->hcurDrag) {
  1021. POINT pt = { x, y };
  1022. if (!PtInRect(&pmdii->rcDrag, pt)) {
  1023. pmdii->hcurDrag = Mouse_SetTestIcon(hdlg, IDI_BLANK);
  1024. /*
  1025. * Tweak the cursor position so it looks like the icon
  1026. * dragged from the original click point.
  1027. */
  1028. ICONINFO ii;
  1029. if (GetIconInfo(pmdii->hcurDrag, &ii)) {
  1030. DeleteObject(ii.hbmMask);
  1031. DeleteObject(ii.hbmColor);
  1032. /*
  1033. * These formulas are heinous.
  1034. *
  1035. * xClick = client coordinates of original click
  1036. * = pmdii->rcDrag.left + pmdii->ptDrag.x
  1037. *
  1038. * xTest = client coordinates of start of clickable icon
  1039. * = pmdii->rcTest.left
  1040. *
  1041. * xOffset = location of click relative to icon corner
  1042. * = xClick - xTest
  1043. *
  1044. * xAdjust = amount the user's click location differs
  1045. * from the actual hotspot
  1046. * = ii.xHotspot - xOffset
  1047. * = ii.xHotspot - xClick + xTest
  1048. */
  1049. pt.x += + ii.xHotspot
  1050. - (pmdii->rcDrag.left + pmdii->ptDrag.x)
  1051. + pmdii->rcTest.left;
  1052. pt.y += + ii.yHotspot
  1053. - (pmdii->rcDrag.top + pmdii->ptDrag.y)
  1054. + pmdii->rcTest.top;
  1055. ClientToScreen(hdlg, &pt);
  1056. SetCursorPos(pt.x, pt.y);
  1057. }
  1058. SetCursor(pmdii->hcurDrag);
  1059. }
  1060. }
  1061. return 0;
  1062. }
  1063. /*****************************************************************************
  1064. *
  1065. * Mouse_OnRButtonUp
  1066. *
  1067. * If the button went up in the menu test area, track a menu.
  1068. *
  1069. *****************************************************************************/
  1070. BOOL PASCAL
  1071. Mouse_OnRButtonUp(HWND hdlg, int x, int y)
  1072. {
  1073. POINT pt = { x, y };
  1074. if (PtInRect(&pmdii->rcTest, pt) && fLpdt) {
  1075. DT dt;
  1076. int id;
  1077. dt = msDt(); /* Save for revert */
  1078. SetDt(Mouse_GetDt(hdlg), 0);
  1079. ClientToScreen(hdlg, &pt); /* Make it screen coordinates */
  1080. id = TrackPopupMenuEx(GetSubMenu(pcdii->hmenu, 0),
  1081. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_VERTICAL |
  1082. TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y,
  1083. hdlg, 0);
  1084. SetDt(dt, 0);
  1085. return 1;
  1086. } else {
  1087. return 0; /* Do the default thing */
  1088. }
  1089. }
  1090. /*****************************************************************************
  1091. *
  1092. * Our window procedure.
  1093. *
  1094. *****************************************************************************/
  1095. /*
  1096. * The HANDLE_WM_* macros weren't designed to be used from a dialog
  1097. * proc, so we need to handle the messages manually. (But carefully.)
  1098. */
  1099. INT_PTR EXPORT
  1100. Mouse_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
  1101. {
  1102. switch (wm) {
  1103. case WM_INITDIALOG: return Mouse_OnInitDialog(hdlg);
  1104. /* We have only one trackbar, so we don't need to check */
  1105. case WM_HSCROLL: Mouse_SetDirty(hdlg); return 1;
  1106. /* We have two updowns, but reloading is cheap, so we just reload both */
  1107. case WM_VSCROLL:
  1108. if (GET_WM_VSCROLL_CODE(wParam, lParam) == SB_THUMBPOSITION) {
  1109. return Mouse_ReloadUpdowns(hdlg);
  1110. }
  1111. break;
  1112. case WM_COMMAND:
  1113. return Mouse_OnCommand(hdlg,
  1114. (int)GET_WM_COMMAND_ID(wParam, lParam),
  1115. (UINT)GET_WM_COMMAND_CMD(wParam, lParam));
  1116. case WM_NOTIFY:
  1117. return Mouse_OnNotify(hdlg, (NMHDR FAR *)lParam);
  1118. case WM_LBUTTONDOWN:
  1119. case WM_LBUTTONDBLCLK:
  1120. return Mouse_OnLButtonDown(hdlg, LOWORD(lParam), HIWORD(lParam));
  1121. case WM_ACTIVATE:
  1122. if (GET_WM_ACTIVATE_STATE(wParam, lParam) == WA_INACTIVE) {
  1123. Mouse_StopDrag(hdlg);
  1124. }
  1125. break;
  1126. case WM_LBUTTONUP:
  1127. Mouse_StopDrag(hdlg);
  1128. break;
  1129. case WM_RBUTTONUP:
  1130. return Mouse_OnRButtonUp(hdlg, LOWORD(lParam), HIWORD(lParam));
  1131. case WM_HELP: Common_OnHelp(lParam, &rgdwHelp[0]); break;
  1132. case WM_CONTEXTMENU: Common_OnContextMenu(wParam, &rgdwHelp[0]); break;
  1133. case WM_MOUSEMOVE:
  1134. return Mouse_OnMouseMove(hdlg, LOWORD(lParam), HIWORD(lParam));
  1135. default: return 0; /* Unhandled */
  1136. }
  1137. return 1; /* Handled */
  1138. }