2010-02-04 13:33:47 +02:00
|
|
|
/***************************************************************************
|
2011-10-23 08:49:43 +03:00
|
|
|
* Copyright (C) 2006 by Massimiliano Torromeo *
|
|
|
|
* massimiliano.torromeo@gmail.com *
|
2010-02-04 13:33:47 +02:00
|
|
|
* *
|
|
|
|
* 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. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
2010-09-17 23:34:26 +03:00
|
|
|
#include "debug.h"
|
|
|
|
#include "inputmanager.h"
|
2014-06-19 00:12:11 +03:00
|
|
|
#include "gmenu2x.h"
|
2010-09-17 23:34:26 +03:00
|
|
|
#include "utilities.h"
|
2011-06-02 06:04:35 +03:00
|
|
|
#include "powersaver.h"
|
2013-07-16 20:36:18 +03:00
|
|
|
#include "menu.h"
|
2010-09-17 23:34:26 +03:00
|
|
|
|
2010-02-04 13:33:47 +02:00
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
2010-09-17 23:31:09 +03:00
|
|
|
|
2011-10-23 09:15:23 +03:00
|
|
|
using namespace std;
|
|
|
|
|
2014-06-19 00:12:11 +03:00
|
|
|
void InputManager::init(GMenu2X *gmenu2x, const string &conffile, Menu *menu) {
|
|
|
|
this->gmenu2x = gmenu2x;
|
2013-07-16 20:36:18 +03:00
|
|
|
this->menu = menu;
|
|
|
|
|
2014-06-19 00:12:11 +03:00
|
|
|
repeatRateChanged();
|
|
|
|
|
2011-10-23 11:38:39 +03:00
|
|
|
for (int i = 0; i < BUTTON_TYPE_SIZE; i++) {
|
2014-04-20 17:08:17 +03:00
|
|
|
buttonMap[i].js_mapped = false;
|
|
|
|
buttonMap[i].kb_mapped = false;
|
2011-10-23 08:49:43 +03:00
|
|
|
}
|
2011-10-23 11:38:39 +03:00
|
|
|
readConfFile(conffile);
|
2010-09-17 23:34:26 +03:00
|
|
|
}
|
|
|
|
|
2011-10-23 10:59:22 +03:00
|
|
|
InputManager::InputManager()
|
|
|
|
{
|
2011-10-23 11:12:11 +03:00
|
|
|
#ifndef SDL_JOYSTICK_DISABLED
|
2013-07-29 08:28:52 +03:00
|
|
|
int i;
|
2013-07-29 23:54:12 +03:00
|
|
|
|
|
|
|
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
|
|
|
|
ERROR("Unable to init joystick subsystem\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-07 18:09:56 +03:00
|
|
|
for (i = 0; i < SDL_NumJoysticks(); i++) {
|
|
|
|
struct Joystick joystick = {
|
|
|
|
SDL_JoystickOpen(i), false, false, false, false,
|
2014-06-19 00:12:11 +03:00
|
|
|
SDL_HAT_CENTERED, nullptr, this,
|
2013-09-07 18:09:56 +03:00
|
|
|
};
|
|
|
|
joysticks.push_back(joystick);
|
|
|
|
}
|
|
|
|
|
2013-07-29 23:54:12 +03:00
|
|
|
DEBUG("Opening %i joysticks\n", i);
|
2011-10-23 11:12:11 +03:00
|
|
|
#endif
|
2010-02-04 13:33:47 +02:00
|
|
|
}
|
|
|
|
|
2013-07-29 08:28:52 +03:00
|
|
|
InputManager::~InputManager()
|
|
|
|
{
|
2011-10-23 11:12:11 +03:00
|
|
|
#ifndef SDL_JOYSTICK_DISABLED
|
2013-09-07 18:09:56 +03:00
|
|
|
for (auto it : joysticks)
|
|
|
|
SDL_JoystickClose(it.joystick);
|
2011-10-23 11:12:11 +03:00
|
|
|
#endif
|
2010-02-04 13:33:47 +02:00
|
|
|
}
|
|
|
|
|
2011-10-23 11:38:39 +03:00
|
|
|
void InputManager::readConfFile(const string &conffile) {
|
2011-10-23 08:49:43 +03:00
|
|
|
ifstream inf(conffile.c_str(), ios_base::in);
|
2011-10-23 11:38:39 +03:00
|
|
|
if (inf.fail()) {
|
|
|
|
ERROR("InputManager: failed to open config file\n");
|
|
|
|
return;
|
2011-10-23 08:49:43 +03:00
|
|
|
}
|
|
|
|
|
2011-10-23 11:38:39 +03:00
|
|
|
string line;
|
|
|
|
while (getline(inf, line, '\n')) {
|
|
|
|
string::size_type pos = line.find("=");
|
|
|
|
string name = trim(line.substr(0,pos));
|
2011-10-23 08:49:43 +03:00
|
|
|
line = trim(line.substr(pos+1,line.length()));
|
|
|
|
|
2011-10-23 11:38:39 +03:00
|
|
|
Button button;
|
2011-10-23 08:49:43 +03:00
|
|
|
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;
|
2011-10-23 11:38:39 +03:00
|
|
|
else {
|
|
|
|
WARNING("InputManager: Ignoring unknown button name \"%s\"\n",
|
|
|
|
name.c_str());
|
|
|
|
continue;
|
|
|
|
}
|
2011-10-23 08:49:43 +03:00
|
|
|
|
|
|
|
pos = line.find(",");
|
2011-10-23 11:38:39 +03:00
|
|
|
string sourceStr = trim(line.substr(0,pos));
|
2011-10-23 08:49:43 +03:00
|
|
|
line = trim(line.substr(pos+1, line.length()));
|
|
|
|
|
2011-10-23 11:38:39 +03:00
|
|
|
if (sourceStr == "keyboard") {
|
2014-04-20 17:08:17 +03:00
|
|
|
buttonMap[button].kb_mapped = true;
|
|
|
|
buttonMap[button].kb_code = atoi(line.c_str());
|
2011-10-23 11:38:39 +03:00
|
|
|
#ifndef SDL_JOYSTICK_DISABLED
|
|
|
|
} else if (sourceStr == "joystick") {
|
2014-04-20 17:08:17 +03:00
|
|
|
buttonMap[button].js_mapped = true;
|
|
|
|
buttonMap[button].js_code = atoi(line.c_str());
|
2011-10-23 11:12:11 +03:00
|
|
|
#endif
|
|
|
|
} else {
|
2011-10-23 11:38:39 +03:00
|
|
|
WARNING("InputManager: Ignoring unknown button source \"%s\"\n",
|
|
|
|
sourceStr.c_str());
|
|
|
|
continue;
|
2011-10-23 11:12:11 +03:00
|
|
|
}
|
2011-10-23 08:49:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
inf.close();
|
2010-02-04 13:33:47 +02:00
|
|
|
}
|
|
|
|
|
2011-10-23 09:57:52 +03:00
|
|
|
InputManager::Button InputManager::waitForPressedButton() {
|
2013-09-07 18:00:57 +03:00
|
|
|
Button button;
|
|
|
|
while (!getButton(&button, true));
|
|
|
|
return button;
|
2010-02-04 13:33:47 +02:00
|
|
|
}
|
|
|
|
|
2014-06-19 00:12:11 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-07 18:00:57 +03:00
|
|
|
bool InputManager::pollButton(Button *button) {
|
|
|
|
return getButton(button, false);
|
2010-02-04 13:33:47 +02:00
|
|
|
}
|
|
|
|
|
2013-09-07 18:00:57 +03:00
|
|
|
bool InputManager::getButton(Button *button, bool wait) {
|
2011-10-23 08:49:43 +03:00
|
|
|
//TODO: when an event is processed, program a new event
|
|
|
|
//in some time, and when it occurs, do a key repeat
|
|
|
|
|
2011-10-23 11:12:11 +03:00
|
|
|
#ifndef SDL_JOYSTICK_DISABLED
|
2013-07-29 08:28:52 +03:00
|
|
|
if (joysticks.size() > 0)
|
2011-10-23 10:59:22 +03:00
|
|
|
SDL_JoystickUpdate();
|
2011-10-23 11:12:11 +03:00
|
|
|
#endif
|
2013-07-29 08:28:52 +03:00
|
|
|
|
2011-10-23 08:49:43 +03:00
|
|
|
SDL_Event event;
|
2013-09-07 18:00:57 +03:00
|
|
|
if (wait)
|
2011-10-23 08:49:43 +03:00
|
|
|
SDL_WaitEvent(&event);
|
2013-09-07 18:00:57 +03:00
|
|
|
else if (!SDL_PollEvent(&event))
|
|
|
|
return false;
|
2011-10-23 08:49:43 +03:00
|
|
|
|
2014-04-20 17:08:17 +03:00
|
|
|
bool is_kb = false, is_js = false;
|
2011-10-23 08:49:43 +03:00
|
|
|
switch(event.type) {
|
|
|
|
case SDL_KEYDOWN:
|
2014-04-20 17:08:17 +03:00
|
|
|
is_kb = true;
|
2011-10-23 08:49:43 +03:00
|
|
|
break;
|
2011-10-23 11:12:11 +03:00
|
|
|
#ifndef SDL_JOYSTICK_DISABLED
|
2014-02-23 18:00:12 +02:00
|
|
|
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);
|
2013-12-30 16:41:52 +02:00
|
|
|
}
|
2011-10-23 08:49:43 +03:00
|
|
|
case SDL_JOYBUTTONDOWN:
|
2014-04-20 17:08:17 +03:00
|
|
|
is_js = true;
|
2011-10-23 08:49:43 +03:00
|
|
|
break;
|
2013-09-07 18:09:56 +03:00
|
|
|
case SDL_JOYAXISMOTION: {
|
2014-04-20 17:08:17 +03:00
|
|
|
is_js = true;
|
2013-09-07 18:09:56 +03:00
|
|
|
|
|
|
|
unsigned int axis = event.jaxis.axis;
|
|
|
|
/* We only handle the first joystick */
|
|
|
|
if (axis > 1)
|
|
|
|
return false;
|
|
|
|
|
2014-02-23 18:00:12 +02:00
|
|
|
Joystick *joystick = &joysticks[event.jaxis.which];
|
|
|
|
bool *axisState = joystick->axisState[axis];
|
2013-09-07 18:09:56 +03:00
|
|
|
|
|
|
|
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 {
|
2014-02-23 18:00:12 +02:00
|
|
|
bool *otherAxisState = joystick->axisState[!axis];
|
|
|
|
if (!otherAxisState[AXIS_STATE_NEGATIVE] &&
|
|
|
|
!otherAxisState[AXIS_STATE_POSITIVE] && (
|
|
|
|
axisState[AXIS_STATE_NEGATIVE] ||
|
|
|
|
axisState[AXIS_STATE_POSITIVE]))
|
|
|
|
stopTimer(joystick);
|
|
|
|
|
2013-09-07 18:09:56 +03:00
|
|
|
axisState[0] = axisState[1] = false;
|
|
|
|
return false;
|
|
|
|
}
|
2014-02-23 18:00:12 +02:00
|
|
|
startTimer(joystick);
|
2013-09-07 18:09:56 +03:00
|
|
|
break;
|
|
|
|
}
|
2011-10-23 11:12:11 +03:00
|
|
|
#endif
|
2013-07-16 20:36:18 +03:00
|
|
|
case SDL_USEREVENT:
|
2013-07-22 06:52:35 +03:00
|
|
|
switch ((enum EventCode) event.user.code) {
|
2013-09-19 18:26:32 +03:00
|
|
|
#ifdef HAVE_LIBOPK
|
2013-07-22 06:52:35 +03:00
|
|
|
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;
|
2013-09-19 18:26:32 +03:00
|
|
|
#endif /* HAVE_LIBOPK */
|
2013-07-22 06:52:35 +03:00
|
|
|
case REPAINT_MENU:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.user.data1)
|
|
|
|
free(event.user.data1);
|
2013-09-07 18:00:57 +03:00
|
|
|
*button = REPAINT;
|
2013-07-16 20:36:18 +03:00
|
|
|
return true;
|
2013-07-22 06:52:35 +03:00
|
|
|
|
2011-10-23 08:49:43 +03:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-07 18:09:56 +03:00
|
|
|
int i = 0;
|
2014-04-20 17:08:17 +03:00
|
|
|
if (is_kb) {
|
2012-01-22 22:49:52 +02:00
|
|
|
for (i = 0; i < BUTTON_TYPE_SIZE; i++) {
|
2014-04-20 17:08:17 +03:00
|
|
|
if (buttonMap[i].kb_mapped
|
|
|
|
&& (unsigned int)event.key.keysym.sym == buttonMap[i].kb_code) {
|
2013-09-07 18:00:57 +03:00
|
|
|
*button = static_cast<Button>(i);
|
2011-10-23 08:49:43 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-10-23 11:12:11 +03:00
|
|
|
#ifndef SDL_JOYSTICK_DISABLED
|
2014-04-20 17:08:17 +03:00
|
|
|
} else if (is_js && event.type == SDL_JOYBUTTONDOWN) {
|
2012-01-22 22:49:52 +02:00
|
|
|
for (i = 0; i < BUTTON_TYPE_SIZE; i++) {
|
2014-04-20 17:08:17 +03:00
|
|
|
if (buttonMap[i].js_mapped
|
|
|
|
&& (unsigned int)event.jbutton.button == buttonMap[i].js_code) {
|
2013-09-07 18:00:57 +03:00
|
|
|
*button = static_cast<Button>(i);
|
2011-10-23 08:49:43 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-10-23 11:12:11 +03:00
|
|
|
#endif
|
2011-10-23 08:49:43 +03:00
|
|
|
}
|
2012-01-22 22:49:52 +02:00
|
|
|
|
|
|
|
if (i == BUTTON_TYPE_SIZE)
|
|
|
|
return false;
|
|
|
|
|
2011-10-23 08:49:43 +03:00
|
|
|
if (wait && PowerSaver::isRunning()) {
|
|
|
|
PowerSaver::getInstance()->resetScreenTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2010-02-04 13:33:47 +02:00
|
|
|
}
|
2014-02-23 18:00:12 +02:00
|
|
|
|
2014-06-19 00:12:11 +03:00
|
|
|
Uint32 keyRepeatCallback(Uint32 timeout, void *d)
|
2014-02-23 18:00:12 +02:00
|
|
|
{
|
|
|
|
struct Joystick *joystick = (struct Joystick *) d;
|
2014-06-19 00:12:11 +03:00
|
|
|
return joystick->inputManager->joystickRepeatCallback(timeout, joystick);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputManager::startTimer(Joystick *joystick)
|
|
|
|
{
|
|
|
|
if (joystick->timer)
|
|
|
|
return;
|
|
|
|
|
|
|
|
joystick->timer = SDL_AddTimer(INPUT_KEY_REPEAT_DELAY,
|
|
|
|
keyRepeatCallback, joystick);
|
|
|
|
}
|
|
|
|
|
|
|
|
Uint32 InputManager::joystickRepeatCallback(Uint32 timeout __attribute__((unused)), struct Joystick *joystick)
|
|
|
|
{
|
2014-02-24 23:34:53 +02:00
|
|
|
Uint8 hatState;
|
2014-02-23 18:00:12 +02:00
|
|
|
|
|
|
|
if (joystick->axisState[1][AXIS_STATE_NEGATIVE])
|
2014-02-24 23:34:53 +02:00
|
|
|
hatState = SDL_HAT_UP;
|
2014-02-23 18:00:12 +02:00
|
|
|
else if (joystick->axisState[1][AXIS_STATE_POSITIVE])
|
2014-02-24 23:34:53 +02:00
|
|
|
hatState = SDL_HAT_DOWN;
|
|
|
|
else if (joystick->axisState[0][AXIS_STATE_NEGATIVE])
|
|
|
|
hatState = SDL_HAT_LEFT;
|
2014-02-23 18:00:12 +02:00
|
|
|
else if (joystick->axisState[0][AXIS_STATE_POSITIVE])
|
2014-02-24 23:34:53 +02:00
|
|
|
hatState = SDL_HAT_RIGHT;
|
|
|
|
else
|
|
|
|
hatState = joystick->hatState;
|
2014-02-23 18:00:12 +02:00
|
|
|
|
|
|
|
SDL_JoyHatEvent e = {
|
|
|
|
.type = SDL_JOYHATMOTION,
|
|
|
|
.which = (Uint8) SDL_JoystickIndex(joystick->joystick),
|
|
|
|
.hat = 0,
|
|
|
|
.value = hatState,
|
|
|
|
};
|
|
|
|
SDL_PushEvent((SDL_Event *) &e);
|
|
|
|
|
2014-06-19 00:12:11 +03:00
|
|
|
return repeatRateMs(gmenu2x->confInt["buttonRepeatRate"]);
|
2014-02-23 18:00:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void InputManager::stopTimer(Joystick *joystick)
|
|
|
|
{
|
|
|
|
if (joystick->timer) {
|
|
|
|
SDL_RemoveTimer(joystick->timer);
|
|
|
|
joystick->timer = nullptr;
|
|
|
|
}
|
|
|
|
}
|