mouse.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 31k
Category:

Windows Kernel

Development Platform:

Visual C++

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