/* * Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/ddio_lnx/lnxjoy.cpp $ * $Revision: 1.3 $ * $Date: 2001/02/07 09:16:45 $ * $Author: icculus $ * * Linux joystick routines * * $Log: sdljoy.cpp,v $ * Revision 1.3 2001/02/07 09:16:45 icculus * More robust debugging information. * * Revision 1.2 2000/06/29 22:15:25 hercules * Fixed hat motion * * Revision 1.1 2000/06/29 09:53:00 hercules * Use SDL joystick support (hats off to you! :) * * Revision 1.3 2000/06/24 01:15:15 icculus * patched to compile. * * Revision 1.2 2000/05/29 05:21:09 icculus * Changed a fprintf(stderr, ...) to an mprintf()... * * Revision 1.1.1.1 2000/04/18 00:00:33 icculus * initial checkin * * * 9 8/22/99 5:55p Jeff * fixed assert * * 8 8/19/99 3:46p Jeff * removed mprintfs * * 7 8/19/99 3:22p Jeff * added support for joystick driver version pre 1.0 * * 6 8/18/99 9:47p Jeff * joystick support! for kernel 2..2+ clients...need to handle before that * still. * * 5 8/17/99 2:32p Jeff * fixed joy_GetPos * * 4 7/14/99 9:06p Jeff * added comment header * * $NoKeywords: $ */ #include #include #include // rcg06182000 need this for specific joystick stuff. #include "args.h" #include "joystick.h" #include "log.h" // --------------------------------------------------------------------------- // globals static int specificJoy = -1; static struct { SDL_Joystick *handle; tJoyInfo caps; } Joysticks[MAX_JOYSTICKS]; static int joyGetNumDevs(void); // closes connection with controller. static void joy_CloseStick(tJoystick joy); // initializes a joystick // if server_adr is valid, a link is opened to another machine with a controller. static bool joy_InitStick(tJoystick joy, char *server_adr); // --------------------------------------------------------------------------- // functions // joystick system initialization bool joy_Init() { // reinitialize joystick if already initialized. joy_Close(); if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { LOG_ERROR << "Could not initialize Joystick"; return false; } // check if this OS supports joysticks if (!joyGetNumDevs()) { return false; } // rcg06182000 specific joystick support. if (specificJoy >= 0) { joy_InitStick((tJoystick)specificJoy, nullptr); } // if else { // initialize joystick list for (int i = 0; i < MAX_JOYSTICKS; i++) { joy_InitStick((tJoystick)i, nullptr); } } // else return true; } void joy_Close() { // initialize joystick list for (int i = 0; i < MAX_JOYSTICKS; i++) { joy_CloseStick((tJoystick)i); } SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } // initializes a joystick // if server_adr is valid, a link is opened to another machine with a controller. static bool joy_InitStick(tJoystick joy, char *server_adr) { // close down already open joystick. joy_CloseStick(joy); // okay, now if this is a remote joystick, open it if (server_adr) { return false; } SDL_Joystick *stick = SDL_JoystickOpen(joy); Joysticks[joy].handle = stick; if (stick) { tJoyInfo caps; memset(&caps, 0, (sizeof(caps))); strncpy(caps.name, SDL_JoystickNameForIndex(joy), sizeof(caps.name) - 1); caps.num_btns = SDL_JoystickNumButtons(stick); int axes = SDL_JoystickNumAxes(stick); switch (axes) { default: // Fall through to 6 axes case 6: caps.axes_mask |= JOYFLAG_VVALID; caps.minv = -32767; caps.maxv = 32768; case 5: caps.axes_mask |= JOYFLAG_UVALID; caps.minu = -32767; caps.maxu = 32768; case 4: caps.axes_mask |= JOYFLAG_RVALID; caps.minr = -32767; caps.maxr = 32768; case 3: caps.axes_mask |= JOYFLAG_ZVALID; caps.minz = -32767; caps.maxz = 32768; case 2: caps.axes_mask |= JOYFLAG_YVALID; caps.miny = -32767; caps.maxy = 32768; case 1: caps.axes_mask |= JOYFLAG_XVALID; caps.minx = -32767; caps.maxx = 32768; case 0: break; } int hats = SDL_JoystickNumHats(stick); switch (hats) { default: // Fall through to 4 hats case 4: caps.axes_mask |= JOYFLAG_POV4VALID; case 3: caps.axes_mask |= JOYFLAG_POV3VALID; case 2: caps.axes_mask |= JOYFLAG_POV2VALID; case 1: caps.axes_mask |= JOYFLAG_POVVALID; case 0: break; } Joysticks[joy].caps = caps; LOG_DEBUG.printf("JOYSTICK: Initialized stick named [%s].", caps.name); LOG_DEBUG.printf("JOYSTICK: (%d) axes, (%d) hats, and (%d) buttons.", axes, hats, caps.num_btns); } return (Joysticks[joy].handle != NULL); } // closes connection with controller. static void joy_CloseStick(tJoystick joy) { SDL_JoystickClose(Joysticks[joy].handle); Joysticks[joy].handle = nullptr; } // returns true if joystick valid bool joy_IsValid(tJoystick joy) { if (specificJoy >= 0) { if (joy != specificJoy) { return false; } } return (Joysticks[joy].handle != NULL); } // retreive information about joystick. void joy_GetJoyInfo(tJoystick joy, tJoyInfo *info) { memcpy(info, &Joysticks[(int)joy].caps, sizeof(tJoyInfo)); } // retreive uncalibrated position of joystick #define LNX_JOYAXIS_RANGE 65535 void joy_GetRawPos(tJoystick joy, tJoyPos *pos) { joy_GetPos(joy, pos); pos->x = (pos->x + 32767); pos->y = (pos->y + 32767); pos->z = (pos->z + 32767); pos->r = (pos->r + 32767); pos->u = (pos->u + 32767); pos->v = (pos->v + 32767); } static inline uint32_t map_hat(Uint8 value) { uint32_t mapped = 0; switch (value) { case SDL_HAT_CENTERED: mapped = JOYPOV_CENTER; break; case SDL_HAT_UP: mapped = 0x00; break; case SDL_HAT_UP | SDL_HAT_RIGHT: mapped = 0x20; break; case SDL_HAT_RIGHT: mapped = 0x40; break; case SDL_HAT_RIGHT | SDL_HAT_DOWN: mapped = 0x60; break; case SDL_HAT_DOWN: mapped = 0x80; break; case SDL_HAT_DOWN | SDL_HAT_LEFT: mapped = 0xA0; break; case SDL_HAT_LEFT: mapped = 0xC0; break; case SDL_HAT_LEFT | SDL_HAT_UP: mapped = 0xE0; break; } return mapped; } // returns the state of a stick, remote or otherwise void joy_GetPos(tJoystick joy, tJoyPos *pos) { SDL_Joystick *stick; int i; memset(pos, 0, (sizeof(*pos))); // retrieve joystick info from the net, or locally. stick = Joysticks[joy].handle; if (stick) { uint32_t mask; mask = Joysticks[joy].caps.axes_mask; if (mask & JOYFLAG_XVALID) { pos->x = SDL_JoystickGetAxis(stick, 0); } if (mask & JOYFLAG_YVALID) { pos->y = SDL_JoystickGetAxis(stick, 1); } if (mask & JOYFLAG_ZVALID) { pos->z = SDL_JoystickGetAxis(stick, 2); } if (mask & JOYFLAG_RVALID) { pos->r = SDL_JoystickGetAxis(stick, 3); } if (mask & JOYFLAG_UVALID) { pos->u = SDL_JoystickGetAxis(stick, 4); } if (mask & JOYFLAG_VVALID) { pos->v = SDL_JoystickGetAxis(stick, 5); } for (i = 0; i < JOYPOV_NUM; ++i) { if (mask & (JOYFLAG_POVVALID << i)) { pos->pov[i] = map_hat(SDL_JoystickGetHat(stick, i)); } } for (i = Joysticks[joy].caps.num_btns; i >= 0; --i) { if (SDL_JoystickGetButton(stick, i)) { pos->buttons |= (1 << i); } } } } static int joyGetNumDevs(void) { int found = 0; // rcg06182000 add support for specific joydev. int rc = FindArgChar("-joystick", 'j'); specificJoy = -1; if ((rc > 0) && (GameArgs[rc + 1] != NULL)) { specificJoy = atoi(GameArgs[rc + 1]); if ((specificJoy >= 0) && (specificJoy < SDL_NumJoysticks())) { found = 1; } else { specificJoy = -1; } } if (specificJoy < 0) { found = SDL_NumJoysticks(); } LOG_INFO.printf("Joystick: Found %d joysticks.", found); return found; } void ddio_InternalJoyFrame(void) { // All the work is done already in SDL_PumpEvents() }