/*************************************************************************** * Copyright (C) 2006 by Massimiliano Torromeo * * massimiliano.torromeo@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "debug.h" #include "inputmanager.h" #include "gmenu2x.h" #include "utilities.h" #include "powersaver.h" #include "menu.h" #include #include using namespace std; void InputManager::init(GMenu2X *gmenu2x, const string &conffile, Menu *menu) { this->gmenu2x = gmenu2x; this->menu = menu; repeatRateChanged(); for (int i = 0; i < BUTTON_TYPE_SIZE; i++) { buttonMap[i].js_mapped = false; buttonMap[i].kb_mapped = false; } readConfFile(conffile); } InputManager::InputManager() { #ifndef SDL_JOYSTICK_DISABLED int i; if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { ERROR("Unable to init joystick subsystem\n"); return; } for (i = 0; i < SDL_NumJoysticks(); i++) { struct Joystick joystick = { SDL_JoystickOpen(i), false, false, false, false, SDL_HAT_CENTERED, nullptr, this, }; joysticks.push_back(joystick); } DEBUG("Opening %i joysticks\n", i); #endif } InputManager::~InputManager() { #ifndef SDL_JOYSTICK_DISABLED for (auto it : joysticks) SDL_JoystickClose(it.joystick); #endif } void InputManager::readConfFile(const string &conffile) { ifstream inf(conffile.c_str(), ios_base::in); if (inf.fail()) { ERROR("InputManager: failed to open config file\n"); return; } string line; while (getline(inf, line, '\n')) { string::size_type pos = line.find("="); string name = trim(line.substr(0,pos)); line = trim(line.substr(pos+1,line.length())); Button button; if (name == "up") button = UP; else if (name == "down") button = DOWN; else if (name == "left") button = LEFT; else if (name == "right") button = RIGHT; else if (name == "accept") button = ACCEPT; else if (name == "cancel") button = CANCEL; else if (name == "altleft") button = ALTLEFT; else if (name == "altright") button = ALTRIGHT; else if (name == "menu") button = MENU; else if (name == "settings") button = SETTINGS; else { WARNING("InputManager: Ignoring unknown button name \"%s\"\n", name.c_str()); continue; } pos = line.find(","); string sourceStr = trim(line.substr(0,pos)); line = trim(line.substr(pos+1, line.length())); if (sourceStr == "keyboard") { buttonMap[button].kb_mapped = true; buttonMap[button].kb_code = atoi(line.c_str()); #ifndef SDL_JOYSTICK_DISABLED } else if (sourceStr == "joystick") { buttonMap[button].js_mapped = true; buttonMap[button].js_code = atoi(line.c_str()); #endif } else { WARNING("InputManager: Ignoring unknown button source \"%s\"\n", sourceStr.c_str()); continue; } } inf.close(); } InputManager::Button InputManager::waitForPressedButton() { Button button; while (!getButton(&button, true)); return button; } static int repeatRateMs(int repeatRate) { return repeatRate == 0 ? 0 : 1000 / repeatRate; } void InputManager::repeatRateChanged() { int ms = repeatRateMs(gmenu2x->confInt["buttonRepeatRate"]); if (ms == 0) { SDL_EnableKeyRepeat(0, 0); } else { SDL_EnableKeyRepeat(INPUT_KEY_REPEAT_DELAY, ms); } } bool InputManager::pollButton(Button *button) { return getButton(button, false); } bool InputManager::getButton(Button *button, bool wait) { //TODO: when an event is processed, program a new event //in some time, and when it occurs, do a key repeat #ifndef SDL_JOYSTICK_DISABLED if (joysticks.size() > 0) SDL_JoystickUpdate(); #endif SDL_Event event; if (wait) SDL_WaitEvent(&event); else if (!SDL_PollEvent(&event)) return false; bool is_kb = false, is_js = false; switch(event.type) { case SDL_KEYDOWN: is_kb = true; break; #ifndef SDL_JOYSTICK_DISABLED case SDL_JOYHATMOTION: { Joystick *joystick = &joysticks[event.jaxis.which]; joystick->hatState = event.jhat.value; switch (event.jhat.value) { case SDL_HAT_CENTERED: stopTimer(joystick); return false; case SDL_HAT_UP: *button = UP; break; case SDL_HAT_DOWN: *button = DOWN; break; case SDL_HAT_LEFT: *button = LEFT; break; case SDL_HAT_RIGHT: *button = RIGHT; break; } startTimer(joystick); } case SDL_JOYBUTTONDOWN: is_js = true; break; case SDL_JOYAXISMOTION: { is_js = true; unsigned int axis = event.jaxis.axis; /* We only handle the first joystick */ if (axis > 1) return false; Joystick *joystick = &joysticks[event.jaxis.which]; bool *axisState = joystick->axisState[axis]; if (event.jaxis.value < -20000) { if (axisState[AXIS_STATE_NEGATIVE]) return false; axisState[AXIS_STATE_NEGATIVE] = true; axisState[AXIS_STATE_POSITIVE] = false; *button = axis ? UP : LEFT; } else if (event.jaxis.value > 20000) { if (axisState[AXIS_STATE_POSITIVE]) return false; axisState[AXIS_STATE_NEGATIVE] = false; axisState[AXIS_STATE_POSITIVE] = true; *button = axis ? DOWN : RIGHT; } else { bool *otherAxisState = joystick->axisState[!axis]; if (!otherAxisState[AXIS_STATE_NEGATIVE] && !otherAxisState[AXIS_STATE_POSITIVE] && ( axisState[AXIS_STATE_NEGATIVE] || axisState[AXIS_STATE_POSITIVE])) stopTimer(joystick); axisState[0] = axisState[1] = false; return false; } startTimer(joystick); break; } #endif case SDL_USEREVENT: switch ((enum EventCode) event.user.code) { #ifdef HAVE_LIBOPK case REMOVE_LINKS: menu->removePackageLink((const char *) event.user.data1); break; case OPEN_PACKAGE: menu->openPackage((const char *) event.user.data1); break; case OPEN_PACKAGES_FROM_DIR: menu->openPackagesFromDir( ((string) (const char *) event.user.data1 + "/apps").c_str()); break; #endif /* HAVE_LIBOPK */ case REPAINT_MENU: default: break; } if (event.user.data1) free(event.user.data1); *button = REPAINT; return true; default: return false; } int i = 0; if (is_kb) { for (i = 0; i < BUTTON_TYPE_SIZE; i++) { if (buttonMap[i].kb_mapped && (unsigned int)event.key.keysym.sym == buttonMap[i].kb_code) { *button = static_cast