/* * Copyright (C) 2007-2010 Team XBMC * http://www.xbmc.org * * 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, 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 XBMC; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * http://www.gnu.org/copyleft/gpl.html * */ #include "system.h" #include "../Key.h" #include "SDLJoystick.h" #include "ButtonTranslator.h" #include "AdvancedSettings.h" #include "utils/log.h" #include #ifdef HAS_SDL_JOYSTICK using namespace std; CJoystick g_Joystick; // global CJoystick::CJoystick() { Reset(); m_NumAxes = 0; m_AxisId = 0; m_JoyId = 0; m_ButtonId = 0; m_HatId = 0; m_HatState = SDL_HAT_CENTERED; m_ActiveFlags = JACTIVE_NONE; for (int i = 0 ; i0) { for(size_t idJoy = 0; idJoy < m_Joysticks.size(); idJoy++) { // any joysticks unplugged? if(SDL_JoystickOpened(idJoy)) SDL_JoystickClose(m_Joysticks[idJoy]); } m_Joysticks.clear(); m_JoyId = -1; } // Set deadzone range SetDeadzone(g_advancedSettings.m_controllerDeadzone); // any joysticks connected? if (SDL_NumJoysticks()>0) { // load joystick names and open all connected joysticks for (int i = 0 ; iMAX_AXES)?MAX_AXES:numax; int axisval; uint8_t hatval; // get button states first, they take priority over axis for (int b = 0 ; b=MAX_AXES) { CLog::Log(LOGERROR, "Axis Id out of range. Maximum supported axis: %d", MAX_AXES); } else { m_Amount[axisId] = axisval; //[-32768 to 32767] } } m_AxisId = GetAxisWithMaxAmount(); if (m_AxisId) { m_JoyId = j; j = numj-1; break; } } if(hatId==-1) { if(m_HatId!=0) CLog::Log(LOGDEBUG, "Joystick %d hat %u Centered", m_JoyId, hatId); m_pressTicksHat = 0; SetHatActive(false); m_HatId = 0; } else { if(hatId!=m_HatId) { CLog::Log(LOGDEBUG, "Joystick %d hat %u Down", m_JoyId, hatId); m_HatId = hatId; m_pressTicksHat = SDL_GetTicks(); } SetHatActive(); } if (buttonId==-1) { if (m_ButtonId!=0) { CLog::Log(LOGDEBUG, "Joystick %d button %d Up", m_JoyId, m_ButtonId); } m_pressTicksButton = 0; SetButtonActive(false); m_ButtonId = 0; } else { if (buttonId!=m_ButtonId) { CLog::Log(LOGDEBUG, "Joystick %d button %d Down", m_JoyId, buttonId); m_ButtonId = buttonId; m_pressTicksButton = SDL_GetTicks(); } SetButtonActive(); } } void CJoystick::Update(SDL_Event& joyEvent) { int buttonId = -1; int axisId = -1; int joyId = -1; bool ignore = false; // not used for now bool axis = false; switch(joyEvent.type) { case SDL_JOYBUTTONDOWN: m_JoyId = joyId = joyEvent.jbutton.which; m_ButtonId = buttonId = joyEvent.jbutton.button + 1; m_pressTicksButton = SDL_GetTicks(); SetButtonActive(); CLog::Log(LOGDEBUG, "Joystick %d button %d Down", joyId, buttonId); break; case SDL_JOYAXISMOTION: joyId = joyEvent.jaxis.which; axisId = joyEvent.jaxis.axis + 1; m_NumAxes = SDL_JoystickNumAxes(m_Joysticks[joyId]); if (axisId<=0 || axisId>=MAX_AXES) { CLog::Log(LOGERROR, "Axis Id out of range. Maximum supported axis: %d", MAX_AXES); ignore = true; break; } axis = true; m_JoyId = joyId; if (joyEvent.jaxis.value==0) { ignore = true; m_Amount[axisId] = 0; } else { m_Amount[axisId] = joyEvent.jaxis.value; //[-32768 to 32767] } m_AxisId = GetAxisWithMaxAmount(); CLog::Log(LOGDEBUG, "Joystick %d Axis %d Amount %d", joyId, axisId, m_Amount[axisId]); break; case SDL_JOYHATMOTION: m_JoyId = joyId = joyEvent.jbutton.which; m_HatId = joyEvent.jhat.hat + 1; m_pressTicksHat = SDL_GetTicks(); m_HatState = joyEvent.jhat.value; SetHatActive(m_HatState != SDL_HAT_CENTERED); CLog::Log(LOGDEBUG, "Joystick %d Hat %d Down with position %d", joyId, buttonId, m_HatState); break; case SDL_JOYBALLMOTION: ignore = true; break; case SDL_JOYBUTTONUP: m_pressTicksButton = 0; SetButtonActive(false); CLog::Log(LOGDEBUG, "Joystick %d button %d Up", joyEvent.jbutton.which, m_ButtonId); default: ignore = true; break; } } bool CJoystick::GetHat(int &id, int &position,bool consider_repeat) { if (!IsHatActive()) return false; position = m_HatState; id = m_HatId; if (!consider_repeat) return true; static uint32_t lastPressTicks = 0; static uint32_t lastTicks = 0; static uint32_t nowTicks = 0; if ((m_HatId>=0) && m_pressTicksHat) { // return the id if it's the first press if (lastPressTicks!=m_pressTicksHat) { lastPressTicks = m_pressTicksHat; return true; } nowTicks = SDL_GetTicks(); if ((nowTicks-m_pressTicksHat)<500) // 500ms delay before we repeat return false; if ((nowTicks-lastTicks)<100) // 100ms delay before successive repeats return false; lastTicks = nowTicks; } return true; } bool CJoystick::GetButton(int &id, bool consider_repeat) { if (!IsButtonActive()) return false; if (!consider_repeat) { id = m_ButtonId; return true; } static uint32_t lastPressTicks = 0; static uint32_t lastTicks = 0; static uint32_t nowTicks = 0; if ((m_ButtonId>=0) && m_pressTicksButton) { // return the id if it's the first press if (lastPressTicks!=m_pressTicksButton) { lastPressTicks = m_pressTicksButton; id = m_ButtonId; return true; } nowTicks = SDL_GetTicks(); if ((nowTicks-m_pressTicksButton)<500) // 500ms delay before we repeat { return false; } if ((nowTicks-lastTicks)<100) // 100ms delay before successive repeats { return false; } lastTicks = nowTicks; } id = m_ButtonId; return true; } int CJoystick::GetAxisWithMaxAmount() { static int maxAmount; static int axis; axis = 0; maxAmount = 0; int tempf; for (int i = 1 ; i<=m_NumAxes ; i++) { tempf = abs(m_Amount[i]); if (tempf>m_DeadzoneRange && tempf>maxAmount) { maxAmount = tempf; axis = i; } } SetAxisActive(0 != maxAmount); return axis; } float CJoystick::GetAmount(int axis) { if (m_Amount[axis] > m_DeadzoneRange) return (float)(m_Amount[axis]-m_DeadzoneRange)/(float)(MAX_AXISAMOUNT-m_DeadzoneRange); if (m_Amount[axis] < -m_DeadzoneRange) return (float)(m_Amount[axis]+m_DeadzoneRange)/(float)(MAX_AXISAMOUNT-m_DeadzoneRange); return 0; } float CJoystick::SetDeadzone(float val) { if (val<0) val=0; if (val>1) val=1; m_DeadzoneRange = (int)(val*MAX_AXISAMOUNT); return val; } #endif