|
|
1.1 root 1: /*
1.1.1.4 root 2: Hatari - joy.c
1.1 root 3:
1.1.1.4 root 4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: Joystick routines.
1.1 root 8:
1.1.1.6 root 9: NOTE: The ST uses the joystick port 1 as the default controller.
1.1 root 10: */
1.1.1.8 ! root 11: const char Joy_rcsid[] = "Hatari $Id: joy.c,v 1.15 2007/12/31 14:54:21 thothy Exp $";
1.1 root 12:
13: #include <SDL.h>
14:
15: #include "main.h"
16: #include "configuration.h"
1.1.1.6 root 17: #include "ioMem.h"
1.1 root 18: #include "joy.h"
1.1.1.5 root 19: #include "log.h"
1.1.1.2 root 20: #include "video.h"
1.1 root 21:
1.1.1.2 root 22: #define JOY_BUTTON1 1
23: #define JOY_BUTTON2 2
1.1 root 24:
1.1.1.2 root 25:
1.1.1.7 root 26: static SDL_Joystick *sdlJoystick[6] = /* SDL's joystick structures */
1.1.1.6 root 27: {
28: NULL, NULL, NULL, NULL, NULL, NULL
29: };
1.1.1.7 root 30:
31: static BOOL bJoystickWorking[6] = /* Is joystick plugged in and working? */
1.1.1.6 root 32: {
33: FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
34: };
35:
36: int JoystickSpaceBar = FALSE; /* State of space-bar on joystick button 2 */
37: static Uint8 nJoyKeyEmu[6];
1.1.1.7 root 38: static Uint16 nSteJoySelect;
1.1 root 39:
40:
41: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 42: /**
! 43: * This function initialises the (real) joysticks.
! 44: */
1.1 root 45: void Joy_Init(void)
46: {
1.1.1.6 root 47: int i, nPadsConnected;
48:
49: /* Initialise SDL's joystick subsystem: */
50: if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
51: {
52: Log_Printf(LOG_ERROR, "Could not init joysticks: %s\n", SDL_GetError());
53: return;
54: }
55:
56: /* Scan joystick connection array for working joysticks */
57: nPadsConnected = SDL_NumJoysticks();
58: for (i = 0; i < nPadsConnected && i < 6; i++)
59: {
60: /* Open the joystick for use */
61: sdlJoystick[i] = SDL_JoystickOpen(i);
62: /* Is joystick ok? */
63: if (sdlJoystick[i] != NULL)
64: {
65: /* Set as working */
66: bJoystickWorking[i] = TRUE;
67: Log_Printf(LOG_DEBUG, "Joystick %i: %s\n", i, SDL_JoystickName(i));
68: }
69: }
70:
71: /* OK, do we have any working joysticks? */
72: if (!bJoystickWorking[0])
73: {
74: /* No, so if first time install need to set cursor emulation */
75: if (bFirstTimeInstall)
76: ConfigureParams.Joysticks.Joy[1].nJoystickMode = JOYSTICK_KEYBOARD;
77: }
1.1.1.2 root 78:
1.1.1.6 root 79: JoystickSpaceBar = FALSE;
1.1 root 80: }
81:
82:
1.1.1.2 root 83: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 84: /**
! 85: * Close the (real) joysticks.
! 86: */
1.1.1.7 root 87: void Joy_UnInit(void)
88: {
89: int i, nPadsConnected;
90:
91: nPadsConnected = SDL_NumJoysticks();
92:
93: for (i = 0; i < nPadsConnected && i < 6; i++)
94: {
95: if (bJoystickWorking[i] == TRUE)
96: {
97: SDL_JoystickClose(sdlJoystick[i]);
98: }
99: }
100: }
101:
102:
103: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 104: /**
! 105: * Read details from joystick using SDL calls
! 106: * NOTE ID is that of SDL
! 107: */
1.1.1.6 root 108: static BOOL Joy_ReadJoystick(int nSdlJoyID, JOYREADING *pJoyReading)
109: {
110: /* Joystick is OK, read position */
111: pJoyReading->XPos = SDL_JoystickGetAxis(sdlJoystick[nSdlJoyID], 0);
112: pJoyReading->YPos = SDL_JoystickGetAxis(sdlJoystick[nSdlJoyID], 1);
113: /* Sets bit #0 if button #1 is pressed: */
114: pJoyReading->Buttons = SDL_JoystickGetButton(sdlJoystick[nSdlJoyID], 0);
115: /* Sets bit #1 if button #2 is pressed: */
116: if (SDL_JoystickGetButton(sdlJoystick[nSdlJoyID], 1))
117: pJoyReading->Buttons |= JOY_BUTTON2;
118:
119: return TRUE;
1.1 root 120: }
121:
1.1.1.2 root 122:
123: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 124: /**
! 125: * Read PC joystick and return ST format byte, i.e. lower 4 bits direction
! 126: * and top bit fire.
! 127: * NOTE : ID 0 is Joystick 0/Mouse and ID 1 is Joystick 1 (default),
! 128: * ID 2 and 3 are STE joypads and ID 4 and 5 are parport joysticks.
! 129: */
1.1.1.6 root 130: Uint8 Joy_GetStickData(int nStJoyId)
1.1 root 131: {
1.1.1.6 root 132: Uint8 nData = 0;
133: JOYREADING JoyReading;
134: int nSdlJoyId;
135:
136: nSdlJoyId = ConfigureParams.Joysticks.Joy[nStJoyId].nJoyId;
137:
138: /* Are we emulating the joystick via the keyboard? */
139: if (ConfigureParams.Joysticks.Joy[nStJoyId].nJoystickMode == JOYSTICK_KEYBOARD)
140: {
141: /* If holding 'SHIFT' we actually want cursor key movement, so ignore any of this */
142: if ( !(SDL_GetModState()&(KMOD_LSHIFT|KMOD_RSHIFT)) )
143: {
144: nData = nJoyKeyEmu[nStJoyId];
145: }
146: }
147: else if (ConfigureParams.Joysticks.Joy[nStJoyId].nJoystickMode == JOYSTICK_REALSTICK
148: && bJoystickWorking[nSdlJoyId])
149: {
150: /* Use real joystick for emulation */
151: if (!Joy_ReadJoystick(nSdlJoyId, &JoyReading))
152: {
153: /* Something is wrong, we cannot read the joystick */
154: bJoystickWorking[nSdlJoyId] = FALSE;
155: return 0;
156: }
157:
158: /* Directions */
159: if (JoyReading.YPos <= JOYRANGE_UP_VALUE)
160: nData |= 0x01;
161: else if (JoyReading.YPos >= JOYRANGE_DOWN_VALUE)
162: nData |= 0x02;
163: if (JoyReading.XPos <= JOYRANGE_LEFT_VALUE)
164: nData |= 0x04;
165: else if (JoyReading.XPos >= JOYRANGE_RIGHT_VALUE)
166: nData |= 0x08;
167:
168: /* PC Joystick button 1 is set as ST joystick button */
169: if (JoyReading.Buttons & JOY_BUTTON1)
170: nData |= 0x80;
171:
172: /* Enable PC Joystick button 2 to mimick space bar (For XenonII, Flying Shark etc...) */
173: if (nStJoyId == JOYID_JOYSTICK1 && (JoyReading.Buttons & JOY_BUTTON2))
174: {
175: /* Only press 'space bar' if not in NULL state */
176: if (!JoystickSpaceBar)
177: {
178: /* Press, ikbd will send packets and de-press */
179: JoystickSpaceBar = JOYSTICK_SPACE_DOWN;
180: }
181: }
182: }
183:
184: /* Ignore fire button every 8 frames if enabled autofire (for both cursor emulation and joystick) */
185: if (ConfigureParams.Joysticks.Joy[nStJoyId].bEnableAutoFire)
186: {
187: if ((nVBLs&0x7)<4)
188: nData &= ~0x80; /* Remove top bit! */
189: }
190:
191: return nData;
1.1 root 192: }
193:
1.1.1.2 root 194:
195: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 196: /**
! 197: * Get the fire button states.
! 198: * Note: More than one fire buttons are only supported for real joystick,
! 199: * not for keyboard emulation!
! 200: */
1.1.1.6 root 201: static int Joy_GetFireButtons(int nStJoyId)
202: {
203: int nButtons = 0;
204: int nSdlJoyId;
205: int i, nMaxButtons;
206:
207: nSdlJoyId = ConfigureParams.Joysticks.Joy[nStJoyId].nJoyId;
208:
209: /* Are we emulating the joystick via the keyboard? */
210: if (ConfigureParams.Joysticks.Joy[nStJoyId].nJoystickMode == JOYSTICK_KEYBOARD)
211: {
212: if (nJoyKeyEmu[nStJoyId] & 0x80)
213: {
214: nButtons |= 1;
215: }
216: }
217: else if (ConfigureParams.Joysticks.Joy[nStJoyId].nJoystickMode == JOYSTICK_REALSTICK
218: && bJoystickWorking[nSdlJoyId])
219: {
220: nMaxButtons = SDL_JoystickNumButtons(sdlJoystick[nSdlJoyId]);
221: if (nMaxButtons > 17)
222: nMaxButtons = 17;
223: /* Now read all fire buttons and set a bit for each pressed button: */
224: for (i = 0; i < nMaxButtons; i++)
225: {
226: if (SDL_JoystickGetButton(sdlJoystick[nSdlJoyId], i))
227: {
228: nButtons |= (1 << i);
229: }
230: }
231: }
1.1.1.2 root 232:
1.1.1.6 root 233: return nButtons;
1.1 root 234: }
235:
1.1.1.2 root 236:
237: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 238: /**
! 239: * Set joystick cursor emulation for given port. This assumes that
! 240: * if the same keys have been defined for "cursor key emulation" in
! 241: * other ports, the emulation for them has been switched off. Returns
! 242: * 1 if the port number was OK, zero for error.
! 243: */
1.1.1.7 root 244: BOOL Joy_SetCursorEmulation(int port)
245: {
246: if (port < 0 || port >= JOYSTICK_COUNT) {
247: return 0;
248: }
249: ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_KEYBOARD;
250: return 1;
251: }
252:
253:
254: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 255: /**
! 256: * Toggle joystick cursor emulation between port 0, port 1 and being off
! 257: * from them. When it's turned off from them, the port's previous state
! 258: * is restored
! 259: */
1.1 root 260: void Joy_ToggleCursorEmulation(void)
261: {
1.1.1.7 root 262: static int saved[2] = { JOYSTICK_DISABLED, JOYSTICK_DISABLED };
263: int i, state, port = 2;
264: for (i = 0; i < 2; i++) {
265: state = ConfigureParams.Joysticks.Joy[i].nJoystickMode;
266: if (state == JOYSTICK_KEYBOARD) {
267: port = i;
268: } else {
269: saved[i] = state;
270: }
271: }
272: switch (port) {
273: case 0: /* (only) in port 0, disable cursor emu */
274: ConfigureParams.Joysticks.Joy[0].nJoystickMode = saved[0];
275: break;
276: case 1: /* (at least) in port 1, switch cursor emu to port 0 */
277: ConfigureParams.Joysticks.Joy[1].nJoystickMode = saved[1];
278: ConfigureParams.Joysticks.Joy[0].nJoystickMode = JOYSTICK_KEYBOARD;
279: break;
280: default: /* neither in port 0 or 1, enable cursor emu to port 1 */
281: ConfigureParams.Joysticks.Joy[1].nJoystickMode = JOYSTICK_KEYBOARD;
1.1.1.6 root 282: }
283: }
284:
285:
286: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 287: /**
! 288: * A key has been pressed down, check if we use it for joystick emulation
! 289: * via keyboard.
! 290: */
1.1.1.6 root 291: BOOL Joy_KeyDown(int symkey, int modkey)
292: {
293: int i;
294:
1.1.1.7 root 295: for (i = 0; i < JOYSTICK_COUNT; i++)
1.1.1.6 root 296: {
297: if (ConfigureParams.Joysticks.Joy[i].nJoystickMode == JOYSTICK_KEYBOARD
298: && !(modkey & KMOD_SHIFT))
299: {
300: if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeUp)
301: {
302: nJoyKeyEmu[i] |= 1;
303: return TRUE;
304: }
305: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeDown)
306: {
307: nJoyKeyEmu[i] |= 2;
308: return TRUE;
309: }
310: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeLeft)
311: {
312: nJoyKeyEmu[i] |= 4;
313: return TRUE;
314: }
315: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeRight)
316: {
317: nJoyKeyEmu[i] |= 8;
318: return TRUE;
319: }
320: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeFire)
321: {
322: nJoyKeyEmu[i] |= 0x80;
323: return TRUE;
324: }
325: }
326: }
327:
328: return FALSE;
329: }
330:
331:
332: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 333: /**
! 334: * A key has been released, check if we use it for joystick emulation
! 335: * via keyboard.
! 336: */
1.1.1.6 root 337: BOOL Joy_KeyUp(int symkey, int modkey)
338: {
339: int i;
340:
1.1.1.7 root 341: for (i = 0; i < JOYSTICK_COUNT; i++)
1.1.1.6 root 342: {
343: if (ConfigureParams.Joysticks.Joy[i].nJoystickMode == JOYSTICK_KEYBOARD
344: && !(modkey & KMOD_SHIFT))
345: {
346: if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeUp)
347: {
348: nJoyKeyEmu[i] &= ~1;
349: return TRUE;
350: }
351: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeDown)
352: {
353: nJoyKeyEmu[i] &= ~2;
354: return TRUE;
355: }
356: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeLeft)
357: {
358: nJoyKeyEmu[i] &= ~4;
359: return TRUE;
360: }
361: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeRight)
362: {
363: nJoyKeyEmu[i] &= ~8;
364: return TRUE;
365: }
366: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeFire)
367: {
368: nJoyKeyEmu[i] &= ~0x80;
369: return TRUE;
370: }
371: }
372: }
373:
374: return FALSE;
375: }
376:
377:
378: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 379: /**
! 380: * Read from STE joypad buttons register (0xff9200)
! 381: */
1.1.1.6 root 382: void Joy_StePadButtons_ReadWord(void)
383: {
384: Uint16 nData = 0xffff;
385:
386: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADA].nJoystickMode != JOYSTICK_DISABLED
387: && (nSteJoySelect & 0x0f) != 0x0f)
388: {
389: int nButtons = Joy_GetFireButtons(JOYID_STEPADA);
390: if (!(nSteJoySelect & 0x1))
391: {
392: if (nButtons & 0x01) /* Fire button A pressed? */
393: nData &= ~2;
394: if (nButtons & 0x10) /* Fire button PAUSE pressed? */
395: nData &= ~1;
396: }
397: else if (!(nSteJoySelect & 0x2))
398: {
399: if (nButtons & 0x02) /* Fire button B pressed? */
400: nData &= ~2;
401: }
402: else if (!(nSteJoySelect & 0x4))
403: {
404: if (nButtons & 0x04) /* Fire button C pressed? */
405: nData &= ~2;
406: }
407: else if (!(nSteJoySelect & 0x8))
408: {
409: if (nButtons & 0x01) /* Fire button OPTION pressed? */
410: nData &= ~2;
411: }
412: }
413:
414: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADB].nJoystickMode != JOYSTICK_DISABLED
415: && (nSteJoySelect & 0xf0) != 0xf0)
416: {
417: int nButtons = Joy_GetFireButtons(JOYID_STEPADB);
418: if (!(nSteJoySelect & 0x10))
419: {
420: if (nButtons & 0x01) /* Fire button A pressed? */
421: nData &= ~8;
422: if (nButtons & 0x10) /* Fire button PAUSE pressed? */
423: nData &= ~4;
424: }
425: else if (!(nSteJoySelect & 0x20))
426: {
427: if (nButtons & 0x02) /* Fire button B pressed? */
428: nData &= ~8;
429: }
430: else if (!(nSteJoySelect & 0x40))
431: {
432: if (nButtons & 0x04) /* Fire button C pressed? */
433: nData &= ~8;
434: }
435: else if (!(nSteJoySelect & 0x80))
436: {
437: if (nButtons & 0x08) /* Fire button OPTION pressed? */
438: nData &= ~8;
439: }
440: }
441:
442: IoMem_WriteWord(0xff9200, nData);
1.1 root 443: }
1.1.1.2 root 444:
1.1.1.6 root 445:
446: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 447: /**
! 448: * Read from STE joypad direction/buttons register (0xff9202)
! 449: */
1.1.1.6 root 450: void Joy_StePadMulti_ReadWord(void)
451: {
452: Uint8 nData = 0xff;
453:
454: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADA].nJoystickMode != JOYSTICK_DISABLED
455: && (nSteJoySelect & 0x0f) != 0x0f)
456: {
457: nData &= 0xf0;
458: if (!(nSteJoySelect & 0x1))
459: {
460: nData |= ~Joy_GetStickData(JOYID_STEPADA) & 0x0f;
461: }
462: else if (!(nSteJoySelect & 0x2))
463: {
464: nData |= ~(Joy_GetFireButtons(JOYID_STEPADA) >> 13) & 0x0f;
465: }
466: else if (!(nSteJoySelect & 0x4))
467: {
468: nData |= ~(Joy_GetFireButtons(JOYID_STEPADA) >> 9) & 0x0f;
469: }
470: else if (!(nSteJoySelect & 0x8))
471: {
472: nData |= ~(Joy_GetFireButtons(JOYID_STEPADA) >> 5) & 0x0f;
473: }
474: }
475:
476: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADB].nJoystickMode != JOYSTICK_DISABLED
477: && (nSteJoySelect & 0xf0) != 0xf0)
478: {
479: nData &= 0x0f;
480: if (!(nSteJoySelect & 0x10))
481: {
482: nData |= ~Joy_GetStickData(JOYID_STEPADB) << 4;
483: }
484: else if (!(nSteJoySelect & 0x20))
485: {
486: nData |= ~(Joy_GetFireButtons(JOYID_STEPADB) >> 13) & 0x0f;
487: }
488: else if (!(nSteJoySelect & 0x40))
489: {
490: nData |= ~(Joy_GetFireButtons(JOYID_STEPADB) >> 9) & 0x0f;
491: }
492: else if (!(nSteJoySelect & 0x80))
493: {
494: nData |= ~(Joy_GetFireButtons(JOYID_STEPADB) >> 5) & 0x0f;
495: }
496: }
497:
498: IoMem_WriteWord(0xff9202, (nData << 8) | 0x0ff);
499: }
500:
501:
502: /*-----------------------------------------------------------------------*/
1.1.1.8 ! root 503: /**
! 504: * Write to STE joypad selection register (0xff9202)
! 505: */
1.1.1.6 root 506: void Joy_StePadMulti_WriteWord(void)
507: {
508: nSteJoySelect = IoMem_ReadWord(0xff9202);
509: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.