1 /**
2 * Keyboard and joystick
3
4 * Copyright (C) 1997, 1998, 1999, 2002, 2003 Seth A. Robinson
5 * Copyright (C) 2005, 2007, 2008, 2009 Sylvain Beucler
6
7 * This file is part of GNU FreeDink
8
9 * GNU FreeDink is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 3 of the
12 * License, or (at your option) any later version.
13
14 * GNU FreeDink is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see
21 * <http://www.gnu.org/licenses/>.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <string.h>
29
30 #include "SDL.h"
31 #include "game_engine.h"
32 #include "log.h"
33 #include "input.h"
34
35 /* Input state */
36 struct seth_joy sjoy;
37
38 /* maps joystick buttons to action IDs (attack/attack/map/...). */
39 /* 10 buttons (indices), 6 different actions + 4 static buttons (values) */
40 static enum buttons_actions buttons_map[NB_BUTTONS];
41
42
43 /* TODO: maybe it's not necessary to SDL_PumpEvents every time, since
44 it's usually done before this function is called */
GetKeyboard(int key)45 int GetKeyboard(int key)
46 {
47 // returns 0 if the key has been depressed, else returns 1 and sets key to code recd.
48 int keystate_size;
49 Uint8* keystate;
50 //SDL_PumpEvents();
51 #if SDL_VERSION_ATLEAST(1, 3, 0)
52 keystate = SDL_GetKeyboardState(&keystate_size);
53 SDLKey scancode = SDL_GetScancodeFromKey(key);
54 return keystate[scancode];
55 #else
56 keystate = SDL_GetKeyState(&keystate_size);
57 return keystate[key];
58 #endif
59 }
60
input_init(void)61 void input_init(void)
62 {
63 /* Enable Unicode to be able to grab what letter the user actually
64 typed, taking the keyboard layout/language into account. Used for
65 the console (game) and the input dialogs (editor). */
66 SDL_EnableUNICODE(1);
67
68 /* Clear keyboard/joystick buffer */
69 memset(&sjoy,0,sizeof(sjoy));
70 {
71 int k = 0;
72 for (k = 0; k < 256; k++)
73 GetKeyboard(k);
74
75 int a = ACTION_FIRST;
76 for (a = ACTION_FIRST; a < ACTION_LAST; a++)
77 sjoy.joybitold[a] = 0;
78 }
79 sjoy.rightold = 0;
80 sjoy.leftold = 0;
81 sjoy.upold = 0;
82 sjoy.downold = 0;
83
84 /* Define default button->action mapping */
85 input_set_default_buttons();
86
87 /* JOY */
88 /* Joystick initialization never makes Dink fail for now. */
89 /* Note: joystick is originaly only used by the game, not the
90 editor. */
91 if (joystick == 1)
92 {
93 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
94 {
95 log_error("Error initializing joystick, skipping: %s", SDL_GetError());
96 joystick = 0;
97 }
98 else
99 {
100 /* first tests if a joystick driver is present */
101 /* if TRUE it makes certain that a joystick is plugged in */
102 if (SDL_NumJoysticks() > 0)
103 {
104 int i;
105 log_info("%i joysticks were found.", SDL_NumJoysticks());
106 log_info("The names of the joysticks are:");
107 for (i=0; i < SDL_NumJoysticks(); i++)
108 log_info(" %s", SDL_JoystickName(i));
109 log_info("Picking the first one...");
110 jinfo = SDL_JoystickOpen(0);
111 /* Don't activate joystick events, Dink polls joystick
112 manually. Plus events would pile up in the queue. */
113 SDL_JoystickEventState(SDL_IGNORE);
114
115 if (jinfo) {
116 log_info("Name: %s", SDL_JoystickName(0));
117 log_info("Number of axes: %d", SDL_JoystickNumAxes(jinfo));
118 log_info("Number of buttons: %d", SDL_JoystickNumButtons(jinfo));
119 log_info("Number of balls: %d", SDL_JoystickNumBalls(jinfo));
120 log_info("Number of hats: %d", SDL_JoystickNumHats(jinfo));
121
122 /* Flush stacked joystick events */
123 {
124 SDL_Event event;
125 while (SDL_PollEvent(&event));
126 }
127
128 joystick = 1;
129 } else {
130 log_error("Couldn't open Joystick #0");
131 joystick = 0;
132 }
133 }
134 }
135 }
136 }
137
input_quit(void)138 void input_quit(void)
139 {
140 if (joystick == 1)
141 {
142 if (jinfo != NULL)
143 {
144 SDL_JoystickClose(jinfo);
145 jinfo = NULL;
146 }
147 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
148 }
149 }
150
input_set_default_buttons(void)151 void input_set_default_buttons(void)
152 {
153 /* Set default button->action mapping */
154 int i = 0;
155 for (i = 0; i < NB_BUTTONS; i++)
156 input_set_button_action(i, ACTION_NOOP);
157
158 input_set_button_action( 1-1, ACTION_ATTACK);
159 input_set_button_action( 2-1, ACTION_TALK);
160 input_set_button_action( 3-1, ACTION_MAGIC);
161 input_set_button_action( 4-1, ACTION_INVENTORY);
162 input_set_button_action( 5-1, ACTION_MENU);
163 input_set_button_action( 6-1, ACTION_MAP);
164 input_set_button_action( 7-1, ACTION_BUTTON7);
165 input_set_button_action( 8-1, ACTION_BUTTON8);
166 input_set_button_action( 9-1, ACTION_BUTTON9);
167 input_set_button_action(10-1, ACTION_BUTTON10);
168
169 #ifdef _PSP
170 /* Alternate mapping, more consistent with other apps on PSP; in
171 addition, the buttons numbering/placement is different than on
172 PC, so it needs to be redefined anyway. */
173 /* Here are names for the button indices returned by SDL, 12 buttons
174 in [0,11]; home/hold/note/screen/vol+/vol- can't be used */
175 enum buttons_psp {
176 BUTTON_TRIANGLE=0, BUTTON_CIRCLE, BUTTON_CROSS, BUTTON_SQUARE,
177 BUTTON_LTRIGGER, BUTTON_RTRIGGER,
178 BUTTON_DOWN, BUTTON_LEFT, BUTTON_UP, BUTTON_RIGHT,
179 BUTTON_SELECT, BUTTON_START, BUTTON_HOME, BUTTON_HOLD };
180 input_set_button_action(BUTTON_TRIANGLE, ACTION_INVENTORY);
181 input_set_button_action(BUTTON_CIRCLE, ACTION_MAGIC);
182 input_set_button_action(BUTTON_CROSS, ACTION_ATTACK);
183 input_set_button_action(BUTTON_SQUARE, ACTION_TALK);
184 input_set_button_action(BUTTON_LTRIGGER, ACTION_MENU);
185 input_set_button_action(BUTTON_RTRIGGER, ACTION_MAP);
186 // TODO: make these also work like d/l/u/r:
187 input_set_button_action(BUTTON_DOWN, ACTION_DOWN);
188 input_set_button_action(BUTTON_LEFT, ACTION_LEFT);
189 input_set_button_action(BUTTON_UP, ACTION_UP);
190 input_set_button_action(BUTTON_RIGHT, ACTION_RIGHT);
191 /* TODO: we could also map:
192 - debug (Alt+D),
193 - pause/resume midi (Alt+N/B)
194 - fast-quit (Alt+Q) - fast-quit is somewhat already available
195 through the classic Home key, although handled differently. */
196 /* Let's also try to get a free key to possibly implement a
197 zooming/switch-view function for small screens, as well as a
198 virtual keyboard feature (like ScummVM)... */
199 /* Maybe also map inventory to start instead of Triangle. */
200 input_set_button_action(BUTTON_START, ACTION_INVENTORY);
201 #endif
202 }
203
input_get_button_action(int button_index)204 enum buttons_actions input_get_button_action(int button_index)
205 {
206 if (button_index >= 0 && button_index < NB_BUTTONS)
207 {
208 return buttons_map[button_index];
209 }
210 return -1; /* error */
211 }
212
213 /**
214 * Set what action will be triggered when button 'button_index' is
215 * pressed. Action '0' currently means 'do nothing'.
216 */
input_set_button_action(int button_index,enum buttons_actions action_index)217 void input_set_button_action(int button_index, enum buttons_actions action_index)
218 {
219 if (button_index >= 0 && button_index < NB_BUTTONS)
220 {
221 if (action_index >= ACTION_FIRST && action_index < ACTION_LAST)
222 buttons_map[button_index] = action_index;
223 else
224 log_error("Attempted to set invalid action %d", action_index);
225 }
226 else
227 {
228 log_error("Attempted to set invalid button %d (internal index %d)",
229 button_index+1, button_index);
230 }
231 }
232