1 /* joystick.c: Joystick emulation support
2 Copyright (c) 2001-2016 Russell Marks, Darren Salt, Philip Kendall
3 Copyright (c) 2015 Stuart Brady
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19 Author contact information:
20
21 E-mail: philip-fuse@shadowmagic.org.uk
22
23 */
24
25 #include <config.h>
26
27 #include <libspectrum.h>
28
29 #include "fuse.h"
30 #include "infrastructure/startup_manager.h"
31 #include "joystick.h"
32 #include "keyboard.h"
33 #include "module.h"
34 #include "periph.h"
35 #include "rzx.h"
36 #include "settings.h"
37 #include "spectrum.h"
38 #include "machine.h"
39 #include "ui/ui.h"
40 #include "ui/uijoystick.h"
41
42 /* Number of joysticks known about & initialised */
43 int joysticks_supported = 0;
44
45 /* The bit masks used by the various joysticks. The order is the same
46 as the ordering of buttons in joystick.h:joystick_button (left,
47 right, up, down, fire ) */
48 static const libspectrum_byte kempston_mask[5] =
49 { 0x02, 0x01, 0x08, 0x04, 0x10 };
50 static const libspectrum_byte timex_mask[5] =
51 { 0x04, 0x08, 0x01, 0x02, 0x80 };
52
53 /* The keys used by the Cursor joystick */
54 static const keyboard_key_name cursor_key[5] =
55 { KEYBOARD_5, KEYBOARD_8, KEYBOARD_7, KEYBOARD_6, KEYBOARD_0 };
56
57 /* The keys used by the two Sinclair joysticks */
58 static const keyboard_key_name sinclair1_key[5] =
59 { KEYBOARD_6, KEYBOARD_7, KEYBOARD_9, KEYBOARD_8, KEYBOARD_0 };
60 static const keyboard_key_name sinclair2_key[5] =
61 { KEYBOARD_1, KEYBOARD_2, KEYBOARD_4, KEYBOARD_3, KEYBOARD_5 };
62
63 /* The current values for the joysticks we can emulate */
64 static libspectrum_byte kempston_value;
65 static libspectrum_byte timex1_value;
66 static libspectrum_byte timex2_value;
67 static libspectrum_byte fuller_value;
68
69 /* The names of the joysticks we can emulate. Order must correspond to
70 that of joystick.h:joystick_type_t */
71 const char *joystick_name[ JOYSTICK_TYPE_COUNT ] = {
72 "None",
73 "Cursor",
74 "Kempston",
75 "Sinclair 1", "Sinclair 2",
76 "Timex 1", "Timex 2",
77 "Fuller"
78 };
79
80 const char *joystick_connection[ JOYSTICK_CONN_COUNT ] = {
81 "None",
82 "Keyboard",
83 "Joystick 1",
84 "Joystick 2",
85 };
86
87 static void joystick_enabled_snapshot( libspectrum_snap *snap );
88 static void joystick_to_snapshot( libspectrum_snap *snap );
89
90 static module_info_t joystick_module_info = {
91
92 /* .reset = */ NULL,
93 /* .romcs = */ NULL,
94 /* .snapshot_enabled = */ joystick_enabled_snapshot,
95 /* .snapshot_from = */ NULL,
96 /* .snapshot_to = */ joystick_to_snapshot,
97
98 };
99
100 static const periph_port_t kempston_strict_decoding[] = {
101 { 0x00e0, 0x0000, joystick_kempston_read, NULL },
102 { 0, 0, NULL, NULL }
103 };
104
105 static const periph_t kempston_strict_periph = {
106 /* .option = */ &settings_current.joy_kempston,
107 /* .ports = */ kempston_strict_decoding,
108 /* .hard_reset = */ 0,
109 /* .activate = */ NULL,
110 };
111
112 static const periph_port_t kempston_loose_decoding[] = {
113 { 0x0020, 0x0000, joystick_kempston_read, NULL },
114 { 0, 0, NULL, NULL }
115 };
116
117 static const periph_t kempston_loose_periph = {
118 /* .option = */ &settings_current.joy_kempston,
119 /* .ports = */ kempston_loose_decoding,
120 /* .hard_reset = */ 0,
121 /* .activate = */ NULL,
122 };
123
124 /* Init/shutdown functions. Errors aren't important here */
125
126 int
joystick_init(void * context)127 joystick_init( void *context )
128 {
129 joysticks_supported = ui_joystick_init();
130 kempston_value = timex1_value = timex2_value = 0x00;
131 fuller_value = 0xff;
132
133 module_register( &joystick_module_info );
134 periph_register( PERIPH_TYPE_KEMPSTON, &kempston_strict_periph );
135 periph_register( PERIPH_TYPE_KEMPSTON_LOOSE, &kempston_loose_periph );
136
137 return 0;
138 }
139
140 void
joystick_end(void)141 joystick_end( void )
142 {
143 ui_joystick_end();
144 }
145
146 void
joystick_register_startup(void)147 joystick_register_startup( void )
148 {
149 startup_manager_module dependencies[] = {
150 STARTUP_MANAGER_MODULE_LIBSPECTRUM,
151 STARTUP_MANAGER_MODULE_SETUID
152 };
153 startup_manager_register( STARTUP_MANAGER_MODULE_JOYSTICK, dependencies,
154 ARRAY_SIZE( dependencies ), joystick_init,
155 joystick_end, NULL );
156 }
157
158 int
joystick_press(int which,joystick_button button,int press)159 joystick_press( int which, joystick_button button, int press )
160 {
161 joystick_type_t type;
162
163 switch( which ) {
164 case 0: type = settings_current.joystick_1_output; break;
165 case 1: type = settings_current.joystick_2_output; break;
166
167 case JOYSTICK_KEYBOARD:
168 type = settings_current.joystick_keyboard_output; break;
169
170 default:
171 return 0;
172 }
173
174 switch( type ) {
175
176 case JOYSTICK_TYPE_CURSOR:
177 if( press ) {
178 keyboard_press( cursor_key[ button ] );
179 } else {
180 keyboard_release( cursor_key[ button ] );
181 }
182 return 1;
183
184 case JOYSTICK_TYPE_KEMPSTON:
185 if( press ) {
186 kempston_value |= kempston_mask[ button ];
187 } else {
188 kempston_value &= ~kempston_mask[ button ];
189 }
190 return 1;
191
192 case JOYSTICK_TYPE_SINCLAIR_1:
193 if( press ) {
194 keyboard_press( sinclair1_key[ button ] );
195 } else {
196 keyboard_release( sinclair1_key[ button ] );
197 }
198 return 1;
199
200 case JOYSTICK_TYPE_SINCLAIR_2:
201 if( press ) {
202 keyboard_press( sinclair2_key[ button ] );
203 } else {
204 keyboard_release( sinclair2_key[ button ] );
205 }
206 return 1;
207
208 case JOYSTICK_TYPE_TIMEX_1:
209 if( press ) {
210 timex1_value |= timex_mask[ button ];
211 } else {
212 timex1_value &= ~timex_mask[ button ];
213 }
214 return 1;
215
216 case JOYSTICK_TYPE_TIMEX_2:
217 if( press ) {
218 timex2_value |= timex_mask[ button ];
219 } else {
220 timex2_value &= ~timex_mask[ button ];
221 }
222 return 1;
223
224 case JOYSTICK_TYPE_FULLER:
225 if( press ) {
226 fuller_value &= ~timex_mask[ button ];
227 } else {
228 fuller_value |= timex_mask[ button ];
229 }
230 return 1;
231
232 case JOYSTICK_TYPE_NONE: return 0;
233 }
234
235 ui_error( UI_ERROR_ERROR, "%s:joystick_press:unknown joystick type %d",
236 __FILE__, type );
237 fuse_abort();
238 }
239
240 /* Read functions for specific interfaces */
241
242 libspectrum_byte
joystick_kempston_read(libspectrum_word port GCC_UNUSED,libspectrum_byte * attached)243 joystick_kempston_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached )
244 {
245 *attached = 0xff; /* TODO: check this */
246 return kempston_value;
247 }
248
249 libspectrum_byte
joystick_timex_read(libspectrum_word port GCC_UNUSED,libspectrum_byte which)250 joystick_timex_read( libspectrum_word port GCC_UNUSED, libspectrum_byte which )
251 {
252 return which ? timex2_value : timex1_value;
253 }
254
255 libspectrum_byte
joystick_fuller_read(libspectrum_word port GCC_UNUSED,libspectrum_byte * attached)256 joystick_fuller_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached )
257 {
258 *attached = 0xff; /* TODO: check this */
259 return fuller_value;
260 }
261
262 static void
joystick_enabled_snapshot(libspectrum_snap * snap)263 joystick_enabled_snapshot( libspectrum_snap *snap )
264 {
265 size_t i;
266 size_t num_joysticks = libspectrum_snap_joystick_active_count( snap );
267 joystick_type_t fuse_type;
268
269 for( i = 0; i < num_joysticks; i++ ) {
270 switch( libspectrum_snap_joystick_list( snap, i ) ) {
271 case LIBSPECTRUM_JOYSTICK_CURSOR:
272 fuse_type = JOYSTICK_TYPE_CURSOR;
273 break;
274 case LIBSPECTRUM_JOYSTICK_KEMPSTON:
275 fuse_type = JOYSTICK_TYPE_KEMPSTON;
276 break;
277 case LIBSPECTRUM_JOYSTICK_SINCLAIR_1:
278 fuse_type = JOYSTICK_TYPE_SINCLAIR_1;
279 break;
280 case LIBSPECTRUM_JOYSTICK_SINCLAIR_2:
281 fuse_type = JOYSTICK_TYPE_SINCLAIR_2;
282 break;
283 case LIBSPECTRUM_JOYSTICK_TIMEX_1:
284 fuse_type = JOYSTICK_TYPE_TIMEX_1;
285 break;
286 case LIBSPECTRUM_JOYSTICK_TIMEX_2:
287 fuse_type = JOYSTICK_TYPE_TIMEX_2;
288 break;
289 case LIBSPECTRUM_JOYSTICK_FULLER:
290 fuse_type = JOYSTICK_TYPE_FULLER;
291 break;
292 default:
293 ui_error( UI_ERROR_INFO, "Ignoring unsupported joystick in snapshot %s",
294 libspectrum_joystick_name( libspectrum_snap_joystick_list( snap, i ) ));
295 continue;
296 }
297
298 if( settings_current.joystick_keyboard_output != fuse_type &&
299 settings_current.joystick_1_output != fuse_type &&
300 settings_current.joystick_2_output != fuse_type &&
301 !rzx_playback ) {
302 switch( ui_confirm_joystick( libspectrum_snap_joystick_list(snap,i),
303 libspectrum_snap_joystick_inputs(snap,i)) ) {
304 case UI_CONFIRM_JOYSTICK_KEYBOARD:
305 settings_current.joystick_keyboard_output = fuse_type;
306 break;
307 case UI_CONFIRM_JOYSTICK_JOYSTICK_1:
308 settings_current.joystick_1_output = fuse_type;
309 break;
310 case UI_CONFIRM_JOYSTICK_JOYSTICK_2:
311 settings_current.joystick_2_output = fuse_type;
312 break;
313 case UI_CONFIRM_JOYSTICK_NONE:
314 break;
315 }
316 }
317
318 /* If the snap was configured for a Kempston joystick, enable
319 our Kempston emulation in case the snap was reading from
320 the joystick to prevent things going haywire */
321 if( fuse_type == JOYSTICK_TYPE_KEMPSTON )
322 settings_current.joy_kempston = 1;
323 }
324 }
325
326 static void
add_joystick(libspectrum_snap * snap,joystick_type_t fuse_type,int inputs)327 add_joystick( libspectrum_snap *snap, joystick_type_t fuse_type, int inputs )
328 {
329 size_t i;
330 size_t num_joysticks = libspectrum_snap_joystick_active_count( snap );
331 libspectrum_joystick libspectrum_type;
332
333 switch( fuse_type ) {
334 case JOYSTICK_TYPE_CURSOR:
335 libspectrum_type = LIBSPECTRUM_JOYSTICK_CURSOR;
336 break;
337 case JOYSTICK_TYPE_KEMPSTON:
338 libspectrum_type = LIBSPECTRUM_JOYSTICK_KEMPSTON;
339 break;
340 case JOYSTICK_TYPE_SINCLAIR_1:
341 libspectrum_type = LIBSPECTRUM_JOYSTICK_SINCLAIR_1;
342 break;
343 case JOYSTICK_TYPE_SINCLAIR_2:
344 libspectrum_type = LIBSPECTRUM_JOYSTICK_SINCLAIR_2;
345 break;
346 case JOYSTICK_TYPE_TIMEX_1:
347 libspectrum_type = LIBSPECTRUM_JOYSTICK_TIMEX_1;
348 break;
349 case JOYSTICK_TYPE_TIMEX_2:
350 libspectrum_type = LIBSPECTRUM_JOYSTICK_TIMEX_2;
351 break;
352 case JOYSTICK_TYPE_FULLER:
353 libspectrum_type = LIBSPECTRUM_JOYSTICK_FULLER;
354 break;
355
356 case JOYSTICK_TYPE_NONE:
357 default:
358 return;
359 }
360
361 for( i = 0; i < num_joysticks; i++ ) {
362 if( libspectrum_snap_joystick_list( snap, i ) == libspectrum_type ) {
363 libspectrum_snap_set_joystick_inputs( snap, i, inputs |
364 libspectrum_snap_joystick_inputs( snap, i ) );
365 return;
366 }
367 }
368
369 libspectrum_snap_set_joystick_list( snap, num_joysticks, libspectrum_type );
370 libspectrum_snap_set_joystick_inputs( snap, num_joysticks, inputs );
371 libspectrum_snap_set_joystick_active_count( snap, num_joysticks + 1 );
372 }
373
374 static void
joystick_to_snapshot(libspectrum_snap * snap)375 joystick_to_snapshot( libspectrum_snap *snap )
376 {
377 if( settings_current.joy_kempston ) {
378 add_joystick( snap, JOYSTICK_TYPE_KEMPSTON,
379 LIBSPECTRUM_JOYSTICK_INPUT_NONE );
380 }
381 add_joystick( snap, settings_current.joystick_keyboard_output,
382 LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
383 add_joystick( snap, settings_current.joystick_1_output,
384 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
385 add_joystick( snap, settings_current.joystick_2_output,
386 LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
387 }
388