2010-11-20 10:37:14 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "SDL.h"
|
|
|
|
|
|
|
|
#include <base/system.h>
|
|
|
|
#include <engine/shared/config.h>
|
|
|
|
#include <engine/graphics.h>
|
|
|
|
#include <engine/input.h>
|
|
|
|
#include <engine/keys.h>
|
|
|
|
|
|
|
|
#include "input.h"
|
|
|
|
|
|
|
|
//print >>f, "int inp_key_code(const char *key_name) { int i; if (!strcmp(key_name, \"-?-\")) return -1; else for (i = 0; i < 512; i++) if (!strcmp(key_strings[i], key_name)) return i; return -1; }"
|
|
|
|
|
|
|
|
// this header is protected so you don't include it from anywere
|
|
|
|
#define KEYS_INCLUDE
|
|
|
|
#include "keynames.h"
|
|
|
|
#undef KEYS_INCLUDE
|
|
|
|
|
2016-04-30 02:02:32 +00:00
|
|
|
void CInput::AddEvent(char *pText, int Key, int Flags)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
|
|
|
if(m_NumEvents != INPUT_BUFFER_SIZE)
|
|
|
|
{
|
|
|
|
m_aInputEvents[m_NumEvents].m_Key = Key;
|
|
|
|
m_aInputEvents[m_NumEvents].m_Flags = Flags;
|
2016-04-30 02:02:32 +00:00
|
|
|
if(!pText)
|
|
|
|
m_aInputEvents[m_NumEvents].m_aText[0] = 0;
|
|
|
|
else
|
|
|
|
str_copy(m_aInputEvents[m_NumEvents].m_aText, pText, sizeof(m_aInputEvents[m_NumEvents].m_aText));
|
2010-05-29 07:25:38 +00:00
|
|
|
m_NumEvents++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CInput::CInput()
|
|
|
|
{
|
|
|
|
mem_zero(m_aInputCount, sizeof(m_aInputCount));
|
|
|
|
mem_zero(m_aInputState, sizeof(m_aInputState));
|
|
|
|
|
|
|
|
m_InputCurrent = 0;
|
|
|
|
m_InputGrabbed = 0;
|
2012-05-02 11:53:28 +00:00
|
|
|
m_InputDispatched = false;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
m_LastRelease = 0;
|
|
|
|
m_ReleaseDelta = -1;
|
|
|
|
|
|
|
|
m_NumEvents = 0;
|
2014-06-16 11:29:18 +00:00
|
|
|
|
|
|
|
m_VideoRestartNeeded = 0;
|
2015-08-26 14:35:32 +00:00
|
|
|
m_pClipboardText = NULL;
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CInput::Init()
|
|
|
|
{
|
|
|
|
m_pGraphics = Kernel()->RequestInterface<IEngineGraphics>();
|
2015-08-24 20:46:28 +00:00
|
|
|
|
2015-08-24 23:48:08 +00:00
|
|
|
MouseModeRelative();
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
2010-10-13 10:47:42 +00:00
|
|
|
void CInput::MouseRelative(float *x, float *y)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2014-06-16 11:29:18 +00:00
|
|
|
#if defined(__ANDROID__) // No relative mouse on Android
|
|
|
|
int nx = 0, ny = 0;
|
|
|
|
SDL_GetMouseState(&nx, &ny);
|
|
|
|
*x = nx;
|
|
|
|
*y = ny;
|
|
|
|
#else
|
2010-05-29 07:25:38 +00:00
|
|
|
int nx = 0, ny = 0;
|
2016-04-30 15:59:58 +00:00
|
|
|
float Sens = ((g_Config.m_ClDyncam && g_Config.m_ClDyncamMousesens) ? g_Config.m_ClDyncamMousesens : g_Config.m_InpMousesens) / 100.0f;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2016-04-30 00:06:41 +00:00
|
|
|
SDL_GetRelativeMouseState(&nx,&ny);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2010-10-13 10:47:42 +00:00
|
|
|
*x = nx*Sens;
|
|
|
|
*y = ny*Sens;
|
2014-06-16 11:29:18 +00:00
|
|
|
#endif
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CInput::MouseModeAbsolute()
|
|
|
|
{
|
|
|
|
m_InputGrabbed = 0;
|
2015-08-24 20:46:28 +00:00
|
|
|
SDL_SetRelativeMouseMode(SDL_FALSE);
|
2015-08-24 23:01:38 +00:00
|
|
|
Graphics()->SetWindowGrab(SDL_FALSE);
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CInput::MouseModeRelative()
|
|
|
|
{
|
|
|
|
m_InputGrabbed = 1;
|
2015-08-24 20:46:28 +00:00
|
|
|
SDL_SetRelativeMouseMode(SDL_TRUE);
|
2015-08-24 23:01:38 +00:00
|
|
|
Graphics()->SetWindowGrab(true);
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int CInput::MouseDoubleClick()
|
|
|
|
{
|
2014-11-25 20:30:16 +00:00
|
|
|
if(m_ReleaseDelta >= 0 && m_ReleaseDelta < (time_freq() / 3))
|
2010-09-03 17:39:20 +00:00
|
|
|
{
|
|
|
|
m_LastRelease = 0;
|
|
|
|
m_ReleaseDelta = -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
2015-08-25 12:24:46 +00:00
|
|
|
const char* CInput::GetClipboardText()
|
|
|
|
{
|
|
|
|
if(m_pClipboardText)
|
|
|
|
{
|
2015-08-26 14:34:33 +00:00
|
|
|
SDL_free(m_pClipboardText);
|
2015-08-25 12:24:46 +00:00
|
|
|
}
|
|
|
|
m_pClipboardText = SDL_GetClipboardText();
|
|
|
|
return m_pClipboardText;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CInput::SetClipboardText(const char *Text)
|
|
|
|
{
|
|
|
|
SDL_SetClipboardText(Text);
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CInput::ClearKeyStates()
|
|
|
|
{
|
|
|
|
mem_zero(m_aInputState, sizeof(m_aInputState));
|
|
|
|
mem_zero(m_aInputCount, sizeof(m_aInputCount));
|
|
|
|
}
|
|
|
|
|
2016-04-29 19:51:54 +00:00
|
|
|
int CInput::KeyState(int Key) const
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2016-04-29 19:51:54 +00:00
|
|
|
return m_aInputState[m_InputCurrent][Key>=KEY_MOUSE_1 ? Key : SDL_GetScancodeFromKey(KeyToKeycode(Key))];
|
|
|
|
}
|
|
|
|
|
|
|
|
int CInput::KeyStateOld(int Key) const
|
|
|
|
{
|
|
|
|
return m_aInputState[m_InputCurrent^1][Key>=KEY_MOUSE_1 ? Key : SDL_GetScancodeFromKey(KeyToKeycode(Key))];
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
2010-12-11 21:04:50 +00:00
|
|
|
int CInput::Update()
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
2012-05-02 11:53:28 +00:00
|
|
|
if(m_InputDispatched)
|
|
|
|
{
|
|
|
|
// clear and begin count on the other one
|
|
|
|
m_InputCurrent^=1;
|
|
|
|
mem_zero(&m_aInputCount[m_InputCurrent], sizeof(m_aInputCount[m_InputCurrent]));
|
|
|
|
mem_zero(&m_aInputState[m_InputCurrent], sizeof(m_aInputState[m_InputCurrent]));
|
|
|
|
m_InputDispatched = false;
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
int i;
|
2015-08-24 20:46:28 +00:00
|
|
|
const Uint8 *pState = SDL_GetKeyboardState(&i);
|
2010-05-29 07:25:38 +00:00
|
|
|
if(i >= KEY_LAST)
|
|
|
|
i = KEY_LAST-1;
|
|
|
|
mem_copy(m_aInputState[m_InputCurrent], pState, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
// these states must always be updated manually because they are not in the GetKeyState from SDL
|
|
|
|
int i = SDL_GetMouseState(NULL, NULL);
|
|
|
|
if(i&SDL_BUTTON(1)) m_aInputState[m_InputCurrent][KEY_MOUSE_1] = 1; // 1 is left
|
|
|
|
if(i&SDL_BUTTON(3)) m_aInputState[m_InputCurrent][KEY_MOUSE_2] = 1; // 3 is right
|
|
|
|
if(i&SDL_BUTTON(2)) m_aInputState[m_InputCurrent][KEY_MOUSE_3] = 1; // 2 is middle
|
|
|
|
if(i&SDL_BUTTON(4)) m_aInputState[m_InputCurrent][KEY_MOUSE_4] = 1;
|
|
|
|
if(i&SDL_BUTTON(5)) m_aInputState[m_InputCurrent][KEY_MOUSE_5] = 1;
|
|
|
|
if(i&SDL_BUTTON(6)) m_aInputState[m_InputCurrent][KEY_MOUSE_6] = 1;
|
|
|
|
if(i&SDL_BUTTON(7)) m_aInputState[m_InputCurrent][KEY_MOUSE_7] = 1;
|
|
|
|
if(i&SDL_BUTTON(8)) m_aInputState[m_InputCurrent][KEY_MOUSE_8] = 1;
|
2014-01-14 19:33:13 +00:00
|
|
|
if(i&SDL_BUTTON(9)) m_aInputState[m_InputCurrent][KEY_MOUSE_9] = 1;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
SDL_Event Event;
|
2016-04-30 01:32:23 +00:00
|
|
|
int IgnoreKeys = false;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
while(SDL_PollEvent(&Event))
|
|
|
|
{
|
|
|
|
int Key = -1;
|
2016-04-29 19:51:54 +00:00
|
|
|
int Scancode = 0;
|
2010-05-29 07:25:38 +00:00
|
|
|
int Action = IInput::FLAG_PRESS;
|
|
|
|
switch (Event.type)
|
|
|
|
{
|
2015-08-24 20:46:28 +00:00
|
|
|
case SDL_TEXTINPUT:
|
2016-04-30 15:59:58 +00:00
|
|
|
if(!IgnoreKeys)
|
|
|
|
AddEvent(Event.text.text, 0, IInput::FLAG_TEXT);
|
2015-08-28 16:16:16 +00:00
|
|
|
break;
|
2010-05-29 07:25:38 +00:00
|
|
|
// handle keys
|
|
|
|
case SDL_KEYDOWN:
|
2016-04-29 19:51:54 +00:00
|
|
|
Key = KeycodeToKey(Event.key.keysym.sym);
|
|
|
|
Scancode = Event.key.keysym.scancode;
|
2010-05-29 07:25:38 +00:00
|
|
|
break;
|
|
|
|
case SDL_KEYUP:
|
|
|
|
Action = IInput::FLAG_RELEASE;
|
2016-04-29 19:51:54 +00:00
|
|
|
Key = KeycodeToKey(Event.key.keysym.sym);
|
|
|
|
Scancode = Event.key.keysym.scancode;
|
2010-05-29 07:25:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
// handle mouse buttons
|
|
|
|
case SDL_MOUSEBUTTONUP:
|
|
|
|
Action = IInput::FLAG_RELEASE;
|
|
|
|
|
|
|
|
if(Event.button.button == 1) // ignore_convention
|
|
|
|
{
|
|
|
|
m_ReleaseDelta = time_get() - m_LastRelease;
|
|
|
|
m_LastRelease = time_get();
|
|
|
|
}
|
|
|
|
|
|
|
|
// fall through
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
|
|
if(Event.button.button == SDL_BUTTON_LEFT) Key = KEY_MOUSE_1; // ignore_convention
|
|
|
|
if(Event.button.button == SDL_BUTTON_RIGHT) Key = KEY_MOUSE_2; // ignore_convention
|
|
|
|
if(Event.button.button == SDL_BUTTON_MIDDLE) Key = KEY_MOUSE_3; // ignore_convention
|
2015-08-27 21:19:15 +00:00
|
|
|
if(Event.button.button == SDL_BUTTON_X1) Key = KEY_MOUSE_4; // ignore_convention
|
|
|
|
if(Event.button.button == SDL_BUTTON_X2) Key = KEY_MOUSE_5; // ignore_convention
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Event.button.button == 6) Key = KEY_MOUSE_6; // ignore_convention
|
|
|
|
if(Event.button.button == 7) Key = KEY_MOUSE_7; // ignore_convention
|
|
|
|
if(Event.button.button == 8) Key = KEY_MOUSE_8; // ignore_convention
|
2014-01-14 19:33:13 +00:00
|
|
|
if(Event.button.button == 9) Key = KEY_MOUSE_9; // ignore_convention
|
2016-04-29 19:51:54 +00:00
|
|
|
Scancode = Key;
|
2010-05-29 07:25:38 +00:00
|
|
|
break;
|
|
|
|
|
2015-08-24 20:46:28 +00:00
|
|
|
case SDL_MOUSEWHEEL:
|
|
|
|
if(Event.wheel.y > 0) Key = KEY_MOUSE_WHEEL_UP; // ignore_convention
|
|
|
|
if(Event.wheel.y < 0) Key = KEY_MOUSE_WHEEL_DOWN; // ignore_convention
|
|
|
|
AddEvent(0, Key, Action);
|
|
|
|
Action = IInput::FLAG_RELEASE;
|
|
|
|
break;
|
|
|
|
|
2016-04-29 22:34:12 +00:00
|
|
|
case SDL_WINDOWEVENT:
|
2016-04-30 01:32:23 +00:00
|
|
|
// Ignore keys following a focus gain as they may be part of global
|
|
|
|
// shortcuts
|
2016-04-30 15:59:58 +00:00
|
|
|
switch (Event.window.event)
|
2016-04-29 22:34:12 +00:00
|
|
|
{
|
2016-04-30 15:59:58 +00:00
|
|
|
case SDL_WINDOWEVENT_RESIZED:
|
|
|
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
|
|
|
Graphics()->Resize(Event.window.data1, Event.window.data2);
|
|
|
|
break;
|
|
|
|
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
|
|
|
case SDL_WINDOWEVENT_FOCUS_LOST:
|
|
|
|
// TODO: Check if from FOCUS_LOST til FOCUS_GAINED is good enough, maybe also ENTER and LEAVE
|
|
|
|
IgnoreKeys = true;
|
|
|
|
break;
|
|
|
|
#if defined(CONF_PLATFORM_MACOSX) // Todo: remove this when fixed in SDL
|
|
|
|
case SDL_WINDOWEVENT_MAXIMIZED:
|
|
|
|
MouseModeAbsolute();
|
|
|
|
MouseModeRelative();
|
|
|
|
break;
|
2016-04-29 22:34:12 +00:00
|
|
|
#endif
|
2016-04-30 15:59:58 +00:00
|
|
|
}
|
2016-04-30 01:32:23 +00:00
|
|
|
break;
|
2016-04-29 22:34:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// other messages
|
|
|
|
case SDL_QUIT:
|
2010-12-11 21:04:50 +00:00
|
|
|
return 1;
|
2014-06-16 11:29:18 +00:00
|
|
|
|
|
|
|
#if defined(__ANDROID__)
|
2016-04-29 20:56:13 +00:00
|
|
|
case SDL_WINDOWEVENT_RESIZED:
|
2014-06-16 11:29:18 +00:00
|
|
|
m_VideoRestartNeeded = 1;
|
|
|
|
break;
|
|
|
|
#endif
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
2016-04-30 01:32:23 +00:00
|
|
|
if(Key >= 0 && Key < 1024 && !IgnoreKeys)
|
2010-05-29 07:25:38 +00:00
|
|
|
{
|
|
|
|
m_aInputCount[m_InputCurrent][Key].m_Presses++;
|
|
|
|
if(Action == IInput::FLAG_PRESS)
|
2016-04-29 19:51:54 +00:00
|
|
|
m_aInputState[m_InputCurrent][Scancode] = 1;
|
2010-05-29 07:25:38 +00:00
|
|
|
AddEvent(0, Key, Action);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2010-12-11 21:04:50 +00:00
|
|
|
|
|
|
|
return 0;
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
|
2014-06-16 11:29:18 +00:00
|
|
|
int CInput::VideoRestartNeeded()
|
|
|
|
{
|
|
|
|
if( m_VideoRestartNeeded )
|
|
|
|
{
|
|
|
|
m_VideoRestartNeeded = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
IEngineInput *CreateEngineInput() { return new CInput; }
|