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.

1242 lines
36 KiB

  1. /*++
  2. Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. mousebut.c
  5. Abstract:
  6. This module contains the routines for the Mouse Buttons Property Sheet
  7. page.
  8. Revision History:
  9. --*/
  10. //
  11. // Include Files.
  12. //
  13. #include "main.h"
  14. #include "util.h"
  15. #include "rc.h"
  16. #include "mousectl.h"
  17. #include <regstr.h>
  18. #include <winerror.h> // needed for ERROR_SUCCESS value
  19. #include "mousehlp.h"
  20. //
  21. // Constant Declarations.
  22. //
  23. const TCHAR szYes[] = TEXT("yes");
  24. const TCHAR szNo[] = TEXT("no");
  25. const TCHAR szDblClkSpeed[] = TEXT("DoubleClickSpeed");
  26. const TCHAR szRegStr_Mouse[] = REGSTR_PATH_MOUSE;
  27. #define SAFE_DESTROYICON(hicon) if (hicon) { DestroyIcon(hicon); hicon=NULL; }
  28. //
  29. // SwapMouseButtons takes:
  30. // TRUE to make it a right mouse
  31. // FALSE to make it a left mouse
  32. //
  33. #define RIGHT TRUE
  34. #define LEFT FALSE
  35. //Identifiers used for setting DoubleClick speed
  36. #define DBLCLICK_MIN 200 // milliseconds
  37. #define DBLCLICK_MAX 900
  38. #define DBLCLICK_DEFAULT_TIME 500
  39. #define DBLCLICK_TIME_SLIDER_MIN 0
  40. #define DBLCLICK_TIME_SLIDER_MAX 10
  41. #define DBLCLICK_RANGE (DBLCLICK_MAX - DBLCLICK_MIN)
  42. #define DBLCLICK_SLIDER_RANGE ( CLICKLOCK_TIME_SLIDER_MAX - CLICKLOCK_TIME_SLIDER_MIN)
  43. #define DBLCLICK_TICKMULT (DBLCLICK_RANGE / DBLCLICK_SLIDER_RANGE)
  44. #define DBLCLICK_TICKS_TO_TIME(ticks) (SHORT) (((DBLCLICK_TIME_SLIDER_MAX - ticks) * DBLCLICK_TICKMULT) + DBLCLICK_MIN)
  45. #define DBLCLICK_TIME_TO_TICKS(time) (SHORT) (DBLCLICK_TIME_SLIDER_MAX - ((time - DBLCLICK_MIN) / DBLCLICK_TICKMULT))
  46. #define CLICKLOCK_TIME_SLIDER_MIN 1 //Minimum ClickLock Time setting for slider control
  47. #define CLICKLOCK_TIME_SLIDER_MAX 11 //Maximum ClickLock Time setting for slider control
  48. #define CLICKLOCK_TIME_FACTOR 200 //Multiplier for translating clicklock time slider units to milliseconds
  49. #define TICKS_PER_CLICK 1
  50. //Size assumed as the default size for icons, used for scaling the icons
  51. #define ICON_SIZEX 32
  52. #define ICON_SIZEY 32
  53. //The font size used for scaling
  54. #define SMALLFONTSIZE 96
  55. #define CLAPPER_CLASS TEXT("Clapper")
  56. //
  57. // From shell\inc\shsemip.h
  58. //
  59. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  60. //
  61. // Typedef Declarations.
  62. //
  63. typedef struct tag_MouseGenStr
  64. {
  65. BOOL bSwap;
  66. BOOL bOrigSwap;
  67. short ClickSpeed;
  68. short OrigDblClkSpeed;
  69. HWND hWndDblClkScroll;
  70. HWND hDlg;
  71. HWND hWndDblClk_TestArea;
  72. RECT DblClkRect;
  73. HICON hIconDblClick[2];
  74. #ifdef SHELL_SINGLE_CLICK
  75. BOOL bShellSingleClick,
  76. bOrigShellSingleClick ;
  77. HICON hIconSglClick,
  78. hIconDblClick ;
  79. #endif //SHELL_SINGLE_CLICK
  80. BOOL bClickLock;
  81. BOOL bOrigClickLock;
  82. DWORD dwClickLockTime;
  83. DWORD dwOrigClickLockTime;
  84. } MOUSEBUTSTR, *PMOUSEBUTSTR, *LPMOUSEBUTSTR;
  85. //
  86. // Context Help Ids.
  87. //
  88. const DWORD aMouseButHelpIds[] =
  89. {
  90. IDC_GROUPBOX_1, IDH_COMM_GROUPBOX,
  91. IDBTN_BUTTONSWAP, IDH_MOUSE_SWITCH,
  92. MOUSE_MOUSEBMP, IDH_MOUSE_SWITCH_PIC,
  93. IDC_GROUPBOX_2, IDH_COMM_GROUPBOX,
  94. IDC_GROUPBOX_4, IDH_COMM_GROUPBOX,
  95. MOUSE_CLICKSCROLL, IDH_MOUSE_DOUBLECLICK,
  96. IDC_DBLCLICK_TEXT, IDH_COMM_GROUPBOX,
  97. IDC_TEST_DOUBLE_CLICK, IDH_MOUSE_DCLICK_TEST_BOX,
  98. MOUSE_DBLCLK_TEST_AREA, IDH_MOUSE_DCLICK_TEST_BOX,
  99. IDC_GROUPBOX_6, IDH_COMM_GROUPBOX,
  100. IDCK_CLICKLOCK, IDH_MOUSE_CLKLCK_CHKBOX,
  101. IDBTN_CLICKLOCK_SETTINGS, IDH_MOUSE_CLKLCK_SETTINGS_BTN,
  102. IDC_CLICKLOCK_TEXT, IDH_COMM_GROUPBOX,
  103. IDC_CLICKLOCK_SETTINGS_TXT, IDH_COMM_GROUPBOX,
  104. IDT_CLICKLOCK_TIME_SETTINGS, IDH_MOUSE_CLKLCK_DIALOG,
  105. IDC_CLICKLOCK_SETTINGS_LEFT_TXT, IDH_MOUSE_CLKLCK_DIALOG,
  106. IDC_CLICKLOCK_SETTINGS_RIGHT_TXT, IDH_MOUSE_CLKLCK_DIALOG,
  107. #ifdef SHELL_SINGLE_CLICK
  108. MOUSE_SGLCLICK, IDH_MOUSE_SGLCLICK,
  109. MOUSE_DBLCLICK, IDH_MOUSE_DBLCLICK,
  110. #endif // SHELL_SINGLE_CLICK
  111. 0,0
  112. };
  113. //
  114. // helper function prototypes
  115. //
  116. void ShellClick_UpdateUI( HWND hDlg, PMOUSEBUTSTR pMstr) ;
  117. void ShellClick_Refresh( PMOUSEBUTSTR pMstr ) ;
  118. //
  119. // Debug Info.
  120. //
  121. #ifdef DEBUG
  122. #define REG_INTEGER 1000
  123. int fTraceRegAccess = 0;
  124. void RegDetails(
  125. int iWrite,
  126. HKEY hk,
  127. LPCTSTR lpszSubKey,
  128. LPCTSTR lpszValueName,
  129. DWORD dwType,
  130. LPTSTR lpszString,
  131. int iValue)
  132. {
  133. TCHAR Buff[256];
  134. TCHAR *lpszReadWrite[] = { TEXT("DESK.CPL:Read"), TEXT("DESK.CPL:Write") };
  135. if (!fTraceRegAccess)
  136. {
  137. return;
  138. }
  139. switch (dwType)
  140. {
  141. case ( REG_SZ ) :
  142. {
  143. wsprintf( Buff,
  144. TEXT("%s String:hk=%#08lx, %s:%s=%s\n\r"),
  145. lpszReadWrite[iWrite],
  146. hk,
  147. lpszSubKey,
  148. lpszValueName,
  149. lpszString );
  150. break;
  151. }
  152. case ( REG_INTEGER ) :
  153. {
  154. wsprintf( Buff,
  155. TEXT("%s int:hk=%#08lx, %s:%s=%d\n\r"),
  156. lpszReadWrite[iWrite],
  157. hk,
  158. lpszSubKey,
  159. lpszValueName,
  160. iValue );
  161. break;
  162. }
  163. case ( REG_BINARY ) :
  164. {
  165. wsprintf( Buff,
  166. TEXT("%s Binary:hk=%#08lx, %s:%s=%#0lx;DataSize:%d\r\n"),
  167. lpszReadWrite[iWrite],
  168. hk,
  169. lpszSubKey,
  170. lpszValueName,
  171. lpszString,
  172. iValue );
  173. break;
  174. }
  175. }
  176. OutputDebugString(Buff);
  177. }
  178. #endif // DEBUG
  179. ////////////////////////////////////////////////////////////////////////////
  180. //
  181. // GetIntFromSubKey
  182. //
  183. // hKey is the handle to the subkey (already pointing to the proper
  184. // location.
  185. //
  186. ////////////////////////////////////////////////////////////////////////////
  187. int GetIntFromSubkey(
  188. HKEY hKey,
  189. LPCTSTR lpszValueName,
  190. int iDefault)
  191. {
  192. TCHAR szValue[20];
  193. DWORD dwSizeofValueBuff = sizeof(szValue);
  194. DWORD dwType;
  195. int iRetValue = iDefault;
  196. if ((RegQueryValueEx( hKey,
  197. (LPTSTR)lpszValueName,
  198. NULL,
  199. &dwType,
  200. (LPBYTE)szValue,
  201. &dwSizeofValueBuff ) == ERROR_SUCCESS) &&
  202. (dwSizeofValueBuff))
  203. {
  204. //
  205. // BOGUS: This handles only the string type entries now!
  206. //
  207. if (dwType == REG_SZ)
  208. {
  209. iRetValue = (int)StrToLong(szValue);
  210. }
  211. #ifdef DEBUG
  212. else
  213. {
  214. OutputDebugString(TEXT("String type expected from Registry\n\r"));
  215. }
  216. #endif
  217. }
  218. #ifdef DEBUG
  219. RegDetails(0, hKey, TEXT(""), lpszValueName, REG_INTEGER, NULL, iRetValue);
  220. #endif
  221. return (iRetValue);
  222. }
  223. ////////////////////////////////////////////////////////////////////////////
  224. //
  225. // GetIntFromReg
  226. //
  227. // Opens the given subkey and gets the int value.
  228. //
  229. ////////////////////////////////////////////////////////////////////////////
  230. int GetIntFromReg(
  231. HKEY hKey,
  232. LPCTSTR lpszSubkey,
  233. LPCTSTR lpszNameValue,
  234. int iDefault)
  235. {
  236. HKEY hk;
  237. int iRetValue = iDefault;
  238. //
  239. // See if the key is present.
  240. //
  241. if (RegOpenKey(hKey, lpszSubkey, &hk) == ERROR_SUCCESS)
  242. {
  243. iRetValue = GetIntFromSubkey(hk, lpszNameValue, iDefault);
  244. RegCloseKey(hk);
  245. }
  246. return (iRetValue);
  247. }
  248. ////////////////////////////////////////////////////////////////////////////
  249. //
  250. // GetStringFromReg
  251. //
  252. // Opens the given subkey and gets the string value.
  253. //
  254. ////////////////////////////////////////////////////////////////////////////
  255. BOOL GetStringFromReg(
  256. HKEY hKey,
  257. LPCTSTR lpszSubkey,
  258. LPCTSTR lpszValueName,
  259. LPCTSTR lpszDefault,
  260. LPTSTR lpszValue,
  261. DWORD dwSizeofValueBuff)
  262. {
  263. HKEY hk;
  264. DWORD dwType;
  265. BOOL fSuccess = FALSE;
  266. //
  267. // See if the key is present.
  268. //
  269. if (RegOpenKey(hKey, lpszSubkey, &hk) == ERROR_SUCCESS)
  270. {
  271. if ((RegQueryValueEx( hk,
  272. (LPTSTR)lpszValueName,
  273. NULL,
  274. &dwType,
  275. (LPBYTE)lpszValue,
  276. &dwSizeofValueBuff ) == ERROR_SUCCESS) &&
  277. (dwSizeofValueBuff))
  278. {
  279. //
  280. // BOGUS: This handles only the string type entries now!
  281. //
  282. #ifdef DEBUG
  283. if (dwType != REG_SZ)
  284. {
  285. OutputDebugString(TEXT("String type expected from Registry\n\r"));
  286. }
  287. else
  288. #endif
  289. fSuccess = TRUE;
  290. }
  291. RegCloseKey(hk);
  292. }
  293. //
  294. // If failure, use the default string.
  295. //
  296. if (!fSuccess)
  297. {
  298. lstrcpy(lpszValue, lpszDefault);
  299. }
  300. #ifdef DEBUG
  301. RegDetails(0, hKey, lpszSubkey, lpszValueName, REG_SZ, lpszValue, 0);
  302. #endif
  303. return (fSuccess);
  304. }
  305. ////////////////////////////////////////////////////////////////////////////
  306. //
  307. // UpdateRegistry
  308. //
  309. // This updates a given value of any data type at a given location in
  310. // the registry.
  311. //
  312. // The value name is passed in as an Id to a string in USER's String
  313. // table.
  314. //
  315. ////////////////////////////////////////////////////////////////////////////
  316. BOOL UpdateRegistry(
  317. HKEY hKey,
  318. LPCTSTR lpszSubkey,
  319. LPCTSTR lpszValueName,
  320. DWORD dwDataType,
  321. LPVOID lpvData,
  322. DWORD dwDataSize)
  323. {
  324. HKEY hk;
  325. if (RegCreateKey(hKey, lpszSubkey, &hk) == ERROR_SUCCESS)
  326. {
  327. RegSetValueEx( hk,
  328. (LPTSTR)lpszValueName,
  329. 0,
  330. dwDataType,
  331. (LPBYTE)lpvData,
  332. dwDataSize );
  333. #ifdef DEBUG
  334. RegDetails(1, hKey, lpszSubkey, lpszValueName, dwDataType, lpvData, (int)dwDataSize);
  335. #endif
  336. RegCloseKey(hk);
  337. return (TRUE);
  338. }
  339. return (FALSE);
  340. }
  341. ////////////////////////////////////////////////////////////////////////////
  342. //
  343. // CenterDlgOverParent
  344. //
  345. ////////////////////////////////////////////////////////////////////////////
  346. void WINAPI CenterDlgOverParent (HWND hWnd)
  347. {
  348. HWND hwndOwner;
  349. RECT rc, rcDlg, rcOwner;
  350. if ((hwndOwner = GetParent(hWnd)) == NULL)
  351. {
  352. return;
  353. }
  354. GetWindowRect(hwndOwner, &rcOwner);
  355. GetWindowRect(hWnd, &rcDlg);
  356. CopyRect(&rc, &rcOwner);
  357. // Offset the owner and dialog box rectangles so that
  358. // right and bottom values represent the width and
  359. // height, and then offset the owner again to discard
  360. // space taken up by the dialog box.
  361. OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
  362. OffsetRect(&rc, -rc.left, -rc.top);
  363. OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
  364. //The new position is the sum of half the remaining
  365. //space and the owner's original position.
  366. SetWindowPos(hWnd,
  367. HWND_TOP,
  368. rcOwner.left + (rc.right / 2),
  369. rcOwner.top + (rc.bottom / 2),
  370. 0, 0, // ignores size arguments
  371. SWP_NOSIZE);
  372. // now let's verify left side is not off screen
  373. GetWindowRect( hWnd, &rc);
  374. if ((rc.left < 0) || (rc.top < 0))
  375. {
  376. if (rc.left < 0)
  377. rc.left = 0;
  378. if (rc.top < 0)
  379. rc.top = 0;
  380. SetWindowPos(hWnd,
  381. HWND_TOP,
  382. rc.left,
  383. rc.top,
  384. 0, 0, // ignores size arguments
  385. SWP_NOSIZE);
  386. }
  387. }
  388. ////////////////////////////////////////////////////////////////////////////
  389. //
  390. // ShowButtonState
  391. //
  392. // Swaps the menu and selection bitmaps.
  393. //
  394. ////////////////////////////////////////////////////////////////////////////
  395. void ShowButtonState(
  396. PMOUSEBUTSTR pMstr)
  397. {
  398. HWND hDlg;
  399. Assert(pMstr);
  400. hDlg = pMstr->hDlg;
  401. MouseControlSetSwap(GetDlgItem(hDlg, MOUSE_MOUSEBMP), pMstr->bSwap);
  402. CheckDlgButton(hDlg,IDBTN_BUTTONSWAP, pMstr->bSwap);
  403. #ifdef SHELL_SINGLE_CLICK
  404. //This was removed
  405. CheckDlgButton(hDlg, MOUSE_SGLCLICK, pMstr->bShellSingleClick);
  406. CheckDlgButton(hDlg, MOUSE_DBLCLICK, !pMstr->bShellSingleClick);
  407. #endif //SHELL_SINGLE_CLICK
  408. }
  409. ////////////////////////////////////////////////////////////////////////////
  410. //
  411. // DestroyMouseButDlg
  412. //
  413. ////////////////////////////////////////////////////////////////////////////
  414. void DestroyMouseButDlg(
  415. PMOUSEBUTSTR pMstr)
  416. {
  417. if (pMstr)
  418. {
  419. #ifdef SHELL_SINGLE_CLICK
  420. SAFE_DESTROYICON( pMstr->hIconSglClick ) ;
  421. SAFE_DESTROYICON( pMstr->hIconDblClick ) ;
  422. #endif
  423. SAFE_DESTROYICON( pMstr->hIconDblClick[0]);
  424. SAFE_DESTROYICON( pMstr->hIconDblClick[1]);
  425. SetWindowLongPtr(pMstr->hDlg, DWLP_USER, 0);
  426. LocalFree((HGLOBAL)pMstr);
  427. }
  428. }
  429. ////////////////////////////////////////////////////////////////////////////
  430. //
  431. // ClickLockSettingsDlg
  432. //
  433. ////////////////////////////////////////////////////////////////////////////
  434. INT_PTR CALLBACK ClickLockSettingsDlg (
  435. HWND hDlg, // dialog window handle
  436. UINT msg, // message identifier
  437. WPARAM wParam, // primary parameter
  438. LPARAM lParam) // secondary parameter
  439. {
  440. static DWORD* pdwClickLockTime;
  441. static HICON hIcon = 0;
  442. switch (msg)
  443. {
  444. case WM_INITDIALOG:
  445. {
  446. WPARAM wSliderSetting; //ClickLock time in terms of slider units
  447. HourGlass (TRUE);
  448. Assert(lParam);
  449. pdwClickLockTime = (DWORD*) lParam; //Save Original value for return
  450. //Convert into slider units from milliseconds. Note that the slider
  451. //values get larger as the ClickLock time gets larger.
  452. wSliderSetting = (*pdwClickLockTime) / CLICKLOCK_TIME_FACTOR;
  453. //Make sure setting is within valid range for ClickLock slider
  454. wSliderSetting = max(wSliderSetting, CLICKLOCK_TIME_SLIDER_MIN);
  455. wSliderSetting = min(wSliderSetting, CLICKLOCK_TIME_SLIDER_MAX);
  456. SendDlgItemMessage (hDlg, IDT_CLICKLOCK_TIME_SETTINGS, TBM_SETRANGE,
  457. TRUE, MAKELONG(CLICKLOCK_TIME_SLIDER_MIN, CLICKLOCK_TIME_SLIDER_MAX));
  458. SendDlgItemMessage (hDlg, IDT_CLICKLOCK_TIME_SETTINGS, TBM_SETPAGESIZE,
  459. 0, TICKS_PER_CLICK); // click movement
  460. SendDlgItemMessage (hDlg, IDT_CLICKLOCK_TIME_SETTINGS, TBM_SETPOS,
  461. TRUE, (LPARAM)(LONG)wSliderSetting);
  462. //icon for the dialog
  463. // (saved in a static variable, and released on WM_DESTROY)
  464. hIcon = LoadIcon((HINSTANCE)GetWindowLongPtr( hDlg, GWLP_HINSTANCE ),
  465. MAKEINTRESOURCE(ICON_CLICKLOCK));
  466. SendMessage( GetDlgItem (hDlg, MOUSE_CLICKICON),
  467. STM_SETICON, (WPARAM)hIcon, 0L );
  468. CenterDlgOverParent(hDlg); //Center dialog here so it doesn't jump around on screen
  469. HourGlass(FALSE);
  470. return(TRUE);
  471. }
  472. case WM_HSCROLL:
  473. {
  474. if (LOWORD(wParam) == TB_ENDTRACK)
  475. {
  476. DWORD dwClTime;
  477. int wSliderSetting = (int) SendMessage (GetDlgItem (hDlg, IDT_CLICKLOCK_TIME_SETTINGS),
  478. TBM_GETPOS, 0, 0L);
  479. dwClTime = wSliderSetting * CLICKLOCK_TIME_FACTOR;
  480. SystemParametersInfo(SPI_SETMOUSECLICKLOCKTIME,
  481. 0,
  482. (PVOID) (LOWORD(dwClTime)),
  483. 0);
  484. }
  485. }
  486. break;
  487. case WM_HELP: //F1
  488. {
  489. WinHelp( ((LPHELPINFO)lParam)->hItemHandle,
  490. HELP_FILE,
  491. HELP_WM_HELP,
  492. (DWORD_PTR)(LPTSTR)aMouseButHelpIds );
  493. }
  494. break;
  495. case WM_CONTEXTMENU: // Display simple "What's This?" menu
  496. {
  497. WinHelp( (HWND) wParam,
  498. HELP_FILE,
  499. HELP_CONTEXTMENU,
  500. (DWORD_PTR)(LPTSTR)aMouseButHelpIds );
  501. }
  502. break;
  503. case WM_DESTROY:
  504. SAFE_DESTROYICON(hIcon);
  505. break;
  506. case WM_COMMAND:
  507. switch(LOWORD(wParam))
  508. {
  509. case IDOK: // Flag to save setting
  510. {
  511. DWORD dwClickLockTime;
  512. int wSliderSetting = (int) SendMessage (GetDlgItem (hDlg, IDT_CLICKLOCK_TIME_SETTINGS),
  513. TBM_GETPOS, 0, 0L);
  514. //verify range
  515. wSliderSetting = max(wSliderSetting, CLICKLOCK_TIME_SLIDER_MIN);
  516. wSliderSetting = min(wSliderSetting, CLICKLOCK_TIME_SLIDER_MAX);
  517. // Convert to milliseconds from slider units.
  518. dwClickLockTime = wSliderSetting * CLICKLOCK_TIME_FACTOR;
  519. *pdwClickLockTime = dwClickLockTime;
  520. EndDialog(hDlg, IDOK);
  521. break;
  522. }
  523. case IDCANCEL: // revert to previous setting
  524. EndDialog(hDlg, IDCANCEL);
  525. break;
  526. default:
  527. return(FALSE);
  528. }
  529. return (TRUE);
  530. default:
  531. return(FALSE);
  532. }
  533. return (TRUE);
  534. }
  535. ////////////////////////////////////////////////////////////////////////////
  536. //
  537. // InitMouseButDlg
  538. //
  539. ////////////////////////////////////////////////////////////////////////////
  540. BOOL InitMouseButDlg(
  541. HWND hDlg)
  542. {
  543. SHELLSTATE shellstate = {0} ;
  544. PMOUSEBUTSTR pMstr = NULL;
  545. HINSTANCE hInstDlg = (HINSTANCE)GetWindowLongPtr( hDlg, GWLP_HINSTANCE ) ;
  546. HWND hwndClickLockSettingsButton = GetDlgItem(hDlg, IDBTN_CLICKLOCK_SETTINGS);
  547. DWORD dwClickLockSetting = 0;
  548. HWND hwndDoubleClickTestArea = NULL;
  549. pMstr = (PMOUSEBUTSTR)LocalAlloc(LPTR , sizeof(MOUSEBUTSTR));
  550. if (pMstr == NULL)
  551. {
  552. return (TRUE);
  553. }
  554. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pMstr);
  555. pMstr->hDlg = hDlg;
  556. //
  557. //Set up the double click test area
  558. //
  559. pMstr->hWndDblClk_TestArea = GetDlgItem(hDlg, MOUSE_DBLCLK_TEST_AREA);
  560. GetWindowRect(pMstr->hWndDblClk_TestArea, &pMstr->DblClkRect);
  561. MapWindowPoints(NULL, hDlg, (LPPOINT) &pMstr->DblClkRect, 2);
  562. pMstr->hIconDblClick[0] = LoadIcon(hInstDlg, MAKEINTRESOURCE(ICON_FOLDER_CLOSED));
  563. pMstr->hIconDblClick[1] = LoadIcon(hInstDlg, MAKEINTRESOURCE(ICON_FOLDER_OPEN));
  564. SendMessage(pMstr->hWndDblClk_TestArea, STM_SETICON, (WPARAM)pMstr->hIconDblClick[0], 0L);
  565. //
  566. // Set (and get), then restore the state of the mouse buttons.
  567. //
  568. (pMstr->bOrigSwap) = (pMstr->bSwap) = SwapMouseButton(TRUE);
  569. SwapMouseButton(pMstr->bOrigSwap);
  570. #ifdef SHELL_SINGLE_CLICK
  571. //
  572. // Get shell single-click behavior:
  573. //
  574. SHGetSetSettings( &shellstate, SSF_DOUBLECLICKINWEBVIEW | SSF_WIN95CLASSIC, FALSE /*get*/ ) ;
  575. pMstr->bShellSingleClick =
  576. pMstr->bOrigShellSingleClick = shellstate.fWin95Classic ? FALSE :
  577. shellstate.fDoubleClickInWebView ? FALSE :
  578. TRUE ;
  579. pMstr->hIconSglClick = LoadIcon( hInstDlg, MAKEINTRESOURCE( IDI_SGLCLICK ) ) ;
  580. pMstr->hIconDblClick = LoadIcon( hInstDlg, MAKEINTRESOURCE( IDI_DBLCLICK ) ) ;
  581. ShellClick_UpdateUI( hDlg, pMstr ) ;
  582. #endif //SHELL_SINGLE_CLICK
  583. //
  584. // Initialize check/radio button state
  585. //
  586. ShowButtonState(pMstr);
  587. pMstr->OrigDblClkSpeed =
  588. pMstr->ClickSpeed = (SHORT) GetIntFromReg( HKEY_CURRENT_USER,
  589. szRegStr_Mouse,
  590. szDblClkSpeed,
  591. DBLCLICK_DEFAULT_TIME );
  592. pMstr->hWndDblClkScroll = GetDlgItem(hDlg, MOUSE_CLICKSCROLL);
  593. SendMessage( pMstr->hWndDblClkScroll,
  594. TBM_SETRANGE,
  595. 0,
  596. MAKELONG(DBLCLICK_TIME_SLIDER_MIN, DBLCLICK_TIME_SLIDER_MAX) );
  597. SendMessage( pMstr->hWndDblClkScroll,
  598. TBM_SETPOS,
  599. TRUE,
  600. (LONG) (DBLCLICK_TIME_TO_TICKS(pMstr->ClickSpeed)) );
  601. SetDoubleClickTime(pMstr->ClickSpeed);
  602. //
  603. //Get clicklock settings and set the checkbox
  604. //
  605. SystemParametersInfo(SPI_GETMOUSECLICKLOCK, 0, (PVOID)&dwClickLockSetting, 0);
  606. pMstr->bOrigClickLock = pMstr->bClickLock = (dwClickLockSetting) ? TRUE : FALSE;
  607. if ( pMstr->bClickLock )
  608. {
  609. CheckDlgButton (hDlg, IDCK_CLICKLOCK, BST_CHECKED);
  610. EnableWindow(hwndClickLockSettingsButton, TRUE);
  611. }
  612. else
  613. {
  614. CheckDlgButton (hDlg, IDCK_CLICKLOCK, BST_UNCHECKED);
  615. EnableWindow(hwndClickLockSettingsButton, FALSE);
  616. }
  617. // click lock speed
  618. {
  619. DWORD dwClTime = 0;
  620. SystemParametersInfo(SPI_GETMOUSECLICKLOCKTIME, 0, (PVOID)&dwClTime, 0);
  621. dwClTime = max(dwClTime, CLICKLOCK_TIME_SLIDER_MIN * CLICKLOCK_TIME_FACTOR);
  622. dwClTime = min(dwClTime, CLICKLOCK_TIME_SLIDER_MAX * CLICKLOCK_TIME_FACTOR);
  623. pMstr->dwOrigClickLockTime = pMstr->dwClickLockTime = dwClTime;
  624. }
  625. return (TRUE);
  626. }
  627. ////////////////////////////////////////////////////////////////////////////
  628. //
  629. // MouseButDlg
  630. //
  631. ////////////////////////////////////////////////////////////////////////////
  632. INT_PTR CALLBACK MouseButDlg(
  633. HWND hDlg,
  634. UINT message,
  635. WPARAM wParam,
  636. LPARAM lParam)
  637. {
  638. static int iTestIcon = 0; //index into hIconDblClick array
  639. PMOUSEBUTSTR pMstr = (PMOUSEBUTSTR)GetWindowLongPtr(hDlg, DWLP_USER);
  640. switch (message)
  641. {
  642. case ( WM_INITDIALOG ) :
  643. {
  644. iTestIcon = 0;
  645. return (InitMouseButDlg(hDlg));
  646. }
  647. case ( WM_DESTROY ) :
  648. {
  649. DestroyMouseButDlg(pMstr);
  650. break;
  651. }
  652. case ( WM_HSCROLL ) :
  653. {
  654. if ((HWND)lParam == pMstr->hWndDblClkScroll)
  655. {
  656. short temp = DBLCLICK_TICKS_TO_TIME((short)SendMessage( (HWND)lParam,
  657. TBM_GETPOS,
  658. 0,
  659. 0L ));
  660. if (temp != pMstr->ClickSpeed)
  661. {
  662. pMstr->ClickSpeed = temp;
  663. SetDoubleClickTime(pMstr->ClickSpeed);
  664. SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
  665. }
  666. }
  667. break;
  668. }
  669. case ( WM_RBUTTONDBLCLK ) :
  670. case ( WM_LBUTTONDBLCLK ) :
  671. {
  672. POINT point = { (int)MAKEPOINTS(lParam).x,
  673. (int)MAKEPOINTS(lParam).y };
  674. if (PtInRect(&pMstr->DblClkRect, point))
  675. {
  676. iTestIcon ^= 1;
  677. SendMessage(pMstr->hWndDblClk_TestArea, STM_SETICON,
  678. (WPARAM)pMstr->hIconDblClick[iTestIcon], 0L);
  679. }
  680. break;
  681. }
  682. case ( WM_COMMAND ) :
  683. {
  684. switch (LOWORD(wParam))
  685. {
  686. case ( IDCK_CLICKLOCK ) :
  687. {
  688. HWND hwndClickLockSettingsButton = GetDlgItem(hDlg, IDBTN_CLICKLOCK_SETTINGS);
  689. SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
  690. pMstr->bClickLock = !(pMstr->bClickLock);
  691. // update control(s) appearance
  692. CheckDlgButton (hDlg, IDCK_CLICKLOCK, ( pMstr->bClickLock ) ? BST_CHECKED : BST_UNCHECKED);
  693. EnableWindow(hwndClickLockSettingsButton, ( pMstr->bClickLock ) ? TRUE : FALSE);
  694. SystemParametersInfo(SPI_SETMOUSECLICKLOCK,
  695. 0,
  696. IntToPtr(pMstr->bClickLock),
  697. 0);
  698. break;
  699. }
  700. case ( IDBTN_CLICKLOCK_SETTINGS ) :
  701. {
  702. LPARAM lRet;
  703. UINT code = HIWORD(wParam);
  704. DWORD dwTempClickLockTime = pMstr->dwClickLockTime;
  705. if (code == BN_CLICKED)
  706. {
  707. lRet = DialogBoxParam ((HINSTANCE)GetWindowLongPtr( hDlg, GWLP_HINSTANCE ),
  708. MAKEINTRESOURCE(IDD_CLICKLOCK_SETTINGS_DLG ),
  709. GetParent (hDlg),
  710. ClickLockSettingsDlg,
  711. (LPARAM) &dwTempClickLockTime);
  712. if (lRet == IDOK &&
  713. pMstr->dwClickLockTime != dwTempClickLockTime)
  714. {
  715. pMstr->dwClickLockTime = dwTempClickLockTime;
  716. SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
  717. }
  718. else if (lRet == IDCANCEL)
  719. {
  720. //set back
  721. DWORD dwClTime = pMstr->dwClickLockTime;
  722. SystemParametersInfo(SPI_SETMOUSECLICKLOCKTIME,
  723. 0,
  724. IntToPtr(LOWORD(dwClTime)),
  725. 0);
  726. }
  727. }
  728. break;
  729. }
  730. case ( IDBTN_BUTTONSWAP) :
  731. {
  732. pMstr->bSwap = !pMstr->bSwap;
  733. SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
  734. SystemParametersInfo( SPI_SETMOUSEBUTTONSWAP,
  735. pMstr->bSwap,
  736. NULL,
  737. 0);
  738. ShowButtonState(pMstr);
  739. }
  740. #ifdef SHELL_SINGLE_CLICK
  741. case ( MOUSE_SGLCLICK ) :
  742. case ( MOUSE_DBLCLICK ) :
  743. {
  744. if( pMstr->bShellSingleClick != (MOUSE_SGLCLICK == LOWORD(wParam)) )
  745. {
  746. pMstr->bShellSingleClick = (MOUSE_SGLCLICK == LOWORD(wParam)) ;
  747. ShellClick_UpdateUI( hDlg, pMstr ) ;
  748. SendMessage( GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L ) ;
  749. }
  750. break ;
  751. }
  752. #endif // SHELL_SINGLE_CLICK
  753. }
  754. break;
  755. }
  756. case ( WM_NOTIFY ) :
  757. {
  758. switch (((NMHDR *)lParam)->code)
  759. {
  760. case ( PSN_APPLY ) :
  761. {
  762. HourGlass(TRUE);
  763. //
  764. // Apply Button Swap setting.
  765. //
  766. if (pMstr->bSwap != pMstr->bOrigSwap)
  767. {
  768. SystemParametersInfo( SPI_SETMOUSEBUTTONSWAP,
  769. pMstr->bSwap,
  770. NULL,
  771. SPIF_UPDATEINIFILE |
  772. SPIF_SENDWININICHANGE );
  773. pMstr->bOrigSwap = pMstr->bSwap;
  774. }
  775. //
  776. // Apply DoubleClickTime setting.
  777. //
  778. if (pMstr->ClickSpeed != pMstr->OrigDblClkSpeed)
  779. {
  780. SystemParametersInfo( SPI_SETDOUBLECLICKTIME,
  781. pMstr->ClickSpeed,
  782. NULL,
  783. SPIF_UPDATEINIFILE |
  784. SPIF_SENDWININICHANGE );
  785. pMstr->OrigDblClkSpeed = pMstr->ClickSpeed;
  786. }
  787. //
  788. // Apply ClickLock setting.
  789. //
  790. if (pMstr->bClickLock != pMstr->bOrigClickLock)
  791. {
  792. SystemParametersInfo(SPI_SETMOUSECLICKLOCK,
  793. 0,
  794. IntToPtr(pMstr->bClickLock),
  795. SPIF_UPDATEINIFILE |
  796. SPIF_SENDWININICHANGE);
  797. pMstr->bOrigClickLock = pMstr->bClickLock;
  798. }
  799. //
  800. // Apply ClickLockTime setting.
  801. //
  802. if (pMstr->dwClickLockTime != pMstr->dwOrigClickLockTime)
  803. {
  804. SystemParametersInfo(SPI_SETMOUSECLICKLOCKTIME,
  805. 0,
  806. (PVOID) (LOWORD(pMstr->dwClickLockTime)),
  807. SPIF_UPDATEINIFILE |
  808. SPIF_SENDWININICHANGE );
  809. pMstr->dwOrigClickLockTime = pMstr->dwClickLockTime;
  810. }
  811. #ifdef SHELL_SINGLE_CLICK
  812. if( pMstr->bOrigShellSingleClick != pMstr->bShellSingleClick )
  813. {
  814. SHELLSTATE shellstate = {0} ;
  815. ULONG dwFlags = SSF_DOUBLECLICKINWEBVIEW ;
  816. shellstate.fWin95Classic =
  817. shellstate.fDoubleClickInWebView = !pMstr->bShellSingleClick ;
  818. // update the WIN95CLASSIC member only if we've chosen single-click.
  819. if( pMstr->bShellSingleClick )
  820. dwFlags |= SSF_WIN95CLASSIC ;
  821. SHGetSetSettings( &shellstate, dwFlags, TRUE ) ;
  822. ShellClick_Refresh( pMstr ) ;
  823. pMstr->bOrigShellSingleClick = pMstr->bShellSingleClick ;
  824. }
  825. #endif //SHELL_SINGLE_CLICK
  826. HourGlass(FALSE);
  827. break;
  828. }
  829. case ( PSN_RESET ) :
  830. {
  831. //
  832. // Reset Button Swap setting.
  833. //
  834. if (pMstr->bSwap != pMstr->bOrigSwap)
  835. {
  836. SystemParametersInfo( SPI_SETMOUSEBUTTONSWAP,
  837. pMstr->bOrigSwap,
  838. NULL,
  839. 0);
  840. }
  841. //
  842. // Reset DoubleClickTime setting.
  843. //
  844. if (pMstr->ClickSpeed != pMstr->OrigDblClkSpeed)
  845. {
  846. SystemParametersInfo( SPI_SETDOUBLECLICKTIME,
  847. pMstr->OrigDblClkSpeed,
  848. NULL,
  849. 0);
  850. }
  851. //
  852. // Reset ClickLock setting.
  853. //
  854. if (pMstr->bClickLock != pMstr->bOrigClickLock)
  855. {
  856. SystemParametersInfo(SPI_SETMOUSECLICKLOCK,
  857. 0,
  858. IntToPtr(pMstr->bOrigClickLock),
  859. 0);
  860. }
  861. //
  862. // Reset ClickLockTime setting.
  863. //
  864. if (pMstr->dwClickLockTime != pMstr->dwOrigClickLockTime)
  865. {
  866. SystemParametersInfo(SPI_SETMOUSECLICKLOCKTIME,
  867. 0,
  868. (PVOID) (LOWORD(pMstr->dwOrigClickLockTime)),
  869. 0);
  870. }
  871. #ifdef SHELL_SINGLE_CLICK
  872. if( pMstr->bOrigShellSingleClick != pMstr->bShellSingleClick )
  873. {
  874. SHELLSTATE shellstate = {0} ;
  875. ULONG dwFlags = SSF_DOUBLECLICKINWEBVIEW ;
  876. shellstate.fWin95Classic =
  877. shellstate.fDoubleClickInWebView = !pMstr->bOrigShellSingleClick ;
  878. // update the WIN95CLASSIC member only if we've chosen single-click.
  879. if( pMstr->bShellSingleClick )
  880. dwFlags |= SSF_WIN95CLASSIC ;
  881. SHGetSetSettings( &shellstate, dwFlags, TRUE ) ;
  882. ShellClick_Refresh( pMstr ) ;
  883. pMstr->bShellSingleClick = pMstr->bOrigShellSingleClick ;
  884. }
  885. #endif //SHELL_SINGLE_CLICK
  886. break;
  887. }
  888. default :
  889. {
  890. return (FALSE);
  891. }
  892. }
  893. break;
  894. }
  895. case ( WM_HELP ) : // F1
  896. {
  897. WinHelp( ((LPHELPINFO)lParam)->hItemHandle,
  898. HELP_FILE,
  899. HELP_WM_HELP,
  900. (DWORD_PTR)(LPTSTR)aMouseButHelpIds );
  901. break;
  902. }
  903. case ( WM_CONTEXTMENU ) : // right mouse click
  904. {
  905. WinHelp( (HWND) wParam,
  906. HELP_FILE,
  907. HELP_CONTEXTMENU,
  908. (DWORD_PTR)(LPTSTR)aMouseButHelpIds );
  909. break;
  910. }
  911. case ( WM_DISPLAYCHANGE ) :
  912. case ( WM_WININICHANGE ) :
  913. case ( WM_SYSCOLORCHANGE ) :
  914. {
  915. SHPropagateMessage(hDlg, message, wParam, lParam, TRUE);
  916. return TRUE;
  917. }
  918. default :
  919. {
  920. return (FALSE);
  921. }
  922. }
  923. return (TRUE);
  924. }
  925. #ifdef SHELL_SINGLE_CLICK
  926. ////////////////////////////////////////////////////////////////////////////
  927. //
  928. // ShellClick_UpdateUI
  929. //
  930. // Assigns the appropriate icon for shell single/double click
  931. //
  932. ////////////////////////////////////////////////////////////////////////////
  933. void ShellClick_UpdateUI(
  934. HWND hDlg,
  935. PMOUSEBUTSTR pMstr)
  936. {
  937. HICON hicon = pMstr->bShellSingleClick ? pMstr->hIconSglClick :
  938. pMstr->hIconDblClick ;
  939. SendMessage( GetDlgItem( hDlg, MOUSE_CLICKICON ), STM_SETICON,
  940. (WPARAM)hicon, 0L ) ;
  941. }
  942. #endif //SHELL_SINGLE_CLICK
  943. ////////////////////////////////////////////////////////////////////////////
  944. //
  945. // IsShellWindow
  946. //
  947. // Determines whether the specified window is a shell folder window.
  948. //
  949. ////////////////////////////////////////////////////////////////////////////
  950. #define c_szExploreClass TEXT("ExploreWClass")
  951. #define c_szIExploreClass TEXT("IEFrame")
  952. #ifdef IE3CLASSNAME
  953. #define c_szCabinetClass TEXT("IEFrame")
  954. #else
  955. #define c_szCabinetClass TEXT("CabinetWClass")
  956. #endif
  957. BOOL IsShellWindow( HWND hwnd )
  958. {
  959. TCHAR szClass[32];
  960. GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
  961. return (lstrcmp(szClass, c_szCabinetClass) == 0) ||
  962. (lstrcmp(szClass, c_szExploreClass) == 0) ||
  963. (lstrcmp(szClass, c_szIExploreClass) == 0) ;
  964. }
  965. //The following value is taken from shdocvw\rcids.h
  966. #ifndef FCIDM_REFRESH
  967. #define FCIDM_REFRESH 0xA220
  968. #endif // FCIDM_REFRESH
  969. ////////////////////////////////////////////////////////////////////////////
  970. //
  971. // ShellClick_RefreshEnumProc
  972. //
  973. // EnumWindow callback for shell refresh.
  974. //
  975. ////////////////////////////////////////////////////////////////////////////
  976. BOOL CALLBACK ShellClick_RefreshEnumProc( HWND hwnd, LPARAM lParam )
  977. {
  978. if( IsShellWindow(hwnd) )
  979. PostMessage(hwnd, WM_COMMAND, FCIDM_REFRESH, 0L);
  980. return(TRUE);
  981. }
  982. ////////////////////////////////////////////////////////////////////////////
  983. //
  984. // ShellClick_Refresh
  985. //
  986. // Re-renders the contents of all shell folder windows.
  987. //
  988. ////////////////////////////////////////////////////////////////////////////
  989. void ShellClick_Refresh( PMOUSEBUTSTR pMstr )
  990. {
  991. HWND hwndDesktop = FindWindowEx(NULL, NULL, TEXT(STR_DESKTOPCLASS), NULL);
  992. if( NULL != hwndDesktop )
  993. PostMessage( hwndDesktop, WM_COMMAND, FCIDM_REFRESH, 0L );
  994. EnumWindows( ShellClick_RefreshEnumProc, 0L ) ;
  995. }