ddnet/src/engine/client/input.cpp

805 lines
21 KiB
C++
Raw Normal View History

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. */
2022-06-06 19:19:08 +00:00
#include <SDL.h>
2010-05-29 07:25:38 +00:00
#include <base/system.h>
2022-06-06 19:19:08 +00:00
#include <engine/console.h>
2010-05-29 07:25:38 +00:00
#include <engine/graphics.h>
#include <engine/input.h>
#include <engine/keys.h>
2020-09-22 16:02:03 +00:00
#include <engine/shared/config.h>
2010-05-29 07:25:38 +00:00
#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; }"
2022-10-25 16:51:56 +00:00
// this header is protected so you don't include it from anywhere
2010-05-29 07:25:38 +00:00
#define KEYS_INCLUDE
#include "keynames.h"
#undef KEYS_INCLUDE
2022-06-06 19:19:08 +00:00
// support older SDL version (pre 2.0.6)
#ifndef SDL_JOYSTICK_AXIS_MIN
2022-06-27 16:51:02 +00:00
#define SDL_JOYSTICK_AXIS_MIN (-32768)
2022-06-06 19:19:08 +00:00
#endif
#ifndef SDL_JOYSTICK_AXIS_MAX
#define SDL_JOYSTICK_AXIS_MAX 32767
#endif
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;
if(pText == nullptr)
2016-04-30 02:02:32 +00:00
m_aInputEvents[m_NumEvents].m_aText[0] = 0;
else
2022-07-09 16:14:56 +00:00
str_copy(m_aInputEvents[m_NumEvents].m_aText, pText);
m_aInputEvents[m_NumEvents].m_InputCount = m_InputCounter;
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_LastUpdate = 0;
m_UpdateTime = 0.0f;
m_InputCounter = 1;
m_InputGrabbed = false;
2010-05-29 07:25:38 +00:00
m_MouseDoubleClick = false;
2010-05-29 07:25:38 +00:00
m_NumEvents = 0;
m_MouseFocus = true;
2014-06-16 11:29:18 +00:00
m_pClipboardText = nullptr;
m_NumTextInputInstances = 0;
m_EditingTextLen = -1;
m_aEditingText[0] = 0;
m_aDropFile[0] = 0;
2010-05-29 07:25:38 +00:00
}
void CInput::Init()
{
m_pGraphics = Kernel()->RequestInterface<IEngineGraphics>();
2022-06-06 19:19:08 +00:00
m_pConsole = Kernel()->RequestInterface<IConsole>();
2015-08-24 20:46:28 +00:00
// increase ime instance counter for menu
SetIMEState(true);
2015-08-24 23:48:08 +00:00
MouseModeRelative();
2022-06-06 19:19:08 +00:00
InitJoysticks();
}
void CInput::Shutdown()
{
SDL_free(m_pClipboardText);
CloseJoysticks();
}
2022-06-06 19:19:08 +00:00
void CInput::InitJoysticks()
{
if(!SDL_WasInit(SDL_INIT_JOYSTICK))
{
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
{
dbg_msg("joystick", "Unable to init SDL joystick system: %s", SDL_GetError());
return;
}
}
const int NumJoysticks = SDL_NumJoysticks();
dbg_msg("joystick", "%d joystick(s) found", NumJoysticks);
for(int i = 0; i < NumJoysticks; i++)
OpenJoystick(i);
UpdateActiveJoystick();
Console()->Chain("inp_controller_guid", ConchainJoystickGuidChanged, this);
}
bool CInput::OpenJoystick(int JoystickIndex)
{
SDL_Joystick *pJoystick = SDL_JoystickOpen(JoystickIndex);
if(!pJoystick)
2022-06-06 19:19:08 +00:00
{
dbg_msg("joystick", "Could not open joystick %d: '%s'", JoystickIndex, SDL_GetError());
return false;
2022-06-06 19:19:08 +00:00
}
if(std::find_if(m_vJoysticks.begin(), m_vJoysticks.end(), [pJoystick](const CJoystick &Joystick) -> bool { return Joystick.m_pDelegate == pJoystick; }) != m_vJoysticks.end())
2022-06-06 19:19:08 +00:00
{
// Joystick has already been added
return false;
2022-06-06 19:19:08 +00:00
}
m_vJoysticks.emplace_back(this, m_vJoysticks.size(), pJoystick);
const CJoystick &Joystick = m_vJoysticks[m_vJoysticks.size() - 1];
dbg_msg("joystick", "Opened joystick %d '%s' (%d axes, %d buttons, %d balls, %d hats)", JoystickIndex, Joystick.GetName(),
Joystick.GetNumAxes(), Joystick.GetNumButtons(), Joystick.GetNumBalls(), Joystick.GetNumHats());
return true;
2022-06-06 19:19:08 +00:00
}
void CInput::UpdateActiveJoystick()
{
m_pActiveJoystick = nullptr;
2022-06-06 19:19:08 +00:00
if(m_vJoysticks.empty())
return;
for(auto &Joystick : m_vJoysticks)
{
if(str_comp(Joystick.GetGUID(), g_Config.m_InpControllerGUID) == 0)
2022-06-06 19:19:08 +00:00
{
m_pActiveJoystick = &Joystick;
return;
}
}
// Fall back to first joystick if no match was found
if(!m_pActiveJoystick)
2022-07-10 19:22:50 +00:00
m_pActiveJoystick = &m_vJoysticks[0]; // NOLINT(readability-container-data-pointer)
2022-06-06 19:19:08 +00:00
}
void CInput::ConchainJoystickGuidChanged(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
pfnCallback(pResult, pCallbackUserData);
if(pResult->NumArguments() == 1)
{
static_cast<CInput *>(pUserData)->UpdateActiveJoystick();
}
2022-06-06 19:19:08 +00:00
}
float CInput::GetJoystickDeadzone()
{
return minimum(g_Config.m_InpControllerTolerance / 50.0f, 0.995f);
2022-06-06 19:19:08 +00:00
}
CInput::CJoystick::CJoystick(CInput *pInput, int Index, SDL_Joystick *pDelegate)
{
m_pInput = pInput;
m_Index = Index;
m_pDelegate = pDelegate;
m_NumAxes = SDL_JoystickNumAxes(pDelegate);
m_NumButtons = SDL_JoystickNumButtons(pDelegate);
m_NumBalls = SDL_JoystickNumBalls(pDelegate);
m_NumHats = SDL_JoystickNumHats(pDelegate);
2022-07-09 16:14:56 +00:00
str_copy(m_aName, SDL_JoystickName(pDelegate));
2022-06-06 19:19:08 +00:00
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(pDelegate), m_aGUID, sizeof(m_aGUID));
m_InstanceID = SDL_JoystickInstanceID(pDelegate);
}
void CInput::CloseJoysticks()
{
if(SDL_WasInit(SDL_INIT_JOYSTICK))
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
2022-06-06 19:19:08 +00:00
m_vJoysticks.clear();
m_pActiveJoystick = nullptr;
}
void CInput::SelectNextJoystick()
{
const int Num = m_vJoysticks.size();
if(Num > 1)
{
m_pActiveJoystick = &m_vJoysticks[(m_pActiveJoystick->GetIndex() + 1) % Num];
2022-07-09 16:14:56 +00:00
str_copy(g_Config.m_InpControllerGUID, m_pActiveJoystick->GetGUID());
2022-06-06 19:19:08 +00:00
}
}
float CInput::CJoystick::GetAxisValue(int Axis)
{
return (SDL_JoystickGetAxis(m_pDelegate, Axis) - SDL_JOYSTICK_AXIS_MIN) / (float)(SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) * 2.0f - 1.0f;
2022-06-06 19:19:08 +00:00
}
void CInput::CJoystick::GetJoystickHatKeys(int Hat, int HatValue, int (&HatKeys)[2])
2022-06-06 19:19:08 +00:00
{
if(HatValue & SDL_HAT_UP)
HatKeys[0] = KEY_JOY_HAT0_UP + Hat * NUM_JOYSTICK_BUTTONS_PER_HAT;
else if(HatValue & SDL_HAT_DOWN)
HatKeys[0] = KEY_JOY_HAT0_DOWN + Hat * NUM_JOYSTICK_BUTTONS_PER_HAT;
else
HatKeys[0] = KEY_UNKNOWN;
if(HatValue & SDL_HAT_LEFT)
HatKeys[1] = KEY_JOY_HAT0_LEFT + Hat * NUM_JOYSTICK_BUTTONS_PER_HAT;
else if(HatValue & SDL_HAT_RIGHT)
HatKeys[1] = KEY_JOY_HAT0_RIGHT + Hat * NUM_JOYSTICK_BUTTONS_PER_HAT;
else
HatKeys[1] = KEY_UNKNOWN;
2022-06-06 19:19:08 +00:00
}
void CInput::CJoystick::GetHatValue(int Hat, int (&HatKeys)[2])
2022-06-06 19:19:08 +00:00
{
return GetJoystickHatKeys(Hat, SDL_JoystickGetHat(m_pDelegate, Hat), HatKeys);
2022-06-06 19:19:08 +00:00
}
bool CInput::CJoystick::Relative(float *pX, float *pY)
{
if(!Input()->m_MouseFocus || !Input()->m_InputGrabbed || !g_Config.m_InpControllerEnable)
2022-06-06 19:19:08 +00:00
return false;
const vec2 RawJoystickPos = vec2(GetAxisValue(g_Config.m_InpControllerX), GetAxisValue(g_Config.m_InpControllerY));
2022-06-06 19:19:08 +00:00
const float Len = length(RawJoystickPos);
const float DeadZone = Input()->GetJoystickDeadzone();
if(Len > DeadZone)
{
const float Factor = 2500.0f * Input()->GetUpdateTime() * maximum((Len - DeadZone) / (1.0f - DeadZone), 0.001f) / Len;
2022-06-06 19:19:08 +00:00
*pX = RawJoystickPos.x * Factor;
*pY = RawJoystickPos.y * Factor;
return true;
}
return false;
}
bool CInput::CJoystick::Absolute(float *pX, float *pY)
{
if(!Input()->m_MouseFocus || !Input()->m_InputGrabbed || !g_Config.m_InpControllerEnable)
2022-06-06 19:19:08 +00:00
return false;
const vec2 RawJoystickPos = vec2(GetAxisValue(g_Config.m_InpControllerX), GetAxisValue(g_Config.m_InpControllerY));
2022-06-06 19:19:08 +00:00
const float DeadZone = Input()->GetJoystickDeadzone();
if(dot(RawJoystickPos, RawJoystickPos) > DeadZone * DeadZone)
{
*pX = RawJoystickPos.x;
*pY = RawJoystickPos.y;
return true;
}
return false;
2010-05-29 07:25:38 +00:00
}
bool CInput::MouseRelative(float *pX, float *pY)
2010-05-29 07:25:38 +00:00
{
if(!m_MouseFocus || !m_InputGrabbed)
return false;
2010-05-29 07:25:38 +00:00
int nx = 0, ny = 0;
2021-08-24 10:18:20 +00:00
#if defined(CONF_PLATFORM_ANDROID) // No relative mouse on Android
static int s_LastX = 0;
static int s_LastY = 0;
2021-08-24 10:18:20 +00:00
SDL_GetMouseState(&nx, &ny);
int XTmp = nx - s_LastX;
int YTmp = ny - s_LastY;
s_LastX = nx;
s_LastY = ny;
2021-08-24 10:18:20 +00:00
nx = XTmp;
ny = YTmp;
#else
2020-09-22 16:02:03 +00:00
SDL_GetRelativeMouseState(&nx, &ny);
2021-08-24 10:18:20 +00:00
#endif
2010-05-29 07:25:38 +00:00
*pX = nx;
*pY = ny;
return *pX != 0.0f || *pY != 0.0f;
2021-09-15 21:52:09 +00:00
}
void CInput::MouseModeAbsolute()
2021-09-15 21:52:09 +00:00
{
m_InputGrabbed = false;
SDL_SetRelativeMouseMode(SDL_FALSE);
Graphics()->SetWindowGrab(false);
2021-09-15 21:52:09 +00:00
}
void CInput::MouseModeRelative()
2021-09-15 21:52:09 +00:00
{
m_InputGrabbed = true;
#if !defined(CONF_PLATFORM_ANDROID) // No relative mouse on Android
2021-09-15 21:52:09 +00:00
SDL_SetRelativeMouseMode(SDL_TRUE);
#endif
Graphics()->SetWindowGrab(true);
// Clear pending relative mouse motion
SDL_GetRelativeMouseState(nullptr, nullptr);
2010-05-29 07:25:38 +00:00
}
void CInput::NativeMousePos(int *pX, int *pY) const
2021-09-12 17:32:00 +00:00
{
SDL_GetMouseState(pX, pY);
2021-09-12 17:32:00 +00:00
}
bool CInput::NativeMousePressed(int Index)
2021-09-12 17:32:00 +00:00
{
int i = SDL_GetMouseState(nullptr, nullptr);
return (i & SDL_BUTTON(Index)) != 0;
2021-09-12 17:32:00 +00:00
}
bool CInput::MouseDoubleClick()
2010-05-29 07:25:38 +00:00
{
if(m_MouseDoubleClick)
{
m_MouseDoubleClick = false;
return true;
}
return false;
2010-05-29 07:25:38 +00:00
}
2020-09-22 16:02:03 +00:00
const char *CInput::GetClipboardText()
{
SDL_free(m_pClipboardText);
m_pClipboardText = SDL_GetClipboardText();
return m_pClipboardText;
}
void CInput::SetClipboardText(const char *pText)
{
SDL_SetClipboardText(pText);
}
void CInput::Clear()
2010-05-29 07:25:38 +00:00
{
mem_zero(m_aInputState, sizeof(m_aInputState));
mem_zero(m_aInputCount, sizeof(m_aInputCount));
m_NumEvents = 0;
2010-05-29 07:25:38 +00:00
}
bool CInput::KeyState(int Key) const
{
if(Key < KEY_FIRST || Key >= KEY_LAST)
return false;
return m_aInputState[Key];
2010-05-29 07:25:38 +00:00
}
2022-06-06 18:18:33 +00:00
void CInput::UpdateMouseState()
{
const int MouseState = SDL_GetMouseState(nullptr, nullptr);
2022-06-06 18:18:33 +00:00
if(MouseState & SDL_BUTTON(SDL_BUTTON_LEFT))
m_aInputState[KEY_MOUSE_1] = 1;
if(MouseState & SDL_BUTTON(SDL_BUTTON_RIGHT))
m_aInputState[KEY_MOUSE_2] = 1;
if(MouseState & SDL_BUTTON(SDL_BUTTON_MIDDLE))
m_aInputState[KEY_MOUSE_3] = 1;
if(MouseState & SDL_BUTTON(SDL_BUTTON_X1))
m_aInputState[KEY_MOUSE_4] = 1;
if(MouseState & SDL_BUTTON(SDL_BUTTON_X2))
m_aInputState[KEY_MOUSE_5] = 1;
if(MouseState & SDL_BUTTON(6))
m_aInputState[KEY_MOUSE_6] = 1;
if(MouseState & SDL_BUTTON(7))
m_aInputState[KEY_MOUSE_7] = 1;
if(MouseState & SDL_BUTTON(8))
m_aInputState[KEY_MOUSE_8] = 1;
if(MouseState & SDL_BUTTON(9))
m_aInputState[KEY_MOUSE_9] = 1;
}
2022-06-06 19:19:08 +00:00
void CInput::UpdateJoystickState()
{
if(!g_Config.m_InpControllerEnable)
2022-06-06 19:19:08 +00:00
return;
IJoystick *pJoystick = GetActiveJoystick();
if(!pJoystick)
return;
const float DeadZone = GetJoystickDeadzone();
for(int Axis = 0; Axis < pJoystick->GetNumAxes(); Axis++)
{
const float Value = pJoystick->GetAxisValue(Axis);
const int LeftKey = KEY_JOY_AXIS_0_LEFT + 2 * Axis;
const int RightKey = LeftKey + 1;
m_aInputState[LeftKey] = Value <= -DeadZone;
m_aInputState[RightKey] = Value >= DeadZone;
}
for(int Hat = 0; Hat < pJoystick->GetNumHats(); Hat++)
{
int HatKeys[2];
pJoystick->GetHatValue(Hat, HatKeys);
for(int Key = KEY_JOY_HAT0_UP + Hat * NUM_JOYSTICK_BUTTONS_PER_HAT; Key <= KEY_JOY_HAT0_DOWN + Hat * NUM_JOYSTICK_BUTTONS_PER_HAT; Key++)
m_aInputState[Key] = HatKeys[0] == Key || HatKeys[1] == Key;
2022-06-06 19:19:08 +00:00
}
}
void CInput::HandleJoystickAxisMotionEvent(const SDL_JoyAxisEvent &Event)
2022-06-06 19:19:08 +00:00
{
if(!g_Config.m_InpControllerEnable)
2022-06-06 19:19:08 +00:00
return;
CJoystick *pJoystick = GetActiveJoystick();
if(!pJoystick || pJoystick->GetInstanceID() != Event.which)
2022-06-06 19:19:08 +00:00
return;
if(Event.axis >= NUM_JOYSTICK_AXES)
2022-06-06 19:19:08 +00:00
return;
const int LeftKey = KEY_JOY_AXIS_0_LEFT + 2 * Event.axis;
2022-06-06 19:19:08 +00:00
const int RightKey = LeftKey + 1;
const float DeadZone = GetJoystickDeadzone();
if(Event.value <= SDL_JOYSTICK_AXIS_MIN * DeadZone && !m_aInputState[LeftKey])
2022-06-06 19:19:08 +00:00
{
m_aInputState[LeftKey] = true;
m_aInputCount[LeftKey] = m_InputCounter;
AddEvent(nullptr, LeftKey, IInput::FLAG_PRESS);
2022-06-06 19:19:08 +00:00
}
else if(Event.value > SDL_JOYSTICK_AXIS_MIN * DeadZone && m_aInputState[LeftKey])
2022-06-06 19:19:08 +00:00
{
m_aInputState[LeftKey] = false;
AddEvent(nullptr, LeftKey, IInput::FLAG_RELEASE);
2022-06-06 19:19:08 +00:00
}
if(Event.value >= SDL_JOYSTICK_AXIS_MAX * DeadZone && !m_aInputState[RightKey])
2022-06-06 19:19:08 +00:00
{
m_aInputState[RightKey] = true;
m_aInputCount[RightKey] = m_InputCounter;
AddEvent(nullptr, RightKey, IInput::FLAG_PRESS);
2022-06-06 19:19:08 +00:00
}
else if(Event.value < SDL_JOYSTICK_AXIS_MAX * DeadZone && m_aInputState[RightKey])
2022-06-06 19:19:08 +00:00
{
m_aInputState[RightKey] = false;
AddEvent(nullptr, RightKey, IInput::FLAG_RELEASE);
2022-06-06 19:19:08 +00:00
}
}
void CInput::HandleJoystickButtonEvent(const SDL_JoyButtonEvent &Event)
2022-06-06 19:19:08 +00:00
{
if(!g_Config.m_InpControllerEnable)
2022-06-06 19:19:08 +00:00
return;
CJoystick *pJoystick = GetActiveJoystick();
if(!pJoystick || pJoystick->GetInstanceID() != Event.which)
2022-06-06 19:19:08 +00:00
return;
if(Event.button >= NUM_JOYSTICK_BUTTONS)
2022-06-06 19:19:08 +00:00
return;
const int Key = Event.button + KEY_JOYSTICK_BUTTON_0;
2022-06-06 19:19:08 +00:00
if(Event.type == SDL_JOYBUTTONDOWN)
{
m_aInputState[Key] = true;
m_aInputCount[Key] = m_InputCounter;
AddEvent(nullptr, Key, IInput::FLAG_PRESS);
2022-06-06 19:19:08 +00:00
}
else if(Event.type == SDL_JOYBUTTONUP)
{
m_aInputState[Key] = false;
AddEvent(nullptr, Key, IInput::FLAG_RELEASE);
2022-06-06 19:19:08 +00:00
}
}
void CInput::HandleJoystickHatMotionEvent(const SDL_JoyHatEvent &Event)
2022-06-06 19:19:08 +00:00
{
if(!g_Config.m_InpControllerEnable)
2022-06-06 19:19:08 +00:00
return;
CJoystick *pJoystick = GetActiveJoystick();
if(!pJoystick || pJoystick->GetInstanceID() != Event.which)
2022-06-06 19:19:08 +00:00
return;
if(Event.hat >= NUM_JOYSTICK_HATS)
2022-06-06 19:19:08 +00:00
return;
int HatKeys[2];
CJoystick::GetJoystickHatKeys(Event.hat, Event.value, HatKeys);
2022-06-06 19:19:08 +00:00
for(int Key = KEY_JOY_HAT0_UP + Event.hat * NUM_JOYSTICK_BUTTONS_PER_HAT; Key <= KEY_JOY_HAT0_DOWN + Event.hat * NUM_JOYSTICK_BUTTONS_PER_HAT; Key++)
2022-06-06 19:19:08 +00:00
{
if(Key != HatKeys[0] && Key != HatKeys[1] && m_aInputState[Key])
2022-06-06 19:19:08 +00:00
{
m_aInputState[Key] = false;
AddEvent(nullptr, Key, IInput::FLAG_RELEASE);
2022-06-06 19:19:08 +00:00
}
}
for(int CurrentKey : HatKeys)
2022-06-06 19:19:08 +00:00
{
if(CurrentKey != KEY_UNKNOWN && !m_aInputState[CurrentKey])
{
m_aInputState[CurrentKey] = true;
m_aInputCount[CurrentKey] = m_InputCounter;
AddEvent(nullptr, CurrentKey, IInput::FLAG_PRESS);
}
2022-06-06 19:19:08 +00:00
}
}
void CInput::HandleJoystickAddedEvent(const SDL_JoyDeviceEvent &Event)
{
if(OpenJoystick(Event.which))
{
UpdateActiveJoystick();
}
}
void CInput::HandleJoystickRemovedEvent(const SDL_JoyDeviceEvent &Event)
{
auto RemovedJoystick = std::find_if(m_vJoysticks.begin(), m_vJoysticks.end(), [Event](const CJoystick &Joystick) -> bool { return Joystick.GetInstanceID() == Event.which; });
if(RemovedJoystick != m_vJoysticks.end())
{
dbg_msg("joystick", "Closed joystick %d '%s'", (*RemovedJoystick).GetIndex(), (*RemovedJoystick).GetName());
auto NextJoystick = m_vJoysticks.erase(RemovedJoystick);
// Adjust indices of following joysticks
while(NextJoystick != m_vJoysticks.end())
{
(*NextJoystick).m_Index--;
++NextJoystick;
}
UpdateActiveJoystick();
}
}
bool CInput::GetIMEState()
{
return m_NumTextInputInstances > 0;
}
void CInput::SetIMEState(bool Activate)
{
if(Activate)
{
if(m_NumTextInputInstances == 0)
SDL_StartTextInput();
m_NumTextInputInstances++;
}
else
{
if(m_NumTextInputInstances == 0)
return;
m_NumTextInputInstances--;
if(m_NumTextInputInstances == 0)
SDL_StopTextInput();
}
}
const char *CInput::GetIMEEditingText()
{
if(m_EditingTextLen > 0)
return m_aEditingText;
else
return "";
}
int CInput::GetEditingCursor()
{
return m_EditingCursor;
}
void CInput::SetEditingPosition(float X, float Y)
{
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
int ScreenWidth = Graphics()->ScreenWidth();
int ScreenHeight = Graphics()->ScreenHeight();
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
2020-09-22 16:02:03 +00:00
vec2 ScreenScale = vec2(ScreenWidth / (ScreenX1 - ScreenX0), ScreenHeight / (ScreenY1 - ScreenY0));
SDL_Rect ImeWindowRect;
ImeWindowRect.x = X * ScreenScale.x;
ImeWindowRect.y = Y * ScreenScale.y;
ImeWindowRect.h = 60;
ImeWindowRect.w = 1000;
SDL_SetTextInputRect(&ImeWindowRect);
}
int CInput::Update()
2010-05-29 07:25:38 +00:00
{
const int64_t Now = time_get();
if(m_LastUpdate != 0)
{
const float Diff = (Now - m_LastUpdate) / (float)time_freq();
m_UpdateTime = m_UpdateTime == 0.0f ? Diff : (m_UpdateTime * 0.8f + Diff * 0.2f);
}
m_LastUpdate = Now;
// keep the counter between 1..0xFFFF, 0 means not pressed
2020-09-22 16:02:03 +00:00
m_InputCounter = (m_InputCounter % 0xFFFF) + 1;
2010-05-29 07:25:38 +00:00
int NumKeyStates;
const Uint8 *pState = SDL_GetKeyboardState(&NumKeyStates);
if(NumKeyStates >= KEY_MOUSE_1)
NumKeyStates = KEY_MOUSE_1;
mem_copy(m_aInputState, pState, NumKeyStates);
mem_zero(m_aInputState + NumKeyStates, KEY_LAST - NumKeyStates);
if(m_EditingTextLen == 0)
m_EditingTextLen = -1;
2022-06-06 18:18:33 +00:00
// these states must always be updated manually because they are not in the SDL_GetKeyboardState from SDL
UpdateMouseState();
2022-06-06 19:19:08 +00:00
UpdateJoystickState();
2010-05-29 07:25:38 +00:00
SDL_Event Event;
bool IgnoreKeys = false;
while(SDL_PollEvent(&Event))
2010-05-29 07:25:38 +00:00
{
int Scancode = 0;
int Action = IInput::FLAG_PRESS;
switch(Event.type)
2010-05-29 07:25:38 +00:00
{
case SDL_TEXTEDITING:
{
m_EditingTextLen = str_length(Event.edit.text);
if(m_EditingTextLen)
2010-05-29 07:25:38 +00:00
{
2022-07-09 16:14:56 +00:00
str_copy(m_aEditingText, Event.edit.text);
m_EditingCursor = 0;
for(int i = 0; i < Event.edit.start; i++)
m_EditingCursor = str_utf8_forward(m_aEditingText, m_EditingCursor);
}
else
2020-09-22 16:02:03 +00:00
{
m_aEditingText[0] = 0;
}
break;
}
case SDL_TEXTINPUT:
m_EditingTextLen = -1;
AddEvent(Event.text.text, KEY_UNKNOWN, IInput::FLAG_TEXT);
break;
// handle keys
case SDL_KEYDOWN:
// See SDL_Keymod for possible modifiers:
// NONE = 0
// LSHIFT = 1
// RSHIFT = 2
// LCTRL = 64
// RCTRL = 128
// LALT = 256
// RALT = 512
// LGUI = 1024
// RGUI = 2048
// NUM = 4096
// CAPS = 8192
// MODE = 16384
// Sum if you want to ignore multiple modifiers.
if(!(Event.key.keysym.mod & g_Config.m_InpIgnoredModifiers))
{
Scancode = g_Config.m_InpTranslatedKeys ? SDL_GetScancodeFromKey(Event.key.keysym.sym) : Event.key.keysym.scancode;
}
break;
case SDL_KEYUP:
Action = IInput::FLAG_RELEASE;
Scancode = g_Config.m_InpTranslatedKeys ? SDL_GetScancodeFromKey(Event.key.keysym.sym) : Event.key.keysym.scancode;
break;
2022-06-06 19:19:08 +00:00
// handle the joystick events
case SDL_JOYAXISMOTION:
HandleJoystickAxisMotionEvent(Event.jaxis);
2022-06-06 19:19:08 +00:00
break;
case SDL_JOYBUTTONUP:
case SDL_JOYBUTTONDOWN:
HandleJoystickButtonEvent(Event.jbutton);
2022-06-06 19:19:08 +00:00
break;
case SDL_JOYHATMOTION:
HandleJoystickHatMotionEvent(Event.jhat);
2022-06-06 19:19:08 +00:00
break;
case SDL_JOYDEVICEADDED:
HandleJoystickAddedEvent(Event.jdevice);
break;
case SDL_JOYDEVICEREMOVED:
HandleJoystickRemovedEvent(Event.jdevice);
break;
// handle mouse buttons
case SDL_MOUSEBUTTONUP:
Action = IInput::FLAG_RELEASE;
2022-06-25 13:30:39 +00:00
[[fallthrough]];
case SDL_MOUSEBUTTONDOWN:
if(Event.button.button == SDL_BUTTON_LEFT)
Scancode = KEY_MOUSE_1;
if(Event.button.button == SDL_BUTTON_RIGHT)
Scancode = KEY_MOUSE_2;
if(Event.button.button == SDL_BUTTON_MIDDLE)
Scancode = KEY_MOUSE_3;
if(Event.button.button == SDL_BUTTON_X1)
Scancode = KEY_MOUSE_4;
if(Event.button.button == SDL_BUTTON_X2)
Scancode = KEY_MOUSE_5;
if(Event.button.button == 6)
Scancode = KEY_MOUSE_6;
if(Event.button.button == 7)
Scancode = KEY_MOUSE_7;
if(Event.button.button == 8)
Scancode = KEY_MOUSE_8;
if(Event.button.button == 9)
Scancode = KEY_MOUSE_9;
if(Event.button.button == SDL_BUTTON_LEFT)
{
if(Event.button.clicks % 2 == 0)
m_MouseDoubleClick = true;
if(Event.button.clicks == 1)
m_MouseDoubleClick = false;
}
break;
case SDL_MOUSEWHEEL:
if(Event.wheel.y > 0)
Scancode = KEY_MOUSE_WHEEL_UP;
if(Event.wheel.y < 0)
Scancode = KEY_MOUSE_WHEEL_DOWN;
if(Event.wheel.x > 0)
Scancode = KEY_MOUSE_WHEEL_LEFT;
if(Event.wheel.x < 0)
Scancode = KEY_MOUSE_WHEEL_RIGHT;
Action |= IInput::FLAG_RELEASE;
break;
case SDL_WINDOWEVENT:
// Ignore keys following a focus gain as they may be part of global
// shortcuts
switch(Event.window.event)
{
case SDL_WINDOWEVENT_MOVED:
Graphics()->Move(Event.window.data1, Event.window.data2);
break;
// listen to size changes, this includes our manual changes and the ones by the window manager
case SDL_WINDOWEVENT_SIZE_CHANGED:
Graphics()->GotResized(Event.window.data1, Event.window.data2, -1);
2020-09-22 16:02:03 +00:00
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
if(m_InputGrabbed)
2020-09-22 16:02:03 +00:00
{
// Enable this in case SDL 2.0.16 has major bugs or 2.0.18 still doesn't fix tabbing out with relative mouse
// MouseModeRelative();
// Clear pending relative mouse motion
SDL_GetRelativeMouseState(nullptr, nullptr);
2020-09-22 16:02:03 +00:00
}
m_MouseFocus = true;
IgnoreKeys = true;
2020-09-22 16:02:03 +00:00
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
m_MouseFocus = false;
IgnoreKeys = true;
if(m_InputGrabbed)
2020-09-22 16:02:03 +00:00
{
// Enable this in case SDL 2.0.16 has major bugs or 2.0.18 still doesn't fix tabbing out with relative mouse
// MouseModeAbsolute();
// Remember that we had relative mouse
m_InputGrabbed = true;
2020-09-22 16:02:03 +00:00
}
break;
case SDL_WINDOWEVENT_MINIMIZED:
Graphics()->WindowDestroyNtf(Event.window.windowID);
2020-09-22 16:02:03 +00:00
break;
case SDL_WINDOWEVENT_MAXIMIZED:
#if defined(CONF_PLATFORM_MACOS) // Todo: remove this when fixed in SDL
MouseModeAbsolute();
MouseModeRelative();
#endif
2022-06-25 13:30:39 +00:00
[[fallthrough]];
case SDL_WINDOWEVENT_RESTORED:
Graphics()->WindowCreateNtf(Event.window.windowID);
2020-09-22 16:02:03 +00:00
break;
2010-05-29 07:25:38 +00:00
}
break;
// other messages
case SDL_QUIT:
return 1;
case SDL_DROPFILE:
str_copy(m_aDropFile, Event.drop.file);
SDL_free(Event.drop.file);
break;
}
2010-05-29 07:25:38 +00:00
if(Scancode > KEY_FIRST && Scancode < g_MaxKeys && !IgnoreKeys && (!SDL_IsTextInputActive() || m_EditingTextLen == -1))
{
if(Action & IInput::FLAG_PRESS)
2010-05-29 07:25:38 +00:00
{
m_aInputState[Scancode] = 1;
m_aInputCount[Scancode] = m_InputCounter;
2010-05-29 07:25:38 +00:00
}
AddEvent(nullptr, Scancode, Action);
2010-05-29 07:25:38 +00:00
}
}
return 0;
2010-05-29 07:25:38 +00:00
}
bool CInput::GetDropFile(char *aBuf, int Len)
{
if(m_aDropFile[0] != '\0')
{
str_copy(aBuf, m_aDropFile, Len);
m_aDropFile[0] = '\0';
return true;
}
return false;
}
2020-09-22 16:02:03 +00:00
IEngineInput *CreateEngineInput()
{
return new CInput;
}