1 /*
2  *
3  *   Copyright (c) 1994, 2002, 2003  Johannes Prix
4  *   Copyright (c) 1994, 2002, 2003  Reinhard Prix
5  *
6  *
7  *  This file is part of Freedroid
8  *
9  *  Freedroid is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  Freedroid is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with Freedroid; see the file COPYING. If not, write to the
21  *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  *  MA  02111-1307  USA
23  *
24  */
25 
26 /*----------------------------------------------------------------------
27  *
28  * Desc: functions for keyboard and joystick handling
29  *
30  *----------------------------------------------------------------------*/
31 
32 #define _input_c
33 
34 #include "system.h"
35 
36 #include "defs.h"
37 #include "struct.h"
38 #include "global.h"
39 #include "proto.h"
40 
41 #ifndef SDL_BUTTON_WHEELUP
42 #define SDL_BUTTON_WHEELUP 4
43 #endif
44 #ifndef SDL_BUTTON_WHEELDOWN
45 #define SDL_BUTTON_WHEELDOWN 5
46 #endif
47 
48 bool show_cursor;    // show mouse-cursor or not?
49 #define CURSOR_KEEP_VISIBLE  3000   // ticks to keep mouse-cursor visible without mouse-input
50 
51 int WheelUpEvents=0;    // count number of not read-out wheel events
52 int WheelDownEvents=0;
53 Uint32 last_mouse_event = 0;  // record when last mouse event took place (SDL ticks)
54 int CurrentlyMouseRightPressed=0;
55 int CurrentlyMouseLeftPressed = 0;
56 
57 bool key_pressed[SDLK_LAST];	// array of states (pressed/released) of all keys
58 int joy_dirstate[4];  // array of 4 directions we map the joystick to
59 
60 SDLMod current_modifiers;
61 
62 SDL_Event event;
63 
64 // direction for joystick->keyboard mappings
65 enum _joy_dirs {
66   JOY_UP = 0,
67   JOY_RIGHT,
68   JOY_DOWN,
69   JOY_LEFT
70 };
71 #define FLAG_NEW 0xf0
72 
73 
sgn(int x)74 int sgn (int x)
75 {
76   return (x ? ((x)/abs(x)) : 0);
77 }
78 
Init_Joy(void)79 void Init_Joy (void)
80 {
81   int num_joy;
82 
83   if (SDL_InitSubSystem (SDL_INIT_JOYSTICK) == -1)
84     {
85       fprintf(stderr, "Couldn't initialize SDL-Joystick: %s\n",SDL_GetError());
86       Terminate(ERR);
87     } else
88       DebugPrintf(1, "\nSDL Joystick initialisation successful.\n");
89 
90 
91   DebugPrintf (1, " %d Joysticks found!\n", num_joy = SDL_NumJoysticks ());
92 
93   if (num_joy > 0)
94     joy = SDL_JoystickOpen (0);
95 
96   if (joy)
97     {
98       DebugPrintf (1, "Identifier: %s\n", SDL_JoystickName (0));
99       DebugPrintf (1, "Number of Axes: %d\n", joy_num_axes = SDL_JoystickNumAxes(joy));
100       DebugPrintf (1, "Number of Buttons: %d\n", SDL_JoystickNumButtons(joy));
101 
102       /* aktivate Joystick event handling */
103       SDL_JoystickEventState (SDL_ENABLE);
104 
105     }
106   else
107     joy = NULL;  /* signals that no yoystick is present */
108 
109 
110   return;
111 }
112 
113 
114 void
ReactToSpecialKeys(void)115 ReactToSpecialKeys(void)
116 {
117   //--------------------
118   // user asked for quit
119   //
120   if ( KeyIsPressedR('q') )
121     QuitGameMenu();
122 
123   if ( KeyIsPressedR('c') && AltPressed() && CtrlPressed() && ShiftPressed() )
124     Cheatmenu ();
125   if ( EscapePressedR() )
126     EscapeMenu ();
127 
128   if ( KeyIsPressedR ('p') )
129     Pause ();
130 
131   if (KeyIsPressedR (SDLK_F12) )
132     TakeScreenshot();
133 
134 } // void ReactToSpecialKeys(void)
135 
136 int
keyboard_update(void)137 keyboard_update(void)
138 {
139   Uint8 axis;
140 
141   // switch mouse-cursor visibility as a function of time of last activity
142   if (SDL_GetTicks () - last_mouse_event > CURSOR_KEEP_VISIBLE)
143     show_cursor = FALSE;
144   else
145     show_cursor = TRUE;
146 
147   while( SDL_PollEvent( &event ) )
148     {
149       switch( event.type )
150 	{
151 	case SDL_QUIT:
152 	  printf("\n\nUser requestet Termination...\n\nTerminating...");
153 	  Terminate(0);
154 	  break;
155 	  /* Look for a keypress */
156 
157 	case SDL_KEYDOWN:
158 	  current_modifiers = event.key.keysym.mod;
159 	  key_pressed[event.key.keysym.sym] = TRUE;
160 	  break;
161 	case SDL_KEYUP:
162 	  current_modifiers = event.key.keysym.mod;
163 	  key_pressed[event.key.keysym.sym] = FALSE;
164 	  break;
165 
166 	case SDL_JOYAXISMOTION:
167 	  axis = event.jaxis.axis;
168 	  if (axis == 0 || ((joy_num_axes >= 5) && (axis == 3)) ) /* x-axis */
169 	    {
170 	      input_axis.x = event.jaxis.value;
171 
172 	      // this is a bit tricky, because we want to allow direction keys
173 	      // to be soft-released. When mapping the joystick->keyboard, we
174 	      // therefore have to make sure that this mapping only occurs when
175 	      // and actual _change_ of the joystick-direction ('digital') occurs
176 	      // so that it behaves like "set"/"release"
177 	      if (joy_sensitivity*event.jaxis.value > 10000)   /* about half tilted */
178 		{
179 		  // compare to previous joy-direction!
180 		  if (!joy_dirstate[JOY_RIGHT])
181 		    {
182 		      key_pressed[SDLK_RIGHT] = TRUE;
183 		      key_pressed[SDLK_LEFT] = FALSE;
184 		    }
185 		  joy_dirstate[JOY_RIGHT] = TRUE;
186 		  joy_dirstate[JOY_LEFT] = FALSE;
187 		}
188 	      else if (joy_sensitivity*event.jaxis.value < -10000)
189 		{
190 		  if (!joy_dirstate[JOY_LEFT])
191 		    {
192 		      key_pressed[SDLK_LEFT] = TRUE;
193 		      key_pressed[SDLK_RIGHT] = FALSE;
194 		    }
195 		  joy_dirstate[JOY_LEFT] = TRUE;
196 		  joy_dirstate[JOY_RIGHT] = FALSE;
197 		}
198 	      else
199 		{
200 		  joy_dirstate[JOY_LEFT] = FALSE;
201 		  joy_dirstate[JOY_RIGHT] = FALSE;
202 		  key_pressed[SDLK_LEFT] = FALSE;
203 		  key_pressed[SDLK_RIGHT] = FALSE;
204 		}
205 	    }
206 	  else if ((axis == 1) || ((joy_num_axes >=5) && (axis == 4))) /* y-axis */
207 	    {
208 	      input_axis.y = event.jaxis.value;
209 
210 	      if (joy_sensitivity*event.jaxis.value > 10000)
211 		{
212 		  if (!joy_dirstate[JOY_DOWN])
213 		    {
214 		      key_pressed[SDLK_DOWN] = TRUE;
215 		      key_pressed[SDLK_UP] = FALSE;
216 		    }
217 		  joy_dirstate[JOY_DOWN] = TRUE;
218 		  joy_dirstate[JOY_UP] =  FALSE;
219 		}
220 	      else if (joy_sensitivity*event.jaxis.value < -10000)
221 		{
222 		  if (!joy_dirstate[JOY_UP])
223 		    {
224 		      key_pressed[SDLK_UP] = TRUE;
225 		      key_pressed[SDLK_DOWN] = FALSE;
226 		    }
227 		  joy_dirstate[JOY_UP] = TRUE;
228 		  joy_dirstate[JOY_DOWN]= FALSE;
229 		}
230 	      else
231 		{
232 		  joy_dirstate[JOY_UP] = FALSE;
233 		  joy_dirstate[JOY_DOWN] = FALSE;
234 		  key_pressed[SDLK_UP] = FALSE;
235 		  key_pressed[SDLK_DOWN] = FALSE;
236 		}
237 	    }
238 
239 	  break;
240 
241 	case SDL_JOYBUTTONDOWN:  // here we do some brute-force remappings...
242 	  // map first button onto fire,
243 	  if (event.jbutton.button == 0)
244 	    key_pressed[SDLK_SPACE] = TRUE;
245 
246 	  // second button onto MouseRight (i.e Takeover)
247 	  else if (event.jbutton.button == 1)
248 	    CurrentlyMouseRightPressed = TRUE;
249 
250 	  // and third button onto 'RSHIFT' , i.e Activate
251 	  else if (event.jbutton.button == 2)
252 	    key_pressed[SDLK_RSHIFT] = TRUE;
253 
254 	  axis_is_active = TRUE;
255 	  break;
256 
257 	case SDL_JOYBUTTONUP:
258 	  // map first button onto fire,
259 	  if (event.jbutton.button == 0)
260 	    key_pressed[SDLK_SPACE] = FALSE;
261 
262 	  // second button onto MouseRight (i.e Takeover)
263 	  else if (event.jbutton.button == 1)
264 	    CurrentlyMouseRightPressed = FALSE;
265 
266 	  // and third button onto 'RSHIFT' , i.e Activate
267 	  else if (event.jbutton.button == 2)
268 	    key_pressed[SDLK_RSHIFT] = FALSE;
269 
270 	  axis_is_active = FALSE;
271 	  break;
272 
273 	case SDL_MOUSEMOTION:
274 	  input_axis.x = event.button.x - UserCenter_x + 16;
275 	  input_axis.y = event.button.y - UserCenter_y + 16;
276 
277 	  last_mouse_event = SDL_GetTicks ();
278 
279 	  break;
280 
281 	  /* Mouse control */
282 	case SDL_MOUSEBUTTONDOWN:
283 	  if (event.button.button == SDL_BUTTON_LEFT)
284 	    {
285 	      CurrentlyMouseLeftPressed = TRUE;
286 	      axis_is_active = TRUE;
287 	    }
288 
289 	  if (event.button.button == SDL_BUTTON_RIGHT)
290 	    CurrentlyMouseRightPressed = TRUE;
291 
292 	  // we just map middle->Rshift (i.e. Activate)
293 	  if (event.button.button == SDL_BUTTON_MIDDLE)
294 	    key_pressed[SDLK_RSHIFT] = TRUE;
295 
296 	  // wheel events are immediately released, so we rather
297 	  // count the number of not yet read-out events
298 	  if (event.button.button == SDL_BUTTON_WHEELUP)
299 	      WheelUpEvents ++;
300 
301 	  if (event.button.button == SDL_BUTTON_WHEELDOWN)
302 	      WheelDownEvents ++;
303 
304 	  last_mouse_event = SDL_GetTicks();
305 	  break;
306 
307         case SDL_MOUSEBUTTONUP:
308 	  if (event.button.button == SDL_BUTTON_LEFT)
309 	    {
310 	      CurrentlyMouseLeftPressed = FALSE;
311 	      axis_is_active = FALSE;
312 	    }
313 
314 	  if (event.button.button == SDL_BUTTON_RIGHT)
315 	    CurrentlyMouseRightPressed = FALSE;
316 
317 	  if (event.button.button == SDL_BUTTON_MIDDLE)  // we just map middle->Escape
318 	    key_pressed[SDLK_RSHIFT] = FALSE;
319 
320 	  break;
321 
322  	default:
323  	  break;
324  	}
325 
326     }
327 
328   return 0;
329 }
330 
331 /*-----------------------------------------------------------------
332  * Desc: should do roughly what getchar() does, but in raw
333  * 	 (SLD) keyboard mode.
334  *
335  * Return: the (SDLKey) of the next key-pressed event cast to (int)
336  *
337  *-----------------------------------------------------------------*/
338 int
getchar_raw(void)339 getchar_raw (void)
340 {
341   SDL_Event event;
342   int Returnkey;
343 
344   //  keyboard_update ();   /* treat all pending keyboard-events */
345 
346   while (1)
347     {
348       SDL_WaitEvent (&event);    /* wait for next event */
349 
350       if (event.type == SDL_KEYDOWN)
351 	{
352 	  /*
353 	   * here we use the fact that, I cite from SDL_keyboard.h:
354 	   * "The keyboard syms have been cleverly chosen to map to ASCII"
355 	   * ... I hope that this design feature is portable, and durable ;)
356 	   */
357 	  Returnkey = (int) event.key.keysym.sym;
358 	  if ( event.key.keysym.mod & KMOD_SHIFT ) Returnkey = toupper( (int)event.key.keysym.sym );
359 	  return ( Returnkey );
360 	}
361       else
362 	{
363 	  SDL_PushEvent (&event);  /* put this event back into the queue */
364 	  keyboard_update ();  /* and treat it the usual way */
365 	  continue;
366 	}
367 
368     } /* while(1) */
369 
370 } /* getchar_raw() */
371 
372 // forget the wheel-counters
373 void
ResetMouseWheel(void)374 ResetMouseWheel (void)
375 {
376   WheelUpEvents = WheelDownEvents = 0;
377   return;
378 }
379 
380 bool
WheelUpPressed(void)381 WheelUpPressed (void)
382 {
383   keyboard_update();
384   if (WheelUpEvents)
385     return (WheelUpEvents--);
386   else
387     return (FALSE);
388 }
389 
390 bool
WheelDownPressed(void)391 WheelDownPressed (void)
392 {
393   keyboard_update();
394   if (WheelDownEvents)
395     return (WheelDownEvents--);
396   else
397     return (FALSE);
398 }
399 
400 bool
KeyIsPressed(SDLKey key)401 KeyIsPressed (SDLKey key)
402 {
403   keyboard_update();
404   return (key_pressed[key]);
405 }
406 
407 
408 // does the same as KeyIsPressed, but automatically releases the key as well..
409 bool
KeyIsPressedR(SDLKey key)410 KeyIsPressedR (SDLKey key)
411 {
412   bool ret;
413   keyboard_update();
414   ret = key_pressed[key];
415   ReleaseKey (key);
416   return (ret);
417 }
418 
419 void
ReleaseKey(SDLKey key)420 ReleaseKey (SDLKey key)
421 {
422   key_pressed[key] = FALSE;
423   return;
424 }
425 
426 bool
ModIsPressed(SDLMod mod)427 ModIsPressed (SDLMod mod)
428 {
429   bool ret;
430   keyboard_update();
431   ret = ( (current_modifiers & mod) != 0) ;
432   return (ret);
433 }
434 
435 bool
NoDirectionPressed(void)436 NoDirectionPressed (void)
437 {
438   if ( (axis_is_active && (input_axis.x || input_axis.y)) ||
439       DownPressed () || UpPressed() || LeftPressed() || RightPressed() )
440     return ( FALSE );
441   else
442     return ( TRUE );
443 } // int NoDirectionPressed(void)
444 
445 
446 bool
MouseRightPressed(void)447 MouseRightPressed(void)
448 {
449   keyboard_update();
450   return (CurrentlyMouseRightPressed);
451 }
452 
453 
454 bool
MouseRightPressedR(void)455 MouseRightPressedR (void)
456 {
457   bool ret;
458   keyboard_update();
459   ret = CurrentlyMouseRightPressed;
460   CurrentlyMouseRightPressed = FALSE;
461   return (ret);
462 }
463 
464 bool
MouseLeftPressed(void)465 MouseLeftPressed(void)
466 {
467   keyboard_update();
468   return CurrentlyMouseLeftPressed;
469 }
470 
471 bool
MouseLeftPressedR(void)472 MouseLeftPressedR (void)
473 {
474   bool ret;
475   keyboard_update();
476   ret = CurrentlyMouseLeftPressed;
477   CurrentlyMouseLeftPressed = FALSE;
478   return (ret);
479 }
480 
481 
482 
483 
484 
485 #undef _intput_c
486