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