1 /** \file joy-win32.c
2 * \brief Joystick support for Windows
3 *
4 * \author Tibor Biczo <crown@mail.matav.hu>
5 * \author Ettore Perazzoli <ettore@comm2000.it>
6 */
7
8 /*
9 * This file is part of VICE, the Versatile Commodore Emulator.
10 * See README for copyright notice.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 * 02111-1307 USA.
26 *
27 */
28
29 #include "vice.h"
30
31 #include "debug_gtk3.h"
32
33 #ifdef WIN32_COMPILE
34
35 #include "cmdline.h"
36 #include "resources.h"
37
38 #ifdef HAVE_DINPUT
39 #include "joy-win32-dinput-handle.h"
40 #endif
41
42 #include <windows.h>
43
44 #include "lib.h"
45 #include "joy.h"
46 #include "joyport.h"
47 #include "joystick.h"
48 #include "keyboard.h"
49 #include "maincpu.h"
50 #include "types.h"
51 #include "ui.h"
52 #include "winjoy.h"
53
54
55 static enum {
56 WIN_JOY_UNINIT,
57 #ifdef HAVE_DINPUT
58 WIN_JOY_DINPUT,
59 #endif
60 WIN_JOY_WINMM
61 } joystick_inited = WIN_JOY_UNINIT;
62
63 /* Notice that this has to be `int' to make resources work. */
64 static int joystick_fire_speed[JOYPORT_MAX_PORTS];
65 static int joystick_fire_axis[JOYPORT_MAX_PORTS];
66 static int joystick_autofire_button[JOYPORT_MAX_PORTS];
67
68 static int joystick_fire_button[JOYPORT_MAX_PORTS];
69
70 /* ------------------------------------------------------------------------ */
71
72 #ifdef HAVE_DINPUT
73 /* Joystick devices. */
74 static LPDIRECTINPUTDEVICE joystick_di_devices[JOYPORT_MAX_PORTS] = {
75 NULL, NULL, NULL, NULL, NULL };
76 static LPDIRECTINPUTDEVICE2 joystick_di_devices2[JOYPORT_MAX_PORTS] = {
77 NULL, NULL, NULL, NULL, NULL };
78
79 typedef struct _JoyAxis {
80 struct _JoyAxis *next;
81 DWORD id;
82 char *name;
83 DWORD dwOffs;
84 } JoyAxis;
85
86 typedef struct _JoyButton {
87 struct _JoyButton *next;
88 DWORD id;
89 char *name;
90 DWORD dwOffs;
91 } JoyButton;
92
93 typedef struct _JoyInfo {
94 struct _JoyInfo *next;
95 GUID guid;
96 char *name;
97 JoyAxis *axes;
98 JoyButton *buttons;
99 int numPOVs;
100 } JoyInfo;
101
102 static JoyInfo *joystick_list = NULL;
103
EnumJoyAxes(LPCDIDEVICEOBJECTINSTANCE lpddoi,LPVOID pvRef)104 static BOOL CALLBACK EnumJoyAxes(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
105 {
106 JoyAxis *axis;
107 JoyInfo *joy;
108
109 joy = (JoyInfo*)pvRef;
110
111 // Save info about axis
112 axis = lib_malloc(sizeof(JoyAxis));
113 axis->next = NULL;
114 axis->id = DIDFT_GETINSTANCE(lpddoi->dwType);
115 axis->name = lib_stralloc(lpddoi->tszName);
116 axis->dwOffs = lpddoi->dwOfs;
117
118 // Link axis into list for this joystick
119 if (joy->axes == NULL) {
120 joy->axes = axis;
121 } else {
122 JoyAxis *s;
123 s = joy->axes;
124 while (s->next != NULL) {
125 s = s->next;
126 }
127 s->next = axis;
128 }
129 return DIENUM_CONTINUE;
130 }
131
EnumJoyButtons(LPCDIDEVICEOBJECTINSTANCE lpddoi,LPVOID pvRef)132 static BOOL CALLBACK EnumJoyButtons(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
133 {
134 JoyButton *button;
135 JoyInfo *joy;
136
137 joy = (JoyInfo*)pvRef;
138
139 // Save info about button
140 button = lib_malloc(sizeof(JoyButton));
141 button->next = NULL;
142 button->id = DIDFT_GETINSTANCE(lpddoi->dwType);
143 button->name = lib_stralloc(lpddoi->tszName);
144 button->dwOffs = lpddoi->dwOfs;
145
146 // Link button into list for this joystick
147 if (joy->buttons == NULL) {
148 joy->buttons = button;
149 } else {
150 JoyButton *s;
151 s = joy->buttons;
152 while (s->next != NULL) {
153 s = s->next;
154 }
155 s->next = button;
156 }
157 return DIENUM_CONTINUE;
158 }
159
EnumJoyPOVs(LPCDIDEVICEOBJECTINSTANCE lpddoi,LPVOID pvRef)160 static BOOL CALLBACK EnumJoyPOVs(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
161 {
162 JoyInfo *joy;
163
164 joy = (JoyInfo*)pvRef;
165
166 // Save info about POV
167 joy->numPOVs += 1;
168
169 return DIENUM_CONTINUE;
170 }
171
joystick_release_axes(JoyAxis * axis)172 static void joystick_release_axes(JoyAxis *axis)
173 {
174 while (axis != NULL) {
175 JoyAxis *next;
176
177 next = axis->next;
178 lib_free(axis->name);
179 lib_free(axis);
180 axis = next;
181 }
182 }
183
joystick_release_buttons(JoyButton * button)184 static void joystick_release_buttons(JoyButton *button)
185 {
186 while (button != NULL) {
187 JoyButton *next;
188
189 next = button->next;
190 lib_free(button->name);
191 lib_free(button);
192 button = next;
193 }
194 }
195
joystick_release_joysticks(void)196 static void joystick_release_joysticks(void)
197 {
198 JoyInfo *joystick;
199
200 joystick = joystick_list;
201
202 while (joystick != NULL) {
203 JoyInfo *next;
204
205 next = joystick->next;
206 lib_free(joystick->name);
207 joystick_release_axes(joystick->axes);
208 joystick_release_buttons(joystick->buttons);
209 lib_free(joystick);
210 joystick = next;
211 }
212 }
213
joystick_di_open(int port_idx,int dev)214 static int joystick_di_open(int port_idx, int dev)
215 {
216 #if 0 /* FIXME */
217 NOT_IMPLEMENTED();
218 #else
219 JoyInfo *joy = joystick_list;
220 int i = 0;
221 LPDIRECTINPUT di = get_directinput_handle();
222 #ifndef HAVE_DINPUT_LIB
223
224 DIOBJECTDATAFORMAT joystick_objects[] = {
225 { &GUID_XAxis, 0, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, DIDOI_ASPECTPOSITION },
226 { &GUID_YAxis, 4, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, DIDOI_ASPECTPOSITION },
227 { &GUID_ZAxis, 8, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, DIDOI_ASPECTPOSITION },
228 { &GUID_RxAxis, 0x0c, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, DIDOI_ASPECTPOSITION },
229 { &GUID_RyAxis, 0x10, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, DIDOI_ASPECTPOSITION },
230 { &GUID_RzAxis, 0x14, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, DIDOI_ASPECTPOSITION },
231 { &GUID_Slider, 0x18, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, DIDOI_ASPECTPOSITION },
232 { &GUID_Slider, 0x1c, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, DIDOI_ASPECTPOSITION },
233 { &GUID_POV, 0x20, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_POV, 0 },
234 { &GUID_POV, 0x24, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_POV, 0 },
235 { &GUID_POV, 0x28, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_POV, 0 },
236 { &GUID_POV, 0x2c, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_POV, 0 },
237 { NULL, 0x30, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
238 { NULL, 0x31, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
239 { NULL, 0x32, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
240 { NULL, 0x33, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
241 { NULL, 0x34, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
242 { NULL, 0x35, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
243 { NULL, 0x36, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
244 { NULL, 0x37, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
245 { NULL, 0x38, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
246 { NULL, 0x39, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
247 { NULL, 0x3a, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
248 { NULL, 0x3b, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
249 { NULL, 0x3c, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
250 { NULL, 0x3d, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
251 { NULL, 0x3e, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
252 { NULL, 0x3f, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
253 { NULL, 0x40, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
254 { NULL, 0x41, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
255 { NULL, 0x42, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
256 { NULL, 0x43, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
257 { NULL, 0x44, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
258 { NULL, 0x45, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
259 { NULL, 0x46, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
260 { NULL, 0x47, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
261 { NULL, 0x48, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
262 { NULL, 0x49, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
263 { NULL, 0x4a, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
264 { NULL, 0x4b, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
265 { NULL, 0x4c, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
266 { NULL, 0x4d, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
267 { NULL, 0x4e, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 },
268 { NULL, 0x4f, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }
269 };
270
271 DIDATAFORMAT data_format_struct = {
272 sizeof(DIDATAFORMAT),
273 sizeof(DIOBJECTDATAFORMAT),
274 DIDF_ABSAXIS,
275 sizeof(DIJOYSTATE),
276 sizeof(joystick_objects) / sizeof(*joystick_objects),
277 joystick_objects
278 };
279 LPCDIDATAFORMAT data_format = &data_format_struct;
280 #else
281 LPCDIDATAFORMAT data_format = &c_dfDIJoystick;
282 #endif
283
284 if (di == NULL) {
285 return 0;
286 }
287 while (joy && i < dev - JOYDEV_HW1) {
288 joy = joy->next;
289 i++;
290 }
291 if (joy) {
292 HINSTANCE ui_active_window = GetModuleHandle(NULL); /* FIXME */
293 IDirectInput_CreateDevice(di, &joy->guid, &joystick_di_devices[port_idx], NULL);
294 IDirectInputDevice_QueryInterface(joystick_di_devices[port_idx], &IID_IDirectInputDevice2, (LPVOID*)&joystick_di_devices2[port_idx]);
295 IDirectInputDevice_SetDataFormat(joystick_di_devices[port_idx], data_format);
296 IDirectInputDevice_SetCooperativeLevel(joystick_di_devices[port_idx],
297 (HWND)ui_active_window, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
298 IDirectInputDevice_Acquire(joystick_di_devices[port_idx]);
299 if (joy->axes) {
300 joystick_release_axes(joy->axes);
301 joy->axes = NULL;
302 }
303 IDirectInputDevice_EnumObjects(joystick_di_devices[port_idx], EnumJoyAxes, (LPVOID)joy, DIDFT_AXIS);
304 if (joy->buttons) {
305 joystick_release_buttons(joy->buttons);
306 joy->buttons = NULL;
307 }
308 IDirectInputDevice_EnumObjects(joystick_di_devices[port_idx], EnumJoyButtons, (LPVOID)joy, DIDFT_BUTTON);
309 joy->numPOVs = 0;
310 IDirectInputDevice_EnumObjects(joystick_di_devices[port_idx], EnumJoyPOVs, (LPVOID)joy, DIDFT_POV);
311 return 0;
312 } else {
313 return -1;
314 }
315 #endif
316 }
317
joystick_di_close(int port_idx)318 static void joystick_di_close(int port_idx)
319 {
320 if (joystick_di_devices[port_idx]) {
321 IDirectInputDevice_Unacquire(joystick_di_devices[port_idx]);
322 if (joystick_di_devices2[port_idx]) {
323 IDirectInputDevice2_Release(joystick_di_devices2[port_idx]);
324 }
325 IDirectInputDevice_Release(joystick_di_devices[port_idx]);
326 }
327 joystick_di_devices[port_idx] = NULL;
328 joystick_di_devices2[port_idx] = NULL;
329 }
330 #endif
331
332 typedef struct joy_winmm_priv_s {
333 UINT uJoyID;
334 JOYCAPS joy_caps;
335 struct joy_winmm_priv_s* next;
336 } joy_winmm_priv_t;
337
338 static joy_winmm_priv_t* joy_winmm_list = NULL;
339
joy_arch_set_device(int port_idx,int new_dev)340 int joy_arch_set_device(int port_idx, int new_dev)
341 {
342 int old_dev = joystick_port_map[port_idx];
343
344 #if 1
345 // FIXME: this assumes there are 2 hardware joysticks when
346 // the real number may be more or less.
347 switch (new_dev) {
348 case JOYDEV_NONE:
349 case JOYDEV_NUMPAD:
350 case JOYDEV_KEYSET1:
351 case JOYDEV_KEYSET2:
352 case JOYDEV_HW1:
353 case JOYDEV_HW2:
354 break;
355 default:
356 return -1;
357 }
358 #endif
359
360 if (joystick_inited == WIN_JOY_UNINIT) {
361 joy_arch_init();
362 }
363
364 #ifdef HAVE_DINPUT
365 if ((joystick_inited == WIN_JOY_DINPUT) && (old_dev >= JOYDEV_HW1)) {
366 joystick_di_close(port_idx);
367 }
368
369 if ((joystick_inited == WIN_JOY_DINPUT) && (new_dev >= JOYDEV_HW1)) {
370 if (joystick_di_open(port_idx, new_dev) < 0) {
371 return -1;
372 }
373 }
374 #endif
375
376 return 0;
377 }
378
set_joystick_fire_speed(int speed,void * param)379 static int set_joystick_fire_speed(int speed, void *param)
380 {
381 int port_idx = vice_ptr_to_int(param);
382
383 if (speed < 1) {
384 speed = 1;
385 }
386 if (speed > 32) {
387 speed = 32;
388 }
389
390 joystick_fire_speed[port_idx] = speed;
391
392 return 0;
393 }
394
set_joystick_fire_axis(int axis,void * param)395 static int set_joystick_fire_axis(int axis, void *param)
396 {
397 int port_idx = vice_ptr_to_int(param);
398
399 if (axis < 0) {
400 axis = 0;
401 }
402
403 joystick_fire_axis[port_idx] = axis;
404
405 return 0;
406 }
407
set_joystick_autofire_button(int button,void * param)408 static int set_joystick_autofire_button(int button, void *param)
409 {
410 int port_idx = vice_ptr_to_int(param);
411
412 if (button < 0) {
413 button = 0;
414 }
415
416 joystick_autofire_button[port_idx] = button;
417
418 return 0;
419 }
420
set_joystick_fire_button(int button,void * param)421 static int set_joystick_fire_button(int button, void *param)
422 {
423 int port_idx = vice_ptr_to_int(param);
424
425 if (button < 0) {
426 button = 0;
427 }
428
429 joystick_fire_button[port_idx] = button;
430
431 return 0;
432 }
433
434 static const resource_int_t joy1_resources_int[] = {
435 { "JoyAutofire1Speed", 16, RES_EVENT_NO, NULL,
436 &joystick_fire_speed[0], set_joystick_fire_speed, (void *)0 },
437 { "JoyAutofire1Axis", 0, RES_EVENT_NO, NULL,
438 &joystick_fire_axis[0], set_joystick_fire_axis, (void *)0 },
439 { "JoyAutofire1Button", 0, RES_EVENT_NO, NULL,
440 &joystick_autofire_button[0], set_joystick_autofire_button, (void *)0 },
441 { "JoyFire1Button", 0, RES_EVENT_NO, NULL,
442 &joystick_fire_button[0], set_joystick_fire_button, (void *)0 },
443 RESOURCE_INT_LIST_END
444 };
445
446 static const resource_int_t joy2_resources_int[] = {
447 { "JoyAutofire2Speed", 16, RES_EVENT_NO, NULL,
448 &joystick_fire_speed[1], set_joystick_fire_speed, (void *)1 },
449 { "JoyAutofire2Axis", 0, RES_EVENT_NO, NULL,
450 &joystick_fire_axis[1], set_joystick_fire_axis, (void *)1 },
451 { "JoyAutofire2Button", 0, RES_EVENT_NO, NULL,
452 &joystick_autofire_button[1], set_joystick_autofire_button, (void *)1 },
453 { "JoyFire2Button", 0, RES_EVENT_NO, NULL,
454 &joystick_fire_button[1], set_joystick_fire_button, (void *)1 },
455 RESOURCE_INT_LIST_END
456 };
457
458 static const resource_int_t joy3_resources_int[] = {
459 { "JoyAutofire3Speed", 16, RES_EVENT_NO, NULL,
460 &joystick_fire_speed[2], set_joystick_fire_speed, (void *)2 },
461 { "JoyAutofire3Axis", 0, RES_EVENT_NO, NULL,
462 &joystick_fire_axis[2], set_joystick_fire_axis, (void *)2 },
463 { "JoyAutofire3Button", 0, RES_EVENT_NO, NULL,
464 &joystick_autofire_button[2], set_joystick_autofire_button, (void *)2 },
465 { "JoyFire3Button", 0, RES_EVENT_NO, NULL,
466 &joystick_fire_button[2], set_joystick_fire_button, (void *)2 },
467 RESOURCE_INT_LIST_END
468 };
469
470 static const resource_int_t joy4_resources_int[] = {
471 { "JoyAutofire4Speed", 16, RES_EVENT_NO, NULL,
472 &joystick_fire_speed[3], set_joystick_fire_speed, (void *)3 },
473 { "JoyAutofire4Axis", 0, RES_EVENT_NO, NULL,
474 &joystick_fire_axis[3], set_joystick_fire_axis, (void *)3 },
475 { "JoyAutofire4Button", 0, RES_EVENT_NO, NULL,
476 &joystick_autofire_button[3], set_joystick_autofire_button, (void *)3 },
477 { "JoyFire4Button", 0, RES_EVENT_NO, NULL,
478 &joystick_fire_button[3], set_joystick_fire_button, (void *)3 },
479 RESOURCE_INT_LIST_END
480 };
481
482 static const resource_int_t joy5_resources_int[] = {
483 { "JoyAutofire5Speed", 16, RES_EVENT_NO, NULL,
484 &joystick_fire_speed[4], set_joystick_fire_speed, (void *)4 },
485 { "JoyAutofire5Axis", 0, RES_EVENT_NO, NULL,
486 &joystick_fire_axis[4], set_joystick_fire_axis, (void *)4 },
487 { "JoyAutofire5Button", 0, RES_EVENT_NO, NULL,
488 &joystick_autofire_button[4], set_joystick_autofire_button, (void *)4 },
489 { "JoyFire5Button", 0, RES_EVENT_NO, NULL,
490 &joystick_fire_button[4], set_joystick_fire_button, (void *)4 },
491 RESOURCE_INT_LIST_END
492 };
493
joy_arch_resources_init(void)494 int joy_arch_resources_init(void)
495 {
496 if (joyport_get_port_name(JOYPORT_1)) {
497 if (resources_register_int(joy1_resources_int) < 0) {
498 return -1;
499 }
500 }
501 if (joyport_get_port_name(JOYPORT_2)) {
502 if (resources_register_int(joy2_resources_int) < 0) {
503 return -1;
504 }
505 }
506 if (joyport_get_port_name(JOYPORT_3)) {
507 if (resources_register_int(joy3_resources_int) < 0) {
508 return -1;
509 }
510 }
511 if (joyport_get_port_name(JOYPORT_4)) {
512 if (resources_register_int(joy4_resources_int) < 0) {
513 return -1;
514 }
515 }
516 if (joyport_get_port_name(JOYPORT_5)) {
517 if (resources_register_int(joy5_resources_int) < 0) {
518 return -1;
519 }
520 }
521
522 return 0;
523 }
524
525 /* ------------------------------------------------------------------------- */
526
527 /* FIXME: fix the resource references */
528
529 /* These don't appear to used anywhere */
530 #if 0
531 static const cmdline_option_t joydev1cmdline_options[] = {
532 { "-joydev1", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
533 NULL, NULL, "JoyDevice1", NULL,
534 /* FIXME */
535 NULL, NULL },
536 CMDLINE_LIST_END
537 };
538
539 static const cmdline_option_t joydev2cmdline_options[] = {
540 { "-joydev2", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
541 NULL, NULL, "JoyDevice2", NULL,
542 /* FIXME */
543 NULL, NULL },
544 CMDLINE_LIST_END
545 };
546
547 static const cmdline_option_t joydev3cmdline_options[] = {
548 { "-extrajoydev1", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
549 NULL, NULL, "JoyDevice3", NULL,
550 /* FIXME */
551 NULL, NULL },
552 CMDLINE_LIST_END
553 };
554
555 static const cmdline_option_t joydev4cmdline_options[] = {
556 { "-extrajoydev2", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
557 NULL, NULL, "JoyDevice4", NULL,
558 /* FIXME */
559 NULL, NULL },
560 CMDLINE_LIST_END
561 };
562
563 static const cmdline_option_t joydev5cmdline_options[] = {
564 { "-extrajoydev3", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
565 NULL, NULL, "JoyDevice5", NULL,
566 /* FIXME */
567 NULL, NULL },
568 CMDLINE_LIST_END
569 };
570 #endif
571
joy_arch_cmdline_options_init(void)572 int joy_arch_cmdline_options_init(void)
573 {
574 #if 0 /* FIXME */
575 if (joyport_get_port_name(JOYPORT_1)) {
576 if (cmdline_register_options(joydev1cmdline_options) < 0) {
577 return -1;
578 }
579 }
580 if (joyport_get_port_name(JOYPORT_2)) {
581 if (cmdline_register_options(joydev2cmdline_options) < 0) {
582 return -1;
583 }
584 }
585 if (joyport_get_port_name(JOYPORT_3)) {
586 if (cmdline_register_options(joydev3cmdline_options) < 0) {
587 return -1;
588 }
589 }
590 if (joyport_get_port_name(JOYPORT_4)) {
591 if (cmdline_register_options(joydev4cmdline_options) < 0) {
592 return -1;
593 }
594 }
595 if (joyport_get_port_name(JOYPORT_5)) {
596 if (cmdline_register_options(joydev5cmdline_options) < 0) {
597 return -1;
598 }
599 }
600 #else
601 NOT_IMPLEMENTED_WARN_ONLY();
602 #endif /* FIXME */
603 return 0;
604 }
605
606 /* ------------------------------------------------------------------------- */
607
608 #ifdef HAVE_DINPUT
EnumCallBack(LPCDIDEVICEINSTANCE lpddi,LPVOID pvref)609 static BOOL CALLBACK EnumCallBack(LPCDIDEVICEINSTANCE lpddi, LPVOID pvref)
610 {
611 JoyInfo *new_joystick;
612
613 new_joystick = lib_malloc(sizeof(JoyInfo));
614 new_joystick->next = NULL;
615 memcpy(&new_joystick->guid, &lpddi->guidInstance, sizeof(GUID));
616 new_joystick->name = lib_stralloc(lpddi->tszInstanceName);
617 new_joystick->axes = NULL;
618 new_joystick->buttons = NULL;
619 new_joystick->numPOVs = 0;
620
621 if (joystick_list == NULL) {
622 joystick_list = new_joystick;
623 } else {
624 JoyInfo *s;
625 s = joystick_list;
626 while (s->next != NULL) {
627 s = s->next;
628 }
629 s->next = new_joystick;
630 }
631 return DIENUM_CONTINUE;
632 }
633 #endif
634
joy_arch_init(void)635 int joy_arch_init(void)
636 {
637 #ifdef HAVE_DINPUT
638 LPDIRECTINPUT di = get_directinput_handle();
639 #endif
640 if (joystick_inited == WIN_JOY_UNINIT) {
641 #ifdef HAVE_DINPUT
642 if (di) {
643 IDirectInput_EnumDevices(di, DIDEVTYPE_JOYSTICK, EnumCallBack, NULL, DIEDFL_ALLDEVICES);
644 joystick_inited = WIN_JOY_DINPUT;
645 }
646 else
647 #endif
648 {
649 joystick_inited = WIN_JOY_WINMM;
650 if (joy_winmm_list == NULL) {
651 joy_winmm_priv_t** joy_add = &joy_winmm_list;
652 UINT wNumDevs = joyGetNumDevs();
653 UINT i;
654 MMRESULT result;
655
656 for (i = JOYSTICKID1; i < wNumDevs; i++) {
657 joy_winmm_priv_t* priv = lib_malloc(sizeof(joy_winmm_priv_t));
658 result = joyGetDevCaps(i, &priv->joy_caps, sizeof(priv->joy_caps));
659 if (result != JOYERR_NOERROR) {
660 lib_free(priv);
661 } else {
662 priv->uJoyID = i;
663 priv->next = NULL;
664 *joy_add = priv;
665 joy_add = &priv->next;
666 }
667 }
668 }
669 }
670 }
671
672 return 0;
673 }
674
joystick_release_winmm_joysticks(void)675 static void joystick_release_winmm_joysticks(void)
676 {
677 joy_winmm_priv_t* joy_list = joy_winmm_list;
678
679 while (joy_list != NULL) {
680 joy_winmm_priv_t* joy_remove = joy_list;
681 joy_list = joy_list->next;
682 free(joy_remove);
683 }
684 }
685
joystick_close(void)686 int joystick_close(void)
687 {
688 #ifdef HAVE_DINPUT
689 if ((joystick_inited == WIN_JOY_DINPUT) && (joystick_port_map[0] >= JOYDEV_HW1)) {
690 joystick_di_close(0);
691 }
692 if ((joystick_inited == WIN_JOY_DINPUT) && (joystick_port_map[1] >= JOYDEV_HW1)) {
693 joystick_di_close(1);
694 }
695 if ((joystick_inited == WIN_JOY_DINPUT) && (joystick_port_map[2] >= JOYDEV_HW1)) {
696 joystick_di_close(2);
697 }
698 if ((joystick_inited == WIN_JOY_DINPUT) && (joystick_port_map[3] >= JOYDEV_HW1)) {
699 joystick_di_close(3);
700 }
701 if ((joystick_inited == WIN_JOY_DINPUT) && (joystick_port_map[4] >= JOYDEV_HW1)) {
702 joystick_di_close(4);
703 }
704 joystick_release_joysticks();
705 #endif
706
707 joystick_release_winmm_joysticks();
708 joystick_inited = WIN_JOY_UNINIT;
709 return 0;
710 }
711
712 static JOYINFOEX joy_info;
713
714 #ifdef HAVE_DINPUT
joystick_di5_update(int joy_no)715 static BYTE joystick_di5_update(int joy_no)
716 {
717 BYTE value;
718 int i;
719 DIPROPRANGE prop;
720 UINT amin;
721 UINT amax;
722 DWORD apos;
723 DIJOYSTATE js;
724 JoyInfo *joy;
725 JoyButton *button;
726 int afire_button;
727 int fire_button;
728
729 value = 0;
730
731 IDirectInputDevice2_Poll(joystick_di_devices2[joy_no]);
732 IDirectInputDevice_GetDeviceState(joystick_di_devices[joy_no], sizeof(DIJOYSTATE), &js);
733
734 // Get boundary values for X axis
735 prop.diph.dwSize = sizeof(DIPROPRANGE);
736 prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
737 prop.diph.dwObj = 0; // Offset of X axis
738 prop.diph.dwHow = DIPH_BYOFFSET;
739 IDirectInputDevice_GetProperty(joystick_di_devices[joy_no], DIPROP_RANGE, (DIPROPHEADER*)&prop);
740 if (js.lX <= prop.lMin + (prop.lMax - prop.lMin) / 4) {
741 value |= 4;
742 }
743 if (js.lX >= prop.lMin + (prop.lMax - prop.lMin) / 4 * 3) {
744 value |= 8;
745 }
746
747 // Get boundary values for Y axis
748 prop.diph.dwSize = sizeof(DIPROPRANGE);
749 prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
750 prop.diph.dwObj = 4; // Offset of Y axis
751 prop.diph.dwHow = DIPH_BYOFFSET;
752 IDirectInputDevice_GetProperty(joystick_di_devices[joy_no], DIPROP_RANGE, (DIPROPHEADER*)&prop);
753 if (js.lY <= prop.lMin + (prop.lMax - prop.lMin) / 4) {
754 value |= 1;
755 }
756 if (js.lY >= prop.lMin + (prop.lMax - prop.lMin) / 4 * 3) {
757 value |= 2;
758 }
759
760 // Find the joystick object
761
762 afire_button = -1;
763 fire_button = -1;
764 joy = joystick_list;
765 i = 0;
766 while (joy && i < joystick_port_map[joy_no] - JOYDEV_HW1) {
767 joy = joy->next;
768 i++;
769 }
770 if (joy && joy->numPOVs > 0) {
771 for (i = 0; i < joy->numPOVs; ++i) {
772 if (LOWORD(js.rgdwPOV[i]) != 0xffff) {
773 if (js.rgdwPOV[i] > 20250 && js.rgdwPOV[i] < 33750) {
774 value |= 4;
775 }
776 if (js.rgdwPOV[i] > 2250 && js.rgdwPOV[i] < 15750) {
777 value |= 8;
778 }
779 if (js.rgdwPOV[i] > 29250 || js.rgdwPOV[i] < 6750) {
780 value |= 1;
781 }
782 if (js.rgdwPOV[i] > 11250 && js.rgdwPOV[i] < 24750) {
783 value |= 2;
784 }
785 }
786 }
787 }
788 if (joy && (joystick_autofire_button[joy_no] > 0)) {
789 button = joy->buttons;
790 i = 0;
791 while (button && i < joystick_autofire_button[joy_no] - 1) {
792 button = button->next;
793 i++;
794 }
795 if (button) {
796 afire_button = button->dwOffs - 48;
797 }
798 }
799 if ((afire_button >= 32) || (afire_button < -1)) {
800 afire_button = -1;
801 }
802 if (joy && (joystick_fire_button[joy_no] > 0)) {
803 button = joy->buttons;
804 i = 0;
805 while (button && i < joystick_fire_button[joy_no] - 1) {
806 button = button->next;
807 i++;
808 }
809 if (button) {
810 fire_button = button->dwOffs - 48;
811 }
812 }
813 if ((fire_button >= 32) || (fire_button < -1)) {
814 fire_button = -1;
815 }
816
817 /* If fire button is not in valid range [0..31] then it means every button is
818 treated as fire button, otherwise the only one selected. */
819 if (fire_button != -1) {
820 if ((fire_button != afire_button) && (js.rgbButtons[fire_button] & 0x80)) {
821 value |= 16;
822 }
823 } else {
824 for (i = 0; i < 32; i++) {
825 if ((i != afire_button) && (js.rgbButtons[i] & 0x80)) {
826 value |= 16;
827 }
828 }
829 }
830 if ((afire_button != -1) && (js.rgbButtons[afire_button] & 0x80)) {
831 if (joystick_fire_axis[joy_no]) {
832 amin = 0;
833 amax = 32;
834 apos = 16;
835 if (joy) {
836 /* Find axis */
837 JoyAxis *axis;
838
839 axis = joy->axes;
840 i = 0;
841 while (axis && i < joystick_fire_axis[joy_no] - 1) {
842 axis = axis->next;
843 i++;
844 }
845 if (axis) {
846 /* Get boundary values for axis */
847 prop.diph.dwSize = sizeof(DIPROPRANGE);
848 prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
849 prop.diph.dwObj = axis->id;
850 prop.diph.dwHow = DIPH_BYID;
851 IDirectInputDevice_GetProperty(joystick_di_devices[joy_no], DIPROP_RANGE, (DIPROPHEADER*)&prop);
852 amin = prop.lMin;
853 amax = prop.lMax;
854 apos = *(DWORD*)(((BYTE*)&js) + axis->dwOffs);
855 }
856 }
857 value |= maincpu_clk / (((amin + apos) * 0x2000) / (amax - amin) + 1) & 16;
858 } else {
859 value |= (maincpu_clk / (joystick_fire_speed[joy_no] * 0x100)) & 16;
860 }
861 }
862 return value;
863 }
864 #endif
865
joystick_update(void)866 void joystick_update(void)
867 {
868 BYTE value;
869 MMRESULT result;
870 int idx;
871 DWORD addflag;
872 UINT amin;
873 UINT amax;
874 DWORD apos;
875 int afire_button;
876 int fire_button;
877 int j;
878
879 #ifdef HAVE_DINPUT
880 if (joystick_inited == WIN_JOY_DINPUT) {
881 int i;
882 for (i = 0; i < 5; i++) {
883 if (joystick_port_map[i] >= JOYDEV_HW1) {
884 joystick_set_value_absolute(i + 1, joystick_di5_update(i));
885 }
886 }
887 } else
888 #endif
889 {
890 joy_winmm_priv_t* current_joy = joy_winmm_list;
891 int index = JOYDEV_HW1;
892 int has_pov;
893
894 while (current_joy) {
895 has_pov = current_joy->joy_caps.wCaps & (JOYCAPS_HASPOV | JOYCAPS_POV4DIR | JOYCAPS_POVCTS);
896 idx = -1;
897 if (joystick_port_map[0] == index && idx == -1) {
898 idx = 0;
899 }
900 if (joystick_port_map[1] == index && idx == -1) {
901 idx = 1;
902 }
903 if (joystick_port_map[2] == index && idx == -1) {
904 idx = 2;
905 }
906 if (joystick_port_map[3] == index && idx == -1) {
907 idx = 3;
908 }
909 if (joystick_port_map[4] == index && idx == -1) {
910 idx = 4;
911 }
912 if (idx != -1) {
913 switch (joystick_fire_axis[idx]) {
914 case 1:
915 addflag = JOY_RETURNZ;
916 break;
917 case 2:
918 addflag = JOY_RETURNV;
919 break;
920 case 3:
921 addflag = JOY_RETURNU;
922 break;
923 case 4:
924 addflag = JOY_RETURNR;
925 break;
926 default:
927 addflag = 0;
928 }
929 joy_info.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNCENTERED | JOY_RETURNX | JOY_RETURNY | addflag;
930 if (has_pov) {
931 joy_info.dwFlags |= JOY_RETURNPOVCTS;
932 }
933 value = 0;
934 joy_info.dwSize = sizeof(JOYINFOEX);
935 result = joyGetPosEx(current_joy->uJoyID, &joy_info);
936 if (result == JOYERR_NOERROR) {
937 if (has_pov && joy_info.dwPOV != JOY_POVCENTERED) {
938 if (joy_info.dwPOV > 20250 && joy_info.dwPOV < 33750) {
939 value |= 4;
940 }
941 if (joy_info.dwPOV > 2250 && joy_info.dwPOV < 15750) {
942 value |= 8;
943 }
944 if (joy_info.dwPOV > 29250 || joy_info.dwPOV < 6750) {
945 value |= 1;
946 }
947 if (joy_info.dwPOV > 11250 && joy_info.dwPOV < 24750) {
948 value |= 2;
949 }
950 }
951 if (joy_info.dwXpos <= current_joy->joy_caps.wXmin + (current_joy->joy_caps.wXmax - current_joy->joy_caps.wXmin) / 4) {
952 value |= 4;
953 }
954 if (joy_info.dwXpos >= current_joy->joy_caps.wXmin + (current_joy->joy_caps.wXmax - current_joy->joy_caps.wXmin) / 4 * 3) {
955 value |= 8;
956 }
957 if (joy_info.dwYpos <= current_joy->joy_caps.wYmin + (current_joy->joy_caps.wYmax - current_joy->joy_caps.wYmin) / 4) {
958 value |= 1;
959 }
960 if (joy_info.dwYpos >= current_joy->joy_caps.wYmin + (current_joy->joy_caps.wYmax - current_joy->joy_caps.wYmin) / 4 * 3) {
961 value |= 2;
962 }
963 afire_button = joystick_autofire_button[idx] - 1;
964 fire_button = joystick_fire_button[idx] - 1;
965 if (fire_button != -1) {
966 if ((fire_button != afire_button) && (joy_info.dwButtons & (1 << fire_button))) {
967 value |= 16;
968 }
969 } else {
970 for (j = 0; j < 32; j++) {
971 if ((j != afire_button) && (joy_info.dwButtons & (1 << j))) {
972 value |= 16;
973 }
974 }
975 }
976 if ((afire_button != -1) && (joy_info.dwButtons & (1 << afire_button))) {
977 if ((joystick_fire_axis[idx]) && (joy_info.dwFlags & addflag)) {
978 switch(joystick_fire_axis[idx]) {
979 case 1:
980 amin = current_joy->joy_caps.wZmin;
981 amax = current_joy->joy_caps.wZmax;
982 apos = joy_info.dwZpos;
983 break;
984 case 2:
985 amin = current_joy->joy_caps.wVmin;
986 amax = current_joy->joy_caps.wVmax;
987 apos = joy_info.dwVpos;
988 break;
989 case 3:
990 amin = current_joy->joy_caps.wUmin;
991 amax = current_joy->joy_caps.wUmax;
992 apos = joy_info.dwUpos;
993 break;
994 case 4:
995 amin = current_joy->joy_caps.wRmin;
996 amax = current_joy->joy_caps.wRmax;
997 apos = joy_info.dwRpos;
998 break;
999 default:
1000 amin = 0;
1001 amax = 32;
1002 apos = 16;
1003 break;
1004 }
1005 value |= maincpu_clk / (((amin + apos) * 0x2000) / (amax - amin) + 1) & 16;
1006 } else {
1007 value |= (maincpu_clk / (joystick_fire_speed[idx] * 0x100)) & 16;
1008 }
1009 }
1010 joystick_set_value_absolute(idx + 1, value);
1011 }
1012 }
1013 current_joy = current_joy->next;
1014 index++;
1015 }
1016 }
1017 }
1018
1019 #ifdef HAVE_DINPUT
joystick_calibrate(HWND hwnd)1020 void joystick_calibrate(HWND hwnd)
1021 {
1022 LPDIRECTINPUT di = get_directinput_handle();
1023
1024 if (di != NULL) {
1025 IDirectInput_RunControlPanel(di,hwnd,0);
1026 }
1027 }
1028 #endif
1029
1030 static JoyInfo *joydx = NULL;
1031 static joy_winmm_priv_t* joywmm = NULL;
1032 static int joystickid = JOYDEV_HW1;
1033
1034 static char joyname[1024];
1035
1036
joystick_ui_reset_device_list(void)1037 void joystick_ui_reset_device_list(void)
1038 {
1039 #ifdef HAVE_DINPUT
1040 if (joystick_inited == WIN_JOY_DINPUT) {
1041 joydx = joystick_list;
1042 } else
1043 #endif
1044 if (joystick_inited == WIN_JOY_WINMM) {
1045 joywmm = joy_winmm_list;
1046 }
1047 joystickid = JOYDEV_HW1;
1048 }
1049
joystick_ui_get_next_device_name(int * id)1050 const char *joystick_ui_get_next_device_name(int *id)
1051 {
1052 char *name = NULL;
1053 #ifdef HAVE_DINPUT
1054 if (joystick_inited == WIN_JOY_DINPUT) {
1055 if (joydx == NULL) {
1056 return NULL;
1057 }
1058 name = joydx->name;
1059 *id = joystickid;
1060 joydx = joydx->next;
1061 joystickid++;
1062 } else
1063 #endif
1064 if (joystick_inited == WIN_JOY_WINMM) {
1065 if (joywmm == NULL) {
1066 return NULL;
1067 }
1068 snprintf(joyname, sizeof(joyname), "PC joystick #%u", joywmm->uJoyID);
1069 name = joyname;
1070 *id = joystickid;
1071 joywmm = joywmm->next;
1072 joystickid++;
1073 }
1074 return name;
1075 }
1076
1077 #if 0
1078 void joystick_ui_get_autofire_axes(HWND joy_hwnd, int device)
1079 {
1080 #ifdef HAVE_DINPUT
1081 int i;
1082 JoyInfo *joy;
1083 JoyAxis *axis;
1084
1085 if (joystick_inited == WIN_JOY_DINPUT) {
1086 device = device - JOYDEV_HW1;
1087 joy = joystick_list;
1088 i = 0;
1089 while (joy && i < device) {
1090 joy = joy->next;
1091 i++;
1092 }
1093 if (joy) {
1094 axis = joy->axes;
1095 while (axis) {
1096 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)axis->name);
1097 axis = axis->next;
1098 }
1099 }
1100 } else
1101 #endif
1102 {
1103 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"Z-axis");
1104 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"V-axis");
1105 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"U-axis");
1106 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"R-axis");
1107 }
1108 }
1109
1110 void joystick_ui_get_autofire_buttons(HWND joy_hwnd, int device)
1111 {
1112 #ifdef HAVE_DINPUT
1113 int i;
1114 JoyInfo *joy;
1115 JoyButton *button;
1116
1117 if (joystick_inited == WIN_JOY_DINPUT) {
1118 device = device - JOYDEV_HW1;
1119 joy = joystick_list;
1120 i = 0;
1121 while (joy && i < device) {
1122 joy = joy->next;
1123 i++;
1124 }
1125 if (joy) {
1126 button = joy->buttons;
1127 while (button) {
1128 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)button->name);
1129 button = button->next;
1130 }
1131 }
1132 } else
1133 #endif
1134 {
1135 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"Button 1");
1136 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"Button 2");
1137 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"Button 3");
1138 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"Button 4");
1139 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"Button 5");
1140 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"Button 6");
1141 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"Button 7");
1142 SendMessage(joy_hwnd, CB_ADDSTRING, 0, (LPARAM)"Button 8");
1143 }
1144 }
1145 #endif
1146
joystick_uses_direct_input(void)1147 int joystick_uses_direct_input(void)
1148 {
1149 #ifdef HAVE_DINPUT
1150 return (joystick_inited == WIN_JOY_DINPUT);
1151 #else
1152 return 0;
1153 #endif
1154 }
1155 #endif
1156
1157