2014-12-11 18:01:57 +00:00
|
|
|
|
/*
|
|
|
|
|
* This file is part of the Colobot: Gold Edition source code
|
|
|
|
|
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
|
|
|
|
|
* http://epsiteс.ch; http://colobot.info; http://github.com/colobot
|
|
|
|
|
*
|
|
|
|
|
* 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 3 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, see http://gnu.org/licenses
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "app/input.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "common/logger.h"
|
|
|
|
|
#include "common/restext.h"
|
|
|
|
|
|
|
|
|
|
#include "graphics/engine/engine.h"
|
|
|
|
|
|
|
|
|
|
#include "object/robotmain.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<> CInput* CSingleton<CInput>::m_instance = nullptr;
|
|
|
|
|
|
|
|
|
|
CInput::CInput()
|
|
|
|
|
{
|
|
|
|
|
m_kmodState = 0;
|
|
|
|
|
m_mousePos = Math::Point();
|
|
|
|
|
m_mouseButtonsState = 0;
|
|
|
|
|
|
2014-12-14 15:54:32 +00:00
|
|
|
|
for(int i=0; i<INPUT_SLOT_MAX; i++)
|
|
|
|
|
m_keyPresses[i] = false;
|
|
|
|
|
|
2014-12-11 18:01:57 +00:00
|
|
|
|
m_joystickDeadzone = 0.2f;
|
|
|
|
|
SetDefaultInputBindings();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CInput::EventProcess(Event& event)
|
|
|
|
|
{
|
|
|
|
|
if(event.type == EVENT_KEY_DOWN ||
|
|
|
|
|
event.type == EVENT_KEY_UP)
|
|
|
|
|
{
|
|
|
|
|
// Use the occasion to update kmods
|
|
|
|
|
m_kmodState = event.kmodState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use the occasion to update mouse button state
|
|
|
|
|
if (event.type == EVENT_MOUSE_BUTTON_DOWN)
|
|
|
|
|
{
|
|
|
|
|
m_mouseButtonsState |= event.mouseButton.button;
|
|
|
|
|
}
|
|
|
|
|
if(event.type == EVENT_MOUSE_BUTTON_UP)
|
|
|
|
|
{
|
|
|
|
|
m_mouseButtonsState &= ~event.mouseButton.button;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(event.type == EVENT_KEY_DOWN ||
|
|
|
|
|
event.type == EVENT_KEY_UP)
|
|
|
|
|
{
|
|
|
|
|
event.key.slot = FindBinding(event.key.key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
event.kmodState = m_kmodState;
|
|
|
|
|
event.mousePos = m_mousePos;
|
|
|
|
|
event.mouseButtonsState = m_mouseButtonsState;
|
|
|
|
|
|
|
|
|
|
|
2014-12-14 15:54:32 +00:00
|
|
|
|
if (event.type == EVENT_KEY_DOWN ||
|
|
|
|
|
event.type == EVENT_KEY_UP)
|
|
|
|
|
{
|
|
|
|
|
m_keyPresses[event.key.slot] = (event.type == EVENT_KEY_DOWN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-12-11 18:01:57 +00:00
|
|
|
|
|
|
|
|
|
/* Motion vector management */
|
|
|
|
|
|
|
|
|
|
if (event.type == EVENT_KEY_DOWN)
|
|
|
|
|
{
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_UP ) m_keyMotion.y = 1.0f;
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_DOWN ) m_keyMotion.y = -1.0f;
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_LEFT ) m_keyMotion.x = -1.0f;
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_RIGHT) m_keyMotion.x = 1.0f;
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_GUP ) m_keyMotion.z = 1.0f;
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_GDOWN) m_keyMotion.z = -1.0f;
|
|
|
|
|
}
|
|
|
|
|
else if (event.type == EVENT_KEY_UP)
|
|
|
|
|
{
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_UP ) m_keyMotion.y = 0.0f;
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_DOWN ) m_keyMotion.y = 0.0f;
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_LEFT ) m_keyMotion.x = 0.0f;
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_RIGHT) m_keyMotion.x = 0.0f;
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_GUP ) m_keyMotion.z = 0.0f;
|
|
|
|
|
if (event.key.slot == INPUT_SLOT_GDOWN) m_keyMotion.z = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
else if (event.type == EVENT_JOY_AXIS)
|
|
|
|
|
{
|
|
|
|
|
if (event.joyAxis.axis == GetJoyAxisBinding(JOY_AXIS_SLOT_X).axis)
|
|
|
|
|
{
|
|
|
|
|
m_joyMotion.x = Math::Neutral(event.joyAxis.value / 32768.0f, m_joystickDeadzone);
|
|
|
|
|
if (GetJoyAxisBinding(JOY_AXIS_SLOT_X).invert)
|
|
|
|
|
m_joyMotion.x *= -1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (event.joyAxis.axis == GetJoyAxisBinding(JOY_AXIS_SLOT_Y).axis)
|
|
|
|
|
{
|
|
|
|
|
m_joyMotion.y = Math::Neutral(event.joyAxis.value / 32768.0f, m_joystickDeadzone);
|
|
|
|
|
if (GetJoyAxisBinding(JOY_AXIS_SLOT_Y).invert)
|
|
|
|
|
m_joyMotion.y *= -1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (event.joyAxis.axis == GetJoyAxisBinding(JOY_AXIS_SLOT_Z).axis)
|
|
|
|
|
{
|
|
|
|
|
m_joyMotion.z = Math::Neutral(event.joyAxis.value / 32768.0f, m_joystickDeadzone);
|
|
|
|
|
if (GetJoyAxisBinding(JOY_AXIS_SLOT_Z).invert)
|
|
|
|
|
m_joyMotion.z *= -1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
event.motionInput = Math::Clamp(m_joyMotion + m_keyMotion, Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector(1.0f, 1.0f, 1.0f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CInput::MouseMove(Math::IntPoint pos)
|
|
|
|
|
{
|
|
|
|
|
m_mousePos = Gfx::CEngine::GetInstancePointer()->WindowToInterfaceCoords(pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int CInput::GetKmods() const
|
|
|
|
|
{
|
|
|
|
|
return m_kmodState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CInput::GetKmodState(int kmod) const
|
|
|
|
|
{
|
|
|
|
|
return (m_kmodState & kmod) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-14 15:54:32 +00:00
|
|
|
|
bool CInput::GetKeyState(InputSlot key) const
|
2014-12-11 18:01:57 +00:00
|
|
|
|
{
|
2014-12-14 15:54:32 +00:00
|
|
|
|
return m_keyPresses[key];
|
2014-12-11 18:01:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CInput::GetMouseButtonState(int index) const
|
|
|
|
|
{
|
|
|
|
|
return (m_mouseButtonsState & (1<<index)) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CInput::ResetKeyStates()
|
|
|
|
|
{
|
|
|
|
|
CLogger::GetInstancePointer()->Trace("Reset key states\n");
|
|
|
|
|
m_kmodState = 0;
|
|
|
|
|
m_keyMotion = Math::Vector(0.0f, 0.0f, 0.0f);
|
|
|
|
|
m_joyMotion = Math::Vector(0.0f, 0.0f, 0.0f);
|
2014-12-14 15:54:32 +00:00
|
|
|
|
for(int i=0; i<INPUT_SLOT_MAX; i++)
|
|
|
|
|
m_keyPresses[i] = false;
|
2014-12-11 18:01:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Math::Point CInput::GetMousePos() const
|
|
|
|
|
{
|
|
|
|
|
return m_mousePos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CInput::SetDefaultInputBindings()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < INPUT_SLOT_MAX; i++)
|
|
|
|
|
{
|
|
|
|
|
m_inputBindings[i].primary = m_inputBindings[i].secondary = KEY_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < JOY_AXIS_SLOT_MAX; i++)
|
|
|
|
|
{
|
|
|
|
|
m_joyAxisBindings[i].axis = AXIS_INVALID;
|
|
|
|
|
m_joyAxisBindings[i].invert = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_inputBindings[INPUT_SLOT_LEFT ].primary = KEY(LEFT);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_RIGHT ].primary = KEY(RIGHT);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_UP ].primary = KEY(UP);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_DOWN ].primary = KEY(DOWN);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_LEFT ].secondary = KEY(a);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_RIGHT ].secondary = KEY(d);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_UP ].secondary = KEY(w);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_DOWN ].secondary = KEY(s);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_GUP ].primary = VIRTUAL_KMOD(SHIFT);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_GDOWN ].primary = VIRTUAL_KMOD(CTRL);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_CAMERA ].primary = KEY(SPACE);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_DESEL ].primary = KEY(KP0);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_ACTION ].primary = KEY(RETURN);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_ACTION ].secondary = KEY(e);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_NEAR ].primary = KEY(KP_PLUS);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_AWAY ].primary = KEY(KP_MINUS);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_NEXT ].primary = KEY(TAB);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_HUMAN ].primary = KEY(HOME);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_QUIT ].primary = KEY(ESCAPE);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_HELP ].primary = KEY(F1);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_PROG ].primary = KEY(F2);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_VISIT ].primary = KEY(KP_PERIOD);
|
2014-12-14 16:05:28 +00:00
|
|
|
|
m_inputBindings[INPUT_SLOT_SPEED05].primary = KEY(F3);
|
2014-12-11 18:01:57 +00:00
|
|
|
|
m_inputBindings[INPUT_SLOT_SPEED10].primary = KEY(F4);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_SPEED15].primary = KEY(F5);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_SPEED20].primary = KEY(F6);
|
2014-12-14 16:05:28 +00:00
|
|
|
|
m_inputBindings[INPUT_SLOT_SPEED30].primary = KEY(F7);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_SPEED40].primary = KEY(F8);
|
2014-12-14 15:54:32 +00:00
|
|
|
|
m_inputBindings[INPUT_SLOT_CAMERA_UP].primary = KEY(PAGEUP);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_CAMERA_DOWN].primary = KEY(PAGEDOWN);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_PAUSE].primary = KEY(PAUSE);
|
|
|
|
|
m_inputBindings[INPUT_SLOT_PAUSE].secondary = KEY(p);
|
2014-12-11 18:01:57 +00:00
|
|
|
|
|
|
|
|
|
m_joyAxisBindings[JOY_AXIS_SLOT_X].axis = 0;
|
|
|
|
|
m_joyAxisBindings[JOY_AXIS_SLOT_Y].axis = 1;
|
|
|
|
|
m_joyAxisBindings[JOY_AXIS_SLOT_Z].axis = 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CInput::SetInputBinding(InputSlot slot, InputBinding binding)
|
|
|
|
|
{
|
|
|
|
|
unsigned int index = static_cast<unsigned int>(slot);
|
|
|
|
|
m_inputBindings[index] = binding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const InputBinding& CInput::GetInputBinding(InputSlot slot)
|
|
|
|
|
{
|
|
|
|
|
unsigned int index = static_cast<unsigned int>(slot);
|
|
|
|
|
return m_inputBindings[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CInput::SetJoyAxisBinding(JoyAxisSlot slot, JoyAxisBinding binding)
|
|
|
|
|
{
|
|
|
|
|
unsigned int index = static_cast<unsigned int>(slot);
|
|
|
|
|
m_joyAxisBindings[index] = binding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const JoyAxisBinding& CInput::GetJoyAxisBinding(JoyAxisSlot slot)
|
|
|
|
|
{
|
|
|
|
|
unsigned int index = static_cast<unsigned int>(slot);
|
|
|
|
|
return m_joyAxisBindings[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CInput::SetJoystickDeadzone(float zone)
|
|
|
|
|
{
|
|
|
|
|
m_joystickDeadzone = zone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float CInput::GetJoystickDeadzone()
|
|
|
|
|
{
|
|
|
|
|
return m_joystickDeadzone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InputSlot CInput::FindBinding(unsigned int key)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < INPUT_SLOT_MAX; i++)
|
|
|
|
|
{
|
|
|
|
|
InputSlot slot = static_cast<InputSlot>(i);
|
|
|
|
|
InputBinding b = GetInputBinding(slot);
|
|
|
|
|
if(b.primary == key || b.secondary == key)
|
|
|
|
|
return slot;
|
|
|
|
|
}
|
|
|
|
|
return INPUT_SLOT_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CInput::SaveKeyBindings()
|
|
|
|
|
{
|
|
|
|
|
std::stringstream key;
|
|
|
|
|
for (int i = 0; i < INPUT_SLOT_MAX; i++)
|
|
|
|
|
{
|
|
|
|
|
InputBinding b = GetInputBinding(static_cast<InputSlot>(i));
|
|
|
|
|
|
|
|
|
|
key << b.primary << " ";
|
|
|
|
|
key << b.secondary << " ";
|
|
|
|
|
}
|
|
|
|
|
return key.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CInput::LoadKeyBindings(std::string keys)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream skey;
|
|
|
|
|
skey.str(keys);
|
|
|
|
|
for (int i = 0; i < INPUT_SLOT_MAX; i++)
|
|
|
|
|
{
|
|
|
|
|
InputBinding b;
|
|
|
|
|
skey >> b.primary;
|
|
|
|
|
skey >> b.secondary;
|
|
|
|
|
SetInputBinding(static_cast<InputSlot>(i), b);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::map<InputSlot, std::string> keyTable =
|
|
|
|
|
{
|
|
|
|
|
{ INPUT_SLOT_LEFT, "left" },
|
|
|
|
|
{ INPUT_SLOT_RIGHT, "right" },
|
|
|
|
|
{ INPUT_SLOT_UP, "up" },
|
|
|
|
|
{ INPUT_SLOT_DOWN, "down" },
|
|
|
|
|
{ INPUT_SLOT_GUP, "gup" },
|
|
|
|
|
{ INPUT_SLOT_GDOWN, "gdown" },
|
|
|
|
|
{ INPUT_SLOT_CAMERA, "camera" },
|
|
|
|
|
{ INPUT_SLOT_DESEL, "desel" },
|
|
|
|
|
{ INPUT_SLOT_ACTION, "action" },
|
|
|
|
|
{ INPUT_SLOT_NEAR, "near" },
|
|
|
|
|
{ INPUT_SLOT_AWAY, "away" },
|
|
|
|
|
{ INPUT_SLOT_NEXT, "next" },
|
|
|
|
|
{ INPUT_SLOT_HUMAN, "human" },
|
|
|
|
|
{ INPUT_SLOT_QUIT, "quit" },
|
|
|
|
|
{ INPUT_SLOT_HELP, "help" },
|
|
|
|
|
{ INPUT_SLOT_PROG, "prog" },
|
|
|
|
|
{ INPUT_SLOT_VISIT, "visit" },
|
2014-12-14 16:05:28 +00:00
|
|
|
|
{ INPUT_SLOT_SPEED05, "speed05" },
|
2014-12-11 18:01:57 +00:00
|
|
|
|
{ INPUT_SLOT_SPEED10, "speed10" },
|
|
|
|
|
{ INPUT_SLOT_SPEED15, "speed15" },
|
2014-12-14 15:54:32 +00:00
|
|
|
|
{ INPUT_SLOT_SPEED20, "speed20" },
|
2014-12-14 16:05:28 +00:00
|
|
|
|
{ INPUT_SLOT_SPEED30, "speed30" },
|
|
|
|
|
{ INPUT_SLOT_SPEED40, "speed40" },
|
2014-12-14 15:54:32 +00:00
|
|
|
|
{ INPUT_SLOT_CAMERA_UP, "camup" },
|
|
|
|
|
{ INPUT_SLOT_CAMERA_DOWN, "camdown" },
|
2014-12-11 18:01:57 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
InputSlot CInput::SearchKeyById(std::string id)
|
|
|
|
|
{
|
|
|
|
|
for(auto& key : keyTable)
|
|
|
|
|
{
|
|
|
|
|
if ( id == key.second )
|
|
|
|
|
{
|
|
|
|
|
return key.first;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return INPUT_SLOT_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CInput::GetKeysString(InputBinding b)
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream ss;
|
|
|
|
|
if ( b.primary != KEY_INVALID )
|
|
|
|
|
{
|
|
|
|
|
std::string iNameStr;
|
|
|
|
|
if ( GetResource(RES_KEY, b.primary, iNameStr) )
|
|
|
|
|
{
|
|
|
|
|
ss << iNameStr;
|
|
|
|
|
|
|
|
|
|
if ( b.secondary != KEY_INVALID )
|
|
|
|
|
{
|
|
|
|
|
if ( GetResource(RES_KEY, b.secondary, iNameStr) )
|
|
|
|
|
{
|
|
|
|
|
std::string textStr;
|
|
|
|
|
GetResource(RES_TEXT, RT_KEY_OR, textStr);
|
|
|
|
|
|
|
|
|
|
ss << textStr << iNameStr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return "?";
|
|
|
|
|
}
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string CInput::GetKeysString(InputSlot slot)
|
|
|
|
|
{
|
|
|
|
|
InputBinding b = GetInputBinding(slot);
|
|
|
|
|
return GetKeysString(b);
|
|
|
|
|
}
|