|
|
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.10 root 11: const char Joy_fileid[] = "Hatari joy.c : " __DATE__ " " __TIME__;
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:
1.1.1.9 root 31: static bool bJoystickWorking[6] = /* Is joystick plugged in and working? */
1.1.1.6 root 32: {
1.1.1.11! root 33: false, false, false, false, false, false
1.1.1.6 root 34: };
35:
1.1.1.11! root 36: int JoystickSpaceBar = false; /* State of space-bar on joystick button 2 */
1.1.1.6 root 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 */
1.1.1.11! root 66: bJoystickWorking[i] = true;
1.1.1.6 root 67: Log_Printf(LOG_DEBUG, "Joystick %i: %s\n", i, SDL_JoystickName(i));
68: }
69: }
70:
1.1.1.11! root 71: JoystickSpaceBar = false;
1.1 root 72: }
73:
74:
1.1.1.2 root 75: /*-----------------------------------------------------------------------*/
1.1.1.8 root 76: /**
77: * Close the (real) joysticks.
78: */
1.1.1.7 root 79: void Joy_UnInit(void)
80: {
81: int i, nPadsConnected;
82:
83: nPadsConnected = SDL_NumJoysticks();
84:
85: for (i = 0; i < nPadsConnected && i < 6; i++)
86: {
1.1.1.11! root 87: if (bJoystickWorking[i] == true)
1.1.1.7 root 88: {
89: SDL_JoystickClose(sdlJoystick[i]);
90: }
91: }
92: }
93:
94:
95: /*-----------------------------------------------------------------------*/
1.1.1.8 root 96: /**
97: * Read details from joystick using SDL calls
98: * NOTE ID is that of SDL
99: */
1.1.1.9 root 100: static bool Joy_ReadJoystick(int nSdlJoyID, JOYREADING *pJoyReading)
1.1.1.6 root 101: {
102: /* Joystick is OK, read position */
103: pJoyReading->XPos = SDL_JoystickGetAxis(sdlJoystick[nSdlJoyID], 0);
104: pJoyReading->YPos = SDL_JoystickGetAxis(sdlJoystick[nSdlJoyID], 1);
105: /* Sets bit #0 if button #1 is pressed: */
106: pJoyReading->Buttons = SDL_JoystickGetButton(sdlJoystick[nSdlJoyID], 0);
107: /* Sets bit #1 if button #2 is pressed: */
108: if (SDL_JoystickGetButton(sdlJoystick[nSdlJoyID], 1))
109: pJoyReading->Buttons |= JOY_BUTTON2;
110:
1.1.1.11! root 111: return true;
1.1 root 112: }
113:
1.1.1.2 root 114:
115: /*-----------------------------------------------------------------------*/
1.1.1.8 root 116: /**
117: * Read PC joystick and return ST format byte, i.e. lower 4 bits direction
118: * and top bit fire.
119: * NOTE : ID 0 is Joystick 0/Mouse and ID 1 is Joystick 1 (default),
120: * ID 2 and 3 are STE joypads and ID 4 and 5 are parport joysticks.
121: */
1.1.1.6 root 122: Uint8 Joy_GetStickData(int nStJoyId)
1.1 root 123: {
1.1.1.6 root 124: Uint8 nData = 0;
125: JOYREADING JoyReading;
126: int nSdlJoyId;
127:
128: nSdlJoyId = ConfigureParams.Joysticks.Joy[nStJoyId].nJoyId;
129:
130: /* Are we emulating the joystick via the keyboard? */
131: if (ConfigureParams.Joysticks.Joy[nStJoyId].nJoystickMode == JOYSTICK_KEYBOARD)
132: {
133: /* If holding 'SHIFT' we actually want cursor key movement, so ignore any of this */
134: if ( !(SDL_GetModState()&(KMOD_LSHIFT|KMOD_RSHIFT)) )
135: {
136: nData = nJoyKeyEmu[nStJoyId];
137: }
138: }
139: else if (ConfigureParams.Joysticks.Joy[nStJoyId].nJoystickMode == JOYSTICK_REALSTICK
140: && bJoystickWorking[nSdlJoyId])
141: {
142: /* Use real joystick for emulation */
143: if (!Joy_ReadJoystick(nSdlJoyId, &JoyReading))
144: {
145: /* Something is wrong, we cannot read the joystick */
1.1.1.11! root 146: bJoystickWorking[nSdlJoyId] = false;
1.1.1.6 root 147: return 0;
148: }
149:
150: /* Directions */
151: if (JoyReading.YPos <= JOYRANGE_UP_VALUE)
1.1.1.11! root 152: nData |= ATARIJOY_BITMASK_UP;
1.1.1.6 root 153: else if (JoyReading.YPos >= JOYRANGE_DOWN_VALUE)
1.1.1.11! root 154: nData |= ATARIJOY_BITMASK_DOWN;
1.1.1.6 root 155: if (JoyReading.XPos <= JOYRANGE_LEFT_VALUE)
1.1.1.11! root 156: nData |= ATARIJOY_BITMASK_LEFT;
1.1.1.6 root 157: else if (JoyReading.XPos >= JOYRANGE_RIGHT_VALUE)
1.1.1.11! root 158: nData |= ATARIJOY_BITMASK_RIGHT;
1.1.1.6 root 159:
160: /* PC Joystick button 1 is set as ST joystick button */
161: if (JoyReading.Buttons & JOY_BUTTON1)
1.1.1.11! root 162: nData |= ATARIJOY_BITMASK_FIRE;
1.1.1.6 root 163:
164: /* Enable PC Joystick button 2 to mimick space bar (For XenonII, Flying Shark etc...) */
165: if (nStJoyId == JOYID_JOYSTICK1 && (JoyReading.Buttons & JOY_BUTTON2))
166: {
1.1.1.11! root 167: if (ConfigureParams.Joysticks.Joy[nStJoyId].bEnableJumpOnFire2)
1.1.1.6 root 168: {
1.1.1.11! root 169: /* If "Jump on Button 2" is enabled, PC Joystick button 2 acts as "ST Joystick up" */
! 170: nData |= ATARIJOY_BITMASK_UP;
! 171: } else {
! 172: /* If "Jump on Button 2" is not enabled, PC Joystick button 2 acts as pressing SPACE on the ST keyboard */
! 173: /* Only press 'space bar' if not in NULL state */
! 174: if (!JoystickSpaceBar)
! 175: {
! 176: /* Press, ikbd will send packets and de-press */
! 177: JoystickSpaceBar = JOYSTICK_SPACE_DOWN;
! 178: }
1.1.1.6 root 179: }
180: }
181: }
182:
183: /* Ignore fire button every 8 frames if enabled autofire (for both cursor emulation and joystick) */
184: if (ConfigureParams.Joysticks.Joy[nStJoyId].bEnableAutoFire)
185: {
186: if ((nVBLs&0x7)<4)
1.1.1.11! root 187: nData &= ~ATARIJOY_BITMASK_FIRE; /* Remove top bit! */
1.1.1.6 root 188: }
189:
190: return nData;
1.1 root 191: }
192:
1.1.1.2 root 193:
194: /*-----------------------------------------------------------------------*/
1.1.1.8 root 195: /**
196: * Get the fire button states.
197: * Note: More than one fire buttons are only supported for real joystick,
198: * not for keyboard emulation!
199: */
1.1.1.6 root 200: static int Joy_GetFireButtons(int nStJoyId)
201: {
202: int nButtons = 0;
203: int nSdlJoyId;
204: int i, nMaxButtons;
205:
206: nSdlJoyId = ConfigureParams.Joysticks.Joy[nStJoyId].nJoyId;
207:
208: /* Are we emulating the joystick via the keyboard? */
209: if (ConfigureParams.Joysticks.Joy[nStJoyId].nJoystickMode == JOYSTICK_KEYBOARD)
210: {
211: if (nJoyKeyEmu[nStJoyId] & 0x80)
212: {
213: nButtons |= 1;
214: }
215: }
216: else if (ConfigureParams.Joysticks.Joy[nStJoyId].nJoystickMode == JOYSTICK_REALSTICK
217: && bJoystickWorking[nSdlJoyId])
218: {
219: nMaxButtons = SDL_JoystickNumButtons(sdlJoystick[nSdlJoyId]);
220: if (nMaxButtons > 17)
221: nMaxButtons = 17;
222: /* Now read all fire buttons and set a bit for each pressed button: */
223: for (i = 0; i < nMaxButtons; i++)
224: {
225: if (SDL_JoystickGetButton(sdlJoystick[nSdlJoyId], i))
226: {
227: nButtons |= (1 << i);
228: }
229: }
230: }
1.1.1.2 root 231:
1.1.1.6 root 232: return nButtons;
1.1 root 233: }
234:
1.1.1.2 root 235:
236: /*-----------------------------------------------------------------------*/
1.1.1.8 root 237: /**
238: * Set joystick cursor emulation for given port. This assumes that
239: * if the same keys have been defined for "cursor key emulation" in
240: * other ports, the emulation for them has been switched off. Returns
241: * 1 if the port number was OK, zero for error.
242: */
1.1.1.9 root 243: bool Joy_SetCursorEmulation(int port)
1.1.1.7 root 244: {
245: if (port < 0 || port >= JOYSTICK_COUNT) {
246: return 0;
247: }
248: ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_KEYBOARD;
249: return 1;
250: }
251:
252:
253: /*-----------------------------------------------------------------------*/
1.1.1.8 root 254: /**
255: * Toggle joystick cursor emulation between port 0, port 1 and being off
256: * from them. When it's turned off from them, the port's previous state
257: * is restored
258: */
1.1 root 259: void Joy_ToggleCursorEmulation(void)
260: {
1.1.1.11! root 261: static JOYSTICKMODE saved[2] = { JOYSTICK_DISABLED, JOYSTICK_DISABLED };
! 262: JOYSTICKMODE state;
! 263: int i, port = 2;
1.1.1.7 root 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.9 root 291: bool Joy_KeyDown(int symkey, int modkey)
1.1.1.6 root 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: {
1.1.1.11! root 302: nJoyKeyEmu[i] &= ~ATARIJOY_BITMASK_DOWN; /* Disable down */
! 303: nJoyKeyEmu[i] |= ATARIJOY_BITMASK_UP; /* Enable up */
! 304: return true;
1.1.1.6 root 305: }
306: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeDown)
307: {
1.1.1.11! root 308: nJoyKeyEmu[i] &= ~ATARIJOY_BITMASK_UP; /* Disable up */
! 309: nJoyKeyEmu[i] |= ATARIJOY_BITMASK_DOWN; /* Enable down */
! 310: return true;
1.1.1.6 root 311: }
312: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeLeft)
313: {
1.1.1.11! root 314: nJoyKeyEmu[i] &= ~ATARIJOY_BITMASK_RIGHT; /* Disable right */
! 315: nJoyKeyEmu[i] |= ATARIJOY_BITMASK_LEFT; /* Enable left */
! 316: return true;
1.1.1.6 root 317: }
318: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeRight)
319: {
1.1.1.11! root 320: nJoyKeyEmu[i] &= ~ATARIJOY_BITMASK_LEFT; /* Disable left */
! 321: nJoyKeyEmu[i] |= ATARIJOY_BITMASK_RIGHT; /* Enable right */
! 322: return true;
1.1.1.6 root 323: }
324: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeFire)
325: {
1.1.1.11! root 326: nJoyKeyEmu[i] |= ATARIJOY_BITMASK_FIRE;
! 327: return true;
1.1.1.6 root 328: }
329: }
330: }
331:
1.1.1.11! root 332: return false;
1.1.1.6 root 333: }
334:
335:
336: /*-----------------------------------------------------------------------*/
1.1.1.8 root 337: /**
338: * A key has been released, check if we use it for joystick emulation
339: * via keyboard.
340: */
1.1.1.9 root 341: bool Joy_KeyUp(int symkey, int modkey)
1.1.1.6 root 342: {
343: int i;
344:
1.1.1.7 root 345: for (i = 0; i < JOYSTICK_COUNT; i++)
1.1.1.6 root 346: {
347: if (ConfigureParams.Joysticks.Joy[i].nJoystickMode == JOYSTICK_KEYBOARD
348: && !(modkey & KMOD_SHIFT))
349: {
350: if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeUp)
351: {
1.1.1.11! root 352: nJoyKeyEmu[i] &= ~ATARIJOY_BITMASK_UP;
! 353: return true;
1.1.1.6 root 354: }
355: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeDown)
356: {
1.1.1.11! root 357: nJoyKeyEmu[i] &= ~ATARIJOY_BITMASK_DOWN;
! 358: return true;
1.1.1.6 root 359: }
360: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeLeft)
361: {
1.1.1.11! root 362: nJoyKeyEmu[i] &= ~ATARIJOY_BITMASK_LEFT;
! 363: return true;
1.1.1.6 root 364: }
365: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeRight)
366: {
1.1.1.11! root 367: nJoyKeyEmu[i] &= ~ATARIJOY_BITMASK_RIGHT;
! 368: return true;
1.1.1.6 root 369: }
370: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeFire)
371: {
1.1.1.11! root 372: nJoyKeyEmu[i] &= ~ATARIJOY_BITMASK_FIRE;
! 373: return true;
1.1.1.6 root 374: }
375: }
376: }
377:
1.1.1.11! root 378: return false;
1.1.1.6 root 379: }
380:
381:
382: /*-----------------------------------------------------------------------*/
1.1.1.8 root 383: /**
384: * Read from STE joypad buttons register (0xff9200)
385: */
1.1.1.6 root 386: void Joy_StePadButtons_ReadWord(void)
387: {
388: Uint16 nData = 0xffff;
389:
390: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADA].nJoystickMode != JOYSTICK_DISABLED
391: && (nSteJoySelect & 0x0f) != 0x0f)
392: {
393: int nButtons = Joy_GetFireButtons(JOYID_STEPADA);
394: if (!(nSteJoySelect & 0x1))
395: {
396: if (nButtons & 0x01) /* Fire button A pressed? */
397: nData &= ~2;
398: if (nButtons & 0x10) /* Fire button PAUSE pressed? */
399: nData &= ~1;
400: }
401: else if (!(nSteJoySelect & 0x2))
402: {
403: if (nButtons & 0x02) /* Fire button B pressed? */
404: nData &= ~2;
405: }
406: else if (!(nSteJoySelect & 0x4))
407: {
408: if (nButtons & 0x04) /* Fire button C pressed? */
409: nData &= ~2;
410: }
411: else if (!(nSteJoySelect & 0x8))
412: {
413: if (nButtons & 0x01) /* Fire button OPTION pressed? */
414: nData &= ~2;
415: }
416: }
417:
418: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADB].nJoystickMode != JOYSTICK_DISABLED
419: && (nSteJoySelect & 0xf0) != 0xf0)
420: {
421: int nButtons = Joy_GetFireButtons(JOYID_STEPADB);
422: if (!(nSteJoySelect & 0x10))
423: {
424: if (nButtons & 0x01) /* Fire button A pressed? */
425: nData &= ~8;
426: if (nButtons & 0x10) /* Fire button PAUSE pressed? */
427: nData &= ~4;
428: }
429: else if (!(nSteJoySelect & 0x20))
430: {
431: if (nButtons & 0x02) /* Fire button B pressed? */
432: nData &= ~8;
433: }
434: else if (!(nSteJoySelect & 0x40))
435: {
436: if (nButtons & 0x04) /* Fire button C pressed? */
437: nData &= ~8;
438: }
439: else if (!(nSteJoySelect & 0x80))
440: {
441: if (nButtons & 0x08) /* Fire button OPTION pressed? */
442: nData &= ~8;
443: }
444: }
445:
446: IoMem_WriteWord(0xff9200, nData);
1.1 root 447: }
1.1.1.2 root 448:
1.1.1.6 root 449:
450: /*-----------------------------------------------------------------------*/
1.1.1.8 root 451: /**
452: * Read from STE joypad direction/buttons register (0xff9202)
453: */
1.1.1.6 root 454: void Joy_StePadMulti_ReadWord(void)
455: {
456: Uint8 nData = 0xff;
457:
458: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADA].nJoystickMode != JOYSTICK_DISABLED
459: && (nSteJoySelect & 0x0f) != 0x0f)
460: {
461: nData &= 0xf0;
462: if (!(nSteJoySelect & 0x1))
463: {
464: nData |= ~Joy_GetStickData(JOYID_STEPADA) & 0x0f;
465: }
466: else if (!(nSteJoySelect & 0x2))
467: {
468: nData |= ~(Joy_GetFireButtons(JOYID_STEPADA) >> 13) & 0x0f;
469: }
470: else if (!(nSteJoySelect & 0x4))
471: {
472: nData |= ~(Joy_GetFireButtons(JOYID_STEPADA) >> 9) & 0x0f;
473: }
474: else if (!(nSteJoySelect & 0x8))
475: {
476: nData |= ~(Joy_GetFireButtons(JOYID_STEPADA) >> 5) & 0x0f;
477: }
478: }
479:
480: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADB].nJoystickMode != JOYSTICK_DISABLED
481: && (nSteJoySelect & 0xf0) != 0xf0)
482: {
483: nData &= 0x0f;
484: if (!(nSteJoySelect & 0x10))
485: {
486: nData |= ~Joy_GetStickData(JOYID_STEPADB) << 4;
487: }
488: else if (!(nSteJoySelect & 0x20))
489: {
490: nData |= ~(Joy_GetFireButtons(JOYID_STEPADB) >> 13) & 0x0f;
491: }
492: else if (!(nSteJoySelect & 0x40))
493: {
494: nData |= ~(Joy_GetFireButtons(JOYID_STEPADB) >> 9) & 0x0f;
495: }
496: else if (!(nSteJoySelect & 0x80))
497: {
498: nData |= ~(Joy_GetFireButtons(JOYID_STEPADB) >> 5) & 0x0f;
499: }
500: }
501:
502: IoMem_WriteWord(0xff9202, (nData << 8) | 0x0ff);
503: }
504:
505:
506: /*-----------------------------------------------------------------------*/
1.1.1.8 root 507: /**
508: * Write to STE joypad selection register (0xff9202)
509: */
1.1.1.6 root 510: void Joy_StePadMulti_WriteWord(void)
511: {
512: nSteJoySelect = IoMem_ReadWord(0xff9202);
513: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.