cl_joystick.c

Go to the documentation of this file.
00001 
00005 /*
00006 Copyright (C) 2002-2007 ioQuake3 team.
00007 Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "../client.h"
00027 #include "cl_input.h"
00028 #include "cl_joystick.h"
00029 #include "../ui/ui_main.h"
00030 #include "../ui/ui_nodes.h"
00031 #include "../ui/node/ui_node_abstractoption.h"
00032 
00033 static SDL_Joystick *stick = NULL;
00034 static cvar_t *in_joystick;
00035 static cvar_t *in_joystickNo;
00036 static cvar_t *in_joystickThreshold;
00037 static cvar_t *in_joystickSpeed;
00038 
00039 static struct {
00040     qboolean buttons[16];
00041     unsigned int oldaxes;
00042     unsigned int oldhats;
00043 } stick_state;
00044 
00045 /* We translate axes movement into keypresses */
00046 static const int joy_keys[16] = {
00047     K_LEFTARROW, K_RIGHTARROW,
00048     K_UPARROW, K_DOWNARROW,
00049     K_JOY16, K_JOY17,
00050     K_JOY18, K_JOY19,
00051     K_JOY20, K_JOY21,
00052     K_JOY22, K_JOY23,
00053 
00054     K_JOY24, K_JOY25,
00055     K_JOY26, K_JOY27
00056 };
00057 
00058 /* translate hat events into keypresses
00059  * the 4 highest buttons are used for the first hat ... */
00060 static const int hat_keys[16] = {
00061     K_JOY29, K_JOY30,
00062     K_JOY31, K_JOY32,
00063     K_JOY25, K_JOY26,
00064     K_JOY27, K_JOY28,
00065     K_JOY21, K_JOY22,
00066     K_JOY23, K_JOY24,
00067     K_JOY17, K_JOY18,
00068     K_JOY19, K_JOY20
00069 };
00070 
00071 void IN_JoystickMove (void)
00072 {
00073     qboolean joy_pressed[lengthof(joy_keys)];
00074     unsigned int axes = 0;
00075     unsigned int hats = 0;
00076     int total = 0;
00077     int i = 0;
00078 
00079     /* check whether a user has changed the joystick number */
00080     if (in_joystickNo->modified)
00081         IN_StartupJoystick();
00082     /* check whether joysticks are disabled */
00083     if (!in_joystick->integer)
00084         return;
00085 
00086     if (!stick)
00087         return;
00088 
00089     SDL_JoystickUpdate();
00090 
00091     memset(joy_pressed, '\0', sizeof(joy_pressed));
00092 
00093     /* update the ball state */
00094     total = SDL_JoystickNumBalls(stick);
00095     if (total > 0) {
00096         int balldx = 0;
00097         int balldy = 0;
00098         for (i = 0; i < total; i++) {
00099             int dx = 0;
00100             int dy = 0;
00101             SDL_JoystickGetBall(stick, i, &dx, &dy);
00102             balldx += dx;
00103             balldy += dy;
00104         }
00105         if (balldx || balldy) {
00106             mousePosX = balldx / viddef.rx;
00107             mousePosY = balldy / viddef.ry;
00108         }
00109     }
00110 
00111     /* now query the stick buttons... */
00112     total = SDL_JoystickNumButtons(stick);
00113     if (total > 0) {
00114         if (total > lengthof(stick_state.buttons))
00115             total = lengthof(stick_state.buttons);
00116         for (i = 0; i < total; i++) {
00117             const qboolean pressed = (SDL_JoystickGetButton(stick, i) != 0);
00118             if (pressed != stick_state.buttons[i]) {
00119                 IN_EventEnqueue(K_JOY1 + i, 0, pressed);
00120                 stick_state.buttons[i] = pressed;
00121             }
00122         }
00123     }
00124 
00125     /* look at the hats... */
00126     total = SDL_JoystickNumHats(stick);
00127     if (total > 0) {
00128         if (total > 4)
00129             total = 4;
00130         for (i = 0; i < total; i++)
00131             ((Uint8 *)&hats)[i] = SDL_JoystickGetHat(stick, i);
00132     }
00133 
00134     /* update hat state */
00135     if (hats != stick_state.oldhats) {
00136         for (i = 0; i < 4; i++) {
00137             if (((Uint8 *)&hats)[i] != ((Uint8 *)&stick_state.oldhats)[i]) {
00138                 /* release event */
00139                 switch (((Uint8 *)&stick_state.oldhats)[i]) {
00140                 case SDL_HAT_UP:
00141                     IN_EventEnqueue(hat_keys[4 * i + 0], 0, qfalse);
00142                     break;
00143                 case SDL_HAT_RIGHT:
00144                     IN_EventEnqueue(hat_keys[4 * i + 1], 0, qfalse);
00145                     break;
00146                 case SDL_HAT_DOWN:
00147                     IN_EventEnqueue(hat_keys[4 * i + 2], 0, qfalse);
00148                     break;
00149                 case SDL_HAT_LEFT:
00150                     IN_EventEnqueue(hat_keys[4 * i + 3], 0, qfalse);
00151                     break;
00152                 case SDL_HAT_RIGHTUP:
00153                     IN_EventEnqueue(hat_keys[4 * i + 0], 0, qfalse);
00154                     IN_EventEnqueue(hat_keys[4 * i + 1], 0, qfalse);
00155                     break;
00156                 case SDL_HAT_RIGHTDOWN:
00157                     IN_EventEnqueue(hat_keys[4 * i + 2], 0, qfalse);
00158                     IN_EventEnqueue(hat_keys[4 * i + 1], 0, qfalse);
00159                     break;
00160                 case SDL_HAT_LEFTUP:
00161                     IN_EventEnqueue(hat_keys[4 * i + 0], 0, qfalse);
00162                     IN_EventEnqueue(hat_keys[4 * i + 3], 0, qfalse);
00163                     break;
00164                 case SDL_HAT_LEFTDOWN:
00165                     IN_EventEnqueue(hat_keys[4 * i + 2], 0, qfalse);
00166                     IN_EventEnqueue(hat_keys[4 * i + 3], 0, qfalse);
00167                     break;
00168                 default:
00169                     break;
00170                 }
00171                 /* press event */
00172                 switch (((Uint8 *)&hats)[i]) {
00173                 case SDL_HAT_UP:
00174                     IN_EventEnqueue(hat_keys[4 * i + 0], 0, qtrue);
00175                     break;
00176                 case SDL_HAT_RIGHT:
00177                     IN_EventEnqueue(hat_keys[4 * i + 1], 0, qtrue);
00178                     break;
00179                 case SDL_HAT_DOWN:
00180                     IN_EventEnqueue(hat_keys[4 * i + 2], 0, qtrue);
00181                     break;
00182                 case SDL_HAT_LEFT:
00183                     IN_EventEnqueue(hat_keys[4 * i + 3], 0, qtrue);
00184                     break;
00185                 case SDL_HAT_RIGHTUP:
00186                     IN_EventEnqueue(hat_keys[4 * i + 0], 0, qtrue);
00187                     IN_EventEnqueue(hat_keys[4 * i + 1], 0, qtrue);
00188                     break;
00189                 case SDL_HAT_RIGHTDOWN:
00190                     IN_EventEnqueue(hat_keys[4 * i + 2], 0, qtrue);
00191                     IN_EventEnqueue(hat_keys[4 * i + 1], 0, qtrue);
00192                     break;
00193                 case SDL_HAT_LEFTUP:
00194                     IN_EventEnqueue(hat_keys[4 * i + 0], 0, qtrue);
00195                     IN_EventEnqueue(hat_keys[4 * i + 3], 0, qtrue);
00196                     break;
00197                 case SDL_HAT_LEFTDOWN:
00198                     IN_EventEnqueue(hat_keys[4 * i + 2], 0, qtrue);
00199                     IN_EventEnqueue(hat_keys[4 * i + 3], 0, qtrue);
00200                     break;
00201                 default:
00202                     break;
00203                 }
00204             }
00205         }
00206     }
00207 
00208     /* save hat state */
00209     stick_state.oldhats = hats;
00210 
00211     /* finally, look at the axes... */
00212     total = SDL_JoystickNumAxes(stick);
00213     if (total >= 2) {
00214         /* the first two axes are used for the cursor movement */
00215         for (i = 0; i < 2; i++) {
00216             const Sint16 axis = SDL_JoystickGetAxis(stick, i);
00217             const float velocity = ((float) axis) / 32767.0f;
00218             if (velocity > -in_joystickThreshold->value && velocity < in_joystickThreshold->value)
00219                 continue;
00220 
00221             if (i & 1) {
00222                 mousePosY += in_joystickSpeed->value * velocity;
00223                 if (mousePosY > (int)viddef.height)
00224                     mousePosY = (int)viddef.height;
00225                 else if (mousePosY < 0)
00226                     mousePosY = 0;
00227             } else {
00228                 mousePosX += in_joystickSpeed->value * velocity;
00229                 if (mousePosX > (int)viddef.width)
00230                     mousePosX = (int)viddef.width;
00231                 else if (mousePosX < 0)
00232                     mousePosX = 0;
00233             }
00234         }
00235     }
00236 
00237 
00238     if (total > 2) {
00239         if (total > 16)
00240             total = 16;
00241         /* every axis except the first two can be normally bound to an action */
00242         for (i = 2; i < total; i++) {
00243             const Sint16 axis = SDL_JoystickGetAxis(stick, i);
00244             const float f = ((float) axis) / 32767.0f;
00245             if (f < -in_joystickThreshold->value) {
00246                 axes |= (1 << (i * 2));
00247             } else if (f > in_joystickThreshold->value) {
00248                 axes |= (1 << ((i * 2) + 1));
00249             }
00250         }
00251     }
00252 
00253 
00254     /* Time to update axes state based on old vs. new. */
00255     if (axes != stick_state.oldaxes) {
00256         for (i = 2; i < 16; i++) {
00257             if ((axes & (1 << i)) && !(stick_state.oldaxes & (1 << i)))
00258                 IN_EventEnqueue(joy_keys[i], 0, qtrue);
00259 
00260             if (!(axes & (1 << i)) && (stick_state.oldaxes & (1 << i)))
00261                 IN_EventEnqueue(joy_keys[i], 0, qfalse);
00262         }
00263     }
00264 
00265     /* Save for future generations. */
00266     stick_state.oldaxes = axes;
00267 }
00268 
00272 void IN_JoystickInitMenu (void)
00273 {
00274     uiNode_t* joystickOptions = NULL;
00275     const int total = SDL_NumJoysticks();
00276 
00277     if (total == 0) {
00278         UI_AddOption(&joystickOptions, "", _("None"), "0");
00279     } else {
00280         int i;
00281         for (i = 0; i < total; i++)
00282             UI_AddOption(&joystickOptions, "", SDL_JoystickName(i), va("%i", i));
00283     }
00284     UI_RegisterOption(OPTION_JOYSTICKS, joystickOptions);
00285 }
00286 
00290 void IN_StartupJoystick (void)
00291 {
00292     int i = 0;
00293     int total = 0;
00294 
00295     in_joystick = Cvar_Get("in_joystick", "0", CVAR_ARCHIVE, "Activate or deactivate the use of a joystick");
00296     in_joystickNo = Cvar_Get("in_joystickNo", "0", CVAR_ARCHIVE, "Joystick to use - 0 is the first - 1 is the second ...");
00297     in_joystickThreshold = Cvar_Get("in_joystickThreshold", "0.05", CVAR_ARCHIVE, "The threshold for the joystick axes");
00298     in_joystickSpeed = Cvar_Get("in_joystickSpeed", "20", CVAR_ARCHIVE, "The joystick speed for the cursor");
00299 
00300     if (stick != NULL) {
00301         Com_Printf("... closing already initialized joystick\n");
00302         SDL_JoystickClose(stick);
00303     }
00304 
00305     stick = NULL;
00306     memset(&stick_state, '\0', sizeof(stick_state));
00307 
00308     if (!SDL_WasInit(SDL_INIT_JOYSTICK)) {
00309         Com_DPrintf(DEBUG_CLIENT, "Calling SDL_Init(SDL_INIT_JOYSTICK)...\n");
00310         if (SDL_Init(SDL_INIT_JOYSTICK) == -1) {
00311             Com_DPrintf(DEBUG_CLIENT, "SDL_Init(SDL_INIT_JOYSTICK) failed: %s\n", SDL_GetError());
00312             return;
00313         }
00314         Com_DPrintf(DEBUG_CLIENT, "SDL_Init(SDL_INIT_JOYSTICK) passed.\n");
00315     }
00316 
00317     total = SDL_NumJoysticks();
00318     Com_Printf("%d possible joysticks\n", total);
00319     for (i = 0; i < total; i++)
00320         Com_DPrintf(DEBUG_CLIENT, "[%d] %s\n", i, SDL_JoystickName(i));
00321 
00322     if (in_joystickNo->integer < 0 || in_joystickNo->integer >= total)
00323         Cvar_Set("in_joystickNo", "0");
00324     in_joystickNo->modified = qfalse;
00325 
00326     stick = SDL_JoystickOpen(in_joystickNo->integer);
00327 
00328     if (stick == NULL) {
00329         Com_Printf("no joystick found.\n");
00330         return;
00331     }
00332 
00333     Com_Printf("joystick %d opened - set cvar in_joystickNo to change this\n", in_joystickNo->integer);
00334     Com_Printf("... name: %s\n", SDL_JoystickName(in_joystickNo->integer));
00335     Com_Printf("... axes: %d\n", SDL_JoystickNumAxes(stick));
00336     Com_Printf("... hats: %d\n", SDL_JoystickNumHats(stick));
00337     Com_Printf("... buttons: %d\n", SDL_JoystickNumButtons(stick));
00338     Com_Printf("... balls: %d\n", SDL_JoystickNumBalls(stick));
00339 
00340     SDL_JoystickEventState(SDL_QUERY);
00341 }
00342 

Generated by  doxygen 1.6.2