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