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