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