2 * Joystick testing control panel applet
4 * Copyright 2012 Lucas Fialho Zawacki
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSUNION
34 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(joycpl
);
39 DECLSPEC_HIDDEN HMODULE hcpl
;
41 /*********************************************************************
44 BOOL WINAPI
DllMain(HINSTANCE hdll
, DWORD reason
, LPVOID reserved
)
46 TRACE("(%p, %d, %p)\n", hdll
, reason
, reserved
);
50 case DLL_WINE_PREATTACH
:
51 return FALSE
; /* prefer native version */
53 case DLL_PROCESS_ATTACH
:
54 DisableThreadLibraryCalls(hdll
);
60 /***********************************************************************
61 * enum_callback [internal]
62 * Enumerates, creates and sets the common data format for all the joystick devices.
63 * First time it checks if space for the joysticks was already reserved
64 * and if not, just counts how many there are.
66 static BOOL CALLBACK
enum_callback(const DIDEVICEINSTANCEW
*instance
, void *context
)
68 struct JoystickData
*data
= context
;
69 struct Joystick
*joystick
;
70 DIPROPRANGE proprange
;
73 if (data
->joysticks
== NULL
)
75 data
->num_joysticks
+= 1;
76 return DIENUM_CONTINUE
;
79 joystick
= &data
->joysticks
[data
->cur_joystick
];
80 data
->cur_joystick
+= 1;
82 IDirectInput8_CreateDevice(data
->di
, &instance
->guidInstance
, &joystick
->device
, NULL
);
83 IDirectInputDevice8_SetDataFormat(joystick
->device
, &c_dfDIJoystick
);
85 joystick
->instance
= *instance
;
87 caps
.dwSize
= sizeof(caps
);
88 IDirectInputDevice8_GetCapabilities(joystick
->device
, &caps
);
90 joystick
->num_buttons
= caps
.dwButtons
;
91 joystick
->num_axes
= caps
.dwAxes
;
92 joystick
->forcefeedback
= caps
.dwFlags
& DIDC_FORCEFEEDBACK
;
94 if (joystick
->forcefeedback
) data
->num_ff
++;
96 /* Set axis range to ease the GUI visualization */
97 proprange
.diph
.dwSize
= sizeof(DIPROPRANGE
);
98 proprange
.diph
.dwHeaderSize
= sizeof(DIPROPHEADER
);
99 proprange
.diph
.dwHow
= DIPH_DEVICE
;
100 proprange
.diph
.dwObj
= 0;
101 proprange
.lMin
= TEST_AXIS_MIN
;
102 proprange
.lMax
= TEST_AXIS_MAX
;
104 IDirectInputDevice_SetProperty(joystick
->device
, DIPROP_RANGE
, &proprange
.diph
);
106 return DIENUM_CONTINUE
;
109 /***********************************************************************
110 * initialize_joysticks [internal]
112 static void initialize_joysticks(struct JoystickData
*data
)
114 data
->num_joysticks
= 0;
115 data
->cur_joystick
= 0;
116 IDirectInput8_EnumDevices(data
->di
, DI8DEVCLASS_GAMECTRL
, enum_callback
, data
, DIEDFL_ATTACHEDONLY
);
117 data
->joysticks
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct Joystick
) * data
->num_joysticks
);
119 /* Get all the joysticks */
120 IDirectInput8_EnumDevices(data
->di
, DI8DEVCLASS_GAMECTRL
, enum_callback
, data
, DIEDFL_ATTACHEDONLY
);
123 /***********************************************************************
124 * destroy_joysticks [internal]
126 static void destroy_joysticks(struct JoystickData
*data
)
130 for (i
= 0; i
< data
->num_joysticks
; i
++)
133 if (data
->joysticks
[i
].forcefeedback
)
135 for (j
= 0; j
< data
->joysticks
[i
].num_effects
; j
++)
136 IDirectInputEffect_Release(data
->joysticks
[i
].effects
[j
].effect
);
138 HeapFree(GetProcessHeap(), 0, data
->joysticks
[i
].effects
);
141 IDirectInputDevice8_Unacquire(data
->joysticks
[i
].device
);
142 IDirectInputDevice8_Release(data
->joysticks
[i
].device
);
145 HeapFree(GetProcessHeap(), 0, data
->joysticks
);
148 /*********************************************************************
149 * list_dlgproc [internal]
152 static INT_PTR CALLBACK
list_dlgproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
154 TRACE("(%p, 0x%08x/%d, 0x%lx)\n", hwnd
, msg
, msg
, lparam
);
160 struct JoystickData
*data
= (struct JoystickData
*) ((PROPSHEETPAGEW
*)lparam
)->lParam
;
162 /* Set dialog information */
163 for (i
= 0; i
< data
->num_joysticks
; i
++)
165 struct Joystick
*joy
= &data
->joysticks
[i
];
166 SendDlgItemMessageW(hwnd
, IDC_JOYSTICKLIST
, LB_ADDSTRING
, 0, (LPARAM
) joy
->instance
.tszInstanceName
);
174 switch (LOWORD(wparam
))
176 case IDC_BUTTONDISABLE
:
177 FIXME("Disable selected joystick from being enumerated\n");
180 case IDC_BUTTONENABLE
:
181 FIXME("Re-Enable selected joystick\n");
196 /*********************************************************************
197 * Joystick testing functions
200 static void dump_joy_state(DIJOYSTATE
* st
, int num_buttons
)
203 TRACE("Ax (% 5d,% 5d,% 5d)\n", st
->lX
,st
->lY
, st
->lZ
);
204 TRACE("RAx (% 5d,% 5d,% 5d)\n", st
->lRx
, st
->lRy
, st
->lRz
);
205 TRACE("Slider (% 5d,% 5d)\n", st
->rglSlider
[0], st
->rglSlider
[1]);
206 TRACE("Pov (% 5d,% 5d,% 5d,% 5d)\n", st
->rgdwPOV
[0], st
->rgdwPOV
[1], st
->rgdwPOV
[2], st
->rgdwPOV
[3]);
209 for(i
=0; i
< num_buttons
; i
++)
210 TRACE(" %c",st
->rgbButtons
[i
] ? 'x' : 'o');
214 static void poll_input(const struct Joystick
*joy
, DIJOYSTATE
*state
)
218 hr
= IDirectInputDevice8_Poll(joy
->device
);
220 /* If it failed, try to acquire the joystick */
223 hr
= IDirectInputDevice8_Acquire(joy
->device
);
224 while (hr
== DIERR_INPUTLOST
) hr
= IDirectInputDevice8_Acquire(joy
->device
);
227 if (hr
== DIERR_OTHERAPPHASPRIO
) return;
229 IDirectInputDevice8_GetDeviceState(joy
->device
, sizeof(DIJOYSTATE
), state
);
232 static DWORD WINAPI
input_thread(void *param
)
234 int axes_pos
[TEST_MAX_AXES
][2];
236 struct JoystickData
*data
= param
;
238 /* Setup POV as clock positions
245 int ma
= TEST_AXIS_MAX
;
246 int pov_val
[9] = {0, 4500, 9000, 13500,
247 18000, 22500, 27000, 31500, -1};
248 int pov_pos
[9][2] = { {0, -ma
}, {ma
/2, -ma
/2}, {ma
, 0}, {ma
/2, ma
/2},
249 {0, ma
}, {-ma
/2, ma
/2}, {-ma
, 0}, {-ma
/2, -ma
/2}, {0, 0} };
251 ZeroMemory(&state
, sizeof(state
));
256 poll_input(&data
->joysticks
[data
->chosen_joystick
], &state
);
258 dump_joy_state(&state
, data
->joysticks
[data
->chosen_joystick
].num_buttons
);
260 /* Indicate pressed buttons */
261 for (i
= 0; i
< data
->joysticks
[data
->chosen_joystick
].num_buttons
; i
++)
262 if (state
.rgbButtons
[i
])
263 SendMessageW(data
->buttons
[i
], BM_SETSTATE
, TRUE
, 0);
265 /* Indicate axis positions, axes showing are hardcoded for now */
266 axes_pos
[0][0] = state
.lX
;
267 axes_pos
[0][1] = state
.lY
;
268 axes_pos
[1][0] = state
.lRx
;
269 axes_pos
[1][1] = state
.lRy
;
270 axes_pos
[2][0] = state
.lZ
;
271 axes_pos
[2][1] = state
.lRz
;
274 for (i
= 0; i
< sizeof(pov_val
)/sizeof(pov_val
[0]); i
++)
276 if (state
.rgdwPOV
[0] == pov_val
[i
])
278 axes_pos
[3][0] = pov_pos
[i
][0];
279 axes_pos
[3][1] = pov_pos
[i
][1];
283 for (i
= 0; i
< TEST_MAX_AXES
; i
++)
284 SetWindowPos(data
->axes
[i
], 0,
285 TEST_AXIS_X
+ TEST_NEXT_AXIS_X
*i
+ axes_pos
[i
][0],
286 TEST_AXIS_Y
+ axes_pos
[i
][1],
287 0, 0, SWP_NOZORDER
| SWP_NOSIZE
);
289 Sleep(TEST_POLL_TIME
);
291 /* Reset button state */
292 for (i
= 0; i
< data
->joysticks
[data
->chosen_joystick
].num_buttons
; i
++)
293 SendMessageW(data
->buttons
[i
], BM_SETSTATE
, FALSE
, 0);
299 static void test_handle_joychange(HWND hwnd
, struct JoystickData
*data
)
303 if (data
->num_joysticks
== 0) return;
305 data
->chosen_joystick
= SendDlgItemMessageW(hwnd
, IDC_TESTSELECTCOMBO
, CB_GETCURSEL
, 0, 0);
307 /* Enable only buttons present in the device */
308 for (i
= 0; i
< TEST_MAX_BUTTONS
; i
++)
309 ShowWindow(data
->buttons
[i
], i
<= data
->joysticks
[data
->chosen_joystick
].num_buttons
);
312 /*********************************************************************
313 * button_number_to_wchar [internal]
314 * Transforms an integer in the interval [0,99] into a 2 character WCHAR string
316 static void button_number_to_wchar(int n
, WCHAR str
[3])
318 str
[1] = n
% 10 + '0';
320 str
[0] = n
% 10 + '0';
324 static void draw_joystick_buttons(HWND hwnd
, struct JoystickData
* data
)
327 int row
= 0, col
= 0;
328 WCHAR button_label
[3];
329 HINSTANCE hinst
= (HINSTANCE
) GetWindowLongPtrW(hwnd
, GWLP_HINSTANCE
);
330 static WCHAR button_class
[] = {'B','u','t','t','o','n','\0'};
332 for (i
= 0; i
< TEST_MAX_BUTTONS
; i
++)
334 if ((i
% TEST_BUTTON_COL_MAX
) == 0 && i
!= 0)
340 button_number_to_wchar(i
+ 1, button_label
);
342 data
->buttons
[i
] = CreateWindowW(button_class
, button_label
, WS_CHILD
,
343 TEST_BUTTON_X
+ TEST_NEXT_BUTTON_X
*col
, TEST_BUTTON_Y
+ TEST_NEXT_BUTTON_Y
*row
,
344 TEST_BUTTON_SIZE_X
, TEST_BUTTON_SIZE_Y
,
345 hwnd
, NULL
, NULL
, hinst
);
351 static void draw_joystick_axes(HWND hwnd
, struct JoystickData
* data
)
354 HINSTANCE hinst
= (HINSTANCE
) GetWindowLongPtrW(hwnd
, GWLP_HINSTANCE
);
355 static const WCHAR button_class
[] = {'B','u','t','t','o','n','\0'};
356 static const WCHAR axes_names
[TEST_MAX_AXES
][7] = { {'X',',','Y','\0'}, {'R','x',',','R','y','\0'},
357 {'Z',',','R','z','\0'}, {'P','O','V','\0'} };
358 static const DWORD axes_idc
[TEST_MAX_AXES
] = { IDC_TESTGROUPXY
, IDC_TESTGROUPRXRY
,
359 IDC_TESTGROUPZRZ
, IDC_TESTGROUPPOV
};
361 for (i
= 0; i
< TEST_MAX_AXES
; i
++)
363 /* Set axis box name */
364 SetWindowTextW(GetDlgItem(hwnd
, axes_idc
[i
]), axes_names
[i
]);
366 data
->axes
[i
] = CreateWindowW( button_class
, NULL
, WS_CHILD
| WS_VISIBLE
,
367 TEST_AXIS_X
+ TEST_NEXT_AXIS_X
*i
, TEST_AXIS_Y
,
368 TEST_AXIS_SIZE_X
, TEST_AXIS_SIZE_Y
,
369 hwnd
, (HMENU
) IDC_JOYSTICKAXES
+ i
, NULL
, hinst
);
373 /*********************************************************************
374 * test_dlgproc [internal]
377 static INT_PTR CALLBACK
test_dlgproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
379 static HANDLE thread
;
380 static struct JoystickData
*data
;
381 TRACE("(%p, 0x%08x/%d, 0x%lx)\n", hwnd
, msg
, msg
, lparam
);
389 data
= (struct JoystickData
*) ((PROPSHEETPAGEW
*)lparam
)->lParam
;
391 /* Add enumerated joysticks to the combobox */
392 for (i
= 0; i
< data
->num_joysticks
; i
++)
394 struct Joystick
*joy
= &data
->joysticks
[i
];
395 SendDlgItemMessageW(hwnd
, IDC_TESTSELECTCOMBO
, CB_ADDSTRING
, 0, (LPARAM
) joy
->instance
.tszInstanceName
);
398 draw_joystick_buttons(hwnd
, data
);
399 draw_joystick_axes(hwnd
, data
);
407 case MAKEWPARAM(IDC_TESTSELECTCOMBO
, CBN_SELCHANGE
):
408 test_handle_joychange(hwnd
, data
);
414 switch(((LPNMHDR
)lparam
)->code
)
420 /* Initialize input thread */
421 if (data
->num_joysticks
> 0)
425 /* Set the first joystick as default */
426 SendDlgItemMessageW(hwnd
, IDC_TESTSELECTCOMBO
, CB_SETCURSEL
, 0, 0);
427 test_handle_joychange(hwnd
, data
);
429 thread
= CreateThread(NULL
, 0, input_thread
, (void*) data
, 0, &tid
);
434 case PSN_RESET
: /* intentional fall-through */
436 /* Stop input thread */
438 MsgWaitForMultipleObjects(1, &thread
, FALSE
, INFINITE
, 0);
447 /*********************************************************************
448 * Joystick force feedback testing functions
451 static void draw_ff_axis(HWND hwnd
, struct JoystickData
*data
)
453 HINSTANCE hinst
= (HINSTANCE
) GetWindowLongPtrW(hwnd
, GWLP_HINSTANCE
);
454 static WCHAR button_class
[] = {'B','u','t','t','o','n','\0'};
456 /* Draw direction axis */
457 data
->ff_axis
= CreateWindowW( button_class
, NULL
, WS_CHILD
| WS_VISIBLE
,
458 FF_AXIS_X
, FF_AXIS_Y
,
459 FF_AXIS_SIZE_X
, FF_AXIS_SIZE_Y
,
460 hwnd
, (HMENU
) IDC_FFAXIS
, NULL
, hinst
);
463 static void initialize_effects_list(HWND hwnd
, struct Joystick
* joy
)
467 SendDlgItemMessageW(hwnd
, IDC_FFEFFECTLIST
, LB_RESETCONTENT
, 0, 0);
469 for (i
=0; i
< joy
->num_effects
; i
++)
471 /* Effect names start with GUID_, so we'll skip this part */
472 WCHAR
*name
= joy
->effects
[i
].info
.tszName
+ 5;
473 SendDlgItemMessageW(hwnd
, IDC_FFEFFECTLIST
, LB_ADDSTRING
, 0, (LPARAM
) name
);
477 static void ff_handle_joychange(HWND hwnd
, struct JoystickData
*data
)
481 if (data
->num_ff
== 0) return;
483 sel
= SendDlgItemMessageW(hwnd
, IDC_FFSELECTCOMBO
, CB_GETCURSEL
, 0, 0);
484 data
->chosen_joystick
= SendDlgItemMessageW(hwnd
, IDC_FFSELECTCOMBO
, CB_GETITEMDATA
, sel
, 0);
485 initialize_effects_list(hwnd
, &data
->joysticks
[data
->chosen_joystick
]);
488 static void ff_handle_effectchange(HWND hwnd
, struct Joystick
*joy
)
490 int sel
= SendDlgItemMessageW(hwnd
, IDC_FFEFFECTLIST
, LB_GETCURSEL
, 0, 0);
494 joy
->chosen_effect
= sel
;
497 static DWORD WINAPI
ff_input_thread(void *param
)
499 struct JoystickData
*data
= param
;
502 ZeroMemory(&state
, sizeof(state
));
507 struct Joystick
*joy
= &data
->joysticks
[data
->chosen_joystick
];
508 int chosen_effect
= joy
->chosen_effect
;
510 DWORD flags
= DIEP_AXES
| DIEP_DIRECTION
| DIEP_NORESTART
;
512 /* Skip this if we have no effects */
513 if (joy
->num_effects
== 0 || chosen_effect
< 0) continue;
515 poll_input(joy
, &state
);
517 /* Set ff parameters and draw the axis */
518 dieffect
= &joy
->effects
[chosen_effect
].params
;
519 dieffect
->rgdwAxes
[0] = state
.lX
;
520 dieffect
->rgdwAxes
[1] = state
.lY
;
522 SetWindowPos(data
->ff_axis
, 0, FF_AXIS_X
+ state
.lX
, FF_AXIS_Y
+ state
.lY
,
523 0, 0, SWP_NOZORDER
| SWP_NOSIZE
);
525 for (i
=0; i
< joy
->num_buttons
; i
++)
526 if (state
.rgbButtons
[i
])
528 IDirectInputEffect_SetParameters(joy
->effects
[chosen_effect
].effect
, dieffect
, flags
);
529 IDirectInputEffect_Start(joy
->effects
[chosen_effect
].effect
, 1, 0);
533 Sleep(TEST_POLL_TIME
);
539 /***********************************************************************
540 * ff_effects_callback [internal]
541 * Enumerates, creates, sets the some parameters and stores all ff effects
542 * supported by the joystick. Works like enum_callback, counting the effects
543 * first and then storing them.
545 static BOOL CALLBACK
ff_effects_callback(const DIEFFECTINFOW
*pdei
, void *pvRef
)
549 DWORD axes
[2] = {DIJOFS_X
, DIJOFS_Y
};
550 int direction
[2] = {0, 0};
551 struct Joystick
*joystick
= pvRef
;
553 if (joystick
->effects
== NULL
)
555 joystick
->num_effects
+= 1;
556 return DIENUM_CONTINUE
;
559 hr
= IDirectInputDevice8_Acquire(joystick
->device
);
561 if (FAILED(hr
)) return DIENUM_CONTINUE
;
563 ZeroMemory(&dieffect
, sizeof(dieffect
));
565 dieffect
.dwSize
= sizeof(dieffect
);
566 dieffect
.dwFlags
= DIEFF_CARTESIAN
;
567 dieffect
.dwDuration
= FF_PLAY_TIME
;
570 dieffect
.rgdwAxes
= axes
;
571 dieffect
.rglDirection
= direction
;
573 if (IsEqualGUID(&pdei
->guid
, &GUID_RampForce
))
578 rforce
.lEnd
= DI_FFNOMINALMAX
;
580 dieffect
.cbTypeSpecificParams
= sizeof(rforce
);
581 dieffect
.lpvTypeSpecificParams
= &rforce
;
582 dieffect
.dwFlags
|= DIEP_TYPESPECIFICPARAMS
;
584 else if (IsEqualGUID(&pdei
->guid
, &GUID_ConstantForce
))
586 DICONSTANTFORCE cforce
;
588 cforce
.lMagnitude
= DI_FFNOMINALMAX
;
590 dieffect
.cbTypeSpecificParams
= sizeof(cforce
);
591 dieffect
.lpvTypeSpecificParams
= &cforce
;
592 dieffect
.dwFlags
|= DIEP_TYPESPECIFICPARAMS
;
594 else if (IsEqualGUID(&pdei
->guid
, &GUID_Sine
) ||
595 IsEqualGUID(&pdei
->guid
, &GUID_Square
) ||
596 IsEqualGUID(&pdei
->guid
, &GUID_Triangle
) ||
597 IsEqualGUID(&pdei
->guid
, &GUID_SawtoothUp
) ||
598 IsEqualGUID(&pdei
->guid
, &GUID_SawtoothDown
))
602 pforce
.dwMagnitude
= DI_FFNOMINALMAX
;
605 pforce
.dwPeriod
= FF_PERIOD_TIME
;
607 dieffect
.cbTypeSpecificParams
= sizeof(pforce
);
608 dieffect
.lpvTypeSpecificParams
= &pforce
;
609 dieffect
.dwFlags
|= DIEP_TYPESPECIFICPARAMS
;
612 hr
= IDirectInputDevice2_CreateEffect(
613 joystick
->device
, &pdei
->guid
, &dieffect
, &joystick
->effects
[joystick
->cur_effect
].effect
, NULL
);
615 joystick
->effects
[joystick
->cur_effect
].params
= dieffect
;
616 joystick
->effects
[joystick
->cur_effect
].info
= *pdei
;
617 joystick
->cur_effect
+= 1;
619 return DIENUM_CONTINUE
;
622 /*********************************************************************
623 * ff_dlgproc [internal]
626 static INT_PTR CALLBACK
ff_dlgproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
628 static HANDLE thread
;
629 static struct JoystickData
*data
;
630 TRACE("(%p, 0x%08x/%d, 0x%lx)\n", hwnd
, msg
, msg
, lparam
);
638 data
= (struct JoystickData
*) ((PROPSHEETPAGEW
*)lparam
)->lParam
;
640 /* Add joysticks with FF support to the combobox and get the effects */
641 for (i
= 0; i
< data
->num_joysticks
; i
++)
643 struct Joystick
*joy
= &data
->joysticks
[i
];
645 if (joy
->forcefeedback
)
647 SendDlgItemMessageW(hwnd
, IDC_FFSELECTCOMBO
, CB_ADDSTRING
, 0, (LPARAM
) joy
->instance
.tszInstanceName
);
648 SendDlgItemMessageW(hwnd
, IDC_FFSELECTCOMBO
, CB_SETITEMDATA
, cur
, i
);
652 /* Count device effects and then store them */
653 joy
->num_effects
= 0;
655 IDirectInputDevice8_EnumEffects(joy
->device
, ff_effects_callback
, (void *) joy
, 0);
656 joy
->effects
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct Effect
) * joy
->num_effects
);
659 IDirectInputDevice8_EnumEffects(joy
->device
, ff_effects_callback
, (void*) joy
, 0);
660 FIXME("%d --- %d\n", joy
->num_effects
, joy
->cur_effect
);
661 joy
->num_effects
= joy
->cur_effect
;
666 draw_ff_axis(hwnd
, data
);
674 case MAKEWPARAM(IDC_FFSELECTCOMBO
, CBN_SELCHANGE
):
675 ff_handle_joychange(hwnd
, data
);
677 SendDlgItemMessageW(hwnd
, IDC_FFEFFECTLIST
, LB_SETCURSEL
, 0, 0);
678 ff_handle_effectchange(hwnd
, &data
->joysticks
[data
->chosen_joystick
]);
681 case MAKEWPARAM(IDC_FFEFFECTLIST
, LBN_SELCHANGE
):
682 ff_handle_effectchange(hwnd
, &data
->joysticks
[data
->chosen_joystick
]);
688 switch(((LPNMHDR
)lparam
)->code
)
691 if (data
->num_ff
> 0)
696 /* Set the first joystick as default */
697 SendDlgItemMessageW(hwnd
, IDC_FFSELECTCOMBO
, CB_SETCURSEL
, 0, 0);
698 ff_handle_joychange(hwnd
, data
);
700 SendDlgItemMessageW(hwnd
, IDC_FFEFFECTLIST
, LB_SETCURSEL
, 0, 0);
701 ff_handle_effectchange(hwnd
, &data
->joysticks
[data
->chosen_joystick
]);
703 thread
= CreateThread(NULL
, 0, ff_input_thread
, (void*) data
, 0, &tid
);
707 case PSN_RESET
: /* intentional fall-through */
711 MsgWaitForMultipleObjects(1, &thread
, FALSE
, INFINITE
, 0);
720 /******************************************************************************
721 * propsheet_callback [internal]
723 static int CALLBACK
propsheet_callback(HWND hwnd
, UINT msg
, LPARAM lparam
)
725 TRACE("(%p, 0x%08x/%d, 0x%lx)\n", hwnd
, msg
, msg
, lparam
);
728 case PSCB_INITIALIZED
:
734 /******************************************************************************
735 * display_cpl_sheets [internal]
737 * Build and display the dialog with all control panel propertysheets
740 static void display_cpl_sheets(HWND parent
, struct JoystickData
*data
)
742 INITCOMMONCONTROLSEX icex
;
743 PROPSHEETPAGEW psp
[NUM_PROPERTY_PAGES
];
744 PROPSHEETHEADERW psh
;
748 /* Initialize common controls */
749 icex
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
750 icex
.dwICC
= ICC_LISTVIEW_CLASSES
| ICC_BAR_CLASSES
;
751 InitCommonControlsEx(&icex
);
753 ZeroMemory(&psh
, sizeof(psh
));
754 ZeroMemory(psp
, sizeof(psp
));
756 /* Fill out all PROPSHEETPAGE */
757 psp
[id
].dwSize
= sizeof (PROPSHEETPAGEW
);
758 psp
[id
].hInstance
= hcpl
;
759 psp
[id
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_LIST
);
760 psp
[id
].pfnDlgProc
= list_dlgproc
;
761 psp
[id
].lParam
= (INT_PTR
) data
;
764 psp
[id
].dwSize
= sizeof (PROPSHEETPAGEW
);
765 psp
[id
].hInstance
= hcpl
;
766 psp
[id
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_TEST
);
767 psp
[id
].pfnDlgProc
= test_dlgproc
;
768 psp
[id
].lParam
= (INT_PTR
) data
;
771 psp
[id
].dwSize
= sizeof (PROPSHEETPAGEW
);
772 psp
[id
].hInstance
= hcpl
;
773 psp
[id
].u
.pszTemplate
= MAKEINTRESOURCEW(IDD_FORCEFEEDBACK
);
774 psp
[id
].pfnDlgProc
= ff_dlgproc
;
775 psp
[id
].lParam
= (INT_PTR
) data
;
778 /* Fill out the PROPSHEETHEADER */
779 psh
.dwSize
= sizeof (PROPSHEETHEADERW
);
780 psh
.dwFlags
= PSH_PROPSHEETPAGE
| PSH_USEICONID
| PSH_USECALLBACK
;
781 psh
.hwndParent
= parent
;
782 psh
.hInstance
= hcpl
;
783 psh
.pszCaption
= MAKEINTRESOURCEW(IDS_CPL_NAME
);
786 psh
.pfnCallback
= propsheet_callback
;
788 /* display the dialog */
789 PropertySheetW(&psh
);
794 /*********************************************************************
795 * CPlApplet (joy.cpl.@)
797 * Control Panel entry point
800 * hWnd [I] Handle for the Control Panel Window
801 * command [I] CPL_* Command
802 * lParam1 [I] first extra Parameter
803 * lParam2 [I] second extra Parameter
806 * Depends on the command
809 LONG CALLBACK
CPlApplet(HWND hwnd
, UINT command
, LPARAM lParam1
, LPARAM lParam2
)
811 static struct JoystickData data
;
812 TRACE("(%p, %u, 0x%lx, 0x%lx)\n", hwnd
, command
, lParam1
, lParam2
);
820 /* Initialize dinput */
821 hr
= DirectInput8Create(GetModuleHandleW(NULL
), DIRECTINPUT_VERSION
, &IID_IDirectInput8W
, (void**)&data
.di
, NULL
);
825 ERR("Failed to initialize DirectInput: 0x%08x\n", hr
);
829 /* Then get all the connected joysticks */
830 initialize_joysticks(&data
);
839 CPLINFO
*appletInfo
= (CPLINFO
*) lParam2
;
841 appletInfo
->idName
= IDS_CPL_NAME
;
842 appletInfo
->idInfo
= IDS_CPL_INFO
;
843 appletInfo
->lData
= 0;
848 display_cpl_sheets(hwnd
, &data
);
852 destroy_joysticks(&data
);
854 /* And destroy dinput too */
855 IDirectInput8_Release(data
.di
);