/* (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. */ #include "SDL.h" #include #include #include #include #include #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 void CInput::AddEvent(int Unicode, int Key, int Flags) { if(m_NumEvents != INPUT_BUFFER_SIZE) { m_aInputEvents[m_NumEvents].m_Unicode = Unicode; m_aInputEvents[m_NumEvents].m_Key = Key; m_aInputEvents[m_NumEvents].m_Flags = Flags; m_NumEvents++; } } CInput::CInput() { mem_zero(m_aInputCount, sizeof(m_aInputCount)); mem_zero(m_aInputState, sizeof(m_aInputState)); m_InputCurrent = 0; m_InputGrabbed = 0; m_InputDispatched = false; m_LastRelease = 0; m_ReleaseDelta = -1; m_NumEvents = 0; m_VideoRestartNeeded = 0; m_pClipboardText = NULL; } void CInput::Init() { m_pGraphics = Kernel()->RequestInterface(); MouseModeRelative(); } void CInput::MouseRelative(float *x, float *y) { #if defined(__ANDROID__) // No relative mouse on Android int nx = 0, ny = 0; SDL_GetMouseState(&nx, &ny); *x = nx; *y = ny; #else int nx = 0, ny = 0; float Sens = ((g_Config.m_ClDyncam && g_Config.m_ClDyncamMousesens) ? g_Config.m_ClDyncamMousesens : g_Config.m_InpMousesens) / 50.0f; SDL_GetRelativeMouseState(&nx,&ny); *x = nx*Sens; *y = ny*Sens; #endif } void CInput::MouseModeAbsolute() { m_InputGrabbed = 0; SDL_SetRelativeMouseMode(SDL_FALSE); Graphics()->SetWindowGrab(SDL_FALSE); } void CInput::MouseModeRelative() { m_InputGrabbed = 1; SDL_SetRelativeMouseMode(SDL_TRUE); Graphics()->SetWindowGrab(true); } int CInput::MouseDoubleClick() { if(m_ReleaseDelta >= 0 && m_ReleaseDelta < (time_freq() / 3)) { m_LastRelease = 0; m_ReleaseDelta = -1; return 1; } return 0; } const char* CInput::GetClipboardText() { if(m_pClipboardText) { SDL_free(m_pClipboardText); } m_pClipboardText = SDL_GetClipboardText(); return m_pClipboardText; } void CInput::SetClipboardText(const char *Text) { SDL_SetClipboardText(Text); } void CInput::ClearKeyStates() { mem_zero(m_aInputState, sizeof(m_aInputState)); mem_zero(m_aInputCount, sizeof(m_aInputCount)); } int CInput::KeyState(int Key) const { 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))]; } int CInput::Update() { 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; } { int i; const Uint8 *pState = SDL_GetKeyboardState(&i); 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; if(i&SDL_BUTTON(9)) m_aInputState[m_InputCurrent][KEY_MOUSE_9] = 1; { SDL_Event Event; int IgnoreKeys = false; while(SDL_PollEvent(&Event)) { int Key = -1; int Scancode = 0; int Action = IInput::FLAG_PRESS; switch (Event.type) { case SDL_TEXTINPUT: { const char *text = Event.text.text; while(*text) { int Code = str_utf8_decode(&text); if(Code == -1) break; AddEvent(Code, 0, 0); } break; } // handle keys case SDL_KEYDOWN: Key = KeycodeToKey(Event.key.keysym.sym); Scancode = Event.key.keysym.scancode; break; case SDL_KEYUP: Action = IInput::FLAG_RELEASE; Key = KeycodeToKey(Event.key.keysym.sym); Scancode = Event.key.keysym.scancode; 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 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 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 if(Event.button.button == 9) Key = KEY_MOUSE_9; // ignore_convention Scancode = Key; break; 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; case SDL_WINDOWEVENT: // Ignore keys following a focus gain as they may be part of global // shortcuts if(Event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) IgnoreKeys = true; #if defined(CONF_PLATFORM_MACOSX) // Todo: remove this when fixed in SDL if(Event.window.event == SDL_WINDOWEVENT_MAXIMIZED) { MouseModeAbsolute(); MouseModeRelative(); } #endif break; // other messages case SDL_QUIT: return 1; #if defined(__ANDROID__) case SDL_WINDOWEVENT_RESIZED: m_VideoRestartNeeded = 1; break; #endif } if(Key >= 0 && Key < 1024 && !IgnoreKeys) { m_aInputCount[m_InputCurrent][Key].m_Presses++; if(Action == IInput::FLAG_PRESS) m_aInputState[m_InputCurrent][Scancode] = 1; AddEvent(0, Key, Action); } } } return 0; } int CInput::VideoRestartNeeded() { if( m_VideoRestartNeeded ) { m_VideoRestartNeeded = 0; return 1; } return 0; } IEngineInput *CreateEngineInput() { return new CInput; }