1 ///////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2010 by The Allacrost Project
3 //                         All Rights Reserved
4 //
5 // This code is licensed under the GNU GPL version 2. It is free software
6 // and you may modify it and/or redistribute it under the terms of this license.
7 // See http://www.gnu.org/copyleft/gpl.html for details.
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 /** ***************************************************************************
11 *** \file   input.cpp
12 *** \author Tyler Olsen, roots@allacrost.org
13 *** \brief  Source file for processing user input
14 *** **************************************************************************/
15 
16 #include "input.h"
17 #include "video.h"
18 #include "script.h"
19 
20 #include "mode_manager.h"
21 #include "system.h"
22 
23 using namespace std;
24 
25 using namespace hoa_utils;
26 using namespace hoa_video;
27 using namespace hoa_script;
28 using namespace hoa_mode_manager;
29 using namespace hoa_system;
30 using namespace hoa_input::private_input;
31 
32 template<> hoa_input::InputEngine* Singleton<hoa_input::InputEngine>::_singleton_reference = NULL;
33 
34 namespace hoa_input {
35 
36 InputEngine* InputManager = NULL;
37 bool INPUT_DEBUG = false;
38 
39 // Initializes class members
InputEngine()40 InputEngine::InputEngine() {
41 	if (INPUT_DEBUG) cout << "INPUT: InputEngine constructor invoked" << endl;
42 	_any_key_press		    = false;
43 	_any_key_release	    = false;
44 	_last_axis_moved      = -1;
45 	_up_state             = false;
46 	_up_press             = false;
47 	_up_release           = false;
48 	_down_state           = false;
49 	_down_press           = false;
50 	_down_release         = false;
51 	_left_state           = false;
52 	_left_press           = false;
53 	_left_release         = false;
54 	_right_state          = false;
55 	_right_press          = false;
56 	_right_release        = false;
57 	_confirm_state        = false;
58 	_confirm_press        = false;
59 	_confirm_release      = false;
60 	_cancel_state         = false;
61 	_cancel_press         = false;
62 	_cancel_release       = false;
63 	_menu_state           = false;
64 	_menu_press           = false;
65 	_menu_release         = false;
66 	_swap_state           = false;
67 	_swap_press           = false;
68 	_swap_release         = false;
69 	_right_select_state   = false;
70 	_right_select_press   = false;
71 	_right_select_release = false;
72 	_left_select_state    = false;
73 	_left_select_press    = false;
74 	_left_select_release  = false;
75 
76 	_pause_press          = false;
77 	_quit_press           = false;
78 
79 	_joyaxis_x_first      = true;
80 	_joyaxis_y_first      = true;
81 	_joystick.js          = NULL;
82 	_joystick.x_axis      = 0;
83 	_joystick.y_axis      = 1;
84 	_joystick.threshold   = 8192;
85 }
86 
87 
88 
~InputEngine()89 InputEngine::~InputEngine() {
90 	if (INPUT_DEBUG) cout << "INPUT: InputEngine destructor invoked" << endl;
91 
92 	// If a joystick is open, close it before exiting
93 	if (_joystick.js != NULL) {
94 		SDL_JoystickClose(_joystick.js);
95 	}
96 }
97 
98 
99 // Initialize singleton pointers and key/joystick systems.
SingletonInitialize()100 bool InputEngine::SingletonInitialize() {
101 	// Initialize the SDL joystick subsystem
102 	if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0) {
103 		cerr << "INPUT ERROR: failed to initailize the SDL joystick subsystem" << endl;
104 		return false;
105 	}
106 
107 	return true;
108 }
109 
110 
111 // This is no longer inside SingletonInitialize because we need to load the lua settings
112 // before initializing the joysticks.
InitializeJoysticks()113 void InputEngine::InitializeJoysticks()
114 {
115 	// Attempt to initialize and setup the joystick system
116 	if (SDL_NumJoysticks() == 0) { // No joysticks found
117 		SDL_JoystickEventState(SDL_IGNORE);
118 		SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
119 	}
120 	else { // At least one joystick exists
121 		SDL_JoystickEventState(SDL_ENABLE);
122 		// TODO: need to allow user to specify which joystick to open, if multiple exist
123 		_joystick.js = SDL_JoystickOpen(_joystick.joy_index);
124 	}
125 }
126 
127 
128 // Loads the default key settings from the lua file and sets them back
RestoreDefaultKeys()129 bool InputEngine::RestoreDefaultKeys() {
130 	// Load the settings file
131 	string in_filename = GetSettingsFilename();
132 	ReadScriptDescriptor settings_file;
133 	if (!settings_file.OpenFile(in_filename)) {
134 		cerr << "INPUT ERROR: failed to open data file for reading: " << in_filename << endl;
135 		return false;
136 	}
137 
138 	// Load all default keys from the table
139 	settings_file.OpenTable("settings");
140 	settings_file.OpenTable("key_defaults");
141 	_key.up           = static_cast<SDLKey>(settings_file.ReadInt("up"));
142 	_key.down         = static_cast<SDLKey>(settings_file.ReadInt("down"));
143 	_key.left         = static_cast<SDLKey>(settings_file.ReadInt("left"));
144 	_key.right        = static_cast<SDLKey>(settings_file.ReadInt("right"));
145 	_key.confirm      = static_cast<SDLKey>(settings_file.ReadInt("confirm"));
146 	_key.cancel       = static_cast<SDLKey>(settings_file.ReadInt("cancel"));
147 	_key.menu         = static_cast<SDLKey>(settings_file.ReadInt("menu"));
148 	_key.swap         = static_cast<SDLKey>(settings_file.ReadInt("swap"));
149 	_key.left_select  = static_cast<SDLKey>(settings_file.ReadInt("left_select"));
150 	_key.right_select = static_cast<SDLKey>(settings_file.ReadInt("right_select"));
151 	_key.pause        = static_cast<SDLKey>(settings_file.ReadInt("pause"));
152 	settings_file.CloseTable();
153 	settings_file.CloseTable();
154 
155 	settings_file.CloseFile();
156 
157 	return true;
158 }
159 
160 
161 // Loads the default joystick settings from the lua file and sets them back
RestoreDefaultJoyButtons()162 bool InputEngine::RestoreDefaultJoyButtons()
163 {
164 	// Load the settings file
165 	string in_filename = GetSettingsFilename();
166 	ReadScriptDescriptor settings_file;
167 	if (settings_file.OpenFile(in_filename) == false) {
168 		cerr << "INPUT ERROR: failed to open data file for reading: " << in_filename << endl;
169 		return false;
170 	}
171 
172 	// Load all default buttons from the table
173 	settings_file.OpenTable("settings");
174 	settings_file.OpenTable("joystick_defaults");
175 	_joystick.confirm      = static_cast<uint8>(settings_file.ReadInt("confirm"));
176 	_joystick.cancel       = static_cast<uint8>(settings_file.ReadInt("cancel"));
177 	_joystick.menu         = static_cast<uint8>(settings_file.ReadInt("menu"));
178 	_joystick.swap         = static_cast<uint8>(settings_file.ReadInt("swap"));
179 	_joystick.left_select  = static_cast<uint8>(settings_file.ReadInt("left_select"));
180 	_joystick.right_select = static_cast<uint8>(settings_file.ReadInt("right_select"));
181 	_joystick.pause        = static_cast<uint8>(settings_file.ReadInt("pause"));
182 	_joystick.quit		   = static_cast<uint8>(settings_file.ReadInt("quit"));
183 	settings_file.CloseTable();
184 	settings_file.CloseTable();
185 
186 	settings_file.CloseFile();
187 
188 	return true;
189 }
190 
191 
192 // Checks if any keyboard key or joystick button is pressed
AnyKeyPress()193 bool InputEngine::AnyKeyPress() {
194 	return _any_key_press;
195 }
196 
197 
198 // Checks if any keyboard key or joystick button is released
AnyKeyRelease()199 bool InputEngine::AnyKeyRelease() {
200 	return _any_key_release;
201 }
202 
203 
204 // Handles all of the event processing for the game.
EventHandler()205 void InputEngine::EventHandler() {
206 	SDL_Event event; // Holds the game event
207 
208 	// Reset all of the press and release flags so that they don't get detected twice.
209 	_any_key_press   = false;
210 	_any_key_release = false;
211 
212 	_up_press             = false;
213 	_up_release           = false;
214 	_down_press           = false;
215 	_down_release         = false;
216 	_left_press           = false;
217 	_left_release         = false;
218 	_right_press          = false;
219 	_right_release        = false;
220 	_confirm_press        = false;
221 	_confirm_release      = false;
222 	_cancel_press         = false;
223 	_cancel_release       = false;
224 	_menu_press           = false;
225 	_menu_release         = false;
226 	_swap_press           = false;
227 	_swap_release         = false;
228 	_right_select_press   = false;
229 	_right_select_release = false;
230 	_left_select_press    = false;
231 	_left_select_release  = false;
232 
233 	_pause_press = false;
234 	_quit_press = false;
235 
236 	// Loops until there are no remaining events to process
237 	while (SDL_PollEvent(&event)) {
238 		_event = event;
239 		if (event.type == SDL_QUIT) {
240 			_quit_press = true;
241 			break;
242 		}
243 		// Check if the window was iconified/minimized or restored
244 		else if (event.type == SDL_ACTIVEEVENT) {
245 			// TEMP: pausing the game on a context switch between another application proved to
246 			// be rather annoying. The code which did this is commented out below. I think it would
247 			// be better if instead the application yielded for a certain amount of time when the
248 			// application looses context.
249 
250 // 			if (event.active.state & SDL_APPACTIVE) {
251 // 				if (event.active.gain == 0) { // Window was iconified/minimized
252 // 					// Check if the game is in pause mode. Otherwise the player might put pause on,
253 // 					// minimize the window and then the pause is off.
254 // 					if (ModeManager->GetGameType() != MODE_MANAGER_PAUSE_MODE) {
255 // 						TogglePause();
256 // 					}
257 // 				}
258 // 				else if (ModeManager->GetGameType() == MODE_MANAGER_PAUSE_MODE) { // Window was restored
259 // 					TogglePause();
260 // 				}
261 // 			}
262 // 			else if (event.active.state & SDL_APPINPUTFOCUS) {
263 // 				if (event.active.gain == 0) { // Window lost keyboard focus (another application was made active)
264 // 					// Check if the game is in pause mode. Otherwise the player might put pause on,
265 // 					// minimize the window and then the pause is off.
266 // 					if (ModeManager->GetGameType() != MODE_MANAGER_PAUSE_MODE) {
267 // 						TogglePause();
268 // 					}
269 // 				}
270 // 				else if (ModeManager->GetGameType() == MODE_MANAGER_PAUSE_MODE) { // Window gain keyboard focus (not sure)
271 // 					TogglePause();
272 // 				}
273 // 			}
274 			break;
275 		}
276 		else if (event.type == SDL_KEYUP || event.type == SDL_KEYDOWN) {
277 			_KeyEventHandler(event.key);
278 		}
279 		else {
280 			_JoystickEventHandler(event);
281 		}
282 	} // while (SDL_PollEvent(&event)
283 } // void InputEngine::EventHandler()
284 
285 
286 
287 // Handles all keyboard events for the game
_KeyEventHandler(SDL_KeyboardEvent & key_event)288 void InputEngine::_KeyEventHandler(SDL_KeyboardEvent& key_event) {
289 	if (key_event.type == SDL_KEYDOWN) { // Key was pressed
290 
291 		_any_key_press = true;
292 
293 		if (key_event.keysym.mod & KMOD_CTRL || key_event.keysym.sym == SDLK_LCTRL || key_event.keysym.sym == SDLK_RCTRL) { // CTRL key was held down
294 
295 			_any_key_press = false; // CTRL isn't "any key"! :)
296 
297 			if (key_event.keysym.sym == SDLK_a) {
298 				// Toggle the display of advanced video engine information
299 				VideoManager->ToggleAdvancedDisplay();
300 			}
301 			else if (key_event.keysym.sym == SDLK_f) {
302 				// Toggle between full-screen and windowed mode
303 				VideoManager->ToggleFullscreen();
304 				VideoManager->ApplySettings();
305 				return;
306 			}
307 			else if (key_event.keysym.sym == SDLK_q) {
308 				_quit_press = true;
309 			}
310 			else if (key_event.keysym.sym == SDLK_r) {
311 				VideoManager->ToggleFPS();
312 				return;
313 			}
314 			else if (key_event.keysym.sym == SDLK_s) {
315 				// Take a screenshot of the current game
316 				static uint32 i = 1;
317 				string path = "";
318 				while (true)
319 				{
320 					path = hoa_utils::GetUserDataPath(true) + "screenshot_" + NumberToString<uint32>(i) + ".jpg";
321 					if (!DoesFileExist(path))
322 						break;
323 					i++;
324 				}
325 				VideoManager->MakeScreenshot(path);
326 				return;
327 			}
328 			else if (key_event.keysym.sym == SDLK_t) {
329 				// Display and cycle through the texture sheets
330 				VideoManager->Textures()->DEBUG_NextTexSheet();
331 				return;
332 			}
333 
334 			//return;
335 		} // endif CTRL pressed
336 
337 		// Note: a switch-case statement won't work here because Key.up is not an
338 		// integer value the compiler will whine and cry about it ;_;
339 		if (key_event.keysym.sym == SDLK_ESCAPE) {
340 			_quit_press = true;
341 			return;
342 		}
343 		else if (key_event.keysym.sym == _key.up) {
344 			_up_state = true;
345 			_up_press = true;
346 			return;
347 		}
348 		else if (key_event.keysym.sym == _key.down) {
349 			_down_state = true;
350 			_down_press = true;
351 			return;
352 		}
353 		else if (key_event.keysym.sym == _key.left) {
354 			_left_state = true;
355 			_left_press = true;
356 			return;
357 		}
358 		else if (key_event.keysym.sym == _key.right) {
359 			_right_state = true;
360 			_right_press = true;
361 			return;
362 		}
363 		else if (key_event.keysym.sym == _key.confirm) {
364 			_confirm_state = true;
365 			_confirm_press = true;
366 			return;
367 		}
368 		else if (key_event.keysym.sym == _key.cancel) {
369 			_cancel_state = true;
370 			_cancel_press = true;
371 			return;
372 		}
373 		else if (key_event.keysym.sym == _key.menu) {
374 			_menu_state = true;
375 			_menu_press = true;
376 			return;
377 		}
378 		else if (key_event.keysym.sym == _key.swap) {
379 			_swap_state = true;
380 			_swap_press = true;
381 			return;
382 		}
383 		else if (key_event.keysym.sym == _key.left_select) {
384 			_left_select_state = true;
385 			_left_select_press = true;
386 			return;
387 		}
388 		else if (key_event.keysym.sym == _key.right_select) {
389 			_right_select_state = true;
390 			_right_select_press = true;
391 			return;
392 		}
393 		else if (key_event.keysym.sym == _key.pause) {
394 			_pause_press = true;
395 			return;
396 		}
397 	}
398 
399 	else { // Key was released
400 
401 		_any_key_press = false;
402 		_any_key_release = true;
403 
404 		if (key_event.keysym.sym == _key.up) {
405 			_up_state = false;
406 			_up_release = true;
407 			return;
408 		}
409 		else if (key_event.keysym.sym == _key.down) {
410 			_down_state = false;
411 			_down_release = true;
412 			return;
413 		}
414 		else if (key_event.keysym.sym == _key.left) {
415 			_left_state = false;
416 			_left_release = true;
417 			return;
418 		}
419 		else if (key_event.keysym.sym == _key.right) {
420 			_right_state = false;
421 			_right_release = true;
422 			return;
423 		}
424 		else if (key_event.keysym.sym == _key.confirm) {
425 			_confirm_state = false;
426 			_confirm_release = true;
427 			return;
428 		}
429 		else if (key_event.keysym.sym == _key.cancel) {
430 			_cancel_state = false;
431 			_cancel_release = true;
432 			return;
433 		}
434 		else if (key_event.keysym.sym == _key.menu) {
435 			_menu_state = false;
436 			_menu_release = true;
437 			return;
438 		}
439 		else if (key_event.keysym.sym == _key.swap) {
440 			_swap_state = false;
441 			_swap_release = true;
442 			return;
443 		}
444 		else if (key_event.keysym.sym == _key.left_select) {
445 			_left_select_state = false;
446 			_left_select_release = true;
447 			return;
448 		}
449 		else if (key_event.keysym.sym == _key.right_select) {
450 			_right_select_state = false;
451 			_right_select_release = true;
452 			return;
453 		}
454 	}
455 } // void InputEngine::_KeyEventHandler(SDL_KeyboardEvent& key_event)
456 
457 // Handles all joystick events for the game
_JoystickEventHandler(SDL_Event & js_event)458 void InputEngine::_JoystickEventHandler(SDL_Event& js_event) {
459 	if (js_event.type == SDL_JOYAXISMOTION) {
460 		if (js_event.jaxis.axis == _joystick.x_axis) {
461 			if (js_event.jaxis.value < -_joystick.threshold) {
462 				if (!_left_state) {
463 					_left_state = true;
464 					_left_press = true;
465 				}
466 			}
467 			else {
468 				_left_state = false;
469 			}
470 
471 			if (js_event.jaxis.value > _joystick.threshold) {
472 				if (!_right_state) {
473 					_right_state = true;
474 					_right_press = true;
475 				}
476 			}
477 			else {
478 				_right_state = false;
479 			}
480 		}
481 		else if (js_event.jaxis.axis == _joystick.y_axis) {
482 			if (js_event.jaxis.value < -_joystick.threshold) {
483 				if (!_up_state) {
484 					_up_state = true;
485 					_up_press = true;
486 				}
487 			}
488 			else {
489 				_up_state = false;
490 			}
491 
492 			if (js_event.jaxis.value > _joystick.threshold) {
493 				if (!_down_state) {
494 					_down_state = true;
495 					_down_press = true;
496 				}
497 			}
498 			else {
499 				_down_state = false;
500 			}
501 		}
502 
503 		if (js_event.jaxis.value > _joystick.threshold
504 			|| js_event.jaxis.value < -_joystick.threshold)
505 			_last_axis_moved = js_event.jaxis.axis;
506 	} // if (js_event.type == SDL_JOYAXISMOTION)
507 
508 	else if (js_event.type == SDL_JOYBUTTONDOWN) {
509 
510 		_any_key_press = true;
511 
512 		if (js_event.jbutton.button == _joystick.confirm) {
513 			_confirm_state = true;
514 			_confirm_press = true;
515 			return;
516 		}
517 		else if (js_event.jbutton.button == _joystick.cancel) {
518 			_cancel_state = true;
519 			_cancel_press = true;
520 			return;
521 		}
522 		else if (js_event.jbutton.button == _joystick.menu) {
523 			_menu_state = true;
524 			_menu_press = true;
525 			return;
526 		}
527 		else if (js_event.jbutton.button == _joystick.swap) {
528 			_swap_state = true;
529 			_swap_press = true;
530 			return;
531 		}
532 		else if (js_event.jbutton.button == _joystick.left_select) {
533 			_left_select_state = true;
534 			_left_select_press = true;
535 			return;
536 		}
537 		else if (js_event.jbutton.button == _joystick.right_select) {
538 			_right_select_state = true;
539 			_right_select_press = true;
540 			return;
541 		}
542 		else if (js_event.jbutton.button == _joystick.pause) {
543 			_pause_press = true;
544 			return;
545 		}
546 		else if (js_event.jbutton.button == _joystick.quit) {
547 			_quit_press = true;
548 			return;
549 		}
550 	} // else if (js_event.type == JOYBUTTONDOWN)
551 
552 	else if (js_event.type == SDL_JOYBUTTONUP) {
553 		_any_key_press = false;
554 		_any_key_release = true;
555 
556 		if (js_event.jbutton.button == _joystick.confirm) {
557 			_confirm_state = false;
558 			_confirm_release = true;
559 			return;
560 		}
561 		else if (js_event.jbutton.button == _joystick.cancel) {
562 			_cancel_state = false;
563 			_cancel_release = true;
564 			return;
565 		}
566 		else if (js_event.jbutton.button == _joystick.menu) {
567 			_menu_state = false;
568 			_menu_release = true;
569 			return;
570 		}
571 		else if (js_event.jbutton.button == _joystick.swap) {
572 			_swap_state = false;
573 			_swap_release = true;
574 			return;
575 		}
576 		else if (js_event.jbutton.button == _joystick.left_select) {
577 			_left_select_state = false;
578 			_left_select_release = true;
579 			return;
580 		}
581 		else if (js_event.jbutton.button == _joystick.right_select) {
582 			_right_select_state = false;
583 			_right_select_release = true;
584 			return;
585 		}
586 	} // else if (js_event.type == JOYBUTTONUP)
587 
588 	// NOTE: SDL_JOYBALLMOTION and SDL_JOYHATMOTION are ignored for now. Should we process them?
589 } // void InputEngine::_JoystickEventHandler(SDL_Event& js_event)
590 
591 
592 // Sets a new key over an older one. If the same key is used elsewhere, the older one is removed
_SetNewKey(SDLKey & old_key,SDLKey new_key)593 void InputEngine::_SetNewKey(SDLKey & old_key, SDLKey new_key) {
594 	if (_key.up == new_key) { // up key used already
595 		_key.up = old_key;
596 		old_key = new_key;
597 		return;
598 	}
599 	if (_key.down == new_key) { // down key used already
600 		_key.down = old_key;
601 		old_key = new_key;
602 		return;
603 	}
604 	if (_key.left == new_key) { // left key used already
605 		_key.left = old_key;
606 		old_key = new_key;
607 		return;
608 	}
609 	if (_key.right == new_key) { // right key used already
610 		_key.right = old_key;
611 		old_key = new_key;
612 		return;
613 	}
614 	if (_key.confirm == new_key) { // confirm key used already
615 		_key.confirm = old_key;
616 		old_key = new_key;
617 		return;
618 	}
619 	if (_key.cancel == new_key) { // cancel key used already
620 		_key.cancel = old_key;
621 		old_key = new_key;
622 		return;
623 	}
624 	if (_key.menu == new_key) { // menu key used already
625 		_key.menu = old_key;
626 		old_key = new_key;
627 		return;
628 	}
629 	if (_key.swap == new_key) { // swap key used already
630 		_key.swap = old_key;
631 		old_key = new_key;
632 		return;
633 	}
634 	if (_key.left_select == new_key) { // left_select key used already
635 		_key.left_select = old_key;
636 		old_key = new_key;
637 		return;
638 	}
639 	if (_key.right_select == new_key) { // right_select key used already
640 		_key.right_select = old_key;
641 		old_key = new_key;
642 		return;
643 	}
644 	if (_key.pause == new_key) { // pause key used already
645 		_key.pause = old_key;
646 		old_key = new_key;
647 		return;
648 	}
649 
650 	old_key = new_key; // Otherwise simply overwrite the old value
651 } // end InputEngine::_SetNewKey(SDLKey & old_key, SDLKey new_key)
652 
653 
654 // Sets a new joystick button over an older one. If the same button is used elsewhere, the older one is removed
_SetNewJoyButton(uint8 & old_button,uint8 new_button)655 void InputEngine::_SetNewJoyButton(uint8 & old_button, uint8 new_button) {
656 	if (_joystick.confirm == new_button) { // confirm button used already
657 		_joystick.confirm = old_button;
658 		old_button = new_button;
659 		return;
660 	}
661 	if (_joystick.cancel == new_button) { // cancel button used already
662 		_joystick.cancel = old_button;
663 		old_button = new_button;
664 		return;
665 	}
666 	if (_joystick.menu == new_button) { // menu button used already
667 		_joystick.menu = old_button;
668 		old_button = new_button;
669 		return;
670 	}
671 	if (_joystick.swap == new_button) { // swap button used already
672 		_joystick.swap = old_button;
673 		old_button = new_button;
674 		return;
675 	}
676 	if (_joystick.left_select == new_button) { // left_select button used already
677 		_joystick.left_select = old_button;
678 		old_button = new_button;
679 		return;
680 	}
681 	if (_joystick.right_select == new_button) { // right_select button used already
682 		_joystick.right_select = old_button;
683 		old_button = new_button;
684 		return;
685 	}
686 	if (_joystick.pause == new_button) { // pause button used already
687 		_joystick.pause = old_button;
688 		old_button = new_button;
689 		return;
690 	}
691 
692 	old_button = new_button; // Otherwise simply overwrite the old value
693 } // end InputEngine::_SetNewJoyButton(uint8 & old_button, uint8 new_button)
694 
695 
696 } // namespace hoa_input
697