xref: /reactos/dll/cpl/main/mouse.c (revision 9ea495ba)
1 /*
2  *  ReactOS
3  *  Copyright (C) 2004, 2007 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /* $Id$
20  *
21  * PROJECT:         ReactOS Main Control Panel
22  * FILE:            lib/cpl/main/mouse.c
23  * PURPOSE:         Mouse Control Panel
24  * PROGRAMMER:      Eric Kohl
25  *                  Johannes Anderwald
26  */
27 
28 //TODO:
29 //  add missing icons
30 
31 #include <windows.h>
32 #include <winuser.h>
33 #include <devguid.h>
34 #include <commctrl.h>
35 #include <cpl.h>
36 #include <tchar.h>
37 #include <math.h>
38 #include <limits.h>
39 #include <shlobj.h>
40 #include <cplext.h>
41 #include <regstr.h>
42 
43 #include <stdio.h>
44 
45 #include "main.h"
46 #include "resource.h"
47 
48 #define DEFAULT_DOUBLE_CLICK_SPEED	500
49 #define DEFAULT_CLICK_LOCK_TIME		2200
50 #define DEFAULT_MOUSE_SPEED		10
51 #define DEFAULT_MOUSE_ACCELERATION	1
52 #define DEFAULT_MOUSE_THRESHOLD1	6
53 #define DEFAULT_MOUSE_THRESHOLD2	10
54 #define MIN_DOUBLE_CLICK_SPEED		200
55 #define MAX_DOUBLE_CLICK_SPEED		900
56 #define DEFAULT_WHEEL_SCROLL_LINES	3
57 
58 typedef struct _BUTTON_DATA
59 {
60     ULONG g_SwapMouseButtons;
61     ULONG g_OrigSwapMouseButtons;
62     ULONG g_DoubleClickSpeed; // = DEFAULT_DOUBLE_CLICK_SPEED;
63     ULONG g_OrigDoubleClickSpeed;
64     BOOL g_ClickLockEnabled; // = 0;
65     DWORD g_ClickLockTime; // = DEFAULT_CLICK_LOCK_TIME;
66 
67     HICON hButtonLeft;
68     HICON hButtonRight;
69 
70     HICON hIcon1;
71     HICON hIcon2;
72     BOOL bClicked;
73 } BUTTON_DATA, *PBUTTON_DATA;
74 
75 
76 typedef struct _POINTER_DATA
77 {
78     BOOL bCursorShadow;
79     BOOL bOrigCursorShadow;
80 
81     INT cxCursor;
82     INT cyCursor;
83 } POINTER_DATA, *PPOINTER_DATA;
84 
85 
86 typedef struct _MOUSE_ACCEL
87 {
88     INT nThreshold1;
89     INT nThreshold2;
90     INT nAcceleration;
91 } MOUSE_ACCEL;
92 
93 typedef struct _OPTION_DATA
94 {
95     ULONG ulMouseSpeed;
96     ULONG ulOrigMouseSpeed;
97 
98     MOUSE_ACCEL MouseAccel;
99     MOUSE_ACCEL OrigMouseAccel;
100 
101     BOOL bSnapToDefaultButton;
102     BOOL bOrigSnapToDefaultButton;
103 
104     UINT uMouseTrails;
105     UINT uOrigMouseTrails;
106 
107     BOOL bMouseVanish;
108     BOOL bOrigMouseVanish;
109 
110     BOOL bMouseSonar;
111     BOOL bOrigMouseSonar;
112 } OPTION_DATA, *POPTION_DATA;
113 
114 
115 typedef struct _WHEEL_DATA
116 {
117     UINT uWheelScrollLines;
118 } WHEEL_DATA, *PWHEEL_DATA;
119 
120 
121 typedef struct _CURSOR_DATA
122 {
123     UINT uStringId;
124     UINT uDefaultCursorId;
125     LPTSTR lpValueName;
126     HCURSOR hCursor;
127     TCHAR szCursorName[MAX_PATH];
128     TCHAR szCursorPath[MAX_PATH];
129 } CURSOR_DATA, *PCURSOR_DATA;
130 
131 
132 CURSOR_DATA g_CursorData[] =
133 {{IDS_ARROW,       100/*OCR_NORMAL*/,      _T("Arrow"),       0, _T(""), _T("")},
134  {IDS_HELP,        112/*OCR_HELP*/,        _T("Help"),        0, _T(""), _T("")},
135  {IDS_APPSTARTING, 111/*OCR_APPSTARTING*/, _T("AppStarting"), 0, _T(""), _T("")},
136  {IDS_WAIT,        102/*OCR_WAIT*/,        _T("Wait"),        0, _T(""), _T("")},
137  {IDS_CROSSHAIR,   103/*OCR_CROSS*/,       _T("Crosshair"),   0, _T(""), _T("")},
138  {IDS_IBEAM,       101/*OCR_IBEAM*/,       _T("IBeam"),       0, _T(""), _T("")},
139  {IDS_NWPEN,       113/*OCR_NWPEN*/,       _T("NWPen"),       0, _T(""), _T("")},
140  {IDS_NO,          110/*OCR_NO*/,          _T("No"),          0, _T(""), _T("")},
141  {IDS_SIZENS,      108/*OCR_SIZENS*/,      _T("SizeNS"),      0, _T(""), _T("")},
142  {IDS_SIZEWE,      107/*OCR_SIZEWE*/,      _T("SizeWE"),      0, _T(""), _T("")},
143  {IDS_SIZENWSE,    105/*OCR_SIZENWSE*/,    _T("SizeNWSE"),    0, _T(""), _T("")},
144  {IDS_SIZENESW,    106/*OCR_SIZENESW*/,    _T("SizeNESW"),    0, _T(""), _T("")},
145  {IDS_SIZEALL,     109/*OCR_SIZEALL*/,     _T("SizeAll"),     0, _T(""), _T("")},
146  {IDS_UPARROW,     104/*OCR_UP*/,          _T("UpArrow"),     0, _T(""), _T("")},
147  {IDS_HAND,        114/*OCR_HAND*/,        _T("Hand"),        0, _T(""), _T("")}};
148 
149 
150 #if 0
151 static VOID
152 DebugMsg(LPTSTR fmt, ...)
153 {
154     TCHAR szBuffer[2048];
155     va_list marker;
156 
157     va_start(marker, fmt);
158     _vstprintf(szBuffer, fmt, marker);
159     va_end(marker);
160 
161     MessageBox(NULL, szBuffer, _T("Debug message"), MB_OK);
162 }
163 #endif
164 
165 
166 /* Property page dialog callback */
167 static INT_PTR CALLBACK
168 MouseHardwareProc(IN HWND hwndDlg,
169                   IN UINT uMsg,
170                   IN WPARAM wParam,
171                   IN LPARAM lParam)
172 {
173     GUID Guids[1];
174     Guids[0] = GUID_DEVCLASS_MOUSE;
175 
176     UNREFERENCED_PARAMETER(lParam);
177     UNREFERENCED_PARAMETER(wParam);
178 
179     switch(uMsg)
180     {
181         case WM_INITDIALOG:
182             /* create the hardware page */
183             DeviceCreateHardwarePageEx(hwndDlg,
184                                        Guids,
185                                        sizeof(Guids) / sizeof(Guids[0]),
186                                        HWPD_STANDARDLIST);
187             break;
188     }
189 
190     return FALSE;
191 }
192 
193 
194 static INT_PTR CALLBACK
195 ClickLockProc(IN HWND hwndDlg,
196               IN UINT uMsg,
197               IN WPARAM wParam,
198               IN LPARAM lParam)
199 {
200     HWND hDlgCtrl;
201     int pos;
202     static HICON hIcon;
203 
204     PBUTTON_DATA pButtonData;
205 
206     pButtonData = (PBUTTON_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
207 
208     switch(uMsg)
209     {
210         case WM_INITDIALOG:
211             pButtonData = (PBUTTON_DATA)lParam;
212             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pButtonData);
213 
214             hDlgCtrl = GetDlgItem(hwndDlg, IDC_SLIDER_CLICK_LOCK);
215             SendMessage(hDlgCtrl, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 10));
216             pos = (pButtonData->g_ClickLockTime - 200) / 200;
217             SendMessage(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos);
218 
219             hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_LOOK_KEY),
220                               IMAGE_ICON, 16, 16, 0);
221             SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
222             return TRUE;
223 
224         case WM_COMMAND:
225             if (LOWORD(wParam) == IDOK)
226             {
227                 hDlgCtrl = GetDlgItem(hwndDlg, IDC_SLIDER_CLICK_LOCK);
228                 pButtonData->g_ClickLockTime = (DWORD) (SendMessage(hDlgCtrl, TBM_GETPOS, 0, 0) * 200) + 200;
229                 EndDialog(hwndDlg, TRUE);
230                 if (hIcon) DestroyIcon(hIcon);
231             }
232             else if (LOWORD(wParam) == IDCANCEL)
233             {
234                 EndDialog(hwndDlg, FALSE);
235                 if (hIcon) DestroyIcon(hIcon);
236             }
237             break;
238     }
239 
240     return FALSE;
241 }
242 
243 
244 static INT_PTR CALLBACK
245 ButtonProc(IN HWND hwndDlg,
246            IN UINT uMsg,
247            IN WPARAM wParam,
248            IN LPARAM lParam)
249 {
250     HWND hDlgCtrl;
251     LRESULT lResult;
252     LPPSHNOTIFY lppsn;
253 
254     PBUTTON_DATA pButtonData;
255 
256     pButtonData = (PBUTTON_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
257 
258     switch (uMsg)
259     {
260         case WM_INITDIALOG:
261             pButtonData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BUTTON_DATA));
262             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pButtonData);
263 
264             pButtonData->g_SwapMouseButtons = GetSystemMetrics(SM_SWAPBUTTON);
265             pButtonData->g_OrigSwapMouseButtons = pButtonData->g_SwapMouseButtons;
266             pButtonData->g_DoubleClickSpeed = GetDoubleClickTime();
267             pButtonData->g_OrigDoubleClickSpeed = pButtonData->g_DoubleClickSpeed;
268 
269             /* Click lock time */
270             SystemParametersInfo(SPI_GETMOUSECLICKLOCK, 0, &pButtonData->g_ClickLockEnabled, 0);
271             SystemParametersInfo(SPI_GETMOUSECLICKLOCKTIME, 0, &pButtonData->g_ClickLockTime, 0);
272 
273             /* Load mouse button icons */
274             pButtonData->hButtonLeft = LoadImage(hApplet, MAKEINTRESOURCE(IDI_MOUSE_LEFT), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
275             pButtonData->hButtonRight = LoadImage(hApplet, MAKEINTRESOURCE(IDI_MOUSE_RIGHT), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
276 
277             /* Load folder icons */
278             pButtonData->hIcon1 = LoadImage(hApplet, MAKEINTRESOURCE(IDI_FOLDER_CLOSED), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
279             pButtonData->hIcon2 = LoadImage(hApplet, MAKEINTRESOURCE(IDI_FOLDER_OPEN), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
280 
281             if (pButtonData->g_SwapMouseButtons)
282             {
283                 SendDlgItemMessage(hwndDlg, IDC_SWAP_MOUSE_BUTTONS, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
284                 SendDlgItemMessage(hwndDlg, IDC_IMAGE_SWAP_MOUSE, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pButtonData->hButtonRight);
285             }
286             else
287             {
288                 SendDlgItemMessage(hwndDlg, IDC_IMAGE_SWAP_MOUSE, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pButtonData->hButtonLeft);
289             }
290 
291             if (pButtonData->g_ClickLockEnabled)
292             {
293                 hDlgCtrl = GetDlgItem(hwndDlg, IDC_CHECK_CLICK_LOCK);
294                 SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
295             }
296             else
297             {
298                 hDlgCtrl = GetDlgItem(hwndDlg, IDC_BUTTON_CLICK_LOCK);
299                 EnableWindow(hDlgCtrl, FALSE);
300             }
301 
302             hDlgCtrl = GetDlgItem(hwndDlg, IDC_SLIDER_DOUBLE_CLICK_SPEED);
303             SendMessage(hDlgCtrl, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 14));
304             SendMessage(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, 14 - ((pButtonData->g_DoubleClickSpeed - 200) / 50));
305 
306 
307             SendDlgItemMessage(hwndDlg, IDC_IMAGE_DOUBLE_CLICK_SPEED, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pButtonData->hIcon1);
308             pButtonData->bClicked = TRUE;
309             return TRUE;
310 
311         case WM_DESTROY:
312             DestroyIcon(pButtonData->hButtonLeft);
313             DestroyIcon(pButtonData->hButtonRight);
314             DestroyIcon(pButtonData->hIcon1);
315             DestroyIcon(pButtonData->hIcon2);
316             HeapFree(GetProcessHeap(), 0, pButtonData);
317             break;
318 
319         case WM_COMMAND:
320             switch(LOWORD(wParam))
321             {
322                 case IDC_SWAP_MOUSE_BUTTONS:
323                     lResult = SendMessage((HWND)lParam, BM_GETCHECK, (WPARAM)0, (LPARAM)0);
324                     if (lResult == BST_CHECKED)
325                     {
326                         pButtonData->g_SwapMouseButtons = FALSE;
327                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
328                         SendDlgItemMessage(hwndDlg, IDC_IMAGE_SWAP_MOUSE, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pButtonData->hButtonLeft);
329                     }
330                     else if (lResult == BST_UNCHECKED)
331                     {
332                         pButtonData->g_SwapMouseButtons = TRUE;
333                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
334                         SendDlgItemMessage(hwndDlg, IDC_IMAGE_SWAP_MOUSE, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pButtonData->hButtonRight);
335                     }
336                     //SystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, pButtonData->g_SwapMouseButtons, NULL, 0);
337                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
338                     break;
339 
340                 case IDC_CHECK_CLICK_LOCK:
341                     lResult = SendMessage((HWND)lParam, BM_GETCHECK, (WPARAM)0, (LPARAM)0);
342                     hDlgCtrl = GetDlgItem(hwndDlg, IDC_BUTTON_CLICK_LOCK);
343                     if (lResult == BST_CHECKED)
344                     {
345                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
346                         pButtonData->g_ClickLockEnabled = FALSE;
347                         EnableWindow(hDlgCtrl, FALSE);
348                     }
349                     else if (lResult == BST_UNCHECKED)
350                     {
351                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
352                         pButtonData->g_ClickLockEnabled = TRUE;
353                         EnableWindow(hDlgCtrl, TRUE);
354                     }
355                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
356                     break;
357 
358                 case IDC_BUTTON_CLICK_LOCK:
359                     DialogBoxParam(hApplet, MAKEINTRESOURCE(IDD_CLICK_LOCK), hwndDlg, ClickLockProc, (LPARAM)pButtonData);
360                     break;
361 
362                 case IDC_IMAGE_DOUBLE_CLICK_SPEED:
363                     if (HIWORD(wParam) == STN_DBLCLK)
364                     {
365                         pButtonData->bClicked = !pButtonData->bClicked;
366                         SendDlgItemMessage(hwndDlg, IDC_IMAGE_DOUBLE_CLICK_SPEED, STM_SETIMAGE, IMAGE_ICON,
367                                            (LPARAM)(pButtonData->bClicked ? pButtonData->hIcon1 : pButtonData->hIcon2));
368                     }
369                     break;
370             }
371             break;
372 
373         case WM_NOTIFY:
374             lppsn = (LPPSHNOTIFY) lParam;
375             if (lppsn->hdr.code == PSN_APPLY)
376             {
377                 if (pButtonData->g_OrigSwapMouseButtons != pButtonData->g_SwapMouseButtons)
378                 {
379                     pButtonData->g_OrigSwapMouseButtons = pButtonData->g_SwapMouseButtons;
380                     SystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, pButtonData->g_OrigSwapMouseButtons, NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
381 
382                 }
383                 SystemParametersInfo(SPI_SETDOUBLECLICKTIME, pButtonData->g_DoubleClickSpeed, NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
384                 //SetDoubleClickTime(pButtonData->g_DoubleClickSpeed);
385 
386 #if (WINVER >= 0x0500)
387                 SystemParametersInfo(SPI_SETMOUSECLICKLOCK, 0, UlongToPtr(pButtonData->g_ClickLockEnabled), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
388                 if (pButtonData->g_ClickLockEnabled)
389                    SystemParametersInfo(SPI_SETMOUSECLICKLOCKTIME, pButtonData->g_ClickLockTime, NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
390 #endif
391             }
392             else if (lppsn->hdr.code == PSN_RESET)
393             {
394                 /* Reset swap mouse button setting */
395                 SystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, pButtonData->g_OrigSwapMouseButtons, NULL, 0);
396 
397                 /* Reset double click speed setting */
398                 SystemParametersInfo(SPI_SETDOUBLECLICKTIME, pButtonData->g_OrigDoubleClickSpeed, NULL, 0);
399                 //SetDoubleClickTime(pButtonData->g_OrigDoubleClickSpeed);
400             }
401             return TRUE;
402 
403         case WM_HSCROLL:
404             if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SLIDER_DOUBLE_CLICK_SPEED))
405             {
406                 switch (LOWORD(wParam))
407                 {
408                     case TB_LINEUP:
409                     case TB_LINEDOWN:
410                     case TB_PAGEUP:
411                     case TB_PAGEDOWN:
412                     case TB_TOP:
413                     case TB_BOTTOM:
414                     case TB_ENDTRACK:
415                         lResult = SendDlgItemMessage(hwndDlg, IDC_SLIDER_DOUBLE_CLICK_SPEED, TBM_GETPOS, 0, 0);
416                         pButtonData->g_DoubleClickSpeed = (14 - (INT)lResult) * 50 + 200;
417                 	//SystemParametersInfo(SPI_SETDOUBLECLICKTIME, pButtonData->g_DoubleClickSpeed, NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
418                         SetDoubleClickTime(pButtonData->g_DoubleClickSpeed);
419                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
420                         break;
421 
422                     case TB_THUMBTRACK:
423                         pButtonData->g_DoubleClickSpeed = (14 - (INT)HIWORD(wParam)) * 50 + 200;
424                         //SystemParametersInfo(SPI_SETDOUBLECLICKTIME, pButtonData->g_DoubleClickSpeed, NULL, 0);
425                         SetDoubleClickTime(pButtonData->g_DoubleClickSpeed);
426                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
427                         break;
428                 }
429             }
430             break;
431     }
432 
433     return FALSE;
434 }
435 
436 
437 static VOID
438 CompressPath(LPTSTR lpShortPath, LPTSTR lpPath)
439 {
440     TCHAR szUserProfile[MAX_PATH];
441     TCHAR szSystemRoot[MAX_PATH];
442     TCHAR szProgramFiles[MAX_PATH];
443     DWORD dwUserProfile;
444     DWORD dwSystemRoot;
445     DWORD dwProgramFiles;
446 
447     dwUserProfile = GetEnvironmentVariable(_T("USERPROFILE"), szUserProfile, MAX_PATH);
448     dwSystemRoot = GetEnvironmentVariable(_T("SystemRoot"), szSystemRoot, MAX_PATH);
449     dwProgramFiles = GetEnvironmentVariable(_T("ProgramFiles"), szProgramFiles, MAX_PATH);
450 
451     if (dwUserProfile > 0 && _tcsncmp(lpPath, szUserProfile, dwUserProfile) == 0)
452     {
453         _tcscpy(lpShortPath, _T("%USERPROFILE%"));
454         _tcscat(lpShortPath, &lpPath[dwUserProfile]);
455     }
456     else if (dwSystemRoot > 0 && _tcsncmp(lpPath, szSystemRoot, dwSystemRoot) == 0)
457     {
458         _tcscpy(lpShortPath, _T("%SystemRoot%"));
459         _tcscat(lpShortPath, &lpPath[dwSystemRoot]);
460     }
461     else if (dwProgramFiles > 0 && _tcsncmp(lpPath, szProgramFiles, dwProgramFiles) == 0)
462     {
463         _tcscpy(lpShortPath, _T("%ProgramFiles%"));
464         _tcscat(lpShortPath, &lpPath[dwProgramFiles]);
465     }
466     else
467     {
468         _tcscpy(lpShortPath, lpPath);
469     }
470 }
471 
472 
473 static BOOL
474 EnumerateCursorSchemes(HWND hwndDlg)
475 {
476     HKEY hCursorKey;
477     DWORD dwIndex;
478     TCHAR szValueName[MAX_PATH];
479     DWORD dwValueName;
480     TCHAR szSystemScheme[MAX_PATH];
481     TCHAR szValueData[2000];
482     TCHAR szTempData[2000];
483     DWORD dwValueData;
484     LONG lError;
485     HWND hDlgCtrl;
486     LRESULT lResult;
487 
488     hDlgCtrl = GetDlgItem(hwndDlg, IDC_COMBO_CURSOR_SCHEME);
489     SendMessage(hDlgCtrl, CB_RESETCONTENT, 0, 0);
490 
491     /* Read the users cursor schemes */
492     lError = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Cursors\\Schemes"),
493                           0, KEY_READ | KEY_QUERY_VALUE , &hCursorKey);
494     if (lError == ERROR_SUCCESS)
495     {
496         for (dwIndex = 0;; dwIndex++)
497         {
498             dwValueName = sizeof(szValueName) / sizeof(TCHAR);
499             dwValueData = sizeof(szValueData) / sizeof(TCHAR);
500             lError = RegEnumValue(hCursorKey, dwIndex, szValueName, &dwValueName,
501                                   NULL, NULL, (LPBYTE)szValueData, &dwValueData);
502             if (lError == ERROR_NO_MORE_ITEMS)
503                 break;
504 
505             ExpandEnvironmentStrings(szValueData, szTempData, 2000);
506 
507             if (_tcslen(szTempData) > 0)
508             {
509                 LPTSTR lpCopy, lpStart;
510 
511                 /* Remove quotation marks */
512                 if (szTempData[0] == _T('"'))
513                 {
514                     lpStart = szValueData + 1;
515                     szTempData[_tcslen(szTempData) - 1] = 0;
516                 }
517                 else
518                 {
519                     lpStart = szTempData;
520                 }
521 
522                 lpCopy = _tcsdup(lpStart);
523 
524                 lResult = SendMessage(hDlgCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)szValueName);
525                 SendMessage(hDlgCtrl, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)lpCopy);
526             }
527         }
528 
529         RegCloseKey(hCursorKey);
530     }
531 
532     /* Read the system cursor schemes */
533     lError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
534                           _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cursors\\Schemes"),
535                           0, KEY_READ | KEY_QUERY_VALUE , &hCursorKey);
536     if (lError == ERROR_SUCCESS)
537     {
538         LoadString(hApplet, IDS_SYSTEM_SCHEME, szSystemScheme, MAX_PATH);
539 
540         for (dwIndex = 0;; dwIndex++)
541         {
542             dwValueName = sizeof(szValueName) / sizeof(TCHAR);
543             dwValueData = sizeof(szValueData) / sizeof(TCHAR);
544             lError = RegEnumValue(hCursorKey, dwIndex, szValueName, &dwValueName,
545                                   NULL, NULL, (LPBYTE)szValueData, &dwValueData);
546             if (lError == ERROR_NO_MORE_ITEMS)
547                 break;
548 
549             if (_tcslen(szValueData) > 0)
550             {
551                 LPTSTR lpCopy, lpStart;
552 
553                 /* Remove quotation marks */
554                 if (szValueData[0] == _T('"'))
555                 {
556                     lpStart = szValueData + 1;
557                     szValueData[_tcslen(szValueData) - 1] = 0;
558                 }
559                 else
560                 {
561                     lpStart = szValueData;
562                 }
563 
564                 lpCopy = _tcsdup(lpStart);
565 
566                 _tcscat(szValueName, TEXT(" "));
567                 _tcscat(szValueName, szSystemScheme);
568 
569                 lResult = SendMessage(hDlgCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)szValueName);
570                 SendMessage(hDlgCtrl, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)lpCopy);
571             }
572         }
573 
574         RegCloseKey(hCursorKey);
575     }
576 
577     /* Add the "(none)" entry */
578     LoadString(hApplet, IDS_NONE, szSystemScheme, MAX_PATH);
579     lResult = SendMessage(hDlgCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)szSystemScheme);
580     SendMessage(hDlgCtrl, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)NULL);
581 
582     return TRUE;
583 }
584 
585 
586 static VOID
587 RefreshCursorList(HWND hwndDlg, BOOL bInit)
588 {
589     INT index;
590     INT i;
591     INT nSel;
592 
593     nSel = bInit ? 0 : SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_GETCURSEL, 0, 0);
594 
595     if (bInit)
596     {
597         SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_RESETCONTENT, 0, 0);
598         for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
599         {
600             LoadString(hApplet, index, g_CursorData[i].szCursorName, MAX_PATH);
601             SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_ADDSTRING, 0, (LPARAM)i);
602         }
603 
604         SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_SETCURSEL, nSel, 0);
605     }
606     else
607     {
608         InvalidateRect(GetDlgItem(hwndDlg, IDC_LISTBOX_CURSOR), NULL, FALSE);
609     }
610 
611     SendDlgItemMessage(hwndDlg, IDC_IMAGE_CURRENT_CURSOR, STM_SETIMAGE, IMAGE_CURSOR,
612                        (LPARAM)g_CursorData[nSel].hCursor);
613 
614     EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_USE_DEFAULT_CURSOR), (g_CursorData[nSel].szCursorPath[0] != 0));
615 }
616 
617 
618 static BOOL
619 DeleteUserCursorScheme(HWND hwndDlg)
620 {
621     TCHAR szSchemeName[MAX_PATH];
622     TCHAR szTitle[128];
623     TCHAR szRawText[256];
624     TCHAR szText[256];
625     HWND hDlgCtrl;
626     HKEY hCuKey;
627     HKEY hCuCursorKey;
628     LONG lResult;
629     INT nSel;
630 
631     hDlgCtrl = GetDlgItem(hwndDlg, IDC_COMBO_CURSOR_SCHEME);
632     nSel = SendMessage(hDlgCtrl, CB_GETCURSEL, 0, 0);
633     if (nSel == CB_ERR)
634         return FALSE;
635 
636     SendMessage(hDlgCtrl, CB_GETLBTEXT, nSel, (LPARAM)szSchemeName);
637 
638     LoadString(hApplet, IDS_REMOVE_TITLE, szTitle, 128);
639     LoadString(hApplet, IDS_REMOVE_TEXT, szRawText, 256);
640 
641     _stprintf(szText, szRawText, szSchemeName);
642 
643     /* Confirm scheme removal */
644     if (MessageBox(hwndDlg, szText, szTitle, MB_YESNO | MB_ICONQUESTION) == IDNO)
645         return TRUE;
646 
647     if (RegOpenCurrentUser(KEY_READ | KEY_SET_VALUE, &hCuKey) != ERROR_SUCCESS)
648         return FALSE;
649 
650     if (RegOpenKeyEx(hCuKey, _T("Control Panel\\Cursors\\Schemes"), 0, KEY_READ | KEY_SET_VALUE, &hCuCursorKey) != ERROR_SUCCESS)
651     {
652         RegCloseKey(hCuKey);
653         return FALSE;
654     }
655 
656     lResult = RegDeleteValue(hCuCursorKey, szSchemeName);
657 
658     RegCloseKey(hCuCursorKey);
659     RegCloseKey(hCuKey);
660 
661     if (lResult == ERROR_SUCCESS)
662     {
663         SendMessage(hDlgCtrl, CB_DELETESTRING, nSel, 0);
664         SendMessage(hDlgCtrl, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
665     }
666 
667     return (lResult == ERROR_SUCCESS);
668 }
669 
670 
671 static INT_PTR CALLBACK
672 SaveSchemeProc(IN HWND hwndDlg,
673                IN UINT uMsg,
674                IN WPARAM wParam,
675                IN LPARAM lParam)
676 {
677     LPTSTR pSchemeName;
678 
679     switch (uMsg)
680     {
681         case WM_INITDIALOG:
682             pSchemeName = (LPTSTR)lParam;
683             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSchemeName);
684             SendDlgItemMessage(hwndDlg, IDC_EDIT_SCHEME_NAME, WM_SETTEXT,
685                                0, (LPARAM)pSchemeName);
686             break;
687 
688         case WM_COMMAND:
689             if (LOWORD(wParam) == IDOK)
690             {
691                 pSchemeName = (LPTSTR)GetWindowLongPtr(hwndDlg, DWLP_USER);
692                 SendDlgItemMessage(hwndDlg, IDC_EDIT_SCHEME_NAME, WM_GETTEXT,
693                                    (WPARAM)MAX_PATH, (LPARAM)pSchemeName);
694                 EndDialog(hwndDlg, TRUE);
695             }
696             else if (LOWORD(wParam) == IDCANCEL)
697             {
698                 EndDialog(hwndDlg, FALSE);
699             }
700             break;
701     }
702 
703     return FALSE;
704 }
705 
706 
707 static BOOL
708 SaveCursorScheme(HWND hwndDlg)
709 {
710     TCHAR szSystemScheme[MAX_PATH];
711     TCHAR szSchemeName[MAX_PATH];
712     TCHAR szNewSchemeName[MAX_PATH];
713     TCHAR szTempPath[MAX_PATH];
714     TCHAR szTitle[128];
715     TCHAR szText[256];
716     INT nSel;
717     INT index, i, nLength;
718     LPTSTR lpSchemeData;
719     HKEY hCuKey;
720     HKEY hCuCursorKey;
721     LONG lError = ERROR_SUCCESS;
722     BOOL bSchemeExists;
723 
724     LoadString(hApplet, IDS_SYSTEM_SCHEME, szSystemScheme, MAX_PATH);
725 
726     nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETCURSEL, 0, 0);
727     if (nSel == CB_ERR)
728        return FALSE;
729 
730     if (nSel == 0)
731     {
732         szSchemeName[0] = 0;
733     }
734     else
735     {
736         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETLBTEXT, nSel, (LPARAM)szNewSchemeName);
737 
738         if (_tcsstr(szNewSchemeName, szSystemScheme))
739         {
740             szNewSchemeName[_tcslen(szNewSchemeName) - _tcslen(szSystemScheme) - 1] = 0;
741         }
742     }
743 
744     /* Ask for a name for the new cursor scheme */
745     if (!DialogBoxParam(hApplet, MAKEINTRESOURCE(IDD_CURSOR_SCHEME_SAVEAS),
746                         hwndDlg, SaveSchemeProc, (LPARAM)szNewSchemeName))
747         return TRUE;
748 
749     /* Check all non-system schemes for the new name */
750     nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETCOUNT, 0, 0);
751     if (nSel == CB_ERR)
752         return FALSE;
753 
754     bSchemeExists = FALSE;
755     for (i = 0; i < nSel; i++)
756     {
757         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETLBTEXT, i, (LPARAM)szSchemeName);
758         if (_tcsstr(szSchemeName, szSystemScheme) == NULL)
759         {
760             if (_tcscmp(szSchemeName, szNewSchemeName) == 0)
761             {
762                 bSchemeExists = TRUE;
763                 break;
764             }
765         }
766     }
767 
768     if (bSchemeExists)
769     {
770         LoadString(hApplet, IDS_OVERWRITE_TITLE, szTitle, 128);
771         LoadString(hApplet, IDS_OVERWRITE_TEXT, szText, 256);
772 
773          /* Confirm scheme overwrite */
774         if (MessageBox(hwndDlg, szText, szTitle, MB_YESNO | MB_ICONQUESTION) == IDNO)
775             return TRUE;
776     }
777 
778     /* Save the cursor scheme */
779     nLength = 0;
780     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
781     {
782         if (i > 0)
783             nLength++;
784         nLength += _tcslen(g_CursorData[i].szCursorPath);
785     }
786     nLength++;
787 
788     lpSchemeData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(TCHAR));
789 
790     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
791     {
792         CompressPath(szTempPath, g_CursorData[i].szCursorPath);
793         if (i > 0)
794             _tcscat(lpSchemeData, _T(","));
795         _tcscat(lpSchemeData, szTempPath);
796     }
797 
798     if (RegOpenCurrentUser(KEY_READ | KEY_SET_VALUE, &hCuKey) != ERROR_SUCCESS)
799         return FALSE;
800 
801     if (RegOpenKeyEx(hCuKey, _T("Control Panel\\Cursors\\Schemes"), 0, KEY_READ | KEY_SET_VALUE, &hCuCursorKey) != ERROR_SUCCESS)
802     {
803         RegCloseKey(hCuKey);
804         return FALSE;
805     }
806 
807     lError = RegSetValueEx(hCuCursorKey, szNewSchemeName, 0,
808                            REG_EXPAND_SZ, (LPBYTE)lpSchemeData,
809                            (_tcslen(lpSchemeData) + 1) * sizeof(TCHAR));
810 
811     RegCloseKey(hCuCursorKey);
812     RegCloseKey(hCuKey);
813 
814     /* Add the new scheme to the scheme list and select it */
815     if (lError == ERROR_SUCCESS)
816     {
817         LPTSTR copy = _tcsdup(lpSchemeData);
818 
819         nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_ADDSTRING, (WPARAM)0, (LPARAM)szNewSchemeName);
820         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_SETITEMDATA, (WPARAM)nSel, (LPARAM)copy);
821         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_SETCURSEL, (WPARAM)nSel, (LPARAM)0);
822     }
823 
824     HeapFree(GetProcessHeap(), 0, lpSchemeData);
825 
826     return (lError == ERROR_SUCCESS);
827 }
828 
829 
830 static BOOL
831 BrowseCursor(HWND hwndDlg)
832 {
833     TCHAR szFileName[MAX_PATH];
834     TCHAR szFilter[MAX_PATH];
835     TCHAR szTitle[MAX_PATH];
836     OPENFILENAME ofn;
837     INT nSel;
838 
839     LoadString(hApplet, IDS_BROWSE_FILTER, szFilter, MAX_PATH);
840     LoadString(hApplet, IDS_BROWSE_TITLE, szTitle, MAX_PATH);
841 
842     memset(szFileName, 0x0, sizeof(szFileName));
843     nSel = SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_GETCURSEL, 0, 0);
844     if (nSel == LB_ERR)
845     {
846         MessageBox(hwndDlg, _T("LB_ERR"), _T(""), MB_ICONERROR);
847         return FALSE;
848     }
849 
850     ZeroMemory(&ofn, sizeof(OPENFILENAME));
851     ofn.lStructSize = sizeof(OPENFILENAME);
852     ofn.hwndOwner = hwndDlg;
853     ofn.lpstrFilter = szFilter;
854     ofn.nFilterIndex = 1;
855     ofn.lpstrFile = szFileName;
856     ofn.nMaxFile = MAX_PATH;
857     ofn.lpstrInitialDir = _T("%WINDIR%\\Cursors");
858     ofn.lpstrTitle = szTitle;
859     ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
860 
861     if (!GetOpenFileName(&ofn))
862         return FALSE;
863 
864     /* Store the new cursor file path */
865     _tcsncpy(g_CursorData[nSel].szCursorPath, szFileName, MAX_PATH);
866 
867     return TRUE;
868 }
869 
870 
871 static VOID
872 LoadCursorScheme(LPTSTR lpName, BOOL bSystem)
873 {
874     UINT index, i;
875 
876     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
877     {
878         if (g_CursorData[i].hCursor != NULL)
879         {
880             DestroyCursor(g_CursorData[i].hCursor);
881             g_CursorData[i].hCursor = 0;
882         }
883         g_CursorData[i].szCursorPath[0] = 0;
884     }
885 
886     if (lpName != NULL)
887     {
888         LPTSTR pStart = lpName;
889         LPTSTR pEnd = pStart;
890         INT nLength;
891 
892         i = 0;
893         while (pEnd)
894         {
895             pEnd = _tcschr(pStart, _T(','));
896             if (pEnd)
897                 nLength = ((INT_PTR)pEnd - (INT_PTR)pStart) / sizeof(TCHAR);
898             else
899                 nLength = _tcslen(pStart);
900 
901             _tcsncpy(g_CursorData[i].szCursorPath, pStart, nLength);
902             g_CursorData[i].szCursorPath[nLength] = 0;
903 
904             pStart = pStart + (nLength + 1);
905             i++;
906         }
907 
908     }
909 
910     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
911     {
912         if (g_CursorData[i].szCursorPath[0] == 0)
913             g_CursorData[i].hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(g_CursorData[i].uDefaultCursorId),
914                                                          IMAGE_CURSOR, 0, 0,
915                                                          LR_DEFAULTSIZE | LR_SHARED);
916         else
917             g_CursorData[i].hCursor = (HCURSOR)LoadImage(NULL, g_CursorData[i].szCursorPath,
918                                                          IMAGE_CURSOR, 0, 0,
919                                                          LR_LOADFROMFILE | LR_DEFAULTSIZE);
920     }
921 }
922 
923 
924 static VOID
925 ReloadCurrentCursorScheme(VOID)
926 {
927     UINT index, i;
928 
929     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
930     {
931         if (g_CursorData[i].hCursor != NULL)
932             DestroyCursor(g_CursorData[i].hCursor);
933 
934         if (g_CursorData[i].szCursorPath[0] == 0)
935             g_CursorData[i].hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(g_CursorData[i].uDefaultCursorId),
936                                                          IMAGE_CURSOR, 0, 0,
937                                                          LR_DEFAULTSIZE | LR_SHARED);
938         else
939             g_CursorData[i].hCursor = (HCURSOR)LoadImage(NULL, g_CursorData[i].szCursorPath,
940                                                          IMAGE_CURSOR, 0, 0,
941                                                          LR_LOADFROMFILE | LR_DEFAULTSIZE);
942     }
943 }
944 
945 
946 static VOID
947 OnDrawItem(UINT idCtl,
948            LPDRAWITEMSTRUCT lpdis,
949            PPOINTER_DATA pPointerData)
950 {
951     RECT rc;
952 
953     if (lpdis->itemState & ODS_SELECTED)
954     {
955         FillRect(lpdis->hDC,
956                  &lpdis->rcItem,
957                  (HBRUSH)(COLOR_HIGHLIGHT + 1));
958         SetBkColor(lpdis->hDC,
959                    GetSysColor(COLOR_HIGHLIGHT));
960         SetTextColor(lpdis->hDC,
961                    GetSysColor(COLOR_HIGHLIGHTTEXT));
962     }
963     else
964     {
965         FillRect(lpdis->hDC,
966                  &lpdis->rcItem,
967                  (HBRUSH)(COLOR_WINDOW + 1));
968         SetBkColor(lpdis->hDC,
969                    GetSysColor(COLOR_WINDOW));
970         SetTextColor(lpdis->hDC,
971                    GetSysColor(COLOR_WINDOWTEXT));
972     }
973 
974     if (lpdis->itemID != (UINT)-1)
975     {
976         CopyRect(&rc, &lpdis->rcItem);
977         rc.left += 5;
978         DrawText(lpdis->hDC,
979                  g_CursorData[lpdis->itemData].szCursorName,
980                  -1,
981                  &rc,
982                  DT_SINGLELINE | DT_VCENTER | DT_LEFT);
983 
984         if (g_CursorData[lpdis->itemData].hCursor != NULL)
985         {
986             DrawIcon(lpdis->hDC,
987                      lpdis->rcItem.right - pPointerData->cxCursor - 4,
988                      lpdis->rcItem.top + 2,
989                      g_CursorData[lpdis->itemData].hCursor);
990         }
991     }
992 
993     if (lpdis->itemState & ODS_FOCUS)
994     {
995         CopyRect(&rc, &lpdis->rcItem);
996         InflateRect(&rc, -1, -1);
997         DrawFocusRect(lpdis->hDC, &rc);
998     }
999 }
1000 
1001 
1002 static VOID
1003 LoadNewCursorScheme(HWND hwndDlg)
1004 {
1005     TCHAR buffer[MAX_PATH];
1006     TCHAR szSystemScheme[MAX_PATH];
1007     HWND hDlgCtrl;
1008     BOOL bEnable;
1009     LPTSTR lpName;
1010     INT nSel;
1011 
1012     nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETCURSEL, 0, 0);
1013     if (nSel == CB_ERR)
1014        return;
1015 
1016     SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETLBTEXT, nSel, (LPARAM)buffer);
1017 
1018     LoadString(hApplet, IDS_SYSTEM_SCHEME, szSystemScheme, MAX_PATH);
1019     if (_tcsstr(buffer, szSystemScheme) || nSel == 0) //avoid the default scheme can be deleted
1020         bEnable = FALSE;
1021     else
1022         bEnable = TRUE;
1023 
1024     /* delete button */
1025     hDlgCtrl = GetDlgItem(hwndDlg, IDC_BUTTON_DELETE_SCHEME);
1026     EnableWindow(hDlgCtrl, bEnable);
1027 
1028     lpName = (LPTSTR)SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETITEMDATA, nSel, 0);
1029     LoadCursorScheme(lpName, !bEnable);
1030     RefreshCursorList(hwndDlg, FALSE);
1031 }
1032 
1033 
1034 static VOID
1035 LoadInitialCursorScheme(HWND hwndDlg)
1036 {
1037     TCHAR szSchemeName[256];
1038     TCHAR szSystemScheme[256];
1039     TCHAR szCursorPath[256];
1040     HKEY hCursorKey;
1041     LONG lError;
1042     DWORD dwDataSize;
1043     DWORD dwSchemeSource = 0;
1044     UINT index, i;
1045     DWORD dwType;
1046     INT nSel;
1047 
1048     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
1049     {
1050         g_CursorData[i].hCursor = 0;
1051         g_CursorData[i].szCursorPath[0] = 0;
1052     }
1053 
1054     lError = RegOpenKeyEx(HKEY_CURRENT_USER,
1055                           _T("Control Panel\\Cursors"),
1056                           0,
1057                           KEY_READ | KEY_QUERY_VALUE,
1058                           &hCursorKey);
1059     if (lError != ERROR_SUCCESS)
1060         return;
1061 
1062     dwDataSize = sizeof(DWORD);
1063     lError = RegQueryValueEx(hCursorKey,
1064                              _T("Scheme Source"),
1065                              NULL,
1066                              NULL,
1067                              (LPBYTE)&dwSchemeSource,
1068                              &dwDataSize);
1069 
1070     if (dwSchemeSource != 0)
1071     {
1072         dwDataSize = 256 * sizeof(TCHAR);
1073         lError = RegQueryValueEx(hCursorKey,
1074                                  NULL,
1075                                  NULL,
1076                                  NULL,
1077                                  (LPBYTE)szSchemeName,
1078                                  &dwDataSize);
1079 
1080         for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
1081         {
1082             dwDataSize = MAX_PATH * sizeof(TCHAR);
1083             lError = RegQueryValueEx(hCursorKey,
1084                                      g_CursorData[i].lpValueName,
1085                                      NULL,
1086                                      &dwType,
1087                                      (LPBYTE)szCursorPath,
1088                                      &dwDataSize);
1089             if (lError == ERROR_SUCCESS)
1090             {
1091                 if (dwType == REG_EXPAND_SZ)
1092                 {
1093                     ExpandEnvironmentStrings(szCursorPath, g_CursorData[i].szCursorPath, MAX_PATH);
1094                 }
1095                 else
1096                 {
1097                     _tcscpy(g_CursorData[i].szCursorPath, szCursorPath);
1098                 }
1099             }
1100         }
1101     }
1102 
1103     RegCloseKey(hCursorKey);
1104 
1105     ReloadCurrentCursorScheme();
1106     RefreshCursorList(hwndDlg, TRUE);
1107 
1108     /* Build the full scheme name */
1109     if (dwSchemeSource == 0)
1110     {
1111         LoadString(hApplet, IDS_NONE, szSchemeName, MAX_PATH);
1112     }
1113     else if (dwSchemeSource == 2)
1114     {
1115         LoadString(hApplet, IDS_SYSTEM_SCHEME, szSystemScheme, MAX_PATH);
1116         _tcscat(szSchemeName, _T(" "));
1117         _tcscat(szSchemeName, szSystemScheme);
1118     }
1119 
1120     /* Search and select the curent scheme name from the scheme list */
1121     nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_FINDSTRINGEXACT, -1, (LPARAM)szSchemeName);
1122     if (nSel != CB_ERR)
1123         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_SETCURSEL, (WPARAM)nSel, (LPARAM)0);
1124 
1125     /* Enable /disable delete button */
1126     EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON_DELETE_SCHEME), (dwSchemeSource == 1));
1127 }
1128 
1129 
1130 static BOOL
1131 ApplyCursorScheme(HWND hwndDlg)
1132 {
1133     TCHAR szSchemeName[MAX_PATH];
1134     TCHAR szSystemScheme[MAX_PATH];
1135     TCHAR szTempPath[MAX_PATH];
1136     LPTSTR lpSchemeData;
1137     DWORD dwNameLength;
1138     DWORD dwSchemeSource;
1139     UINT index, i;
1140     HKEY hCursorKey;
1141     INT nSel;
1142 
1143     nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETCURSEL, 0, 0);
1144     if (nSel == CB_ERR)
1145        return FALSE;
1146 
1147     lpSchemeData = (LPTSTR)SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETITEMDATA, nSel, 0);
1148     if (lpSchemeData == NULL)
1149     {
1150         /* "None" cursor scheme */
1151         dwSchemeSource = 0;
1152         szSchemeName[0] = 0;
1153         dwNameLength = 0;
1154     }
1155     else
1156     {
1157         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETLBTEXT, nSel, (LPARAM)szSchemeName);
1158         LoadString(hApplet, IDS_SYSTEM_SCHEME, szSystemScheme, MAX_PATH);
1159 
1160         if (_tcsstr(szSchemeName, szSystemScheme))
1161         {
1162             /* System scheme */
1163             dwSchemeSource = 2;
1164             szSchemeName[_tcslen(szSchemeName) - _tcslen(szSystemScheme) - 1] = 0;
1165         }
1166         else
1167         {
1168             /* User scheme */
1169             dwSchemeSource = 1;
1170         }
1171 
1172         dwNameLength = (_tcslen(szSchemeName) + 1) * sizeof(TCHAR);
1173     }
1174 
1175     if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Cursors"), 0,
1176                      KEY_READ | KEY_SET_VALUE, &hCursorKey) != ERROR_SUCCESS)
1177         return FALSE;
1178 
1179     RegSetValueEx(hCursorKey, NULL, 0, REG_SZ,
1180                   (LPBYTE)szSchemeName, dwNameLength);
1181 
1182     RegSetValueEx(hCursorKey, _T("Scheme Source"), 0, REG_DWORD,
1183                   (LPBYTE)&dwSchemeSource, sizeof(DWORD));
1184 
1185     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
1186     {
1187         CompressPath(szTempPath, g_CursorData[i].szCursorPath);
1188         RegSetValueEx(hCursorKey, g_CursorData[i].lpValueName, 0,
1189                       REG_EXPAND_SZ, (LPBYTE)szTempPath,
1190                       (_tcslen(szTempPath) + 1) * sizeof(TCHAR));
1191     }
1192 
1193     RegCloseKey(hCursorKey);
1194 
1195     /* Force the system to reload its cursors */
1196     SystemParametersInfo(SPI_SETCURSORS, 0, NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1197 
1198     return TRUE;
1199 }
1200 
1201 
1202 static INT_PTR CALLBACK
1203 PointerProc(IN HWND hwndDlg,
1204             IN UINT uMsg,
1205             IN WPARAM wParam,
1206             IN LPARAM lParam)
1207 {
1208     PPOINTER_DATA pPointerData;
1209     LPPSHNOTIFY lppsn;
1210     INT nSel;
1211 
1212     pPointerData = (PPOINTER_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
1213 
1214     switch (uMsg)
1215     {
1216         case WM_INITDIALOG:
1217             pPointerData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(POINTER_DATA));
1218             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pPointerData);
1219 
1220             pPointerData->cxCursor = GetSystemMetrics(SM_CXCURSOR);
1221             pPointerData->cyCursor = GetSystemMetrics(SM_CYCURSOR);
1222 
1223             EnumerateCursorSchemes(hwndDlg);
1224             LoadInitialCursorScheme(hwndDlg);
1225 
1226             /* Get cursor shadow setting */
1227             SystemParametersInfo(SPI_GETCURSORSHADOW, 0, &pPointerData->bCursorShadow, 0);
1228             pPointerData->bOrigCursorShadow = pPointerData->bCursorShadow;
1229 
1230             if (pPointerData->bCursorShadow)
1231             {
1232                 SendDlgItemMessage(hwndDlg, IDC_CHECK_CURSOR_SHADOW, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1233             }
1234 
1235             if ((INT)wParam == IDC_LISTBOX_CURSOR)
1236                 return TRUE;
1237             else
1238                 return FALSE;
1239 
1240         case WM_MEASUREITEM:
1241             ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = GetSystemMetrics(SM_CYCURSOR) + 4;
1242             break;
1243 
1244         case WM_DRAWITEM:
1245             if (wParam == IDC_LISTBOX_CURSOR)
1246                 OnDrawItem((UINT)wParam, (LPDRAWITEMSTRUCT)lParam, pPointerData);
1247             return TRUE;
1248 
1249         case WM_DESTROY:
1250             HeapFree(GetProcessHeap(), 0, pPointerData);
1251             break;
1252 
1253         case WM_NOTIFY:
1254             lppsn = (LPPSHNOTIFY) lParam;
1255             if (lppsn->hdr.code == PSN_APPLY)
1256             {
1257                 ApplyCursorScheme(hwndDlg);
1258 //#if (WINVER >= 0x0500)
1259                 if (pPointerData->bOrigCursorShadow != pPointerData->bCursorShadow)
1260                 {
1261                     SystemParametersInfo(SPI_SETCURSORSHADOW, 0, UlongToPtr(pPointerData->bCursorShadow), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1262                     pPointerData->bOrigCursorShadow = pPointerData->bCursorShadow;
1263                 }
1264 //#endif
1265                 return TRUE;
1266             }
1267             else if (lppsn->hdr.code == PSN_RESET)
1268             {
1269 //#if (WINVER >= 0x0500)
1270                 SystemParametersInfo(SPI_SETCURSORSHADOW, 0, UlongToPtr(pPointerData->bOrigCursorShadow), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1271 //#endif
1272             }
1273             break;
1274 
1275         case WM_COMMAND:
1276             switch (LOWORD(wParam))
1277             {
1278                 case IDC_COMBO_CURSOR_SCHEME:
1279                     if (HIWORD(wParam) == CBN_SELENDOK)
1280                     {
1281                         LoadNewCursorScheme(hwndDlg);
1282                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1283                     }
1284                     break;
1285 
1286                 case IDC_LISTBOX_CURSOR:
1287                     switch (HIWORD(wParam))
1288                     {
1289                         case LBN_SELCHANGE:
1290                             nSel = SendMessage((HWND)lParam, LB_GETCURSEL, 0, 0);
1291                             SendDlgItemMessage(hwndDlg, IDC_IMAGE_CURRENT_CURSOR, STM_SETIMAGE, IMAGE_CURSOR,
1292                                                (LPARAM)g_CursorData[nSel].hCursor);
1293                             EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_USE_DEFAULT_CURSOR),
1294                                          (g_CursorData[nSel].szCursorPath[0] != 0));
1295                             break;
1296 
1297                         case LBN_DBLCLK:
1298                             if (BrowseCursor(hwndDlg))
1299                             {
1300                                 /* Update cursor list and preview */
1301                                 ReloadCurrentCursorScheme();
1302                                 RefreshCursorList(hwndDlg, FALSE);
1303 
1304                                 /* Enable the "Set Default" button */
1305                                 EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_USE_DEFAULT_CURSOR), TRUE);
1306 
1307                                 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1308                             }
1309                             break;
1310                     }
1311                     break;
1312 
1313                 case IDC_BUTTON_SAVEAS_SCHEME:
1314                     SaveCursorScheme(hwndDlg);
1315                     break;
1316 
1317                 case IDC_BUTTON_USE_DEFAULT_CURSOR:
1318                     nSel = SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_GETCURSEL, 0, 0);
1319                     if (nSel != LB_ERR)
1320                     {
1321                         /* Clean the path of the currently selected cursor */
1322                         memset(g_CursorData[nSel].szCursorPath, 0x0, MAX_PATH * sizeof(TCHAR));
1323 
1324                         /* Update cursor list and preview */
1325                         ReloadCurrentCursorScheme();
1326                         RefreshCursorList(hwndDlg, FALSE);
1327 
1328                         /* Disable the "Set Default" button */
1329                         EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_USE_DEFAULT_CURSOR), FALSE);
1330 
1331                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1332                     }
1333                     break;
1334 
1335                 case IDC_BUTTON_BROWSE_CURSOR:
1336                     if (BrowseCursor(hwndDlg))
1337                     {
1338                         /* Update cursor list and preview */
1339                         ReloadCurrentCursorScheme();
1340                         RefreshCursorList(hwndDlg, FALSE);
1341 
1342                         /* Enable the "Set Default" button */
1343                         EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_USE_DEFAULT_CURSOR), TRUE);
1344 
1345                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1346                     }
1347                     break;
1348 
1349                 case IDC_BUTTON_DELETE_SCHEME:
1350                     DeleteUserCursorScheme(hwndDlg);
1351                     break;
1352 
1353                 case IDC_CHECK_CURSOR_SHADOW:
1354                     if(IsDlgButtonChecked(hwndDlg, IDC_CHECK_CURSOR_SHADOW))
1355                     {
1356                         pPointerData->bCursorShadow = FALSE;
1357                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
1358 //#if (WINVER >= 0x0500)
1359 //                        SystemParametersInfo(SPI_SETCURSORSHADOW, 0, (PVOID)pPointerData->bCursorShadow, 0);
1360 //#endif
1361 //                        PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1362                     }
1363                     else
1364                     {
1365                         pPointerData->bCursorShadow = TRUE;
1366                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1367                     }
1368 //#if (WINVER >= 0x0500)
1369                     //SystemParametersInfo(SPI_SETCURSORSHADOW, 0, (PVOID)pPointerData->bCursorShadow, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1370 //#endif
1371                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1372                     break;
1373             }
1374             break;
1375     }
1376 
1377     return FALSE;
1378 }
1379 
1380 
1381 static INT_PTR CALLBACK
1382 OptionProc(IN HWND hwndDlg,
1383            IN UINT uMsg,
1384            IN WPARAM wParam,
1385            IN LPARAM lParam)
1386 {
1387     POPTION_DATA pOptionData;
1388     HWND hDlgCtrl;
1389     LPPSHNOTIFY lppsn;
1390 
1391     pOptionData = (POPTION_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
1392 
1393     switch(uMsg)
1394     {
1395         case WM_INITDIALOG:
1396             pOptionData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OPTION_DATA));
1397             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pOptionData);
1398 
1399             /* Get mouse sensitivity */
1400             if (!SystemParametersInfo(SPI_GETMOUSESPEED, 0, &pOptionData->ulMouseSpeed, 0))
1401                 pOptionData->ulMouseSpeed = DEFAULT_MOUSE_SPEED;
1402             pOptionData->ulOrigMouseSpeed = pOptionData->ulMouseSpeed;
1403 
1404 
1405             if (!SystemParametersInfo(SPI_GETMOUSE, 0, &pOptionData->MouseAccel, 0))
1406             {
1407                 pOptionData->MouseAccel.nAcceleration = DEFAULT_MOUSE_ACCELERATION;
1408                 pOptionData->MouseAccel.nThreshold1 = DEFAULT_MOUSE_THRESHOLD1;
1409                 pOptionData->MouseAccel.nThreshold2 = DEFAULT_MOUSE_THRESHOLD2;
1410             }
1411             pOptionData->OrigMouseAccel.nAcceleration = pOptionData->MouseAccel.nAcceleration;
1412             pOptionData->OrigMouseAccel.nThreshold1 = pOptionData->MouseAccel.nThreshold1;
1413             pOptionData->OrigMouseAccel.nThreshold2 = pOptionData->MouseAccel.nThreshold2;
1414 
1415             /* snap to default button */
1416             SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0, &pOptionData->bSnapToDefaultButton, 0);
1417             pOptionData->bOrigSnapToDefaultButton = pOptionData->bSnapToDefaultButton;
1418 
1419             /* mouse trails */
1420             SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &pOptionData->uMouseTrails, 0);
1421             pOptionData->uOrigMouseTrails = pOptionData->uMouseTrails;
1422 
1423             /* hide pointer while typing */
1424             SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &pOptionData->bMouseVanish, 0);
1425             pOptionData->bOrigMouseVanish = pOptionData->bMouseVanish;
1426 
1427             /* show pointer with Ctrl-Key */
1428             SystemParametersInfo(SPI_GETMOUSESONAR, 0, &pOptionData->bMouseSonar, 0);
1429             pOptionData->bOrigMouseSonar = pOptionData->bMouseSonar;
1430 
1431             /* Set mouse speed */
1432             hDlgCtrl = GetDlgItem(hwndDlg, IDC_SLIDER_MOUSE_SPEED);
1433             SendMessage(hDlgCtrl, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 19));
1434             SendMessage(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pOptionData->ulMouseSpeed - 1);
1435 
1436             if (pOptionData->MouseAccel.nAcceleration)
1437             {
1438                 hDlgCtrl = GetDlgItem(hwndDlg, IDC_CHECK_POINTER_PRECISION);
1439                 SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1440             }
1441 
1442             if (pOptionData->bSnapToDefaultButton)
1443             {
1444                 hDlgCtrl = GetDlgItem(hwndDlg, IDC_CHECK_SNAP_TO);
1445                 SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1446             }
1447 
1448             /* set mouse trail */
1449             hDlgCtrl = GetDlgItem(hwndDlg, IDC_SLIDER_POINTER_TRAIL);
1450             SendMessage(hDlgCtrl, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 5));
1451             if (pOptionData->uMouseTrails < 2)
1452             {
1453                 SendMessage(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)5);
1454                 EnableWindow(hDlgCtrl, FALSE);
1455                 EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_TRAIL_SHORT), FALSE);
1456                 EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_TRAIL_LONG), FALSE);
1457             }
1458             else
1459             {
1460                 SendDlgItemMessage(hwndDlg, IDC_CHECK_POINTER_TRAIL, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1461                 SendMessage(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pOptionData->uMouseTrails - 2);
1462             }
1463 
1464             if (pOptionData->bMouseVanish)
1465             {
1466                 hDlgCtrl = GetDlgItem(hwndDlg, IDC_CHECK_HIDE_POINTER);
1467                 SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1468             }
1469 
1470             if (pOptionData->bMouseSonar)
1471             {
1472                 hDlgCtrl = GetDlgItem(hwndDlg, IDC_CHECK_SHOW_POINTER);
1473                 SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1474             }
1475 
1476             break;
1477 
1478         case WM_DESTROY:
1479             HeapFree(GetProcessHeap(), 0, pOptionData);
1480             break;
1481 
1482         case WM_COMMAND:
1483             switch(LOWORD(wParam))
1484             {
1485                 case IDC_CHECK_POINTER_PRECISION:
1486                     if(IsDlgButtonChecked(hwndDlg, IDC_CHECK_POINTER_PRECISION))
1487                     {
1488                         pOptionData->MouseAccel.nAcceleration = 0;
1489                         pOptionData->MouseAccel.nThreshold1 = 0;
1490                         pOptionData->MouseAccel.nThreshold2 = 0;
1491                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
1492                     }
1493                     else
1494                     {
1495                         pOptionData->MouseAccel.nAcceleration = 1;
1496                         pOptionData->MouseAccel.nThreshold1 = 6;
1497                         pOptionData->MouseAccel.nThreshold2 = 10;
1498                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1499                     }
1500                     SystemParametersInfo(SPI_SETMOUSE, 0, &pOptionData->MouseAccel, 0);
1501                     break;
1502 
1503                 case IDC_CHECK_SNAP_TO:
1504                     if(IsDlgButtonChecked(hwndDlg, IDC_CHECK_SNAP_TO))
1505                     {
1506                         pOptionData->bSnapToDefaultButton = 0;
1507                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
1508                     }
1509                     else
1510                     {
1511                         pOptionData->bSnapToDefaultButton = 1;
1512                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1513                     }
1514                     SystemParametersInfo(SPI_SETSNAPTODEFBUTTON, (UINT)pOptionData->bSnapToDefaultButton, 0, 0);
1515                     break;
1516 
1517                 case IDC_CHECK_POINTER_TRAIL:
1518                     hDlgCtrl = GetDlgItem(hwndDlg, IDC_SLIDER_POINTER_TRAIL);
1519                     if(IsDlgButtonChecked(hwndDlg, IDC_CHECK_POINTER_TRAIL))
1520                     {
1521                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
1522                         EnableWindow(hDlgCtrl, FALSE);
1523                         EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_TRAIL_SHORT), FALSE);
1524                         EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_TRAIL_LONG), FALSE);
1525                         pOptionData->uMouseTrails = 0;
1526                     }
1527                     else
1528                     {
1529                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1530                         EnableWindow(hDlgCtrl, TRUE);
1531                         EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_TRAIL_SHORT), TRUE);
1532                         EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT_TRAIL_LONG), TRUE);
1533                         pOptionData->uMouseTrails = (UINT)SendMessage(hDlgCtrl, TBM_GETPOS, 0, 0) + 2;
1534                     }
1535                     SystemParametersInfo(SPI_SETMOUSETRAILS, pOptionData->uMouseTrails, 0, 0);
1536                     break;
1537 
1538                 case IDC_CHECK_HIDE_POINTER:
1539                     if(IsDlgButtonChecked(hwndDlg, IDC_CHECK_HIDE_POINTER))
1540                     {
1541                         pOptionData->bMouseVanish = FALSE;
1542                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
1543                     }
1544                     else
1545                     {
1546                         pOptionData->bMouseVanish = TRUE;
1547                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1548                     }
1549                     SystemParametersInfo(SPI_SETMOUSEVANISH, 0, IntToPtr(pOptionData->bMouseVanish), 0);
1550                     break;
1551 
1552                 case IDC_CHECK_SHOW_POINTER:
1553                     if(IsDlgButtonChecked(hwndDlg, IDC_CHECK_SHOW_POINTER))
1554                     {
1555                         pOptionData->bMouseSonar = FALSE;
1556                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
1557                     }
1558                     else
1559                     {
1560                         pOptionData->bMouseSonar = TRUE;
1561                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1562                     }
1563                     SystemParametersInfo(SPI_SETMOUSESONAR, 0, IntToPtr(pOptionData->bMouseSonar), 0);
1564                     break;
1565 
1566             }
1567             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1568             break;
1569 
1570         case WM_NOTIFY:
1571             lppsn = (LPPSHNOTIFY)lParam;
1572             if (lppsn->hdr.code == PSN_APPLY)
1573             {
1574                 /* Set mouse speed */
1575                 if (pOptionData->ulOrigMouseSpeed != pOptionData->ulMouseSpeed)
1576                 {
1577                     SystemParametersInfo(SPI_SETMOUSESPEED, 0, IntToPtr(pOptionData->ulMouseSpeed), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1578                     pOptionData->ulOrigMouseSpeed = pOptionData->ulMouseSpeed;
1579                 }
1580 
1581                 if (pOptionData->OrigMouseAccel.nAcceleration != pOptionData->MouseAccel.nAcceleration)
1582                 {
1583                     SystemParametersInfo(SPI_SETMOUSE, 0, &pOptionData->MouseAccel, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1584                     pOptionData->OrigMouseAccel.nAcceleration = pOptionData->MouseAccel.nAcceleration;
1585                     pOptionData->OrigMouseAccel.nThreshold1 = pOptionData->MouseAccel.nThreshold1;
1586                     pOptionData->OrigMouseAccel.nThreshold2 = pOptionData->MouseAccel.nThreshold2;
1587                 }
1588 
1589 
1590                 /* set snap to default button */
1591                 if (pOptionData->bOrigSnapToDefaultButton != pOptionData->bSnapToDefaultButton)
1592                 {
1593                     SystemParametersInfo(SPI_SETSNAPTODEFBUTTON, (UINT)pOptionData->bSnapToDefaultButton, 0, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1594                     pOptionData->bOrigSnapToDefaultButton = pOptionData->bSnapToDefaultButton;
1595                 }
1596 
1597                 /* Set mouse trails setting */
1598                 if (pOptionData->uOrigMouseTrails != pOptionData->uMouseTrails)
1599                 {
1600                     SystemParametersInfo(SPI_SETMOUSETRAILS, pOptionData->uMouseTrails, 0, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1601                     pOptionData->uOrigMouseTrails = pOptionData->uMouseTrails;
1602                 }
1603 
1604                 /* hide pointer while typing */
1605                 if (pOptionData->bOrigMouseVanish != pOptionData->bMouseVanish)
1606                 {
1607                     SystemParametersInfo(SPI_SETMOUSEVANISH, 0, IntToPtr(pOptionData->bMouseVanish), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1608                     pOptionData->bOrigMouseVanish = pOptionData->bMouseVanish;
1609                 }
1610 
1611                 /* show pointer with Ctrl-Key */
1612                 if (pOptionData->bOrigMouseSonar != pOptionData->bMouseSonar)
1613                 {
1614                     SystemParametersInfo(SPI_SETMOUSESONAR, 0, IntToPtr(pOptionData->bMouseSonar), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1615                     pOptionData->bOrigMouseSonar = pOptionData->bMouseSonar;
1616                 }
1617                 return TRUE;
1618             }
1619             else if (lppsn->hdr.code == PSN_RESET)
1620             {
1621                 /* Set the original mouse speed */
1622                 SystemParametersInfo(SPI_SETMOUSESPEED, 0, IntToPtr(pOptionData->ulOrigMouseSpeed), 0);
1623                 SystemParametersInfo(SPI_SETMOUSE, 0, &pOptionData->OrigMouseAccel, 0);
1624                 SystemParametersInfo(SPI_SETSNAPTODEFBUTTON, (UINT)pOptionData->bOrigSnapToDefaultButton, 0, 0);
1625                 SystemParametersInfo(SPI_SETMOUSETRAILS, pOptionData->uOrigMouseTrails, 0, 0);
1626                 SystemParametersInfo(SPI_SETMOUSEVANISH, 0, IntToPtr(pOptionData->bOrigMouseVanish), 0);
1627                 SystemParametersInfo(SPI_SETMOUSESONAR, 0,IntToPtr(pOptionData->bOrigMouseSonar), 0);
1628             }
1629             break;
1630 
1631         case WM_HSCROLL:
1632             if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SLIDER_MOUSE_SPEED))
1633             {
1634                 switch (LOWORD(wParam))
1635                 {
1636                     case TB_LINEUP:
1637                     case TB_LINEDOWN:
1638                     case TB_PAGEUP:
1639                     case TB_PAGEDOWN:
1640                     case TB_TOP:
1641                     case TB_BOTTOM:
1642                     case TB_ENDTRACK:
1643                         pOptionData->ulMouseSpeed = (ULONG)SendDlgItemMessage(hwndDlg, IDC_SLIDER_MOUSE_SPEED, TBM_GETPOS, 0, 0) + 1;
1644                         SystemParametersInfo(SPI_SETMOUSESPEED, 0, IntToPtr(pOptionData->ulMouseSpeed), SPIF_SENDCHANGE);
1645                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1646                         break;
1647 #if 0
1648                     case TB_THUMBTRACK:
1649                         pOptionData->ulMouseSpeed = (ULONG)HIWORD(wParam) + 1;
1650                         SystemParametersInfo(SPI_SETMOUSESPEED, 0, (PVOID)pOptionData->ulMouseSpeed, SPIF_SENDCHANGE);
1651                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1652                         break;
1653 #endif
1654                 }
1655             }
1656             else if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SLIDER_POINTER_TRAIL))
1657             {
1658                 switch (LOWORD(wParam))
1659                 {
1660                     case TB_LINEUP:
1661                     case TB_LINEDOWN:
1662                     case TB_PAGEUP:
1663                     case TB_PAGEDOWN:
1664                     case TB_TOP:
1665                     case TB_BOTTOM:
1666                     case TB_ENDTRACK:
1667                         pOptionData->uMouseTrails = (ULONG)SendDlgItemMessage(hwndDlg, IDC_SLIDER_POINTER_TRAIL, TBM_GETPOS, 0, 0) + 2;
1668                         SystemParametersInfo(SPI_SETMOUSETRAILS, pOptionData->uMouseTrails, 0, SPIF_UPDATEINIFILE);
1669                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1670                         break;
1671 
1672                     case TB_THUMBTRACK:
1673                         pOptionData->uMouseTrails = (ULONG)HIWORD(wParam) + 2;
1674                         SystemParametersInfo(SPI_SETMOUSETRAILS, pOptionData->uMouseTrails, 0, SPIF_UPDATEINIFILE);
1675                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1676                         break;
1677                 }
1678             }
1679             break;
1680     }
1681 
1682     return FALSE;
1683 }
1684 
1685 
1686 static VOID
1687 ShowDialogWheelControls(HWND hwndDlg, UINT uWheelScrollLines, BOOL bInit)
1688 {
1689     HWND hDlgCtrl;
1690 
1691     if (uWheelScrollLines != WHEEL_PAGESCROLL)
1692     {
1693         hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_WHEEL_SCROLL_LINES);
1694         SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1695 
1696         hDlgCtrl = GetDlgItem(hwndDlg, IDC_EDIT_WHEEL_SCROLL_LINES);
1697         EnableWindow(hDlgCtrl, TRUE);
1698 
1699         hDlgCtrl = GetDlgItem(hwndDlg, IDC_UPDOWN_WHEEL_SCROLL_LINES);
1700         EnableWindow(hDlgCtrl, TRUE);
1701 
1702         hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_WHEEL_SCROLL_PAGE);
1703         SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
1704     }
1705     else
1706     {
1707         hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_WHEEL_SCROLL_LINES);
1708         SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
1709 
1710         hDlgCtrl = GetDlgItem(hwndDlg, IDC_EDIT_WHEEL_SCROLL_LINES);
1711         EnableWindow(hDlgCtrl, FALSE);
1712 
1713         hDlgCtrl = GetDlgItem(hwndDlg, IDC_UPDOWN_WHEEL_SCROLL_LINES);
1714         EnableWindow(hDlgCtrl, FALSE);
1715 
1716         hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_WHEEL_SCROLL_PAGE);
1717         SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1718 
1719         /* Set the default scroll lines value */
1720         if (bInit == TRUE)
1721             SetDlgItemInt(hwndDlg, IDC_EDIT_WHEEL_SCROLL_LINES, DEFAULT_WHEEL_SCROLL_LINES, FALSE);
1722     }
1723 }
1724 
1725 
1726 static INT_PTR CALLBACK
1727 WheelProc(IN HWND hwndDlg,
1728           IN UINT uMsg,
1729           IN WPARAM wParam,
1730           IN LPARAM lParam)
1731 {
1732     LPPSHNOTIFY lppsn;
1733     PWHEEL_DATA pWheelData;
1734 
1735     pWheelData = (PWHEEL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
1736 
1737     switch (uMsg)
1738     {
1739         case WM_INITDIALOG:
1740             pWheelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WHEEL_DATA));
1741             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pWheelData);
1742 
1743             /* Get wheel scroll lines */
1744             SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &pWheelData->uWheelScrollLines, 0);
1745 
1746             ShowDialogWheelControls(hwndDlg, pWheelData->uWheelScrollLines, TRUE);
1747             SendDlgItemMessage(hwndDlg, IDC_UPDOWN_WHEEL_SCROLL_LINES, UDM_SETRANGE, 0, MAKELONG((short)100, (short)0));
1748             if (pWheelData->uWheelScrollLines != WHEEL_PAGESCROLL)
1749             {
1750                 SetDlgItemInt(hwndDlg, IDC_EDIT_WHEEL_SCROLL_LINES, pWheelData->uWheelScrollLines, FALSE);
1751             }
1752             return TRUE;
1753 
1754         case WM_DESTROY:
1755             HeapFree(GetProcessHeap(), 0, pWheelData);
1756             break;
1757 
1758         case WM_COMMAND:
1759             switch (LOWORD(wParam))
1760             {
1761                 case IDC_RADIO_WHEEL_SCROLL_LINES:
1762                     pWheelData->uWheelScrollLines = GetDlgItemInt(hwndDlg, IDC_EDIT_WHEEL_SCROLL_LINES, NULL, FALSE);
1763                     ShowDialogWheelControls(hwndDlg, pWheelData->uWheelScrollLines, FALSE);
1764                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1765                     break;
1766 
1767                 case IDC_RADIO_WHEEL_SCROLL_PAGE:
1768                     pWheelData->uWheelScrollLines = WHEEL_PAGESCROLL;
1769                     ShowDialogWheelControls(hwndDlg, pWheelData->uWheelScrollLines, FALSE);
1770                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1771                     break;
1772 
1773                 case IDC_EDIT_WHEEL_SCROLL_LINES:
1774                     if (pWheelData && HIWORD(wParam) == EN_CHANGE)
1775                     {
1776                         pWheelData->uWheelScrollLines = GetDlgItemInt(hwndDlg, IDC_EDIT_WHEEL_SCROLL_LINES, NULL, FALSE);
1777                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1778                     }
1779                     break;
1780             }
1781             break;
1782 
1783         case WM_NOTIFY:
1784             lppsn = (LPPSHNOTIFY)lParam;
1785             if (lppsn->hdr.code == PSN_APPLY)
1786             {
1787                 SystemParametersInfo(SPI_SETWHEELSCROLLLINES, pWheelData->uWheelScrollLines,
1788                                      0, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1789                 return TRUE;
1790             }
1791             break;
1792     }
1793 
1794     return FALSE;
1795 }
1796 
1797 static const struct
1798 {
1799     WORD idDlg;
1800     DLGPROC DlgProc;
1801     UINT uiReplaceWith;
1802 } PropPages[] =
1803 {
1804     { IDD_PAGE_BUTTON, ButtonProc, CPLPAGE_MOUSE_BUTTONS },
1805     { IDD_PAGE_POINTER, PointerProc, 0 },
1806     { IDD_PAGE_OPTION, OptionProc, CPLPAGE_MOUSE_PTRMOTION },
1807     { IDD_PAGE_WHEEL, WheelProc, CPLPAGE_MOUSE_WHEEL },
1808     { IDD_HARDWARE, MouseHardwareProc, 0 },
1809 };
1810 
1811 LONG APIENTRY
1812 MouseApplet(HWND hwnd, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
1813 {
1814     HPROPSHEETPAGE hpsp[MAX_CPL_PAGES];
1815     PROPSHEETHEADER psh;
1816     HPSXA hpsxa;
1817     TCHAR Caption[256];
1818     UINT i;
1819     LONG ret;
1820 
1821     UNREFERENCED_PARAMETER(lParam1);
1822     UNREFERENCED_PARAMETER(lParam2);
1823     UNREFERENCED_PARAMETER(uMsg);
1824     UNREFERENCED_PARAMETER(hwnd);
1825 
1826     LoadString(hApplet, IDS_CPLNAME_1, Caption, sizeof(Caption) / sizeof(TCHAR));
1827 
1828     ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
1829     psh.dwSize = sizeof(PROPSHEETHEADER);
1830     psh.dwFlags = PSH_PROPTITLE;
1831     psh.hwndParent = hwnd;
1832     psh.hInstance = hApplet;
1833     psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCE(IDC_CPLICON_1));
1834     psh.pszCaption = Caption;
1835     psh.nStartPage = 0;
1836     psh.phpage = hpsp;
1837 
1838     /* Load additional pages provided by shell extensions */
1839     hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Mouse"), MAX_CPL_PAGES - psh.nPages);
1840 
1841     for (i = 0; i != sizeof(PropPages) / sizeof(PropPages[0]); i++)
1842     {
1843         /* Override the background page if requested by a shell extension */
1844         if (PropPages[i].uiReplaceWith != 0 && hpsxa != NULL &&
1845             SHReplaceFromPropSheetExtArray(hpsxa, PropPages[i].uiReplaceWith, PropSheetAddPage, (LPARAM)&psh) != 0)
1846         {
1847             /* The shell extension added one or more pages to replace a page.
1848                Don't create the built-in page anymore! */
1849             continue;
1850         }
1851 
1852         InitPropSheetPage(&psh, PropPages[i].idDlg, PropPages[i].DlgProc);
1853     }
1854 
1855     if (hpsxa != NULL)
1856         SHAddFromPropSheetExtArray(hpsxa, PropSheetAddPage, (LPARAM)&psh);
1857 
1858     ret = (LONG)(PropertySheet(&psh) != -1);
1859 
1860     if (hpsxa != NULL)
1861         SHDestroyPropSheetExtArray(hpsxa);
1862 
1863     return ret;
1864 }
1865 
1866 /* EOF */
1867