|
|
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: {
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: 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: {
87: if (bJoystickWorking[i] == TRUE)
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:
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 */
146: bJoystickWorking[nSdlJoyId] = FALSE;
147: return 0;
148: }
149:
150: /* Directions */
151: if (JoyReading.YPos <= JOYRANGE_UP_VALUE)
152: nData |= 0x01;
153: else if (JoyReading.YPos >= JOYRANGE_DOWN_VALUE)
154: nData |= 0x02;
155: if (JoyReading.XPos <= JOYRANGE_LEFT_VALUE)
156: nData |= 0x04;
157: else if (JoyReading.XPos >= JOYRANGE_RIGHT_VALUE)
158: nData |= 0x08;
159:
160: /* PC Joystick button 1 is set as ST joystick button */
161: if (JoyReading.Buttons & JOY_BUTTON1)
162: nData |= 0x80;
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: {
167: /* Only press 'space bar' if not in NULL state */
168: if (!JoystickSpaceBar)
169: {
170: /* Press, ikbd will send packets and de-press */
171: JoystickSpaceBar = JOYSTICK_SPACE_DOWN;
172: }
173: }
174: }
175:
176: /* Ignore fire button every 8 frames if enabled autofire (for both cursor emulation and joystick) */
177: if (ConfigureParams.Joysticks.Joy[nStJoyId].bEnableAutoFire)
178: {
179: if ((nVBLs&0x7)<4)
180: nData &= ~0x80; /* Remove top bit! */
181: }
182:
183: return nData;
1.1 root 184: }
185:
1.1.1.2 root 186:
187: /*-----------------------------------------------------------------------*/
1.1.1.8 root 188: /**
189: * Get the fire button states.
190: * Note: More than one fire buttons are only supported for real joystick,
191: * not for keyboard emulation!
192: */
1.1.1.6 root 193: static int Joy_GetFireButtons(int nStJoyId)
194: {
195: int nButtons = 0;
196: int nSdlJoyId;
197: int i, nMaxButtons;
198:
199: nSdlJoyId = ConfigureParams.Joysticks.Joy[nStJoyId].nJoyId;
200:
201: /* Are we emulating the joystick via the keyboard? */
202: if (ConfigureParams.Joysticks.Joy[nStJoyId].nJoystickMode == JOYSTICK_KEYBOARD)
203: {
204: if (nJoyKeyEmu[nStJoyId] & 0x80)
205: {
206: nButtons |= 1;
207: }
208: }
209: else if (ConfigureParams.Joysticks.Joy[nStJoyId].nJoystickMode == JOYSTICK_REALSTICK
210: && bJoystickWorking[nSdlJoyId])
211: {
212: nMaxButtons = SDL_JoystickNumButtons(sdlJoystick[nSdlJoyId]);
213: if (nMaxButtons > 17)
214: nMaxButtons = 17;
215: /* Now read all fire buttons and set a bit for each pressed button: */
216: for (i = 0; i < nMaxButtons; i++)
217: {
218: if (SDL_JoystickGetButton(sdlJoystick[nSdlJoyId], i))
219: {
220: nButtons |= (1 << i);
221: }
222: }
223: }
1.1.1.2 root 224:
1.1.1.6 root 225: return nButtons;
1.1 root 226: }
227:
1.1.1.2 root 228:
229: /*-----------------------------------------------------------------------*/
1.1.1.8 root 230: /**
231: * Set joystick cursor emulation for given port. This assumes that
232: * if the same keys have been defined for "cursor key emulation" in
233: * other ports, the emulation for them has been switched off. Returns
234: * 1 if the port number was OK, zero for error.
235: */
1.1.1.9 root 236: bool Joy_SetCursorEmulation(int port)
1.1.1.7 root 237: {
238: if (port < 0 || port >= JOYSTICK_COUNT) {
239: return 0;
240: }
241: ConfigureParams.Joysticks.Joy[port].nJoystickMode = JOYSTICK_KEYBOARD;
242: return 1;
243: }
244:
245:
246: /*-----------------------------------------------------------------------*/
1.1.1.8 root 247: /**
248: * Toggle joystick cursor emulation between port 0, port 1 and being off
249: * from them. When it's turned off from them, the port's previous state
250: * is restored
251: */
1.1 root 252: void Joy_ToggleCursorEmulation(void)
253: {
1.1.1.7 root 254: static int saved[2] = { JOYSTICK_DISABLED, JOYSTICK_DISABLED };
255: int i, state, port = 2;
256: for (i = 0; i < 2; i++) {
257: state = ConfigureParams.Joysticks.Joy[i].nJoystickMode;
258: if (state == JOYSTICK_KEYBOARD) {
259: port = i;
260: } else {
261: saved[i] = state;
262: }
263: }
264: switch (port) {
265: case 0: /* (only) in port 0, disable cursor emu */
266: ConfigureParams.Joysticks.Joy[0].nJoystickMode = saved[0];
267: break;
268: case 1: /* (at least) in port 1, switch cursor emu to port 0 */
269: ConfigureParams.Joysticks.Joy[1].nJoystickMode = saved[1];
270: ConfigureParams.Joysticks.Joy[0].nJoystickMode = JOYSTICK_KEYBOARD;
271: break;
272: default: /* neither in port 0 or 1, enable cursor emu to port 1 */
273: ConfigureParams.Joysticks.Joy[1].nJoystickMode = JOYSTICK_KEYBOARD;
1.1.1.6 root 274: }
275: }
276:
277:
278: /*-----------------------------------------------------------------------*/
1.1.1.8 root 279: /**
280: * A key has been pressed down, check if we use it for joystick emulation
281: * via keyboard.
282: */
1.1.1.9 root 283: bool Joy_KeyDown(int symkey, int modkey)
1.1.1.6 root 284: {
285: int i;
286:
1.1.1.7 root 287: for (i = 0; i < JOYSTICK_COUNT; i++)
1.1.1.6 root 288: {
289: if (ConfigureParams.Joysticks.Joy[i].nJoystickMode == JOYSTICK_KEYBOARD
290: && !(modkey & KMOD_SHIFT))
291: {
292: if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeUp)
293: {
1.1.1.9 root 294: nJoyKeyEmu[i] &= ~2; /* Disable down */
295: nJoyKeyEmu[i] |= 1; /* Enable up */
1.1.1.6 root 296: return TRUE;
297: }
298: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeDown)
299: {
1.1.1.9 root 300: nJoyKeyEmu[i] &= ~1; /* Disable up */
301: nJoyKeyEmu[i] |= 2; /* Enable down */
1.1.1.6 root 302: return TRUE;
303: }
304: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeLeft)
305: {
1.1.1.9 root 306: nJoyKeyEmu[i] &= ~8; /* Disable right */
307: nJoyKeyEmu[i] |= 4; /* Enable left */
1.1.1.6 root 308: return TRUE;
309: }
310: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeRight)
311: {
1.1.1.9 root 312: nJoyKeyEmu[i] &= ~4; /* Disable left */
313: nJoyKeyEmu[i] |= 8; /* Enable right */
1.1.1.6 root 314: return TRUE;
315: }
316: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeFire)
317: {
318: nJoyKeyEmu[i] |= 0x80;
319: return TRUE;
320: }
321: }
322: }
323:
324: return FALSE;
325: }
326:
327:
328: /*-----------------------------------------------------------------------*/
1.1.1.8 root 329: /**
330: * A key has been released, check if we use it for joystick emulation
331: * via keyboard.
332: */
1.1.1.9 root 333: bool Joy_KeyUp(int symkey, int modkey)
1.1.1.6 root 334: {
335: int i;
336:
1.1.1.7 root 337: for (i = 0; i < JOYSTICK_COUNT; i++)
1.1.1.6 root 338: {
339: if (ConfigureParams.Joysticks.Joy[i].nJoystickMode == JOYSTICK_KEYBOARD
340: && !(modkey & KMOD_SHIFT))
341: {
342: if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeUp)
343: {
344: nJoyKeyEmu[i] &= ~1;
345: return TRUE;
346: }
347: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeDown)
348: {
349: nJoyKeyEmu[i] &= ~2;
350: return TRUE;
351: }
352: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeLeft)
353: {
354: nJoyKeyEmu[i] &= ~4;
355: return TRUE;
356: }
357: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeRight)
358: {
359: nJoyKeyEmu[i] &= ~8;
360: return TRUE;
361: }
362: else if (symkey == ConfigureParams.Joysticks.Joy[i].nKeyCodeFire)
363: {
364: nJoyKeyEmu[i] &= ~0x80;
365: return TRUE;
366: }
367: }
368: }
369:
370: return FALSE;
371: }
372:
373:
374: /*-----------------------------------------------------------------------*/
1.1.1.8 root 375: /**
376: * Read from STE joypad buttons register (0xff9200)
377: */
1.1.1.6 root 378: void Joy_StePadButtons_ReadWord(void)
379: {
380: Uint16 nData = 0xffff;
381:
382: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADA].nJoystickMode != JOYSTICK_DISABLED
383: && (nSteJoySelect & 0x0f) != 0x0f)
384: {
385: int nButtons = Joy_GetFireButtons(JOYID_STEPADA);
386: if (!(nSteJoySelect & 0x1))
387: {
388: if (nButtons & 0x01) /* Fire button A pressed? */
389: nData &= ~2;
390: if (nButtons & 0x10) /* Fire button PAUSE pressed? */
391: nData &= ~1;
392: }
393: else if (!(nSteJoySelect & 0x2))
394: {
395: if (nButtons & 0x02) /* Fire button B pressed? */
396: nData &= ~2;
397: }
398: else if (!(nSteJoySelect & 0x4))
399: {
400: if (nButtons & 0x04) /* Fire button C pressed? */
401: nData &= ~2;
402: }
403: else if (!(nSteJoySelect & 0x8))
404: {
405: if (nButtons & 0x01) /* Fire button OPTION pressed? */
406: nData &= ~2;
407: }
408: }
409:
410: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADB].nJoystickMode != JOYSTICK_DISABLED
411: && (nSteJoySelect & 0xf0) != 0xf0)
412: {
413: int nButtons = Joy_GetFireButtons(JOYID_STEPADB);
414: if (!(nSteJoySelect & 0x10))
415: {
416: if (nButtons & 0x01) /* Fire button A pressed? */
417: nData &= ~8;
418: if (nButtons & 0x10) /* Fire button PAUSE pressed? */
419: nData &= ~4;
420: }
421: else if (!(nSteJoySelect & 0x20))
422: {
423: if (nButtons & 0x02) /* Fire button B pressed? */
424: nData &= ~8;
425: }
426: else if (!(nSteJoySelect & 0x40))
427: {
428: if (nButtons & 0x04) /* Fire button C pressed? */
429: nData &= ~8;
430: }
431: else if (!(nSteJoySelect & 0x80))
432: {
433: if (nButtons & 0x08) /* Fire button OPTION pressed? */
434: nData &= ~8;
435: }
436: }
437:
438: IoMem_WriteWord(0xff9200, nData);
1.1 root 439: }
1.1.1.2 root 440:
1.1.1.6 root 441:
442: /*-----------------------------------------------------------------------*/
1.1.1.8 root 443: /**
444: * Read from STE joypad direction/buttons register (0xff9202)
445: */
1.1.1.6 root 446: void Joy_StePadMulti_ReadWord(void)
447: {
448: Uint8 nData = 0xff;
449:
450: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADA].nJoystickMode != JOYSTICK_DISABLED
451: && (nSteJoySelect & 0x0f) != 0x0f)
452: {
453: nData &= 0xf0;
454: if (!(nSteJoySelect & 0x1))
455: {
456: nData |= ~Joy_GetStickData(JOYID_STEPADA) & 0x0f;
457: }
458: else if (!(nSteJoySelect & 0x2))
459: {
460: nData |= ~(Joy_GetFireButtons(JOYID_STEPADA) >> 13) & 0x0f;
461: }
462: else if (!(nSteJoySelect & 0x4))
463: {
464: nData |= ~(Joy_GetFireButtons(JOYID_STEPADA) >> 9) & 0x0f;
465: }
466: else if (!(nSteJoySelect & 0x8))
467: {
468: nData |= ~(Joy_GetFireButtons(JOYID_STEPADA) >> 5) & 0x0f;
469: }
470: }
471:
472: if (ConfigureParams.Joysticks.Joy[JOYID_STEPADB].nJoystickMode != JOYSTICK_DISABLED
473: && (nSteJoySelect & 0xf0) != 0xf0)
474: {
475: nData &= 0x0f;
476: if (!(nSteJoySelect & 0x10))
477: {
478: nData |= ~Joy_GetStickData(JOYID_STEPADB) << 4;
479: }
480: else if (!(nSteJoySelect & 0x20))
481: {
482: nData |= ~(Joy_GetFireButtons(JOYID_STEPADB) >> 13) & 0x0f;
483: }
484: else if (!(nSteJoySelect & 0x40))
485: {
486: nData |= ~(Joy_GetFireButtons(JOYID_STEPADB) >> 9) & 0x0f;
487: }
488: else if (!(nSteJoySelect & 0x80))
489: {
490: nData |= ~(Joy_GetFireButtons(JOYID_STEPADB) >> 5) & 0x0f;
491: }
492: }
493:
494: IoMem_WriteWord(0xff9202, (nData << 8) | 0x0ff);
495: }
496:
497:
498: /*-----------------------------------------------------------------------*/
1.1.1.8 root 499: /**
500: * Write to STE joypad selection register (0xff9202)
501: */
1.1.1.6 root 502: void Joy_StePadMulti_WriteWord(void)
503: {
504: nSteJoySelect = IoMem_ReadWord(0xff9202);
505: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.