Root/
Source at commit cb1b26e5e67d79ca9d03e85db06ec6c2e5b3557a created 8 years 5 months ago. By Maarten ter Huurne, Quit GMenu2X when window is closed in main screen | |
---|---|
1 | /*************************************************************************** |
2 | * Copyright (C) 2006 by Massimiliano Torromeo * |
3 | * massimiliano.torromeo@gmail.com * |
4 | * * |
5 | * This program is free software; you can redistribute it and/or modify * |
6 | * it under the terms of the GNU General Public License as published by * |
7 | * the Free Software Foundation; either version 2 of the License, or * |
8 | * (at your option) any later version. * |
9 | * * |
10 | * This program is distributed in the hope that it will be useful, * |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
13 | * GNU General Public License for more details. * |
14 | * * |
15 | * You should have received a copy of the GNU General Public License * |
16 | * along with this program; if not, write to the * |
17 | * Free Software Foundation, Inc., * |
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
19 | ***************************************************************************/ |
20 | |
21 | #include "debug.h" |
22 | #include "inputmanager.h" |
23 | #include "gmenu2x.h" |
24 | #include "utilities.h" |
25 | #include "powersaver.h" |
26 | #include "menu.h" |
27 | |
28 | #include <iostream> |
29 | #include <fstream> |
30 | |
31 | using namespace std; |
32 | |
33 | bool InputManager::init(Menu *menu) |
34 | { |
35 | this->menu = menu; |
36 | |
37 | repeatRateChanged(); |
38 | |
39 | for (int i = 0; i < BUTTON_TYPE_SIZE; i++) { |
40 | buttonMap[i].js_mapped = false; |
41 | buttonMap[i].kb_mapped = false; |
42 | } |
43 | |
44 | /* If a user-specified input.conf file exists, we load it; |
45 | * otherwise, we load the default one. */ |
46 | string input_file = gmenu2x.getHome() + "/input.conf"; |
47 | DEBUG("Loading user-specific input.conf file: %s.\n", input_file.c_str()); |
48 | if (!readConfFile(input_file)) { |
49 | input_file = GMENU2X_SYSTEM_DIR "/input.conf"; |
50 | DEBUG("Loading system input.conf file: %s.\n", input_file.c_str()); |
51 | if (!readConfFile(input_file)) { |
52 | ERROR("InputManager: failed to open config file\n"); |
53 | return false; |
54 | } |
55 | } |
56 | |
57 | return true; |
58 | } |
59 | |
60 | InputManager::InputManager(GMenu2X& gmenu2x, PowerSaver& powerSaver) |
61 | : gmenu2x(gmenu2x) |
62 | , powerSaver(powerSaver) |
63 | { |
64 | #ifndef SDL_JOYSTICK_DISABLED |
65 | int i; |
66 | |
67 | if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { |
68 | ERROR("Unable to init joystick subsystem\n"); |
69 | return; |
70 | } |
71 | |
72 | for (i = 0; i < SDL_NumJoysticks(); i++) { |
73 | struct Joystick joystick = { |
74 | SDL_JoystickOpen(i), false, false, false, false, |
75 | SDL_HAT_CENTERED, nullptr, this, |
76 | }; |
77 | joysticks.push_back(joystick); |
78 | } |
79 | |
80 | DEBUG("Opening %i joysticks\n", i); |
81 | #endif |
82 | } |
83 | |
84 | InputManager::~InputManager() |
85 | { |
86 | #ifndef SDL_JOYSTICK_DISABLED |
87 | for (auto it : joysticks) |
88 | SDL_JoystickClose(it.joystick); |
89 | #endif |
90 | } |
91 | |
92 | bool InputManager::readConfFile(const string &conffile) { |
93 | ifstream inf(conffile.c_str(), ios_base::in); |
94 | if (inf.is_open()) { |
95 | string line; |
96 | while (getline(inf, line, '\n')) { |
97 | string::size_type pos = line.find("="); |
98 | string name = trim(line.substr(0,pos)); |
99 | line = trim(line.substr(pos+1,line.length())); |
100 | |
101 | Button button; |
102 | if (name == "up") button = UP; |
103 | else if (name == "down") button = DOWN; |
104 | else if (name == "left") button = LEFT; |
105 | else if (name == "right") button = RIGHT; |
106 | else if (name == "accept") button = ACCEPT; |
107 | else if (name == "cancel") button = CANCEL; |
108 | else if (name == "altleft") button = ALTLEFT; |
109 | else if (name == "altright") button = ALTRIGHT; |
110 | else if (name == "menu") button = MENU; |
111 | else if (name == "settings") button = SETTINGS; |
112 | else { |
113 | WARNING("InputManager: Ignoring unknown button name \"%s\"\n", |
114 | name.c_str()); |
115 | continue; |
116 | } |
117 | |
118 | pos = line.find(","); |
119 | string sourceStr = trim(line.substr(0,pos)); |
120 | line = trim(line.substr(pos+1, line.length())); |
121 | |
122 | if (sourceStr == "keyboard") { |
123 | buttonMap[button].kb_mapped = true; |
124 | buttonMap[button].kb_code = atoi(line.c_str()); |
125 | #ifndef SDL_JOYSTICK_DISABLED |
126 | } else if (sourceStr == "joystick") { |
127 | buttonMap[button].js_mapped = true; |
128 | buttonMap[button].js_code = atoi(line.c_str()); |
129 | #endif |
130 | } else { |
131 | WARNING("InputManager: Ignoring unknown button source \"%s\"\n", |
132 | sourceStr.c_str()); |
133 | continue; |
134 | } |
135 | } |
136 | |
137 | inf.close(); |
138 | return true; |
139 | } else { |
140 | return false; |
141 | } |
142 | } |
143 | |
144 | InputManager::Button InputManager::waitForPressedButton() { |
145 | Button button; |
146 | while (!getButton(&button, true)); |
147 | return button; |
148 | } |
149 | |
150 | static int repeatRateMs(int repeatRate) |
151 | { |
152 | return repeatRate == 0 ? 0 : 1000 / repeatRate; |
153 | } |
154 | |
155 | void InputManager::repeatRateChanged() { |
156 | int ms = repeatRateMs(gmenu2x.confInt["buttonRepeatRate"]); |
157 | if (ms == 0) { |
158 | SDL_EnableKeyRepeat(0, 0); |
159 | } else { |
160 | SDL_EnableKeyRepeat(INPUT_KEY_REPEAT_DELAY, ms); |
161 | } |
162 | } |
163 | |
164 | bool InputManager::pollButton(Button *button) { |
165 | return getButton(button, false); |
166 | } |
167 | |
168 | bool InputManager::getButton(Button *button, bool wait) { |
169 | //TODO: when an event is processed, program a new event |
170 | //in some time, and when it occurs, do a key repeat |
171 | |
172 | #ifndef SDL_JOYSTICK_DISABLED |
173 | if (joysticks.size() > 0) |
174 | SDL_JoystickUpdate(); |
175 | #endif |
176 | |
177 | SDL_Event event; |
178 | if (wait) |
179 | SDL_WaitEvent(&event); |
180 | else if (!SDL_PollEvent(&event)) |
181 | return false; |
182 | |
183 | bool is_kb = false, is_js = false; |
184 | switch(event.type) { |
185 | case SDL_KEYDOWN: |
186 | is_kb = true; |
187 | break; |
188 | #ifndef SDL_JOYSTICK_DISABLED |
189 | case SDL_JOYHATMOTION: { |
190 | Joystick *joystick = &joysticks[event.jaxis.which]; |
191 | joystick->hatState = event.jhat.value; |
192 | |
193 | switch (event.jhat.value) { |
194 | case SDL_HAT_CENTERED: |
195 | stopTimer(joystick); |
196 | return false; |
197 | case SDL_HAT_UP: |
198 | *button = UP; |
199 | break; |
200 | case SDL_HAT_DOWN: |
201 | *button = DOWN; |
202 | break; |
203 | case SDL_HAT_LEFT: |
204 | *button = LEFT; |
205 | break; |
206 | case SDL_HAT_RIGHT: |
207 | *button = RIGHT; |
208 | break; |
209 | } |
210 | startTimer(joystick); |
211 | } |
212 | case SDL_JOYBUTTONDOWN: |
213 | is_js = true; |
214 | break; |
215 | case SDL_JOYAXISMOTION: { |
216 | is_js = true; |
217 | |
218 | unsigned int axis = event.jaxis.axis; |
219 | /* We only handle the first joystick */ |
220 | if (axis > 1) |
221 | return false; |
222 | |
223 | Joystick *joystick = &joysticks[event.jaxis.which]; |
224 | bool *axisState = joystick->axisState[axis]; |
225 | |
226 | if (event.jaxis.value < -20000) { |
227 | if (axisState[AXIS_STATE_NEGATIVE]) |
228 | return false; |
229 | axisState[AXIS_STATE_NEGATIVE] = true; |
230 | axisState[AXIS_STATE_POSITIVE] = false; |
231 | *button = axis ? UP : LEFT; |
232 | } else if (event.jaxis.value > 20000) { |
233 | if (axisState[AXIS_STATE_POSITIVE]) |
234 | return false; |
235 | axisState[AXIS_STATE_NEGATIVE] = false; |
236 | axisState[AXIS_STATE_POSITIVE] = true; |
237 | *button = axis ? DOWN : RIGHT; |
238 | } else { |
239 | bool *otherAxisState = joystick->axisState[!axis]; |
240 | if (!otherAxisState[AXIS_STATE_NEGATIVE] && |
241 | !otherAxisState[AXIS_STATE_POSITIVE] && ( |
242 | axisState[AXIS_STATE_NEGATIVE] || |
243 | axisState[AXIS_STATE_POSITIVE])) |
244 | stopTimer(joystick); |
245 | |
246 | axisState[0] = axisState[1] = false; |
247 | return false; |
248 | } |
249 | startTimer(joystick); |
250 | break; |
251 | } |
252 | #endif |
253 | case SDL_USEREVENT: |
254 | switch ((enum EventCode) event.user.code) { |
255 | #ifdef HAVE_LIBOPK |
256 | case REMOVE_LINKS: |
257 | menu->removePackageLink((const char *) event.user.data1); |
258 | break; |
259 | case OPEN_PACKAGE: |
260 | menu->openPackage((const char *) event.user.data1); |
261 | break; |
262 | case OPEN_PACKAGES_FROM_DIR: |
263 | menu->openPackagesFromDir( |
264 | ((string) (const char *) event.user.data1 |
265 | + "/apps").c_str()); |
266 | break; |
267 | #endif /* HAVE_LIBOPK */ |
268 | case REPAINT_MENU: |
269 | default: |
270 | break; |
271 | } |
272 | |
273 | if (event.user.data1) |
274 | free(event.user.data1); |
275 | *button = REPAINT; |
276 | return true; |
277 | |
278 | case SDL_QUIT: |
279 | *button = QUIT; |
280 | return true; |
281 | |
282 | default: |
283 | return false; |
284 | } |
285 | |
286 | int i = 0; |
287 | if (is_kb) { |
288 | for (i = 0; i < BUTTON_TYPE_SIZE; i++) { |
289 | if (buttonMap[i].kb_mapped |
290 | && (unsigned int)event.key.keysym.sym == buttonMap[i].kb_code) { |
291 | *button = static_cast<Button>(i); |
292 | break; |
293 | } |
294 | } |
295 | #ifndef SDL_JOYSTICK_DISABLED |
296 | } else if (is_js && event.type == SDL_JOYBUTTONDOWN) { |
297 | for (i = 0; i < BUTTON_TYPE_SIZE; i++) { |
298 | if (buttonMap[i].js_mapped |
299 | && (unsigned int)event.jbutton.button == buttonMap[i].js_code) { |
300 | *button = static_cast<Button>(i); |
301 | break; |
302 | } |
303 | } |
304 | #endif |
305 | } |
306 | |
307 | if (i == BUTTON_TYPE_SIZE) |
308 | return false; |
309 | |
310 | if (wait) { |
311 | powerSaver.resetScreenTimer(); |
312 | } |
313 | |
314 | return true; |
315 | } |
316 | |
317 | Uint32 keyRepeatCallback(Uint32 timeout, void *d) |
318 | { |
319 | struct Joystick *joystick = (struct Joystick *) d; |
320 | return joystick->inputManager->joystickRepeatCallback(timeout, joystick); |
321 | } |
322 | |
323 | void InputManager::startTimer(Joystick *joystick) |
324 | { |
325 | if (joystick->timer) |
326 | return; |
327 | |
328 | joystick->timer = SDL_AddTimer(INPUT_KEY_REPEAT_DELAY, |
329 | keyRepeatCallback, joystick); |
330 | } |
331 | |
332 | Uint32 InputManager::joystickRepeatCallback(Uint32 timeout __attribute__((unused)), struct Joystick *joystick) |
333 | { |
334 | Uint8 hatState; |
335 | |
336 | if (joystick->axisState[1][AXIS_STATE_NEGATIVE]) |
337 | hatState = SDL_HAT_UP; |
338 | else if (joystick->axisState[1][AXIS_STATE_POSITIVE]) |
339 | hatState = SDL_HAT_DOWN; |
340 | else if (joystick->axisState[0][AXIS_STATE_NEGATIVE]) |
341 | hatState = SDL_HAT_LEFT; |
342 | else if (joystick->axisState[0][AXIS_STATE_POSITIVE]) |
343 | hatState = SDL_HAT_RIGHT; |
344 | else |
345 | hatState = joystick->hatState; |
346 | |
347 | SDL_JoyHatEvent e = { |
348 | .type = SDL_JOYHATMOTION, |
349 | .which = (Uint8) SDL_JoystickIndex(joystick->joystick), |
350 | .hat = 0, |
351 | .value = hatState, |
352 | }; |
353 | SDL_PushEvent((SDL_Event *) &e); |
354 | |
355 | return repeatRateMs(gmenu2x.confInt["buttonRepeatRate"]); |
356 | } |
357 | |
358 | void InputManager::stopTimer(Joystick *joystick) |
359 | { |
360 | if (joystick->timer) { |
361 | SDL_RemoveTimer(joystick->timer); |
362 | joystick->timer = nullptr; |
363 | } |
364 | } |
365 |
Branches:
install_locations
master
opkrun
packages