xref: /reactos/dll/cpl/main/mouse.c (revision a69b0c9f)
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 /*
20  * PROJECT:         ReactOS Main Control Panel
21  * FILE:            dll/cpl/main/mouse.c
22  * PURPOSE:         Mouse Control Panel
23  * PROGRAMMER:      Eric Kohl
24  *                  Johannes Anderwald
25  */
26 
27 // TODO:
28 //  Add missing icons
29 
30 #include "main.h"
31 
32 #include <commdlg.h>
33 #include <cplext.h>
34 #include <tchar.h>
35 
36 #define DEFAULT_DOUBLE_CLICK_SPEED	500
37 #define DEFAULT_CLICK_LOCK_TIME		2200
38 #define DEFAULT_MOUSE_SPEED		10
39 #define DEFAULT_MOUSE_ACCELERATION	1
40 #define DEFAULT_MOUSE_THRESHOLD1	6
41 #define DEFAULT_MOUSE_THRESHOLD2	10
42 #define MIN_DOUBLE_CLICK_SPEED		200
43 #define MAX_DOUBLE_CLICK_SPEED		900
44 #define DEFAULT_WHEEL_SCROLL_LINES	3
45 
46 typedef struct _BUTTON_DATA
47 {
48     ULONG g_SwapMouseButtons;
49     ULONG g_OrigSwapMouseButtons;
50     ULONG g_DoubleClickSpeed; // = DEFAULT_DOUBLE_CLICK_SPEED;
51     ULONG g_OrigDoubleClickSpeed;
52     BOOL g_ClickLockEnabled;  // = 0;
53     DWORD g_ClickLockTime;    // = DEFAULT_CLICK_LOCK_TIME;
54 
55     HICON hButtonLeft;
56     HICON hButtonRight;
57 
58     HICON hIcon1;
59     HICON hIcon2;
60     BOOL bClicked;
61 } BUTTON_DATA, *PBUTTON_DATA;
62 
63 
64 typedef struct _POINTER_DATA
65 {
66     BOOL bCursorShadow;
67     BOOL bOrigCursorShadow;
68 
69     INT cxCursor;
70     INT cyCursor;
71 } POINTER_DATA, *PPOINTER_DATA;
72 
73 
74 typedef struct _MOUSE_ACCEL
75 {
76     INT nThreshold1;
77     INT nThreshold2;
78     INT nAcceleration;
79 } MOUSE_ACCEL;
80 
81 typedef struct _OPTION_DATA
82 {
83     ULONG ulMouseSpeed;
84     ULONG ulOrigMouseSpeed;
85 
86     MOUSE_ACCEL MouseAccel;
87     MOUSE_ACCEL OrigMouseAccel;
88 
89     BOOL bSnapToDefaultButton;
90     BOOL bOrigSnapToDefaultButton;
91 
92     UINT uMouseTrails;
93     UINT uOrigMouseTrails;
94 
95     BOOL bMouseVanish;
96     BOOL bOrigMouseVanish;
97 
98     BOOL bMouseSonar;
99     BOOL bOrigMouseSonar;
100 } OPTION_DATA, *POPTION_DATA;
101 
102 
103 typedef struct _WHEEL_DATA
104 {
105     UINT uWheelScrollLines;
106 } WHEEL_DATA, *PWHEEL_DATA;
107 
108 
109 typedef struct _CURSOR_DATA
110 {
111     UINT uStringId;
112     UINT uDefaultCursorId;
113     LPTSTR lpValueName;
114     HCURSOR hCursor;
115     TCHAR szCursorName[MAX_PATH];
116     TCHAR szCursorPath[MAX_PATH];
117 } CURSOR_DATA, *PCURSOR_DATA;
118 
119 
120 CURSOR_DATA g_CursorData[] =
121 {{IDS_ARROW,       100/*OCR_NORMAL*/,      _T("Arrow"),       0, _T(""), _T("")},
122  {IDS_HELP,        112/*OCR_HELP*/,        _T("Help"),        0, _T(""), _T("")},
123  {IDS_APPSTARTING, 111/*OCR_APPSTARTING*/, _T("AppStarting"), 0, _T(""), _T("")},
124  {IDS_WAIT,        102/*OCR_WAIT*/,        _T("Wait"),        0, _T(""), _T("")},
125  {IDS_CROSSHAIR,   103/*OCR_CROSS*/,       _T("Crosshair"),   0, _T(""), _T("")},
126  {IDS_IBEAM,       101/*OCR_IBEAM*/,       _T("IBeam"),       0, _T(""), _T("")},
127  {IDS_NWPEN,       113/*OCR_NWPEN*/,       _T("NWPen"),       0, _T(""), _T("")},
128  {IDS_NO,          110/*OCR_NO*/,          _T("No"),          0, _T(""), _T("")},
129  {IDS_SIZENS,      108/*OCR_SIZENS*/,      _T("SizeNS"),      0, _T(""), _T("")},
130  {IDS_SIZEWE,      107/*OCR_SIZEWE*/,      _T("SizeWE"),      0, _T(""), _T("")},
131  {IDS_SIZENWSE,    105/*OCR_SIZENWSE*/,    _T("SizeNWSE"),    0, _T(""), _T("")},
132  {IDS_SIZENESW,    106/*OCR_SIZENESW*/,    _T("SizeNESW"),    0, _T(""), _T("")},
133  {IDS_SIZEALL,     109/*OCR_SIZEALL*/,     _T("SizeAll"),     0, _T(""), _T("")},
134  {IDS_UPARROW,     104/*OCR_UP*/,          _T("UpArrow"),     0, _T(""), _T("")},
135  {IDS_HAND,        114/*OCR_HAND*/,        _T("Hand"),        0, _T(""), _T("")}};
136 
137 
138 #if 0
139 static VOID
140 DebugMsg(LPTSTR fmt, ...)
141 {
142     TCHAR szBuffer[2048];
143     va_list marker;
144 
145     va_start(marker, fmt);
146     _vstprintf(szBuffer, fmt, marker);
147     va_end(marker);
148 
149     MessageBox(NULL, szBuffer, _T("Debug message"), MB_OK);
150 }
151 #endif
152 
153 
154 /* Property page dialog callback */
155 static INT_PTR CALLBACK
MouseHardwareProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)156 MouseHardwareProc(IN HWND hwndDlg,
157                   IN UINT uMsg,
158                   IN WPARAM wParam,
159                   IN LPARAM lParam)
160 {
161     GUID Guids[1];
162     Guids[0] = GUID_DEVCLASS_MOUSE;
163 
164     UNREFERENCED_PARAMETER(lParam);
165     UNREFERENCED_PARAMETER(wParam);
166 
167     switch(uMsg)
168     {
169         case WM_INITDIALOG:
170             /* create the hardware page */
171             DeviceCreateHardwarePageEx(hwndDlg,
172                                        Guids,
173                                        sizeof(Guids) / sizeof(Guids[0]),
174                                        HWPD_STANDARDLIST);
175             break;
176     }
177 
178     return FALSE;
179 }
180 
181 
182 static INT_PTR CALLBACK
ClickLockProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)183 ClickLockProc(IN HWND hwndDlg,
184               IN UINT uMsg,
185               IN WPARAM wParam,
186               IN LPARAM lParam)
187 {
188     HWND hDlgCtrl;
189     int pos;
190     static HICON hIcon;
191 
192     PBUTTON_DATA pButtonData;
193 
194     pButtonData = (PBUTTON_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
195 
196     switch(uMsg)
197     {
198         case WM_INITDIALOG:
199             pButtonData = (PBUTTON_DATA)lParam;
200             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pButtonData);
201 
202             hDlgCtrl = GetDlgItem(hwndDlg, IDC_SLIDER_CLICK_LOCK);
203             SendMessage(hDlgCtrl, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 10));
204             pos = (pButtonData->g_ClickLockTime - 200) / 200;
205             SendMessage(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pos);
206 
207             hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_LOCK_KEY),
208                               IMAGE_ICON, 16, 16, 0);
209             SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
210             return TRUE;
211 
212         case WM_COMMAND:
213             if (LOWORD(wParam) == IDOK)
214             {
215                 hDlgCtrl = GetDlgItem(hwndDlg, IDC_SLIDER_CLICK_LOCK);
216                 pButtonData->g_ClickLockTime = (DWORD) (SendMessage(hDlgCtrl, TBM_GETPOS, 0, 0) * 200) + 200;
217                 EndDialog(hwndDlg, TRUE);
218                 if (hIcon) DestroyIcon(hIcon);
219             }
220             else if (LOWORD(wParam) == IDCANCEL)
221             {
222                 EndDialog(hwndDlg, FALSE);
223                 if (hIcon) DestroyIcon(hIcon);
224             }
225             break;
226     }
227 
228     return FALSE;
229 }
230 
231 
232 static INT_PTR CALLBACK
ButtonProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)233 ButtonProc(IN HWND hwndDlg,
234            IN UINT uMsg,
235            IN WPARAM wParam,
236            IN LPARAM lParam)
237 {
238     HWND hDlgCtrl;
239     LRESULT lResult;
240     LPPSHNOTIFY lppsn;
241 
242     PBUTTON_DATA pButtonData;
243 
244     pButtonData = (PBUTTON_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
245 
246     switch (uMsg)
247     {
248         case WM_INITDIALOG:
249             pButtonData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BUTTON_DATA));
250             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pButtonData);
251 
252             pButtonData->g_SwapMouseButtons = GetSystemMetrics(SM_SWAPBUTTON);
253             pButtonData->g_OrigSwapMouseButtons = pButtonData->g_SwapMouseButtons;
254             pButtonData->g_DoubleClickSpeed = GetDoubleClickTime();
255             pButtonData->g_OrigDoubleClickSpeed = pButtonData->g_DoubleClickSpeed;
256 
257             /* Click lock time */
258             SystemParametersInfo(SPI_GETMOUSECLICKLOCK, 0, &pButtonData->g_ClickLockEnabled, 0);
259             SystemParametersInfo(SPI_GETMOUSECLICKLOCKTIME, 0, &pButtonData->g_ClickLockTime, 0);
260 
261             /* Load mouse button icons */
262             pButtonData->hButtonLeft = LoadImage(hApplet, MAKEINTRESOURCE(IDI_MOUSE_LEFT), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
263             pButtonData->hButtonRight = LoadImage(hApplet, MAKEINTRESOURCE(IDI_MOUSE_RIGHT), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
264 
265             /* Load folder icons */
266             pButtonData->hIcon1 = LoadImage(hApplet, MAKEINTRESOURCE(IDI_FOLDER_CLOSED), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
267             pButtonData->hIcon2 = LoadImage(hApplet, MAKEINTRESOURCE(IDI_FOLDER_OPEN), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
268 
269             if (pButtonData->g_SwapMouseButtons)
270             {
271                 SendDlgItemMessage(hwndDlg, IDC_SWAP_MOUSE_BUTTONS, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
272                 SendDlgItemMessage(hwndDlg, IDC_IMAGE_SWAP_MOUSE, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pButtonData->hButtonRight);
273             }
274             else
275             {
276                 SendDlgItemMessage(hwndDlg, IDC_IMAGE_SWAP_MOUSE, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pButtonData->hButtonLeft);
277             }
278 
279             if (pButtonData->g_ClickLockEnabled)
280             {
281                 hDlgCtrl = GetDlgItem(hwndDlg, IDC_CHECK_CLICK_LOCK);
282                 SendMessage(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
283             }
284             else
285             {
286                 hDlgCtrl = GetDlgItem(hwndDlg, IDC_BUTTON_CLICK_LOCK);
287                 EnableWindow(hDlgCtrl, FALSE);
288             }
289 
290             hDlgCtrl = GetDlgItem(hwndDlg, IDC_SLIDER_DOUBLE_CLICK_SPEED);
291             SendMessage(hDlgCtrl, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 14));
292             SendMessage(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, 14 - ((pButtonData->g_DoubleClickSpeed - 200) / 50));
293 
294 
295             SendDlgItemMessage(hwndDlg, IDC_IMAGE_DOUBLE_CLICK_SPEED, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pButtonData->hIcon1);
296             pButtonData->bClicked = TRUE;
297             return TRUE;
298 
299         case WM_DESTROY:
300             DestroyIcon(pButtonData->hButtonLeft);
301             DestroyIcon(pButtonData->hButtonRight);
302             DestroyIcon(pButtonData->hIcon1);
303             DestroyIcon(pButtonData->hIcon2);
304             HeapFree(GetProcessHeap(), 0, pButtonData);
305             break;
306 
307         case WM_COMMAND:
308             switch(LOWORD(wParam))
309             {
310                 case IDC_SWAP_MOUSE_BUTTONS:
311                     lResult = SendMessage((HWND)lParam, BM_GETCHECK, (WPARAM)0, (LPARAM)0);
312                     if (lResult == BST_CHECKED)
313                     {
314                         pButtonData->g_SwapMouseButtons = FALSE;
315                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
316                         SendDlgItemMessage(hwndDlg, IDC_IMAGE_SWAP_MOUSE, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pButtonData->hButtonLeft);
317                     }
318                     else if (lResult == BST_UNCHECKED)
319                     {
320                         pButtonData->g_SwapMouseButtons = TRUE;
321                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
322                         SendDlgItemMessage(hwndDlg, IDC_IMAGE_SWAP_MOUSE, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pButtonData->hButtonRight);
323                     }
324                     //SystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, pButtonData->g_SwapMouseButtons, NULL, 0);
325                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
326                     break;
327 
328                 case IDC_CHECK_CLICK_LOCK:
329                     lResult = SendMessage((HWND)lParam, BM_GETCHECK, (WPARAM)0, (LPARAM)0);
330                     hDlgCtrl = GetDlgItem(hwndDlg, IDC_BUTTON_CLICK_LOCK);
331                     if (lResult == BST_CHECKED)
332                     {
333                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
334                         pButtonData->g_ClickLockEnabled = FALSE;
335                         EnableWindow(hDlgCtrl, FALSE);
336                     }
337                     else if (lResult == BST_UNCHECKED)
338                     {
339                         SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
340                         pButtonData->g_ClickLockEnabled = TRUE;
341                         EnableWindow(hDlgCtrl, TRUE);
342                     }
343                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
344                     break;
345 
346                 case IDC_BUTTON_CLICK_LOCK:
347                     DialogBoxParam(hApplet, MAKEINTRESOURCE(IDD_CLICK_LOCK), hwndDlg, ClickLockProc, (LPARAM)pButtonData);
348                     break;
349 
350                 case IDC_IMAGE_DOUBLE_CLICK_SPEED:
351                     if (HIWORD(wParam) == STN_DBLCLK)
352                     {
353                         pButtonData->bClicked = !pButtonData->bClicked;
354                         SendDlgItemMessage(hwndDlg, IDC_IMAGE_DOUBLE_CLICK_SPEED, STM_SETIMAGE, IMAGE_ICON,
355                                            (LPARAM)(pButtonData->bClicked ? pButtonData->hIcon1 : pButtonData->hIcon2));
356                     }
357                     break;
358             }
359             break;
360 
361         case WM_NOTIFY:
362             lppsn = (LPPSHNOTIFY) lParam;
363             if (lppsn->hdr.code == PSN_APPLY)
364             {
365                 if (pButtonData->g_OrigSwapMouseButtons != pButtonData->g_SwapMouseButtons)
366                 {
367                     pButtonData->g_OrigSwapMouseButtons = pButtonData->g_SwapMouseButtons;
368                     SystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, pButtonData->g_OrigSwapMouseButtons, NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
369 
370                 }
371                 SystemParametersInfo(SPI_SETDOUBLECLICKTIME, pButtonData->g_DoubleClickSpeed, NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
372                 //SetDoubleClickTime(pButtonData->g_DoubleClickSpeed);
373 
374 #if (WINVER >= 0x0500)
375                 SystemParametersInfo(SPI_SETMOUSECLICKLOCK, 0, UlongToPtr(pButtonData->g_ClickLockEnabled), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
376                 if (pButtonData->g_ClickLockEnabled)
377                    SystemParametersInfo(SPI_SETMOUSECLICKLOCKTIME, pButtonData->g_ClickLockTime, NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
378 #endif
379             }
380             else if (lppsn->hdr.code == PSN_RESET)
381             {
382                 /* Reset swap mouse button setting */
383                 SystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, pButtonData->g_OrigSwapMouseButtons, NULL, 0);
384 
385                 /* Reset double-click speed setting */
386                 SystemParametersInfo(SPI_SETDOUBLECLICKTIME, pButtonData->g_OrigDoubleClickSpeed, NULL, 0);
387                 //SetDoubleClickTime(pButtonData->g_OrigDoubleClickSpeed);
388             }
389             return TRUE;
390 
391         case WM_HSCROLL:
392             if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SLIDER_DOUBLE_CLICK_SPEED))
393             {
394                 switch (LOWORD(wParam))
395                 {
396                     case TB_LINEUP:
397                     case TB_LINEDOWN:
398                     case TB_PAGEUP:
399                     case TB_PAGEDOWN:
400                     case TB_TOP:
401                     case TB_BOTTOM:
402                     case TB_ENDTRACK:
403                         lResult = SendDlgItemMessage(hwndDlg, IDC_SLIDER_DOUBLE_CLICK_SPEED, TBM_GETPOS, 0, 0);
404                         pButtonData->g_DoubleClickSpeed = (14 - (INT)lResult) * 50 + 200;
405                         //SystemParametersInfo(SPI_SETDOUBLECLICKTIME, pButtonData->g_DoubleClickSpeed, NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
406                         SetDoubleClickTime(pButtonData->g_DoubleClickSpeed);
407                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
408                         break;
409 
410                     case TB_THUMBTRACK:
411                         pButtonData->g_DoubleClickSpeed = (14 - (INT)HIWORD(wParam)) * 50 + 200;
412                         //SystemParametersInfo(SPI_SETDOUBLECLICKTIME, pButtonData->g_DoubleClickSpeed, NULL, 0);
413                         SetDoubleClickTime(pButtonData->g_DoubleClickSpeed);
414                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
415                         break;
416                 }
417             }
418             break;
419     }
420 
421     return FALSE;
422 }
423 
424 
425 static VOID
CompressPath(LPTSTR lpShortPath,LPTSTR lpPath)426 CompressPath(LPTSTR lpShortPath, LPTSTR lpPath)
427 {
428     TCHAR szUserProfile[MAX_PATH];
429     TCHAR szSystemRoot[MAX_PATH];
430     TCHAR szProgramFiles[MAX_PATH];
431     DWORD dwUserProfile;
432     DWORD dwSystemRoot;
433     DWORD dwProgramFiles;
434 
435     dwUserProfile = GetEnvironmentVariable(_T("USERPROFILE"), szUserProfile, MAX_PATH);
436     dwSystemRoot = GetEnvironmentVariable(_T("SystemRoot"), szSystemRoot, MAX_PATH);
437     dwProgramFiles = GetEnvironmentVariable(_T("ProgramFiles"), szProgramFiles, MAX_PATH);
438 
439     if (dwUserProfile > 0 && _tcsncmp(lpPath, szUserProfile, dwUserProfile) == 0)
440     {
441         _tcscpy(lpShortPath, _T("%USERPROFILE%"));
442         _tcscat(lpShortPath, &lpPath[dwUserProfile]);
443     }
444     else if (dwSystemRoot > 0 && _tcsncmp(lpPath, szSystemRoot, dwSystemRoot) == 0)
445     {
446         _tcscpy(lpShortPath, _T("%SystemRoot%"));
447         _tcscat(lpShortPath, &lpPath[dwSystemRoot]);
448     }
449     else if (dwProgramFiles > 0 && _tcsncmp(lpPath, szProgramFiles, dwProgramFiles) == 0)
450     {
451         _tcscpy(lpShortPath, _T("%ProgramFiles%"));
452         _tcscat(lpShortPath, &lpPath[dwProgramFiles]);
453     }
454     else
455     {
456         _tcscpy(lpShortPath, lpPath);
457     }
458 }
459 
460 
461 static BOOL
EnumerateCursorSchemes(HWND hwndDlg)462 EnumerateCursorSchemes(HWND hwndDlg)
463 {
464     HKEY hCursorKey;
465     DWORD dwIndex;
466     TCHAR szValueName[MAX_PATH];
467     DWORD dwValueName;
468     TCHAR szSystemScheme[MAX_PATH];
469     TCHAR szValueData[2000];
470     TCHAR szTempData[2000];
471     DWORD dwValueData;
472     LONG lError;
473     HWND hDlgCtrl;
474     LRESULT lResult;
475 
476     hDlgCtrl = GetDlgItem(hwndDlg, IDC_COMBO_CURSOR_SCHEME);
477     SendMessage(hDlgCtrl, CB_RESETCONTENT, 0, 0);
478 
479     /* Read the users cursor schemes */
480     lError = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Cursors\\Schemes"),
481                           0, KEY_READ | KEY_QUERY_VALUE , &hCursorKey);
482     if (lError == ERROR_SUCCESS)
483     {
484         for (dwIndex = 0;; dwIndex++)
485         {
486             dwValueName = sizeof(szValueName) / sizeof(TCHAR);
487             dwValueData = sizeof(szValueData) / sizeof(TCHAR);
488             lError = RegEnumValue(hCursorKey, dwIndex, szValueName, &dwValueName,
489                                   NULL, NULL, (LPBYTE)szValueData, &dwValueData);
490             if (lError == ERROR_NO_MORE_ITEMS)
491                 break;
492 
493             ExpandEnvironmentStrings(szValueData, szTempData, 2000);
494 
495             if (_tcslen(szTempData) > 0)
496             {
497                 LPTSTR lpCopy, lpStart;
498 
499                 /* Remove quotation marks */
500                 if (szTempData[0] == _T('"'))
501                 {
502                     lpStart = szTempData + 1;
503                     szTempData[_tcslen(szTempData) - 1] = 0;
504                 }
505                 else
506                 {
507                     lpStart = szTempData;
508                 }
509 
510                 lpCopy = _tcsdup(lpStart);
511 
512                 lResult = SendMessage(hDlgCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)szValueName);
513                 SendMessage(hDlgCtrl, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)lpCopy);
514             }
515         }
516 
517         RegCloseKey(hCursorKey);
518     }
519 
520     /* Read the system cursor schemes */
521     lError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
522                           _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cursors\\Schemes"),
523                           0, KEY_READ | KEY_QUERY_VALUE , &hCursorKey);
524     if (lError == ERROR_SUCCESS)
525     {
526         LoadString(hApplet, IDS_SYSTEM_SCHEME, szSystemScheme, MAX_PATH);
527 
528         for (dwIndex = 0;; dwIndex++)
529         {
530             dwValueName = sizeof(szValueName) / sizeof(TCHAR);
531             dwValueData = sizeof(szValueData) / sizeof(TCHAR);
532             lError = RegEnumValue(hCursorKey, dwIndex, szValueName, &dwValueName,
533                                   NULL, NULL, (LPBYTE)szValueData, &dwValueData);
534             if (lError == ERROR_NO_MORE_ITEMS)
535                 break;
536 
537             if (_tcslen(szValueData) > 0)
538             {
539                 LPTSTR lpCopy, lpStart;
540 
541                 /* Remove quotation marks */
542                 if (szValueData[0] == _T('"'))
543                 {
544                     lpStart = szValueData + 1;
545                     szValueData[_tcslen(szValueData) - 1] = 0;
546                 }
547                 else
548                 {
549                     lpStart = szValueData;
550                 }
551 
552                 lpCopy = _tcsdup(lpStart);
553 
554                 _tcscat(szValueName, TEXT(" "));
555                 _tcscat(szValueName, szSystemScheme);
556 
557                 lResult = SendMessage(hDlgCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)szValueName);
558                 SendMessage(hDlgCtrl, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)lpCopy);
559             }
560         }
561 
562         RegCloseKey(hCursorKey);
563     }
564 
565     /* Add the "(none)" entry */
566     LoadString(hApplet, IDS_NONE, szSystemScheme, MAX_PATH);
567     lResult = SendMessage(hDlgCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)szSystemScheme);
568     SendMessage(hDlgCtrl, CB_SETITEMDATA, (WPARAM)lResult, (LPARAM)NULL);
569 
570     return TRUE;
571 }
572 
573 
574 static VOID
RefreshCursorList(HWND hwndDlg,BOOL bInit)575 RefreshCursorList(HWND hwndDlg, BOOL bInit)
576 {
577     INT index;
578     INT i;
579     INT nSel;
580 
581     nSel = bInit ? 0 : SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_GETCURSEL, 0, 0);
582 
583     if (bInit)
584     {
585         SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_RESETCONTENT, 0, 0);
586         for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
587         {
588             LoadString(hApplet, index, g_CursorData[i].szCursorName, MAX_PATH);
589             SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_ADDSTRING, 0, (LPARAM)i);
590         }
591 
592         SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_SETCURSEL, nSel, 0);
593     }
594     else
595     {
596         InvalidateRect(GetDlgItem(hwndDlg, IDC_LISTBOX_CURSOR), NULL, FALSE);
597     }
598 
599     SendDlgItemMessage(hwndDlg, IDC_IMAGE_CURRENT_CURSOR, STM_SETIMAGE, IMAGE_CURSOR,
600                        (LPARAM)g_CursorData[nSel].hCursor);
601 
602     EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON_USE_DEFAULT_CURSOR), (g_CursorData[nSel].szCursorPath[0] != 0));
603 }
604 
605 
606 static BOOL
DeleteUserCursorScheme(HWND hwndDlg)607 DeleteUserCursorScheme(HWND hwndDlg)
608 {
609     TCHAR szSchemeName[MAX_PATH];
610     TCHAR szTitle[128];
611     TCHAR szRawText[256];
612     TCHAR szText[256];
613     HWND hDlgCtrl;
614     HKEY hCuKey;
615     HKEY hCuCursorKey;
616     LONG lResult;
617     INT nSel;
618 
619     hDlgCtrl = GetDlgItem(hwndDlg, IDC_COMBO_CURSOR_SCHEME);
620     nSel = SendMessage(hDlgCtrl, CB_GETCURSEL, 0, 0);
621     if (nSel == CB_ERR)
622         return FALSE;
623 
624     SendMessage(hDlgCtrl, CB_GETLBTEXT, nSel, (LPARAM)szSchemeName);
625 
626     LoadString(hApplet, IDS_REMOVE_TITLE, szTitle, 128);
627     LoadString(hApplet, IDS_REMOVE_TEXT, szRawText, 256);
628 
629     _stprintf(szText, szRawText, szSchemeName);
630 
631     /* Confirm scheme removal */
632     if (MessageBox(hwndDlg, szText, szTitle, MB_YESNO | MB_ICONQUESTION) == IDNO)
633         return TRUE;
634 
635     if (RegOpenCurrentUser(KEY_READ | KEY_SET_VALUE, &hCuKey) != ERROR_SUCCESS)
636         return FALSE;
637 
638     if (RegOpenKeyEx(hCuKey, _T("Control Panel\\Cursors\\Schemes"), 0, KEY_READ | KEY_SET_VALUE, &hCuCursorKey) != ERROR_SUCCESS)
639     {
640         RegCloseKey(hCuKey);
641         return FALSE;
642     }
643 
644     lResult = RegDeleteValue(hCuCursorKey, szSchemeName);
645 
646     RegCloseKey(hCuCursorKey);
647     RegCloseKey(hCuKey);
648 
649     if (lResult == ERROR_SUCCESS)
650     {
651         SendMessage(hDlgCtrl, CB_DELETESTRING, nSel, 0);
652         SendMessage(hDlgCtrl, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
653     }
654 
655     return (lResult == ERROR_SUCCESS);
656 }
657 
658 
659 static INT_PTR CALLBACK
SaveSchemeProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)660 SaveSchemeProc(IN HWND hwndDlg,
661                IN UINT uMsg,
662                IN WPARAM wParam,
663                IN LPARAM lParam)
664 {
665     LPTSTR pSchemeName;
666 
667     switch (uMsg)
668     {
669         case WM_INITDIALOG:
670             pSchemeName = (LPTSTR)lParam;
671             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSchemeName);
672             SendDlgItemMessage(hwndDlg, IDC_EDIT_SCHEME_NAME, WM_SETTEXT,
673                                0, (LPARAM)pSchemeName);
674             break;
675 
676         case WM_COMMAND:
677             if (LOWORD(wParam) == IDOK)
678             {
679                 pSchemeName = (LPTSTR)GetWindowLongPtr(hwndDlg, DWLP_USER);
680                 SendDlgItemMessage(hwndDlg, IDC_EDIT_SCHEME_NAME, WM_GETTEXT,
681                                    (WPARAM)MAX_PATH, (LPARAM)pSchemeName);
682                 EndDialog(hwndDlg, TRUE);
683             }
684             else if (LOWORD(wParam) == IDCANCEL)
685             {
686                 EndDialog(hwndDlg, FALSE);
687             }
688             break;
689     }
690 
691     return FALSE;
692 }
693 
694 
695 static BOOL
SaveCursorScheme(HWND hwndDlg)696 SaveCursorScheme(HWND hwndDlg)
697 {
698     TCHAR szSystemScheme[MAX_PATH];
699     TCHAR szSchemeName[MAX_PATH];
700     TCHAR szNewSchemeName[MAX_PATH];
701     TCHAR szTempPath[MAX_PATH];
702     TCHAR szTitle[128];
703     TCHAR szText[256];
704     INT nSel;
705     INT index, i, nLength;
706     LPTSTR lpSchemeData;
707     HKEY hCuKey;
708     HKEY hCuCursorKey;
709     LONG lError = ERROR_SUCCESS;
710     BOOL bSchemeExists;
711 
712     LoadString(hApplet, IDS_SYSTEM_SCHEME, szSystemScheme, MAX_PATH);
713 
714     nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETCURSEL, 0, 0);
715     if (nSel == CB_ERR)
716        return FALSE;
717 
718     if (nSel == 0)
719     {
720         szSchemeName[0] = 0;
721         szNewSchemeName[0] = 0;
722     }
723     else
724     {
725         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETLBTEXT, nSel, (LPARAM)szNewSchemeName);
726 
727         if (_tcsstr(szNewSchemeName, szSystemScheme))
728         {
729             szNewSchemeName[_tcslen(szNewSchemeName) - _tcslen(szSystemScheme) - 1] = 0;
730         }
731     }
732 
733     /* Ask for a name for the new cursor scheme */
734     if (!DialogBoxParam(hApplet, MAKEINTRESOURCE(IDD_CURSOR_SCHEME_SAVEAS),
735                         hwndDlg, SaveSchemeProc, (LPARAM)szNewSchemeName))
736         return TRUE;
737 
738     /* Check all non-system schemes for the new name */
739     nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETCOUNT, 0, 0);
740     if (nSel == CB_ERR)
741         return FALSE;
742 
743     bSchemeExists = FALSE;
744     for (i = 0; i < nSel; i++)
745     {
746         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETLBTEXT, i, (LPARAM)szSchemeName);
747         if (_tcsstr(szSchemeName, szSystemScheme) == NULL)
748         {
749             if (_tcscmp(szSchemeName, szNewSchemeName) == 0)
750             {
751                 bSchemeExists = TRUE;
752                 break;
753             }
754         }
755     }
756 
757     if (bSchemeExists)
758     {
759         LoadString(hApplet, IDS_OVERWRITE_TITLE, szTitle, 128);
760         LoadString(hApplet, IDS_OVERWRITE_TEXT, szText, 256);
761 
762          /* Confirm scheme overwrite */
763         if (MessageBox(hwndDlg, szText, szTitle, MB_YESNO | MB_ICONQUESTION) == IDNO)
764             return TRUE;
765     }
766 
767     /* Save the cursor scheme */
768     nLength = 0;
769     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
770     {
771         if (i > 0)
772             nLength++;
773         nLength += _tcslen(g_CursorData[i].szCursorPath);
774     }
775     nLength++;
776 
777     lpSchemeData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength * sizeof(TCHAR));
778 
779     if(!lpSchemeData)
780         return FALSE;
781 
782     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
783     {
784         CompressPath(szTempPath, g_CursorData[i].szCursorPath);
785         if (i > 0)
786             _tcscat(lpSchemeData, _T(","));
787         _tcscat(lpSchemeData, szTempPath);
788     }
789 
790     if (RegOpenCurrentUser(KEY_READ | KEY_SET_VALUE, &hCuKey) != ERROR_SUCCESS)
791     {
792         HeapFree(GetProcessHeap(), 0, lpSchemeData);
793         return FALSE;
794     }
795 
796     if (RegOpenKeyEx(hCuKey, _T("Control Panel\\Cursors\\Schemes"), 0, KEY_READ | KEY_SET_VALUE, &hCuCursorKey) != ERROR_SUCCESS)
797     {
798         RegCloseKey(hCuKey);
799         HeapFree(GetProcessHeap(), 0, lpSchemeData);
800         return FALSE;
801     }
802 
803     lError = RegSetValueEx(hCuCursorKey, szNewSchemeName, 0,
804                            REG_EXPAND_SZ, (LPBYTE)lpSchemeData,
805                            (_tcslen(lpSchemeData) + 1) * sizeof(TCHAR));
806 
807     RegCloseKey(hCuCursorKey);
808     RegCloseKey(hCuKey);
809 
810     /* Add the new scheme to the scheme list and select it */
811     if (lError == ERROR_SUCCESS)
812     {
813         LPTSTR copy = _tcsdup(lpSchemeData);
814 
815         nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_ADDSTRING, (WPARAM)0, (LPARAM)szNewSchemeName);
816         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_SETITEMDATA, (WPARAM)nSel, (LPARAM)copy);
817         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_SETCURSEL, (WPARAM)nSel, (LPARAM)0);
818     }
819 
820     HeapFree(GetProcessHeap(), 0, lpSchemeData);
821 
822     return (lError == ERROR_SUCCESS);
823 }
824 
825 
826 static BOOL
BrowseCursor(HWND hwndDlg)827 BrowseCursor(HWND hwndDlg)
828 {
829     TCHAR szFileName[MAX_PATH];
830     TCHAR szFilter[MAX_PATH];
831     TCHAR szTitle[MAX_PATH];
832     OPENFILENAME ofn;
833     INT nSel;
834 
835     LoadString(hApplet, IDS_BROWSE_FILTER, szFilter, MAX_PATH);
836     LoadString(hApplet, IDS_BROWSE_TITLE, szTitle, MAX_PATH);
837 
838     memset(szFileName, 0x0, sizeof(szFileName));
839     nSel = SendDlgItemMessage(hwndDlg, IDC_LISTBOX_CURSOR, LB_GETCURSEL, 0, 0);
840     if (nSel == LB_ERR)
841     {
842         MessageBox(hwndDlg, _T("LB_ERR"), _T(""), MB_ICONERROR);
843         return FALSE;
844     }
845 
846     ZeroMemory(&ofn, sizeof(OPENFILENAME));
847     ofn.lStructSize = sizeof(OPENFILENAME);
848     ofn.hwndOwner = hwndDlg;
849     ofn.lpstrFilter = szFilter;
850     ofn.nFilterIndex = 1;
851     ofn.lpstrFile = szFileName;
852     ofn.nMaxFile = MAX_PATH;
853     ofn.lpstrInitialDir = _T("%WINDIR%\\Cursors");
854     ofn.lpstrTitle = szTitle;
855     ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
856 
857     if (!GetOpenFileName(&ofn))
858         return FALSE;
859 
860     /* Store the new cursor file path */
861     _tcsncpy(g_CursorData[nSel].szCursorPath, szFileName, MAX_PATH);
862 
863     return TRUE;
864 }
865 
866 
867 static VOID
LoadCursorScheme(LPTSTR lpName,BOOL bSystem)868 LoadCursorScheme(LPTSTR lpName, BOOL bSystem)
869 {
870     UINT index, i;
871 
872     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
873     {
874         if (g_CursorData[i].hCursor != NULL)
875         {
876             DestroyCursor(g_CursorData[i].hCursor);
877             g_CursorData[i].hCursor = 0;
878         }
879         g_CursorData[i].szCursorPath[0] = 0;
880     }
881 
882     if (lpName != NULL)
883     {
884         LPTSTR pStart = lpName;
885         LPTSTR pEnd = pStart;
886         INT nLength;
887 
888         i = 0;
889         while (pEnd)
890         {
891             pEnd = _tcschr(pStart, _T(','));
892             if (pEnd)
893                 nLength = ((INT_PTR)pEnd - (INT_PTR)pStart) / sizeof(TCHAR);
894             else
895                 nLength = _tcslen(pStart);
896 
897             _tcsncpy(g_CursorData[i].szCursorPath, pStart, nLength);
898             g_CursorData[i].szCursorPath[nLength] = 0;
899 
900             pStart = pStart + (nLength + 1);
901             i++;
902         }
903 
904     }
905 
906     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
907     {
908         if (g_CursorData[i].szCursorPath[0] == 0)
909             g_CursorData[i].hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(g_CursorData[i].uDefaultCursorId),
910                                                          IMAGE_CURSOR, 0, 0,
911                                                          LR_DEFAULTSIZE | LR_SHARED);
912         else
913             g_CursorData[i].hCursor = (HCURSOR)LoadImage(NULL, g_CursorData[i].szCursorPath,
914                                                          IMAGE_CURSOR, 0, 0,
915                                                          LR_LOADFROMFILE | LR_DEFAULTSIZE);
916     }
917 }
918 
919 
920 static VOID
ReloadCurrentCursorScheme(VOID)921 ReloadCurrentCursorScheme(VOID)
922 {
923     UINT index, i;
924 
925     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
926     {
927         if (g_CursorData[i].hCursor != NULL)
928             DestroyCursor(g_CursorData[i].hCursor);
929 
930         if (g_CursorData[i].szCursorPath[0] == 0)
931             g_CursorData[i].hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(g_CursorData[i].uDefaultCursorId),
932                                                          IMAGE_CURSOR, 0, 0,
933                                                          LR_DEFAULTSIZE | LR_SHARED);
934         else
935             g_CursorData[i].hCursor = (HCURSOR)LoadImage(NULL, g_CursorData[i].szCursorPath,
936                                                          IMAGE_CURSOR, 0, 0,
937                                                          LR_LOADFROMFILE | LR_DEFAULTSIZE);
938     }
939 }
940 
941 
942 static VOID
OnDrawItem(UINT idCtl,LPDRAWITEMSTRUCT lpdis,PPOINTER_DATA pPointerData)943 OnDrawItem(UINT idCtl,
944            LPDRAWITEMSTRUCT lpdis,
945            PPOINTER_DATA pPointerData)
946 {
947     RECT rc;
948 
949     if (lpdis->itemState & ODS_SELECTED)
950     {
951         FillRect(lpdis->hDC,
952                  &lpdis->rcItem,
953                  (HBRUSH)(COLOR_HIGHLIGHT + 1));
954         SetBkColor(lpdis->hDC,
955                    GetSysColor(COLOR_HIGHLIGHT));
956         SetTextColor(lpdis->hDC,
957                    GetSysColor(COLOR_HIGHLIGHTTEXT));
958     }
959     else
960     {
961         FillRect(lpdis->hDC,
962                  &lpdis->rcItem,
963                  (HBRUSH)(COLOR_WINDOW + 1));
964         SetBkColor(lpdis->hDC,
965                    GetSysColor(COLOR_WINDOW));
966         SetTextColor(lpdis->hDC,
967                    GetSysColor(COLOR_WINDOWTEXT));
968     }
969 
970     if (lpdis->itemID != (UINT)-1)
971     {
972         CopyRect(&rc, &lpdis->rcItem);
973         rc.left += 5;
974         DrawText(lpdis->hDC,
975                  g_CursorData[lpdis->itemData].szCursorName,
976                  -1,
977                  &rc,
978                  DT_SINGLELINE | DT_VCENTER | DT_LEFT);
979 
980         if (g_CursorData[lpdis->itemData].hCursor != NULL)
981         {
982             DrawIcon(lpdis->hDC,
983                      lpdis->rcItem.right - pPointerData->cxCursor - 4,
984                      lpdis->rcItem.top + 2,
985                      g_CursorData[lpdis->itemData].hCursor);
986         }
987     }
988 
989     if (lpdis->itemState & ODS_FOCUS)
990     {
991         CopyRect(&rc, &lpdis->rcItem);
992         InflateRect(&rc, -1, -1);
993         DrawFocusRect(lpdis->hDC, &rc);
994     }
995 }
996 
997 
998 static VOID
LoadNewCursorScheme(HWND hwndDlg)999 LoadNewCursorScheme(HWND hwndDlg)
1000 {
1001     TCHAR buffer[MAX_PATH];
1002     TCHAR szSystemScheme[MAX_PATH];
1003     HWND hDlgCtrl;
1004     BOOL bEnable;
1005     LPTSTR lpName;
1006     INT nSel;
1007 
1008     nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETCURSEL, 0, 0);
1009     if (nSel == CB_ERR)
1010        return;
1011 
1012     SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETLBTEXT, nSel, (LPARAM)buffer);
1013 
1014     LoadString(hApplet, IDS_SYSTEM_SCHEME, szSystemScheme, MAX_PATH);
1015     if (_tcsstr(buffer, szSystemScheme) || nSel == 0) // Avoid the default scheme - Can be deleted
1016         bEnable = FALSE;
1017     else
1018         bEnable = TRUE;
1019 
1020     /* Delete button */
1021     hDlgCtrl = GetDlgItem(hwndDlg, IDC_BUTTON_DELETE_SCHEME);
1022     EnableWindow(hDlgCtrl, bEnable);
1023 
1024     lpName = (LPTSTR)SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETITEMDATA, nSel, 0);
1025     LoadCursorScheme(lpName, !bEnable);
1026     RefreshCursorList(hwndDlg, FALSE);
1027 }
1028 
1029 
1030 static VOID
LoadInitialCursorScheme(HWND hwndDlg)1031 LoadInitialCursorScheme(HWND hwndDlg)
1032 {
1033     TCHAR szSchemeName[MAX_PATH];
1034     TCHAR szSystemScheme[MAX_PATH];
1035     TCHAR szCursorPath[MAX_PATH];
1036     HKEY hCursorKey;
1037     LONG lError;
1038     DWORD dwDataSize;
1039     DWORD dwSchemeSource = 0;
1040     UINT index, i;
1041     DWORD dwType;
1042     INT nSel;
1043 
1044     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
1045     {
1046         g_CursorData[i].hCursor = 0;
1047         g_CursorData[i].szCursorPath[0] = 0;
1048     }
1049 
1050     lError = RegOpenKeyEx(HKEY_CURRENT_USER,
1051                           _T("Control Panel\\Cursors"),
1052                           0,
1053                           KEY_READ | KEY_QUERY_VALUE,
1054                           &hCursorKey);
1055     if (lError != ERROR_SUCCESS)
1056         return;
1057 
1058     dwDataSize = sizeof(DWORD);
1059     lError = RegQueryValueEx(hCursorKey,
1060                              _T("Scheme Source"),
1061                              NULL,
1062                              NULL,
1063                              (LPBYTE)&dwSchemeSource,
1064                              &dwDataSize);
1065 
1066     if (dwSchemeSource != 0)
1067     {
1068         dwDataSize = MAX_PATH * sizeof(TCHAR);
1069         lError = RegQueryValueEx(hCursorKey,
1070                                  NULL,
1071                                  NULL,
1072                                  NULL,
1073                                  (LPBYTE)szSchemeName,
1074                                  &dwDataSize);
1075 
1076         for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
1077         {
1078             dwDataSize = MAX_PATH * sizeof(TCHAR);
1079             lError = RegQueryValueEx(hCursorKey,
1080                                      g_CursorData[i].lpValueName,
1081                                      NULL,
1082                                      &dwType,
1083                                      (LPBYTE)szCursorPath,
1084                                      &dwDataSize);
1085             if (lError == ERROR_SUCCESS)
1086             {
1087                 if (dwType == REG_EXPAND_SZ)
1088                 {
1089                     ExpandEnvironmentStrings(szCursorPath, g_CursorData[i].szCursorPath, MAX_PATH);
1090                 }
1091                 else
1092                 {
1093                     _tcscpy(g_CursorData[i].szCursorPath, szCursorPath);
1094                 }
1095             }
1096         }
1097     }
1098 
1099     RegCloseKey(hCursorKey);
1100 
1101     ReloadCurrentCursorScheme();
1102     RefreshCursorList(hwndDlg, TRUE);
1103 
1104     /* Build the full scheme name */
1105     if (dwSchemeSource == 0)
1106     {
1107         LoadString(hApplet, IDS_NONE, szSchemeName, MAX_PATH);
1108     }
1109     else if (dwSchemeSource == 2)
1110     {
1111         LoadString(hApplet, IDS_SYSTEM_SCHEME, szSystemScheme, MAX_PATH);
1112         _tcsncat(szSchemeName, _T(" "), MAX_PATH - _tcslen(szSchemeName) - 1);
1113         _tcsncat(szSchemeName, szSystemScheme, MAX_PATH - _tcslen(szSchemeName) - 1);
1114     }
1115 
1116     /* Search and select the current scheme name from the scheme list */
1117     nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_FINDSTRINGEXACT, -1, (LPARAM)szSchemeName);
1118     if (nSel != CB_ERR)
1119         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_SETCURSEL, (WPARAM)nSel, (LPARAM)0);
1120 
1121     /* Enable /disable delete button */
1122     EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON_DELETE_SCHEME), (dwSchemeSource == 1));
1123 }
1124 
1125 
1126 static BOOL
ApplyCursorScheme(HWND hwndDlg)1127 ApplyCursorScheme(HWND hwndDlg)
1128 {
1129     TCHAR szSchemeName[MAX_PATH];
1130     TCHAR szSystemScheme[MAX_PATH];
1131     TCHAR szTempPath[MAX_PATH];
1132     LPTSTR lpSchemeData;
1133     DWORD dwNameLength;
1134     DWORD dwSchemeSource;
1135     UINT index, i;
1136     HKEY hCursorKey;
1137     INT nSel;
1138 
1139     nSel = SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETCURSEL, 0, 0);
1140     if (nSel == CB_ERR)
1141        return FALSE;
1142 
1143     lpSchemeData = (LPTSTR)SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETITEMDATA, nSel, 0);
1144     if (lpSchemeData == NULL)
1145     {
1146         /* "None" cursor scheme */
1147         dwSchemeSource = 0;
1148         szSchemeName[0] = 0;
1149         dwNameLength = 0;
1150     }
1151     else
1152     {
1153         SendDlgItemMessage(hwndDlg, IDC_COMBO_CURSOR_SCHEME, CB_GETLBTEXT, nSel, (LPARAM)szSchemeName);
1154         LoadString(hApplet, IDS_SYSTEM_SCHEME, szSystemScheme, MAX_PATH);
1155 
1156         if (_tcsstr(szSchemeName, szSystemScheme))
1157         {
1158             /* System scheme */
1159             dwSchemeSource = 2;
1160             szSchemeName[_tcslen(szSchemeName) - _tcslen(szSystemScheme) - 1] = 0;
1161         }
1162         else
1163         {
1164             /* User scheme */
1165             dwSchemeSource = 1;
1166         }
1167 
1168         dwNameLength = (_tcslen(szSchemeName) + 1) * sizeof(TCHAR);
1169     }
1170 
1171     if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Cursors"), 0,
1172                      KEY_READ | KEY_SET_VALUE, &hCursorKey) != ERROR_SUCCESS)
1173         return FALSE;
1174 
1175     RegSetValueEx(hCursorKey, NULL, 0, REG_SZ,
1176                   (LPBYTE)szSchemeName, dwNameLength);
1177 
1178     RegSetValueEx(hCursorKey, _T("Scheme Source"), 0, REG_DWORD,
1179                   (LPBYTE)&dwSchemeSource, sizeof(DWORD));
1180 
1181     for (index = IDS_ARROW, i = 0; index <= IDS_HAND; index++, i++)
1182     {
1183         CompressPath(szTempPath, g_CursorData[i].szCursorPath);
1184         RegSetValueEx(hCursorKey, g_CursorData[i].lpValueName, 0,
1185                       REG_EXPAND_SZ, (LPBYTE)szTempPath,
1186                       (_tcslen(szTempPath) + 1) * sizeof(TCHAR));
1187     }
1188 
1189     RegCloseKey(hCursorKey);
1190 
1191     /* Force the system to reload its cursors */
1192     SystemParametersInfo(SPI_SETCURSORS, 0, NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1193 
1194     return TRUE;
1195 }
1196 
1197 
1198 static INT_PTR CALLBACK
PointerProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)1199 PointerProc(IN HWND hwndDlg,
1200             IN UINT uMsg,
1201             IN WPARAM wParam,
1202             IN LPARAM lParam)
1203 {
1204     PPOINTER_DATA pPointerData;
1205     LPPSHNOTIFY lppsn;
1206     INT nSel;
1207 
1208     pPointerData = (PPOINTER_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
1209 
1210     switch (uMsg)
1211     {
1212         case WM_INITDIALOG:
1213             pPointerData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(POINTER_DATA));
1214             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pPointerData);
1215 
1216             pPointerData->cxCursor = GetSystemMetrics(SM_CXCURSOR);
1217             pPointerData->cyCursor = GetSystemMetrics(SM_CYCURSOR);
1218 
1219             EnumerateCursorSchemes(hwndDlg);
1220             LoadInitialCursorScheme(hwndDlg);
1221 
1222             /* Get cursor shadow setting */
1223             SystemParametersInfo(SPI_GETCURSORSHADOW, 0, &pPointerData->bCursorShadow, 0);
1224             pPointerData->bOrigCursorShadow = pPointerData->bCursorShadow;
1225 
1226             if (pPointerData->bCursorShadow)
1227             {
1228                 SendDlgItemMessage(hwndDlg, IDC_CHECK_CURSOR_SHADOW, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
1229             }
1230 
1231             if ((INT)wParam == IDC_LISTBOX_CURSOR)
1232                 return TRUE;
1233             else
1234                 return FALSE;
1235 
1236         case WM_MEASUREITEM:
1237             ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = GetSystemMetrics(SM_CYCURSOR) + 4;
1238             break;
1239 
1240         case WM_DRAWITEM:
1241             if (wParam == IDC_LISTBOX_CURSOR)
1242                 OnDrawItem((UINT)wParam, (LPDRAWITEMSTRUCT)lParam, pPointerData);
1243             return TRUE;
1244 
1245         case WM_DESTROY:
1246             HeapFree(GetProcessHeap(), 0, pPointerData);
1247             break;
1248 
1249         case WM_NOTIFY:
1250             lppsn = (LPPSHNOTIFY) lParam;
1251             if (lppsn->hdr.code == PSN_APPLY)
1252             {
1253                 ApplyCursorScheme(hwndDlg);
1254 //#if (WINVER >= 0x0500)
1255                 if (pPointerData->bOrigCursorShadow != pPointerData->bCursorShadow)
1256                 {
1257                     SystemParametersInfo(SPI_SETCURSORSHADOW, 0, UlongToPtr(pPointerData->bCursorShadow), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1258                     pPointerData->bOrigCursorShadow = pPointerData->bCursorShadow;
1259                 }
1260 //#endif
1261                 return TRUE;
1262             }
1263             else if (lppsn->hdr.code == PSN_RESET)
1264             {
1265 //#if (WINVER >= 0x0500)
1266                 SystemParametersInfo(SPI_SETCURSORSHADOW, 0, UlongToPtr(pPointerData->bOrigCursorShadow), SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
1267 //#endif
1268             }
1269             break;
1270 
1271         case WM_COMMAND:
1272             switch (LOWORD(wParam))
1273             {
1274                 case IDC_COMBO_CURSOR_SCHEME:
1275                     if (HIWORD(wParam) == CBN_SELENDOK)
1276                     {
1277                         LoadNewCursorScheme(hwndDlg);
1278                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1279                     }
1280                     break;
1281 
1282                 case IDC_LISTBOX_CURSOR:
1283                     switch (HIWORD(wParam))
1284                     {
1285                         case LBN_SELCHANGE:
1286                             nSel = SendMessage((HWND)lParam, LB_GETCURSEL, 0, 0);
1287 
1288                             if(nSel == LB_ERR)
1289                                 break;
1290 
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
OptionProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)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(1, 20));
1434             SendMessage(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pOptionData->ulMouseSpeed);
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);
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
ShowDialogWheelControls(HWND hwndDlg,UINT uWheelScrollLines,BOOL bInit)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 != FALSE)
1721             SetDlgItemInt(hwndDlg, IDC_EDIT_WHEEL_SCROLL_LINES, DEFAULT_WHEEL_SCROLL_LINES, FALSE);
1722     }
1723 }
1724 
1725 
1726 static INT_PTR CALLBACK
WheelProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)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 int CALLBACK
PropSheetProc(HWND hwndDlg,UINT uMsg,LPARAM lParam)1798 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
1799 {
1800     // NOTE: This callback is needed to set large icon correctly.
1801     HICON hIcon;
1802     switch (uMsg)
1803     {
1804         case PSCB_INITIALIZED:
1805         {
1806             hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDC_CPLICON_1));
1807             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
1808             break;
1809         }
1810     }
1811     return 0;
1812 }
1813 
1814 static const struct
1815 {
1816     WORD idDlg;
1817     DLGPROC DlgProc;
1818     UINT uiReplaceWith;
1819 } PropPages[] =
1820 {
1821     { IDD_PAGE_BUTTON, ButtonProc, CPLPAGE_MOUSE_BUTTONS },
1822     { IDD_PAGE_POINTER, PointerProc, 0 },
1823     { IDD_PAGE_OPTION, OptionProc, CPLPAGE_MOUSE_PTRMOTION },
1824     { IDD_PAGE_WHEEL, WheelProc, CPLPAGE_MOUSE_WHEEL },
1825     { IDD_HARDWARE, MouseHardwareProc, 0 },
1826 };
1827 
1828 LONG APIENTRY
MouseApplet(HWND hwnd,UINT uMsg,LPARAM lParam1,LPARAM lParam2)1829 MouseApplet(HWND hwnd, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
1830 {
1831     HPROPSHEETPAGE hpsp[MAX_CPL_PAGES];
1832     PROPSHEETHEADER psh;
1833     HPSXA hpsxa;
1834     UINT i;
1835     INT nPage = 0;
1836     LONG ret;
1837 
1838     UNREFERENCED_PARAMETER(lParam1);
1839     UNREFERENCED_PARAMETER(lParam2);
1840     UNREFERENCED_PARAMETER(uMsg);
1841     UNREFERENCED_PARAMETER(hwnd);
1842 
1843     if (uMsg == CPL_STARTWPARMSW && lParam2 != 0)
1844         nPage = _wtoi((PWSTR)lParam2);
1845 
1846     ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
1847     psh.dwSize = sizeof(PROPSHEETHEADER);
1848     psh.dwFlags = PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK;
1849     psh.hwndParent = hwnd;
1850     psh.hInstance = hApplet;
1851     psh.pszIcon = MAKEINTRESOURCEW(IDC_CPLICON_1);
1852     psh.pszCaption = MAKEINTRESOURCEW(IDS_CPLNAME_1);
1853     psh.nStartPage = 0;
1854     psh.phpage = hpsp;
1855     psh.pfnCallback = PropSheetProc;
1856 
1857     /* Load additional pages provided by shell extensions */
1858     hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Mouse"), MAX_CPL_PAGES - psh.nPages);
1859 
1860     for (i = 0; i != sizeof(PropPages) / sizeof(PropPages[0]); i++)
1861     {
1862         /* Override the background page if requested by a shell extension */
1863         if (PropPages[i].uiReplaceWith != 0 && hpsxa != NULL &&
1864             SHReplaceFromPropSheetExtArray(hpsxa, PropPages[i].uiReplaceWith, PropSheetAddPage, (LPARAM)&psh) != 0)
1865         {
1866             /* The shell extension added one or more pages to replace a page.
1867                Don't create the built-in page anymore! */
1868             continue;
1869         }
1870 
1871         InitPropSheetPage(&psh, PropPages[i].idDlg, PropPages[i].DlgProc);
1872     }
1873 
1874     if (hpsxa != NULL)
1875         SHAddFromPropSheetExtArray(hpsxa, PropSheetAddPage, (LPARAM)&psh);
1876 
1877     if (nPage != 0 && nPage <= psh.nPages)
1878         psh.nStartPage = nPage;
1879 
1880     ret = (LONG)(PropertySheet(&psh) != -1);
1881 
1882     if (hpsxa != NULL)
1883         SHDestroyPropSheetExtArray(hpsxa);
1884 
1885     return ret;
1886 }
1887 
1888 /* EOF */
1889