mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Moved input handling from GuiHandler to set of classes in eventsSDL dir
This commit is contained in:
parent
5bd044521a
commit
5e86b00dda
155
client/CMT.cpp
155
client/CMT.cpp
@ -14,36 +14,27 @@
|
||||
|
||||
#include "CGameInfo.h"
|
||||
#include "mainmenu/CMainMenu.h"
|
||||
#include "mainmenu/CPrologEpilogVideo.h"
|
||||
#include "gui/CursorHandler.h"
|
||||
#include "eventsSDL/InputHandler.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "CVideoHandler.h"
|
||||
#include "CMusicHandler.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "gui/WindowHandler.h"
|
||||
#include "CServerHandler.h"
|
||||
#include "gui/NotificationHandler.h"
|
||||
#include "ClientCommandManager.h"
|
||||
#include "windows/CMessage.h"
|
||||
#include "render/IScreenHandler.h"
|
||||
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/CConsoleHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
#include "../lib/mapping/CCampaignHandler.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
|
||||
#include "../lib/logging/CBasicLogConfigurator.h"
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <vstd/StringUtils.h>
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_hints.h>
|
||||
#include <SDL_main.h>
|
||||
|
||||
#ifdef VCMI_WINDOWS
|
||||
#include <SDL_syswm.h>
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
#include "../lib/CAndroidVMHelper.h"
|
||||
@ -54,15 +45,14 @@
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
extern boost::mutex eventsM;
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace po_style = boost::program_options::command_line_style;
|
||||
namespace bfs = boost::filesystem;
|
||||
|
||||
extern boost::thread_specific_ptr<bool> inGuiThread;
|
||||
|
||||
std::queue<SDL_Event> SDLEventsQueue;
|
||||
boost::mutex eventsM;
|
||||
|
||||
static po::variables_map vm;
|
||||
|
||||
#ifndef VCMI_IOS
|
||||
@ -331,7 +321,7 @@ int main(int argc, char * argv[])
|
||||
#endif
|
||||
|
||||
#ifdef SDL_HINT_MOUSE_TOUCH_EVENTS
|
||||
if(GH.isPointerRelativeMode)
|
||||
if(settings["general"]["userRelativePointer"].Bool())
|
||||
{
|
||||
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
|
||||
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||
@ -469,147 +459,18 @@ void playIntro()
|
||||
}
|
||||
}
|
||||
|
||||
static void handleEvent(SDL_Event & ev)
|
||||
{
|
||||
if((ev.type==SDL_QUIT) ||(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4 && (ev.key.keysym.mod & KMOD_ALT)))
|
||||
{
|
||||
#ifdef VCMI_ANDROID
|
||||
handleQuit(false);
|
||||
#else
|
||||
handleQuit();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#ifdef VCMI_ANDROID
|
||||
else if (ev.type == SDL_KEYDOWN && ev.key.keysym.scancode == SDL_SCANCODE_AC_BACK)
|
||||
{
|
||||
handleQuit(true);
|
||||
}
|
||||
#endif
|
||||
else if(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4)
|
||||
{
|
||||
Settings full = settings.write["video"]["fullscreen"];
|
||||
full->Bool() = !full->Bool();
|
||||
return;
|
||||
}
|
||||
else if(ev.type == SDL_USEREVENT)
|
||||
{
|
||||
switch(static_cast<EUserEvent>(ev.user.code))
|
||||
{
|
||||
case EUserEvent::FORCE_QUIT:
|
||||
{
|
||||
handleQuit(false);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case EUserEvent::RETURN_TO_MAIN_MENU:
|
||||
{
|
||||
CSH->endGameplay();
|
||||
GH.defActionsDef = 63;
|
||||
CMM->menu->switchToTab("main");
|
||||
}
|
||||
break;
|
||||
case EUserEvent::RESTART_GAME:
|
||||
{
|
||||
CSH->sendRestartGame();
|
||||
}
|
||||
break;
|
||||
case EUserEvent::CAMPAIGN_START_SCENARIO:
|
||||
{
|
||||
CSH->campaignServerRestartLock.set(true);
|
||||
CSH->endGameplay();
|
||||
auto ourCampaign = std::shared_ptr<CCampaignState>(reinterpret_cast<CCampaignState *>(ev.user.data1));
|
||||
auto & epilogue = ourCampaign->camp->scenarios[ourCampaign->mapsConquered.back()].epilog;
|
||||
auto finisher = [=]()
|
||||
{
|
||||
if(ourCampaign->mapsRemaining.size())
|
||||
{
|
||||
GH.windows().pushWindow(CMM);
|
||||
GH.windows().pushWindow(CMM->menu);
|
||||
CMM->openCampaignLobby(ourCampaign);
|
||||
}
|
||||
};
|
||||
if(epilogue.hasPrologEpilog)
|
||||
{
|
||||
GH.windows().createAndPushWindow<CPrologEpilogVideo>(epilogue, finisher);
|
||||
}
|
||||
else
|
||||
{
|
||||
CSH->campaignServerRestartLock.waitUntil(false);
|
||||
finisher();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EUserEvent::RETURN_TO_MENU_LOAD:
|
||||
CSH->endGameplay();
|
||||
GH.defActionsDef = 63;
|
||||
CMM->menu->switchToTab("load");
|
||||
break;
|
||||
case EUserEvent::FULLSCREEN_TOGGLED:
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
|
||||
GH.onScreenResize();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
logGlobal->error("Unknown user event. Code %d", ev.user.code);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if(ev.type == SDL_WINDOWEVENT)
|
||||
{
|
||||
switch (ev.window.event) {
|
||||
case SDL_WINDOWEVENT_RESTORED:
|
||||
#ifndef VCMI_IOS
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
|
||||
GH.onScreenResize();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if(ev.type == SDL_SYSWMEVENT)
|
||||
{
|
||||
if(!settings["session"]["headless"].Bool() && settings["general"]["notifications"].Bool())
|
||||
{
|
||||
NotificationHandler::handleSdlEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
//preprocessing
|
||||
if(ev.type == SDL_MOUSEMOTION)
|
||||
{
|
||||
CCS->curh->cursorMove(ev.motion.x, ev.motion.y);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(eventsM);
|
||||
SDLEventsQueue.push(ev);
|
||||
}
|
||||
}
|
||||
|
||||
static void mainLoop()
|
||||
{
|
||||
SettingsListener resChanged = settings.listen["video"]["resolution"];
|
||||
SettingsListener fsChanged = settings.listen["video"]["fullscreen"];
|
||||
resChanged([](const JsonNode &newState){ CGuiHandler::pushUserEvent(EUserEvent::FULLSCREEN_TOGGLED); });
|
||||
fsChanged([](const JsonNode &newState){ CGuiHandler::pushUserEvent(EUserEvent::FULLSCREEN_TOGGLED); });
|
||||
resChanged([](const JsonNode &newState){ GH.pushUserEvent(EUserEvent::FULLSCREEN_TOGGLED); });
|
||||
fsChanged([](const JsonNode &newState){ GH.pushUserEvent(EUserEvent::FULLSCREEN_TOGGLED); });
|
||||
|
||||
inGuiThread.reset(new bool(true));
|
||||
|
||||
while(1) //main SDL events loop
|
||||
{
|
||||
SDL_Event ev;
|
||||
|
||||
while(1 == SDL_PollEvent(&ev))
|
||||
{
|
||||
handleEvent(ev);
|
||||
}
|
||||
|
||||
GH.input().fetchEvents();
|
||||
CSH->applyPacksOnLobbyScreen();
|
||||
GH.renderFrame();
|
||||
}
|
||||
|
@ -27,6 +27,14 @@ set(client_SRCS
|
||||
battle/BattleWindow.cpp
|
||||
battle/CreatureAnimation.cpp
|
||||
|
||||
eventsSDL/NotificationHandler.cpp
|
||||
eventsSDL/InputHandler.cpp
|
||||
eventsSDL/UserEventHandler.cpp
|
||||
eventsSDL/InputSourceKeyboard.cpp
|
||||
eventsSDL/InputSourceMouse.cpp
|
||||
eventsSDL/InputSourceText.cpp
|
||||
eventsSDL/InputSourceTouch.cpp
|
||||
|
||||
gui/CGuiHandler.cpp
|
||||
gui/CIntObject.cpp
|
||||
gui/CursorHandler.cpp
|
||||
@ -34,7 +42,6 @@ set(client_SRCS
|
||||
gui/EventsReceiver.cpp
|
||||
gui/InterfaceObjectConfigurable.cpp
|
||||
gui/FramerateManager.cpp
|
||||
gui/NotificationHandler.cpp
|
||||
gui/ShortcutHandler.cpp
|
||||
gui/WindowHandler.cpp
|
||||
|
||||
@ -162,6 +169,14 @@ set(client_HEADERS
|
||||
battle/BattleWindow.h
|
||||
battle/CreatureAnimation.h
|
||||
|
||||
eventsSDL/NotificationHandler.h
|
||||
eventsSDL/InputHandler.h
|
||||
eventsSDL/UserEventHandler.h
|
||||
eventsSDL/InputSourceKeyboard.h
|
||||
eventsSDL/InputSourceMouse.h
|
||||
eventsSDL/InputSourceText.h
|
||||
eventsSDL/InputSourceTouch.h
|
||||
|
||||
gui/CGuiHandler.h
|
||||
gui/CIntObject.h
|
||||
gui/CursorHandler.h
|
||||
@ -170,7 +185,6 @@ set(client_HEADERS
|
||||
gui/InterfaceObjectConfigurable.h
|
||||
gui/FramerateManager.h
|
||||
gui/MouseButton.h
|
||||
gui/NotificationHandler.h
|
||||
gui/Shortcut.h
|
||||
gui/ShortcutHandler.h
|
||||
gui/TextAlignment.h
|
||||
@ -337,7 +351,7 @@ if(WIN32)
|
||||
endif()
|
||||
target_compile_definitions(vcmiclient PRIVATE WINDOWS_IGNORE_PACKING_MISMATCH)
|
||||
|
||||
# TODO: very hacky, find proper solution to copy AI dlls into bin dir
|
||||
# TODO: very hacky, find proper solution to copy AI dlls into bin dir
|
||||
if(MSVC)
|
||||
add_custom_command(TARGET vcmiclient POST_BUILD
|
||||
WORKING_DIRECTORY "$<TARGET_FILE_DIR:vcmiclient>"
|
||||
|
@ -74,7 +74,7 @@
|
||||
#include "CServerHandler.h"
|
||||
// FIXME: only needed for CGameState::mutex
|
||||
#include "../lib/CGameState.h"
|
||||
#include "gui/NotificationHandler.h"
|
||||
#include "eventsSDL/NotificationHandler.h"
|
||||
#include "adventureMap/CInGameConsole.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
|
@ -843,7 +843,7 @@ void CServerHandler::threadHandleConnection()
|
||||
if(client)
|
||||
{
|
||||
state = EClientState::DISCONNECTING;
|
||||
CGuiHandler::pushUserEvent(EUserEvent::RETURN_TO_MAIN_MENU);
|
||||
GH.pushUserEvent(EUserEvent::RETURN_TO_MAIN_MENU);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -371,7 +371,7 @@ void CVideoPlayer::update( int x, int y, SDL_Surface *dst, bool forceRedraw, boo
|
||||
auto packet_duration = frame->duration;
|
||||
#endif
|
||||
double frameEndTime = (frame->pts + packet_duration) * av_q2d(format->streams[stream]->time_base);
|
||||
frameTime += GH.framerateManager().getElapsedMilliseconds() / 1000.0;
|
||||
frameTime += GH.framerate().getElapsedMilliseconds() / 1000.0;
|
||||
|
||||
if (frameTime >= frameEndTime )
|
||||
{
|
||||
|
250
client/eventsSDL/InputHandler.cpp
Normal file
250
client/eventsSDL/InputHandler.cpp
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* InputHandler.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "InputHandler.h"
|
||||
|
||||
#include "NotificationHandler.h"
|
||||
#include "InputSourceMouse.h"
|
||||
#include "InputSourceKeyboard.h"
|
||||
#include "InputSourceTouch.h"
|
||||
#include "InputSourceText.h"
|
||||
#include "UserEventHandler.h"
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/CursorHandler.h"
|
||||
#include "../gui/EventDispatcher.h"
|
||||
#include "../CMT.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CGameInfo.h"
|
||||
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
|
||||
std::queue<SDL_Event> SDLEventsQueue;
|
||||
boost::mutex eventsM;
|
||||
|
||||
InputHandler::InputHandler()
|
||||
: mouseHandler(std::make_unique<InputSourceMouse>())
|
||||
, keyboardHandler(std::make_unique<InputSourceKeyboard>())
|
||||
, fingerHandler(std::make_unique<InputSourceTouch>())
|
||||
, textHandler(std::make_unique<InputSourceText>())
|
||||
, userHandler(std::make_unique<UserEventHandler>())
|
||||
, mouseButtonsMask(0)
|
||||
, pointerSpeedMultiplier(settings["general"]["relativePointerSpeedMultiplier"].Float())
|
||||
{
|
||||
}
|
||||
|
||||
InputHandler::~InputHandler() = default;
|
||||
|
||||
void InputHandler::handleCurrentEvent(const SDL_Event & current)
|
||||
{
|
||||
switch (current.type)
|
||||
{
|
||||
case SDL_KEYDOWN:
|
||||
return keyboardHandler->handleEventKeyDown(current.key);
|
||||
case SDL_KEYUP:
|
||||
return keyboardHandler->handleEventKeyUp(current.key);
|
||||
case SDL_MOUSEMOTION:
|
||||
return mouseHandler->handleEventMouseMotion(current.motion);
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
return mouseHandler->handleEventMouseButtonDown(current.button);
|
||||
case SDL_MOUSEWHEEL:
|
||||
return mouseHandler->handleEventMouseWheel(current.wheel);
|
||||
case SDL_TEXTINPUT:
|
||||
return textHandler->handleEventTextInput(current.text);
|
||||
case SDL_TEXTEDITING:
|
||||
return textHandler->handleEventTextEditing(current.edit);
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
return mouseHandler->handleEventMouseButtonUp(current.button);
|
||||
case SDL_FINGERMOTION:
|
||||
return fingerHandler->handleEventFingerMotion(current.tfinger);
|
||||
case SDL_FINGERDOWN:
|
||||
return fingerHandler->handleEventFingerDown(current.tfinger);
|
||||
case SDL_FINGERUP:
|
||||
return fingerHandler->handleEventFingerUp(current.tfinger);
|
||||
}
|
||||
}
|
||||
|
||||
void InputHandler::processEvents()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(eventsM);
|
||||
while(!SDLEventsQueue.empty())
|
||||
{
|
||||
GH.events().allowEventHandling(true);
|
||||
SDL_Event currentEvent = SDLEventsQueue.front();
|
||||
|
||||
if (currentEvent.type == SDL_MOUSEMOTION)
|
||||
{
|
||||
cursorPosition = Point(currentEvent.motion.x, currentEvent.motion.y);
|
||||
mouseButtonsMask = currentEvent.motion.state;
|
||||
}
|
||||
SDLEventsQueue.pop();
|
||||
|
||||
// In a sequence of mouse motion events, skip all but the last one.
|
||||
// This prevents freezes when every motion event takes longer to handle than interval at which
|
||||
// the events arrive (like dragging on the minimap in world view, with redraw at every event)
|
||||
// so that the events would start piling up faster than they can be processed.
|
||||
if ((currentEvent.type == SDL_MOUSEMOTION) && !SDLEventsQueue.empty() && (SDLEventsQueue.front().type == SDL_MOUSEMOTION))
|
||||
continue;
|
||||
|
||||
handleCurrentEvent(currentEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void InputHandler::preprocessEvent(const SDL_Event & ev)
|
||||
{
|
||||
if((ev.type==SDL_QUIT) ||(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4 && (ev.key.keysym.mod & KMOD_ALT)))
|
||||
{
|
||||
#ifdef VCMI_ANDROID
|
||||
handleQuit(false);
|
||||
#else
|
||||
handleQuit();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#ifdef VCMI_ANDROID
|
||||
else if (ev.type == SDL_KEYDOWN && ev.key.keysym.scancode == SDL_SCANCODE_AC_BACK)
|
||||
{
|
||||
handleQuit(true);
|
||||
}
|
||||
#endif
|
||||
else if(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4)
|
||||
{
|
||||
Settings full = settings.write["video"]["fullscreen"];
|
||||
full->Bool() = !full->Bool();
|
||||
return;
|
||||
}
|
||||
else if(ev.type == SDL_USEREVENT)
|
||||
{
|
||||
userHandler->handleUserEvent(ev.user);
|
||||
|
||||
return;
|
||||
}
|
||||
else if(ev.type == SDL_WINDOWEVENT)
|
||||
{
|
||||
switch (ev.window.event) {
|
||||
case SDL_WINDOWEVENT_RESTORED:
|
||||
#ifndef VCMI_IOS
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
|
||||
GH.onScreenResize();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if(ev.type == SDL_SYSWMEVENT)
|
||||
{
|
||||
if(!settings["session"]["headless"].Bool() && settings["general"]["notifications"].Bool())
|
||||
{
|
||||
NotificationHandler::handleSdlEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
//preprocessing
|
||||
if(ev.type == SDL_MOUSEMOTION)
|
||||
{
|
||||
CCS->curh->cursorMove(ev.motion.x, ev.motion.y);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(eventsM);
|
||||
SDLEventsQueue.push(ev);
|
||||
}
|
||||
}
|
||||
|
||||
void InputHandler::fetchEvents()
|
||||
{
|
||||
SDL_Event ev;
|
||||
|
||||
while(1 == SDL_PollEvent(&ev))
|
||||
{
|
||||
preprocessEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
bool InputHandler::isKeyboardCtrlDown() const
|
||||
{
|
||||
#ifdef VCMI_MAC
|
||||
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LGUI] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RGUI];
|
||||
#else
|
||||
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LCTRL] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RCTRL];
|
||||
#endif
|
||||
}
|
||||
|
||||
bool InputHandler::isKeyboardAltDown() const
|
||||
{
|
||||
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LALT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RALT];
|
||||
}
|
||||
|
||||
bool InputHandler::isKeyboardShiftDown() const
|
||||
{
|
||||
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RSHIFT];
|
||||
}
|
||||
|
||||
|
||||
void InputHandler::fakeMoveCursor(float dx, float dy)
|
||||
{
|
||||
int x, y, w, h;
|
||||
|
||||
SDL_Event event;
|
||||
SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
sme.state = SDL_GetMouseState(&x, &y);
|
||||
SDL_GetWindowSize(mainWindow, &w, &h);
|
||||
|
||||
sme.x = GH.getCursorPosition().x + (int)(pointerSpeedMultiplier * w * dx);
|
||||
sme.y = GH.getCursorPosition().y + (int)(pointerSpeedMultiplier * h * dy);
|
||||
|
||||
vstd::abetween(sme.x, 0, w);
|
||||
vstd::abetween(sme.y, 0, h);
|
||||
|
||||
event.motion = sme;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
void InputHandler::startTextInput(const Rect & where)
|
||||
{
|
||||
textHandler->startTextInput(where);
|
||||
}
|
||||
|
||||
void InputHandler::stopTextInput()
|
||||
{
|
||||
textHandler->stopTextInput();
|
||||
}
|
||||
|
||||
bool InputHandler::isMouseButtonPressed(MouseButton button) const
|
||||
{
|
||||
static_assert(static_cast<uint32_t>(MouseButton::LEFT) == SDL_BUTTON_LEFT, "mismatch between VCMI and SDL enum!");
|
||||
static_assert(static_cast<uint32_t>(MouseButton::MIDDLE) == SDL_BUTTON_MIDDLE, "mismatch between VCMI and SDL enum!");
|
||||
static_assert(static_cast<uint32_t>(MouseButton::RIGHT) == SDL_BUTTON_RIGHT, "mismatch between VCMI and SDL enum!");
|
||||
static_assert(static_cast<uint32_t>(MouseButton::EXTRA1) == SDL_BUTTON_X1, "mismatch between VCMI and SDL enum!");
|
||||
static_assert(static_cast<uint32_t>(MouseButton::EXTRA2) == SDL_BUTTON_X2, "mismatch between VCMI and SDL enum!");
|
||||
|
||||
uint32_t index = static_cast<uint32_t>(button);
|
||||
return mouseButtonsMask & SDL_BUTTON(index);
|
||||
}
|
||||
|
||||
void InputHandler::pushUserEvent(EUserEvent usercode, void * userdata)
|
||||
{
|
||||
SDL_Event event;
|
||||
event.type = SDL_USEREVENT;
|
||||
event.user.code = static_cast<int32_t>(usercode);
|
||||
event.user.data1 = userdata;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
const Point & InputHandler::getCursorPosition() const
|
||||
{
|
||||
return cursorPosition;
|
||||
}
|
59
client/eventsSDL/InputHandler.h
Normal file
59
client/eventsSDL/InputHandler.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* InputHandler.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../lib/Rect.h"
|
||||
|
||||
enum class EUserEvent;
|
||||
enum class MouseButton;
|
||||
union SDL_Event;
|
||||
|
||||
class InputSourceMouse;
|
||||
class InputSourceKeyboard;
|
||||
class InputSourceTouch;
|
||||
class InputSourceText;
|
||||
class UserEventHandler;
|
||||
|
||||
class InputHandler
|
||||
{
|
||||
Point cursorPosition;
|
||||
float pointerSpeedMultiplier;
|
||||
int mouseButtonsMask;
|
||||
|
||||
void preprocessEvent(const SDL_Event & event);
|
||||
void handleCurrentEvent(const SDL_Event & current);
|
||||
|
||||
std::unique_ptr<InputSourceMouse> mouseHandler;
|
||||
std::unique_ptr<InputSourceKeyboard> keyboardHandler;
|
||||
std::unique_ptr<InputSourceTouch> fingerHandler;
|
||||
std::unique_ptr<InputSourceText> textHandler;
|
||||
std::unique_ptr<UserEventHandler> userHandler;
|
||||
|
||||
public:
|
||||
InputHandler();
|
||||
~InputHandler();
|
||||
|
||||
void fetchEvents();
|
||||
void processEvents();
|
||||
|
||||
void fakeMoveCursor(float dx, float dy);
|
||||
void startTextInput(const Rect & where);
|
||||
void stopTextInput();
|
||||
bool isMouseButtonPressed(MouseButton button) const;
|
||||
void pushUserEvent(EUserEvent usercode, void * userdata);
|
||||
|
||||
const Point & getCursorPosition() const;
|
||||
|
||||
/// returns true if chosen keyboard key is currently pressed down
|
||||
bool isKeyboardAltDown() const;
|
||||
bool isKeyboardCtrlDown() const;
|
||||
bool isKeyboardShiftDown() const;
|
||||
};
|
76
client/eventsSDL/InputSourceKeyboard.cpp
Normal file
76
client/eventsSDL/InputSourceKeyboard.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* InputSourceKeyboard.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "InputSourceKeyboard.h"
|
||||
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/EventDispatcher.h"
|
||||
#include "../gui/ShortcutHandler.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
|
||||
void InputSourceKeyboard::handleEventKeyDown(const SDL_KeyboardEvent & key)
|
||||
{
|
||||
if(key.repeat != 0)
|
||||
return; // ignore periodic event resends
|
||||
|
||||
assert(key.state == SDL_PRESSED);
|
||||
|
||||
if(key.keysym.sym >= SDLK_F1 && key.keysym.sym <= SDLK_F15 && settings["session"]["spectate"].Bool())
|
||||
{
|
||||
//TODO: we need some central place for all interface-independent hotkeys
|
||||
Settings s = settings.write["session"];
|
||||
switch(key.keysym.sym)
|
||||
{
|
||||
case SDLK_F5:
|
||||
if(settings["session"]["spectate-locked-pim"].Bool())
|
||||
CPlayerInterface::pim->unlock();
|
||||
else
|
||||
CPlayerInterface::pim->lock();
|
||||
s["spectate-locked-pim"].Bool() = !settings["session"]["spectate-locked-pim"].Bool();
|
||||
break;
|
||||
|
||||
case SDLK_F6:
|
||||
s["spectate-ignore-hero"].Bool() = !settings["session"]["spectate-ignore-hero"].Bool();
|
||||
break;
|
||||
|
||||
case SDLK_F7:
|
||||
s["spectate-skip-battle"].Bool() = !settings["session"]["spectate-skip-battle"].Bool();
|
||||
break;
|
||||
|
||||
case SDLK_F8:
|
||||
s["spectate-skip-battle-result"].Bool() = !settings["session"]["spectate-skip-battle-result"].Bool();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto shortcutsVector = GH.shortcuts().translateKeycode(key.keysym.sym);
|
||||
|
||||
GH.events().dispatchShortcutPressed(shortcutsVector);
|
||||
}
|
||||
|
||||
void InputSourceKeyboard::handleEventKeyUp(const SDL_KeyboardEvent & key)
|
||||
{
|
||||
if(key.repeat != 0)
|
||||
return; // ignore periodic event resends
|
||||
|
||||
assert(key.state == SDL_RELEASED);
|
||||
|
||||
auto shortcutsVector = GH.shortcuts().translateKeycode(key.keysym.sym);
|
||||
|
||||
GH.events().dispatchShortcutReleased(shortcutsVector);
|
||||
}
|
20
client/eventsSDL/InputSourceKeyboard.h
Normal file
20
client/eventsSDL/InputSourceKeyboard.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* InputSourceKeyboard.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct SDL_KeyboardEvent;
|
||||
|
||||
class InputSourceKeyboard
|
||||
{
|
||||
public:
|
||||
void handleEventKeyDown(const SDL_KeyboardEvent & current);
|
||||
void handleEventKeyUp(const SDL_KeyboardEvent & current);
|
||||
};
|
72
client/eventsSDL/InputSourceMouse.cpp
Normal file
72
client/eventsSDL/InputSourceMouse.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* InputSourceMouse.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "InputSourceMouse.h"
|
||||
|
||||
#include "../../lib/Point.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/EventDispatcher.h"
|
||||
#include "../gui/MouseButton.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
|
||||
void InputSourceMouse::handleEventMouseMotion(const SDL_MouseMotionEvent & motion)
|
||||
{
|
||||
GH.events().dispatchMouseMoved(Point(motion.x, motion.y));
|
||||
}
|
||||
|
||||
void InputSourceMouse::handleEventMouseButtonDown(const SDL_MouseButtonEvent & button)
|
||||
{
|
||||
Point position(button.x, button.y);
|
||||
|
||||
switch(button.button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT:
|
||||
if(button.clicks > 1)
|
||||
GH.events().dispatchMouseDoubleClick(position);
|
||||
else
|
||||
GH.events().dispatchMouseButtonPressed(MouseButton::LEFT, position);
|
||||
break;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
GH.events().dispatchMouseButtonPressed(MouseButton::RIGHT, position);
|
||||
break;
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
GH.events().dispatchMouseButtonPressed(MouseButton::MIDDLE, position);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void InputSourceMouse::handleEventMouseWheel(const SDL_MouseWheelEvent & wheel)
|
||||
{
|
||||
// SDL doesn't have the proper values for mouse positions on SDL_MOUSEWHEEL, refetch them
|
||||
int x = 0, y = 0;
|
||||
SDL_GetMouseState(&x, &y);
|
||||
|
||||
GH.events().dispatchMouseScrolled(Point(wheel.x, wheel.y), Point(x, y));
|
||||
}
|
||||
|
||||
void InputSourceMouse::handleEventMouseButtonUp(const SDL_MouseButtonEvent & button)
|
||||
{
|
||||
Point position(button.x, button.y);
|
||||
|
||||
switch(button.button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT:
|
||||
GH.events().dispatchMouseButtonReleased(MouseButton::LEFT, position);
|
||||
break;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
GH.events().dispatchMouseButtonReleased(MouseButton::RIGHT, position);
|
||||
break;
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
GH.events().dispatchMouseButtonReleased(MouseButton::MIDDLE, position);
|
||||
break;
|
||||
}
|
||||
}
|
24
client/eventsSDL/InputSourceMouse.h
Normal file
24
client/eventsSDL/InputSourceMouse.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* InputSourceMouse.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct SDL_MouseWheelEvent;
|
||||
struct SDL_MouseMotionEvent;
|
||||
struct SDL_MouseButtonEvent;
|
||||
|
||||
class InputSourceMouse
|
||||
{
|
||||
public:
|
||||
void handleEventMouseMotion(const SDL_MouseMotionEvent & current);
|
||||
void handleEventMouseButtonDown(const SDL_MouseButtonEvent & current);
|
||||
void handleEventMouseWheel(const SDL_MouseWheelEvent & current);
|
||||
void handleEventMouseButtonUp(const SDL_MouseButtonEvent & current);
|
||||
};
|
92
client/eventsSDL/InputSourceText.cpp
Normal file
92
client/eventsSDL/InputSourceText.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* InputSourceText.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "InputSourceText.h"
|
||||
|
||||
#include "../CMT.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/EventDispatcher.h"
|
||||
|
||||
#include "../../lib/Rect.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_render.h>
|
||||
|
||||
#ifdef VCMI_APPLE
|
||||
# include <dispatch/dispatch.h>
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_IOS
|
||||
# include "ios/utils.h"
|
||||
#endif
|
||||
|
||||
void InputSourceText::handleEventTextInput(const SDL_TextInputEvent & text)
|
||||
{
|
||||
GH.events().dispatchTextInput(text.text);
|
||||
}
|
||||
|
||||
void InputSourceText::handleEventTextEditing(const SDL_TextEditingEvent & text)
|
||||
{
|
||||
GH.events().dispatchTextEditing(text.text);
|
||||
}
|
||||
|
||||
void InputSourceText::startTextInput(const Rect & whereInput)
|
||||
{
|
||||
#ifdef VCMI_APPLE
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#endif
|
||||
|
||||
// TODO ios: looks like SDL bug actually, try fixing there
|
||||
auto renderer = SDL_GetRenderer(mainWindow);
|
||||
float scaleX, scaleY;
|
||||
SDL_Rect viewport;
|
||||
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
|
||||
SDL_RenderGetViewport(renderer, &viewport);
|
||||
|
||||
#ifdef VCMI_IOS
|
||||
const auto nativeScale = iOS_utils::screenScale();
|
||||
scaleX /= nativeScale;
|
||||
scaleY /= nativeScale;
|
||||
#endif
|
||||
|
||||
SDL_Rect rectInScreenCoordinates;
|
||||
rectInScreenCoordinates.x = (viewport.x + whereInput.x) * scaleX;
|
||||
rectInScreenCoordinates.y = (viewport.y + whereInput.y) * scaleY;
|
||||
rectInScreenCoordinates.w = whereInput.w * scaleX;
|
||||
rectInScreenCoordinates.h = whereInput.h * scaleY;
|
||||
|
||||
SDL_SetTextInputRect(&rectInScreenCoordinates);
|
||||
|
||||
if (SDL_IsTextInputActive() == SDL_FALSE)
|
||||
{
|
||||
SDL_StartTextInput();
|
||||
}
|
||||
|
||||
#ifdef VCMI_APPLE
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputSourceText::stopTextInput()
|
||||
{
|
||||
#ifdef VCMI_APPLE
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#endif
|
||||
|
||||
if (SDL_IsTextInputActive() == SDL_TRUE)
|
||||
{
|
||||
SDL_StopTextInput();
|
||||
}
|
||||
|
||||
#ifdef VCMI_APPLE
|
||||
});
|
||||
#endif
|
||||
}
|
28
client/eventsSDL/InputSourceText.h
Normal file
28
client/eventsSDL/InputSourceText.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* InputSourceText.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class Rect;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
struct SDL_TextEditingEvent;
|
||||
struct SDL_TextInputEvent;
|
||||
|
||||
class InputSourceText
|
||||
{
|
||||
public:
|
||||
void handleEventTextInput(const SDL_TextInputEvent & current);
|
||||
void handleEventTextEditing(const SDL_TextEditingEvent & current);
|
||||
|
||||
void startTextInput(const Rect & where);
|
||||
void stopTextInput();
|
||||
};
|
128
client/eventsSDL/InputSourceTouch.cpp
Normal file
128
client/eventsSDL/InputSourceTouch.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* InputSourceTouch.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "InputSourceTouch.h"
|
||||
|
||||
#include "InputHandler.h"
|
||||
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../CMT.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/EventDispatcher.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_render.h>
|
||||
|
||||
InputSourceTouch::InputSourceTouch()
|
||||
: multifinger(false)
|
||||
, isPointerRelativeMode(settings["general"]["userRelativePointer"].Bool())
|
||||
{
|
||||
}
|
||||
|
||||
void InputSourceTouch::handleEventFingerMotion(const SDL_TouchFingerEvent & tfinger)
|
||||
{
|
||||
if(isPointerRelativeMode)
|
||||
{
|
||||
GH.input().fakeMoveCursor(tfinger.dx, tfinger.dy);
|
||||
}
|
||||
}
|
||||
|
||||
void InputSourceTouch::handleEventFingerDown(const SDL_TouchFingerEvent & tfinger)
|
||||
{
|
||||
auto fingerCount = SDL_GetNumTouchFingers(tfinger.touchId);
|
||||
|
||||
multifinger = fingerCount > 1;
|
||||
|
||||
if(isPointerRelativeMode)
|
||||
{
|
||||
if(tfinger.x > 0.5)
|
||||
{
|
||||
bool isRightClick = tfinger.y < 0.5;
|
||||
|
||||
fakeMouseButtonEventRelativeMode(true, isRightClick);
|
||||
}
|
||||
}
|
||||
#ifndef VCMI_IOS
|
||||
else if(fingerCount == 2)
|
||||
{
|
||||
Point position = convertTouchToMouse(tfinger);
|
||||
|
||||
GH.events().dispatchMouseMoved(position);
|
||||
GH.events().dispatchMouseButtonPressed(MouseButton::RIGHT, position);
|
||||
}
|
||||
#endif //VCMI_IOS
|
||||
}
|
||||
|
||||
void InputSourceTouch::handleEventFingerUp(const SDL_TouchFingerEvent & tfinger)
|
||||
{
|
||||
#ifndef VCMI_IOS
|
||||
auto fingerCount = SDL_GetNumTouchFingers(tfinger.touchId);
|
||||
#endif //VCMI_IOS
|
||||
|
||||
if(isPointerRelativeMode)
|
||||
{
|
||||
if(tfinger.x > 0.5)
|
||||
{
|
||||
bool isRightClick = tfinger.y < 0.5;
|
||||
|
||||
fakeMouseButtonEventRelativeMode(false, isRightClick);
|
||||
}
|
||||
}
|
||||
#ifndef VCMI_IOS
|
||||
else if(multifinger)
|
||||
{
|
||||
Point position = convertTouchToMouse(tfinger);
|
||||
GH.events().dispatchMouseMoved(position);
|
||||
GH.events().dispatchMouseButtonReleased(MouseButton::RIGHT, position);
|
||||
multifinger = fingerCount != 0;
|
||||
}
|
||||
#endif //VCMI_IOS
|
||||
}
|
||||
|
||||
Point InputSourceTouch::convertTouchToMouse(const SDL_TouchFingerEvent & tfinger)
|
||||
{
|
||||
return Point(tfinger.x * GH.screenDimensions().x, tfinger.y * GH.screenDimensions().y);
|
||||
}
|
||||
|
||||
void InputSourceTouch::fakeMouseButtonEventRelativeMode(bool down, bool right)
|
||||
{
|
||||
SDL_Event event;
|
||||
SDL_MouseButtonEvent sme = {SDL_MOUSEBUTTONDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
if(!down)
|
||||
{
|
||||
sme.type = SDL_MOUSEBUTTONUP;
|
||||
}
|
||||
|
||||
sme.button = right ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT;
|
||||
|
||||
sme.x = GH.getCursorPosition().x;
|
||||
sme.y = GH.getCursorPosition().y;
|
||||
|
||||
float xScale, yScale;
|
||||
int w, h, rLogicalWidth, rLogicalHeight;
|
||||
|
||||
SDL_GetWindowSize(mainWindow, &w, &h);
|
||||
SDL_RenderGetLogicalSize(mainRenderer, &rLogicalWidth, &rLogicalHeight);
|
||||
SDL_RenderGetScale(mainRenderer, &xScale, &yScale);
|
||||
|
||||
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
|
||||
moveCursorToPosition(Point((int)(sme.x * xScale) + (w - rLogicalWidth * xScale) / 2, (int)(sme.y * yScale + (h - rLogicalHeight * yScale) / 2)));
|
||||
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
|
||||
|
||||
event.button = sme;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
void InputSourceTouch::moveCursorToPosition(const Point & position)
|
||||
{
|
||||
SDL_WarpMouseInWindow(mainWindow, position.x, position.y);
|
||||
}
|
36
client/eventsSDL/InputSourceTouch.h
Normal file
36
client/eventsSDL/InputSourceTouch.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* InputSourceTouch.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class Point;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
struct SDL_TouchFingerEvent;
|
||||
|
||||
class InputSourceTouch
|
||||
{
|
||||
bool multifinger;
|
||||
bool isPointerRelativeMode;
|
||||
|
||||
/// moves mouse pointer into specified position inside vcmi window
|
||||
void moveCursorToPosition(const Point & position);
|
||||
Point convertTouchToMouse(const SDL_TouchFingerEvent & current);
|
||||
|
||||
void fakeMouseButtonEventRelativeMode(bool down, bool right);
|
||||
|
||||
public:
|
||||
InputSourceTouch();
|
||||
|
||||
void handleEventFingerMotion(const SDL_TouchFingerEvent & current);
|
||||
void handleEventFingerDown(const SDL_TouchFingerEvent & current);
|
||||
void handleEventFingerUp(const SDL_TouchFingerEvent & current);
|
||||
};
|
@ -10,11 +10,11 @@
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "NotificationHandler.h"
|
||||
#include <SDL_video.h>
|
||||
#include <SDL_events.h>
|
||||
|
||||
#if defined(VCMI_WINDOWS)
|
||||
#include <SDL_syswm.h>
|
||||
#include <SDL_video.h>
|
||||
#include <SDL_events.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files:
|
87
client/eventsSDL/UserEventHandler.cpp
Normal file
87
client/eventsSDL/UserEventHandler.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* EventHandlerSDLUser.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "UserEventHandler.h"
|
||||
|
||||
#include "../CMT.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CServerHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/WindowHandler.h"
|
||||
#include "../mainmenu/CMainMenu.h"
|
||||
#include "../mainmenu/CPrologEpilogVideo.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
|
||||
void UserEventHandler::handleUserEvent(const SDL_UserEvent & user)
|
||||
{
|
||||
switch(static_cast<EUserEvent>(user.code))
|
||||
{
|
||||
case EUserEvent::FORCE_QUIT:
|
||||
{
|
||||
handleQuit(false);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case EUserEvent::RETURN_TO_MAIN_MENU:
|
||||
{
|
||||
CSH->endGameplay();
|
||||
GH.defActionsDef = 63;
|
||||
CMM->menu->switchToTab("main");
|
||||
}
|
||||
break;
|
||||
case EUserEvent::RESTART_GAME:
|
||||
{
|
||||
CSH->sendRestartGame();
|
||||
}
|
||||
break;
|
||||
case EUserEvent::CAMPAIGN_START_SCENARIO:
|
||||
{
|
||||
CSH->campaignServerRestartLock.set(true);
|
||||
CSH->endGameplay();
|
||||
auto ourCampaign = std::shared_ptr<CCampaignState>(reinterpret_cast<CCampaignState *>(user.data1));
|
||||
auto & epilogue = ourCampaign->camp->scenarios[ourCampaign->mapsConquered.back()].epilog;
|
||||
auto finisher = [=]()
|
||||
{
|
||||
if(!ourCampaign->mapsRemaining.empty())
|
||||
{
|
||||
GH.windows().pushWindow(CMM);
|
||||
GH.windows().pushWindow(CMM->menu);
|
||||
CMM->openCampaignLobby(ourCampaign);
|
||||
}
|
||||
};
|
||||
if(epilogue.hasPrologEpilog)
|
||||
{
|
||||
GH.windows().createAndPushWindow<CPrologEpilogVideo>(epilogue, finisher);
|
||||
}
|
||||
else
|
||||
{
|
||||
CSH->campaignServerRestartLock.waitUntil(false);
|
||||
finisher();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EUserEvent::RETURN_TO_MENU_LOAD:
|
||||
CSH->endGameplay();
|
||||
GH.defActionsDef = 63;
|
||||
CMM->menu->switchToTab("load");
|
||||
break;
|
||||
case EUserEvent::FULLSCREEN_TOGGLED:
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
|
||||
GH.onScreenResize();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
logGlobal->error("Unknown user event. Code %d", user.code);
|
||||
break;
|
||||
}
|
||||
}
|
19
client/eventsSDL/UserEventHandler.h
Normal file
19
client/eventsSDL/UserEventHandler.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* EventHandlerSDLUser.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct SDL_UserEvent;
|
||||
|
||||
class UserEventHandler
|
||||
{
|
||||
public:
|
||||
void handleUserEvent(const SDL_UserEvent & current);
|
||||
};
|
@ -17,6 +17,7 @@
|
||||
#include "FramerateManager.h"
|
||||
#include "WindowHandler.h"
|
||||
#include "EventDispatcher.h"
|
||||
#include "../eventsSDL/InputHandler.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../render/Colors.h"
|
||||
@ -30,17 +31,6 @@
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
|
||||
#include <SDL_render.h>
|
||||
#include <SDL_timer.h>
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_keycode.h>
|
||||
|
||||
#ifdef VCMI_APPLE
|
||||
#include <dispatch/dispatch.h>
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_IOS
|
||||
#include "ios/utils.h"
|
||||
#endif
|
||||
|
||||
CGuiHandler GH;
|
||||
|
||||
@ -80,382 +70,38 @@ SSetCaptureState::~SSetCaptureState()
|
||||
|
||||
void CGuiHandler::init()
|
||||
{
|
||||
inputHandlerInstance = std::make_unique<InputHandler>();
|
||||
eventDispatcherInstance = std::make_unique<EventDispatcher>();
|
||||
windowHandlerInstance = std::make_unique<WindowHandler>();
|
||||
screenHandlerInstance = std::make_unique<ScreenHandler>();
|
||||
shortcutsHandlerInstance = std::make_unique<ShortcutHandler>();
|
||||
framerateManagerInstance = std::make_unique<FramerateManager>(settings["video"]["targetfps"].Integer());
|
||||
|
||||
isPointerRelativeMode = settings["general"]["userRelativePointer"].Bool();
|
||||
pointerSpeedMultiplier = settings["general"]["relativePointerSpeedMultiplier"].Float();
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEvents()
|
||||
{
|
||||
eventDispatcher().dispatchTimer(framerateManager().getElapsedMilliseconds());
|
||||
events().dispatchTimer(framerate().getElapsedMilliseconds());
|
||||
|
||||
//player interface may want special event handling
|
||||
if(nullptr != LOCPLINT && LOCPLINT->capturedAllEvents())
|
||||
return;
|
||||
|
||||
boost::unique_lock<boost::mutex> lock(eventsM);
|
||||
while(!SDLEventsQueue.empty())
|
||||
{
|
||||
eventDispatcher().allowEventHandling(true);
|
||||
SDL_Event currentEvent = SDLEventsQueue.front();
|
||||
|
||||
if (currentEvent.type == SDL_MOUSEMOTION)
|
||||
{
|
||||
cursorPosition = Point(currentEvent.motion.x, currentEvent.motion.y);
|
||||
mouseButtonsMask = currentEvent.motion.state;
|
||||
}
|
||||
SDLEventsQueue.pop();
|
||||
|
||||
// In a sequence of mouse motion events, skip all but the last one.
|
||||
// This prevents freezes when every motion event takes longer to handle than interval at which
|
||||
// the events arrive (like dragging on the minimap in world view, with redraw at every event)
|
||||
// so that the events would start piling up faster than they can be processed.
|
||||
if ((currentEvent.type == SDL_MOUSEMOTION) && !SDLEventsQueue.empty() && (SDLEventsQueue.front().type == SDL_MOUSEMOTION))
|
||||
continue;
|
||||
|
||||
handleCurrentEvent(currentEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void CGuiHandler::convertTouchToMouse(SDL_Event * current)
|
||||
{
|
||||
int rLogicalWidth, rLogicalHeight;
|
||||
|
||||
SDL_RenderGetLogicalSize(mainRenderer, &rLogicalWidth, &rLogicalHeight);
|
||||
|
||||
int adjustedMouseY = (int)(current->tfinger.y * rLogicalHeight);
|
||||
int adjustedMouseX = (int)(current->tfinger.x * rLogicalWidth);
|
||||
|
||||
current->button.x = adjustedMouseX;
|
||||
current->motion.x = adjustedMouseX;
|
||||
current->button.y = adjustedMouseY;
|
||||
current->motion.y = adjustedMouseY;
|
||||
}
|
||||
|
||||
void CGuiHandler::fakeMoveCursor(float dx, float dy)
|
||||
{
|
||||
int x, y, w, h;
|
||||
|
||||
SDL_Event event;
|
||||
SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
sme.state = SDL_GetMouseState(&x, &y);
|
||||
SDL_GetWindowSize(mainWindow, &w, &h);
|
||||
|
||||
sme.x = CCS->curh->position().x + (int)(GH.pointerSpeedMultiplier * w * dx);
|
||||
sme.y = CCS->curh->position().y + (int)(GH.pointerSpeedMultiplier * h * dy);
|
||||
|
||||
vstd::abetween(sme.x, 0, w);
|
||||
vstd::abetween(sme.y, 0, h);
|
||||
|
||||
event.motion = sme;
|
||||
SDL_PushEvent(&event);
|
||||
input().processEvents();
|
||||
}
|
||||
|
||||
void CGuiHandler::fakeMouseMove()
|
||||
{
|
||||
fakeMoveCursor(0, 0);
|
||||
input().fakeMoveCursor(0, 0);
|
||||
}
|
||||
|
||||
void CGuiHandler::startTextInput(const Rect & whereInput)
|
||||
{
|
||||
#ifdef VCMI_APPLE
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#endif
|
||||
|
||||
// TODO ios: looks like SDL bug actually, try fixing there
|
||||
auto renderer = SDL_GetRenderer(mainWindow);
|
||||
float scaleX, scaleY;
|
||||
SDL_Rect viewport;
|
||||
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
|
||||
SDL_RenderGetViewport(renderer, &viewport);
|
||||
|
||||
#ifdef VCMI_IOS
|
||||
const auto nativeScale = iOS_utils::screenScale();
|
||||
scaleX /= nativeScale;
|
||||
scaleY /= nativeScale;
|
||||
#endif
|
||||
|
||||
SDL_Rect rectInScreenCoordinates;
|
||||
rectInScreenCoordinates.x = (viewport.x + whereInput.x) * scaleX;
|
||||
rectInScreenCoordinates.y = (viewport.y + whereInput.y) * scaleY;
|
||||
rectInScreenCoordinates.w = whereInput.w * scaleX;
|
||||
rectInScreenCoordinates.h = whereInput.h * scaleY;
|
||||
|
||||
SDL_SetTextInputRect(&rectInScreenCoordinates);
|
||||
|
||||
if (SDL_IsTextInputActive() == SDL_FALSE)
|
||||
{
|
||||
SDL_StartTextInput();
|
||||
}
|
||||
|
||||
#ifdef VCMI_APPLE
|
||||
});
|
||||
#endif
|
||||
input().startTextInput(whereInput);
|
||||
}
|
||||
|
||||
void CGuiHandler::stopTextInput()
|
||||
{
|
||||
#ifdef VCMI_APPLE
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#endif
|
||||
|
||||
if (SDL_IsTextInputActive() == SDL_TRUE)
|
||||
{
|
||||
SDL_StopTextInput();
|
||||
}
|
||||
|
||||
#ifdef VCMI_APPLE
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGuiHandler::fakeMouseButtonEventRelativeMode(bool down, bool right)
|
||||
{
|
||||
SDL_Event event;
|
||||
SDL_MouseButtonEvent sme = {SDL_MOUSEBUTTONDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
if(!down)
|
||||
{
|
||||
sme.type = SDL_MOUSEBUTTONUP;
|
||||
}
|
||||
|
||||
sme.button = right ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT;
|
||||
|
||||
sme.x = CCS->curh->position().x;
|
||||
sme.y = CCS->curh->position().y;
|
||||
|
||||
float xScale, yScale;
|
||||
int w, h, rLogicalWidth, rLogicalHeight;
|
||||
|
||||
SDL_GetWindowSize(mainWindow, &w, &h);
|
||||
SDL_RenderGetLogicalSize(mainRenderer, &rLogicalWidth, &rLogicalHeight);
|
||||
SDL_RenderGetScale(mainRenderer, &xScale, &yScale);
|
||||
|
||||
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
|
||||
moveCursorToPosition( Point(
|
||||
(int)(sme.x * xScale) + (w - rLogicalWidth * xScale) / 2,
|
||||
(int)(sme.y * yScale + (h - rLogicalHeight * yScale) / 2)));
|
||||
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
|
||||
|
||||
event.button = sme;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
void CGuiHandler::handleCurrentEvent( SDL_Event & current )
|
||||
{
|
||||
switch (current.type)
|
||||
{
|
||||
case SDL_KEYDOWN:
|
||||
return handleEventKeyDown(current);
|
||||
case SDL_KEYUP:
|
||||
return handleEventKeyUp(current);
|
||||
case SDL_MOUSEMOTION:
|
||||
return handleEventMouseMotion(current);
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
return handleEventMouseButtonDown(current);
|
||||
case SDL_MOUSEWHEEL:
|
||||
return handleEventMouseWheel(current);
|
||||
case SDL_TEXTINPUT:
|
||||
return handleEventTextInput(current);
|
||||
case SDL_TEXTEDITING:
|
||||
return handleEventTextEditing(current);
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
return handleEventMouseButtonUp(current);
|
||||
case SDL_FINGERMOTION:
|
||||
return handleEventFingerMotion(current);
|
||||
case SDL_FINGERDOWN:
|
||||
return handleEventFingerDown(current);
|
||||
case SDL_FINGERUP:
|
||||
return handleEventFingerUp(current);
|
||||
}
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventKeyDown(SDL_Event & current)
|
||||
{
|
||||
SDL_KeyboardEvent key = current.key;
|
||||
|
||||
if(key.repeat != 0)
|
||||
return; // ignore periodic event resends
|
||||
|
||||
assert(key.state == SDL_PRESSED);
|
||||
|
||||
if(current.type == SDL_KEYDOWN && key.keysym.sym >= SDLK_F1 && key.keysym.sym <= SDLK_F15 && settings["session"]["spectate"].Bool())
|
||||
{
|
||||
//TODO: we need some central place for all interface-independent hotkeys
|
||||
Settings s = settings.write["session"];
|
||||
switch(key.keysym.sym)
|
||||
{
|
||||
case SDLK_F5:
|
||||
if(settings["session"]["spectate-locked-pim"].Bool())
|
||||
LOCPLINT->pim->unlock();
|
||||
else
|
||||
LOCPLINT->pim->lock();
|
||||
s["spectate-locked-pim"].Bool() = !settings["session"]["spectate-locked-pim"].Bool();
|
||||
break;
|
||||
|
||||
case SDLK_F6:
|
||||
s["spectate-ignore-hero"].Bool() = !settings["session"]["spectate-ignore-hero"].Bool();
|
||||
break;
|
||||
|
||||
case SDLK_F7:
|
||||
s["spectate-skip-battle"].Bool() = !settings["session"]["spectate-skip-battle"].Bool();
|
||||
break;
|
||||
|
||||
case SDLK_F8:
|
||||
s["spectate-skip-battle-result"].Bool() = !settings["session"]["spectate-skip-battle-result"].Bool();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto shortcutsVector = shortcutsHandler().translateKeycode(key.keysym.sym);
|
||||
|
||||
eventDispatcher().dispatchShortcutPressed(shortcutsVector);
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventKeyUp(SDL_Event & current)
|
||||
{
|
||||
SDL_KeyboardEvent key = current.key;
|
||||
|
||||
if(key.repeat != 0)
|
||||
return; // ignore periodic event resends
|
||||
|
||||
assert(key.state == SDL_RELEASED);
|
||||
|
||||
auto shortcutsVector = shortcutsHandler().translateKeycode(key.keysym.sym);
|
||||
|
||||
eventDispatcher().dispatchShortcutReleased(shortcutsVector);
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventMouseMotion(SDL_Event & current)
|
||||
{
|
||||
eventDispatcher().dispatchMouseMoved(Point(current.motion.x, current.motion.y));
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventMouseButtonDown(SDL_Event & current)
|
||||
{
|
||||
switch(current.button.button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT:
|
||||
if (current.button.clicks > 1)
|
||||
eventDispatcher().dispatchMouseDoubleClick(Point(current.button.x, current.button.y));
|
||||
else
|
||||
eventDispatcher().dispatchMouseButtonPressed(MouseButton::LEFT, Point(current.button.x, current.button.y));
|
||||
break;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
eventDispatcher().dispatchMouseButtonPressed(MouseButton::RIGHT, Point(current.button.x, current.button.y));
|
||||
break;
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
eventDispatcher().dispatchMouseButtonPressed(MouseButton::MIDDLE, Point(current.button.x, current.button.y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventMouseWheel(SDL_Event & current)
|
||||
{
|
||||
// SDL doesn't have the proper values for mouse positions on SDL_MOUSEWHEEL, refetch them
|
||||
int x = 0, y = 0;
|
||||
SDL_GetMouseState(&x, &y);
|
||||
|
||||
eventDispatcher().dispatchMouseScrolled(Point(current.wheel.x, current.wheel.y), Point(x, y));
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventTextInput(SDL_Event & current)
|
||||
{
|
||||
eventDispatcher().dispatchTextInput(current.text.text);
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventTextEditing(SDL_Event & current)
|
||||
{
|
||||
eventDispatcher().dispatchTextEditing(current.text.text);
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventMouseButtonUp(SDL_Event & current)
|
||||
{
|
||||
if(!multifinger)
|
||||
{
|
||||
switch(current.button.button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT:
|
||||
eventDispatcher().dispatchMouseButtonReleased(MouseButton::LEFT, Point(current.button.x, current.button.y));
|
||||
break;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
eventDispatcher().dispatchMouseButtonReleased(MouseButton::RIGHT, Point(current.button.x, current.button.y));
|
||||
break;
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
eventDispatcher().dispatchMouseButtonReleased(MouseButton::MIDDLE, Point(current.button.x, current.button.y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventFingerMotion(SDL_Event & current)
|
||||
{
|
||||
if(isPointerRelativeMode)
|
||||
{
|
||||
fakeMoveCursor(current.tfinger.dx, current.tfinger.dy);
|
||||
}
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventFingerDown(SDL_Event & current)
|
||||
{
|
||||
auto fingerCount = SDL_GetNumTouchFingers(current.tfinger.touchId);
|
||||
|
||||
multifinger = fingerCount > 1;
|
||||
|
||||
if(isPointerRelativeMode)
|
||||
{
|
||||
if(current.tfinger.x > 0.5)
|
||||
{
|
||||
bool isRightClick = current.tfinger.y < 0.5;
|
||||
|
||||
fakeMouseButtonEventRelativeMode(true, isRightClick);
|
||||
}
|
||||
}
|
||||
#ifndef VCMI_IOS
|
||||
else if(fingerCount == 2)
|
||||
{
|
||||
convertTouchToMouse(¤t);
|
||||
|
||||
eventDispatcher().dispatchMouseMoved(Point(current.button.x, current.button.y));
|
||||
eventDispatcher().dispatchMouseButtonPressed(MouseButton::RIGHT, Point(current.button.x, current.button.y));
|
||||
}
|
||||
#endif //VCMI_IOS
|
||||
}
|
||||
|
||||
void CGuiHandler::handleEventFingerUp(SDL_Event & current)
|
||||
{
|
||||
#ifndef VCMI_IOS
|
||||
auto fingerCount = SDL_GetNumTouchFingers(current.tfinger.touchId);
|
||||
#endif //VCMI_IOS
|
||||
|
||||
if(isPointerRelativeMode)
|
||||
{
|
||||
if(current.tfinger.x > 0.5)
|
||||
{
|
||||
bool isRightClick = current.tfinger.y < 0.5;
|
||||
|
||||
fakeMouseButtonEventRelativeMode(false, isRightClick);
|
||||
}
|
||||
}
|
||||
#ifndef VCMI_IOS
|
||||
else if(multifinger)
|
||||
{
|
||||
convertTouchToMouse(¤t);
|
||||
eventDispatcher().dispatchMouseMoved(Point(current.button.x, current.button.y));
|
||||
eventDispatcher().dispatchMouseButtonReleased(MouseButton::RIGHT, Point(current.button.x, current.button.y));
|
||||
multifinger = fingerCount != 0;
|
||||
}
|
||||
#endif //VCMI_IOS
|
||||
input().stopTextInput();
|
||||
}
|
||||
|
||||
void CGuiHandler::renderFrame()
|
||||
@ -493,14 +139,12 @@ void CGuiHandler::renderFrame()
|
||||
windows().onFrameRendered();
|
||||
}
|
||||
|
||||
framerateManager().framerateDelay(); // holds a constant FPS
|
||||
framerate().framerateDelay(); // holds a constant FPS
|
||||
}
|
||||
|
||||
CGuiHandler::CGuiHandler()
|
||||
: defActionsDef(0)
|
||||
, captureChildren(false)
|
||||
, multifinger(false)
|
||||
, mouseButtonsMask(0)
|
||||
, curInt(nullptr)
|
||||
, fakeStatusBar(std::make_shared<EmptyStatusBar>())
|
||||
, terminate_cond (new CondSh<bool>(false))
|
||||
@ -512,50 +156,41 @@ CGuiHandler::~CGuiHandler()
|
||||
delete terminate_cond;
|
||||
}
|
||||
|
||||
ShortcutHandler & CGuiHandler::shortcutsHandler()
|
||||
ShortcutHandler & CGuiHandler::shortcuts()
|
||||
{
|
||||
assert(shortcutsHandlerInstance);
|
||||
return *shortcutsHandlerInstance;
|
||||
}
|
||||
|
||||
FramerateManager & CGuiHandler::framerateManager()
|
||||
FramerateManager & CGuiHandler::framerate()
|
||||
{
|
||||
assert(framerateManagerInstance);
|
||||
return *framerateManagerInstance;
|
||||
}
|
||||
|
||||
void CGuiHandler::moveCursorToPosition(const Point & position)
|
||||
{
|
||||
SDL_WarpMouseInWindow(mainWindow, position.x, position.y);
|
||||
}
|
||||
|
||||
bool CGuiHandler::isKeyboardCtrlDown() const
|
||||
{
|
||||
#ifdef VCMI_MAC
|
||||
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LGUI] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RGUI];
|
||||
#else
|
||||
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LCTRL] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RCTRL];
|
||||
#endif
|
||||
return inputHandlerInstance->isKeyboardCtrlDown();
|
||||
}
|
||||
|
||||
bool CGuiHandler::isKeyboardAltDown() const
|
||||
{
|
||||
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LALT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RALT];
|
||||
return inputHandlerInstance->isKeyboardAltDown();
|
||||
}
|
||||
|
||||
bool CGuiHandler::isKeyboardShiftDown() const
|
||||
{
|
||||
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RSHIFT];
|
||||
return inputHandlerInstance->isKeyboardShiftDown();
|
||||
}
|
||||
|
||||
void CGuiHandler::breakEventHandling()
|
||||
{
|
||||
eventDispatcher().allowEventHandling(false);
|
||||
events().allowEventHandling(false);
|
||||
}
|
||||
|
||||
const Point & CGuiHandler::getCursorPosition() const
|
||||
{
|
||||
return cursorPosition;
|
||||
return inputHandlerInstance->getCursorPosition();
|
||||
}
|
||||
|
||||
Point CGuiHandler::screenDimensions() const
|
||||
@ -565,19 +200,12 @@ Point CGuiHandler::screenDimensions() const
|
||||
|
||||
bool CGuiHandler::isMouseButtonPressed() const
|
||||
{
|
||||
return mouseButtonsMask > 0;
|
||||
return isMouseButtonPressed(MouseButton::LEFT) || isMouseButtonPressed(MouseButton::MIDDLE) || isMouseButtonPressed(MouseButton::RIGHT);
|
||||
}
|
||||
|
||||
bool CGuiHandler::isMouseButtonPressed(MouseButton button) const
|
||||
{
|
||||
static_assert(static_cast<uint32_t>(MouseButton::LEFT) == SDL_BUTTON_LEFT, "mismatch between VCMI and SDL enum!");
|
||||
static_assert(static_cast<uint32_t>(MouseButton::MIDDLE) == SDL_BUTTON_MIDDLE, "mismatch between VCMI and SDL enum!");
|
||||
static_assert(static_cast<uint32_t>(MouseButton::RIGHT) == SDL_BUTTON_RIGHT, "mismatch between VCMI and SDL enum!");
|
||||
static_assert(static_cast<uint32_t>(MouseButton::EXTRA1) == SDL_BUTTON_X1, "mismatch between VCMI and SDL enum!");
|
||||
static_assert(static_cast<uint32_t>(MouseButton::EXTRA2) == SDL_BUTTON_X2, "mismatch between VCMI and SDL enum!");
|
||||
|
||||
uint32_t index = static_cast<uint32_t>(button);
|
||||
return mouseButtonsMask & SDL_BUTTON(index);
|
||||
return inputHandlerInstance->isMouseButtonPressed(button);
|
||||
}
|
||||
|
||||
void CGuiHandler::drawFPSCounter()
|
||||
@ -585,7 +213,7 @@ void CGuiHandler::drawFPSCounter()
|
||||
static SDL_Rect overlay = { 0, 0, 64, 32};
|
||||
uint32_t black = SDL_MapRGB(screen->format, 10, 10, 10);
|
||||
SDL_FillRect(screen, &overlay, black);
|
||||
std::string fps = std::to_string(framerateManager().getFramerate());
|
||||
std::string fps = std::to_string(framerate().getFramerate());
|
||||
graphics->fonts[FONT_BIG]->renderTextLeft(screen, fps, Colors::YELLOW, Point(10, 10));
|
||||
}
|
||||
|
||||
@ -596,16 +224,12 @@ bool CGuiHandler::amIGuiThread()
|
||||
|
||||
void CGuiHandler::pushUserEvent(EUserEvent usercode)
|
||||
{
|
||||
pushUserEvent(usercode, nullptr);
|
||||
inputHandlerInstance->pushUserEvent(usercode, nullptr);
|
||||
}
|
||||
|
||||
void CGuiHandler::pushUserEvent(EUserEvent usercode, void * userdata)
|
||||
{
|
||||
SDL_Event event;
|
||||
event.type = SDL_USEREVENT;
|
||||
event.user.code = static_cast<int32_t>(usercode);
|
||||
event.user.data1 = userdata;
|
||||
SDL_PushEvent(&event);
|
||||
inputHandlerInstance->pushUserEvent(usercode, userdata);
|
||||
}
|
||||
|
||||
IScreenHandler & CGuiHandler::screenHandler()
|
||||
@ -613,11 +237,16 @@ IScreenHandler & CGuiHandler::screenHandler()
|
||||
return *screenHandlerInstance;
|
||||
}
|
||||
|
||||
EventDispatcher & CGuiHandler::eventDispatcher()
|
||||
EventDispatcher & CGuiHandler::events()
|
||||
{
|
||||
return *eventDispatcherInstance;
|
||||
}
|
||||
|
||||
InputHandler & CGuiHandler::input()
|
||||
{
|
||||
return *inputHandlerInstance;
|
||||
}
|
||||
|
||||
WindowHandler & CGuiHandler::windows()
|
||||
{
|
||||
assert(windowHandlerInstance);
|
||||
|
@ -31,18 +31,17 @@ class IShowActivatable;
|
||||
class IScreenHandler;
|
||||
class WindowHandler;
|
||||
class EventDispatcher;
|
||||
class InputHandler;
|
||||
|
||||
// TODO: event handling need refactoring
|
||||
// TODO: event handling need refactoring. Perhaps convert into delayed function call?
|
||||
enum class EUserEvent
|
||||
{
|
||||
/*CHANGE_SCREEN_RESOLUTION = 1,*/
|
||||
RETURN_TO_MAIN_MENU = 2,
|
||||
//STOP_CLIENT = 3,
|
||||
RESTART_GAME = 4,
|
||||
RETURN_TO_MAIN_MENU,
|
||||
RESTART_GAME,
|
||||
RETURN_TO_MENU_LOAD,
|
||||
FULLSCREEN_TOGGLED,
|
||||
CAMPAIGN_START_SCENARIO,
|
||||
FORCE_QUIT, //quit client without question
|
||||
FORCE_QUIT,
|
||||
};
|
||||
|
||||
// Handles GUI logic and drawing
|
||||
@ -55,41 +54,22 @@ private:
|
||||
/// Status bar of current window, if any. Uses weak_ptr to allow potential hanging reference after owned window has been deleted
|
||||
std::weak_ptr<IStatusBar> currentStatusBar;
|
||||
|
||||
Point cursorPosition;
|
||||
uint32_t mouseButtonsMask;
|
||||
|
||||
std::unique_ptr<ShortcutHandler> shortcutsHandlerInstance;
|
||||
std::unique_ptr<WindowHandler> windowHandlerInstance;
|
||||
|
||||
std::unique_ptr<IScreenHandler> screenHandlerInstance;
|
||||
std::unique_ptr<FramerateManager> framerateManagerInstance;
|
||||
std::unique_ptr<EventDispatcher> eventDispatcherInstance;
|
||||
|
||||
void handleCurrentEvent(SDL_Event ¤t);
|
||||
void convertTouchToMouse(SDL_Event * current);
|
||||
void fakeMoveCursor(float dx, float dy);
|
||||
void fakeMouseButtonEventRelativeMode(bool down, bool right);
|
||||
|
||||
void handleEventKeyDown(SDL_Event & current);
|
||||
void handleEventKeyUp(SDL_Event & current);
|
||||
void handleEventMouseMotion(SDL_Event & current);
|
||||
void handleEventMouseButtonDown(SDL_Event & current);
|
||||
void handleEventMouseWheel(SDL_Event & current);
|
||||
void handleEventTextInput(SDL_Event & current);
|
||||
void handleEventTextEditing(SDL_Event & current);
|
||||
void handleEventMouseButtonUp(SDL_Event & current);
|
||||
void handleEventFingerMotion(SDL_Event & current);
|
||||
void handleEventFingerDown(SDL_Event & current);
|
||||
void handleEventFingerUp(SDL_Event & current);
|
||||
std::unique_ptr<InputHandler> inputHandlerInstance;
|
||||
|
||||
public:
|
||||
|
||||
/// returns current position of mouse cursor, relative to vcmi window
|
||||
const Point & getCursorPosition() const;
|
||||
|
||||
ShortcutHandler & shortcutsHandler();
|
||||
FramerateManager & framerateManager();
|
||||
EventDispatcher & eventDispatcher();
|
||||
ShortcutHandler & shortcuts();
|
||||
FramerateManager & framerate();
|
||||
EventDispatcher & events();
|
||||
InputHandler & input();
|
||||
|
||||
/// Returns current logical screen dimensions
|
||||
/// May not match size of window if user has UI scaling different from 100%
|
||||
@ -109,9 +89,6 @@ public:
|
||||
void startTextInput(const Rect & where);
|
||||
void stopTextInput();
|
||||
|
||||
/// moves mouse pointer into specified position inside vcmi window
|
||||
void moveCursorToPosition(const Point & position);
|
||||
|
||||
IScreenHandler & screenHandler();
|
||||
|
||||
WindowHandler & windows();
|
||||
@ -124,10 +101,6 @@ public:
|
||||
|
||||
IUpdateable *curInt;
|
||||
|
||||
bool multifinger;
|
||||
bool isPointerRelativeMode;
|
||||
float pointerSpeedMultiplier;
|
||||
|
||||
ui8 defActionsDef; //default auto actions
|
||||
bool captureChildren; //all newly created objects will get their parents from stack and will be added to parents children list
|
||||
std::list<CIntObject *> createdObj; //stack of objs being created
|
||||
@ -146,9 +119,9 @@ public:
|
||||
void breakEventHandling(); //current event won't be propagated anymore
|
||||
void drawFPSCounter(); // draws the FPS to the upper left corner of the screen
|
||||
|
||||
static bool amIGuiThread();
|
||||
static void pushUserEvent(EUserEvent usercode);
|
||||
static void pushUserEvent(EUserEvent usercode, void * userdata);
|
||||
bool amIGuiThread();
|
||||
void pushUserEvent(EUserEvent usercode);
|
||||
void pushUserEvent(EUserEvent usercode, void * userdata);
|
||||
|
||||
CondSh<bool> * terminate_cond; // confirm termination
|
||||
};
|
||||
|
@ -251,7 +251,7 @@ void CursorHandler::updateSpellcastCursor()
|
||||
{
|
||||
static const float frameDisplayDuration = 0.1f; // H3 uses 100 ms per frame
|
||||
|
||||
frameTime += GH.framerateManager().getElapsedMilliseconds() / 1000.f;
|
||||
frameTime += GH.framerate().getElapsedMilliseconds() / 1000.f;
|
||||
size_t newFrame = frame;
|
||||
|
||||
while (frameTime >= frameDisplayDuration)
|
||||
|
@ -51,14 +51,14 @@ void AEventsReceiver::activateEvents(ui16 what)
|
||||
assert((what & GENERAL) || (activeState & GENERAL));
|
||||
|
||||
activeState |= GENERAL;
|
||||
GH.eventDispatcher().handleElementActivate(this, what);
|
||||
GH.events().handleElementActivate(this, what);
|
||||
}
|
||||
|
||||
void AEventsReceiver::deactivateEvents(ui16 what)
|
||||
{
|
||||
if (what & GENERAL)
|
||||
activeState &= ~GENERAL;
|
||||
GH.eventDispatcher().handleElementDeActivate(this, what & activeState);
|
||||
GH.events().handleElementDeActivate(this, what & activeState);
|
||||
}
|
||||
|
||||
void AEventsReceiver::click(MouseButton btn, tribool down, bool previousState)
|
||||
|
@ -224,7 +224,7 @@ EShortcut InterfaceObjectConfigurable::readHotkey(const JsonNode & config) const
|
||||
return EShortcut::NONE;
|
||||
}
|
||||
|
||||
EShortcut result = GH.shortcutsHandler().findShortcut(config.String());
|
||||
EShortcut result = GH.shortcuts().findShortcut(config.String());
|
||||
if (result == EShortcut::NONE)
|
||||
logGlobal->error("Invalid hotkey '%s' in interface configuration!", config.String());
|
||||
return result;;
|
||||
|
@ -233,7 +233,7 @@ std::shared_ptr<CButton> CMenuEntry::createButton(CMenuScreen * parent, const Js
|
||||
if(posy < 0)
|
||||
posy = pos.h + posy;
|
||||
|
||||
EShortcut shortcut = GH.shortcutsHandler().findShortcut(button["shortcut"].String());
|
||||
EShortcut shortcut = GH.shortcuts().findShortcut(button["shortcut"].String());
|
||||
|
||||
auto result = std::make_shared<CButton>(Point(posx, posy), button["name"].String(), help, command, shortcut);
|
||||
|
||||
|
@ -98,8 +98,8 @@ void MapViewActions::handleSwipeMove(const Point & cursorPosition)
|
||||
if(!swipeEnabled() && !GH.isMouseButtonPressed(MouseButton::MIDDLE))
|
||||
return;
|
||||
|
||||
// on mobile platforms with enabled swipe any button is enough
|
||||
if(swipeEnabled() && (!GH.isMouseButtonPressed() || GH.multifinger))
|
||||
// on mobile platforms with enabled swipe we use left button
|
||||
if(swipeEnabled() && !GH.isMouseButtonPressed(MouseButton::LEFT))
|
||||
return;
|
||||
|
||||
if(!isSwiping)
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/NotificationHandler.h"
|
||||
#include "../eventsSDL/NotificationHandler.h"
|
||||
#include "../gui/WindowHandler.h"
|
||||
#include "CMT.h"
|
||||
#include "SDL_Extensions.h"
|
||||
|
Loading…
Reference in New Issue
Block a user