Browse Source

Merge pull request #1544 from IvanSavenko/sdl_remove_event_access

Reduce access to SDL events outside of GUI Handler
Ivan Savenko 2 years ago
parent
commit
4cb71e476e
59 changed files with 617 additions and 541 deletions
  1. 3 3
      client/CMT.cpp
  2. 3 0
      client/CMakeLists.txt
  3. 7 28
      client/CPlayerInterface.cpp
  4. 0 4
      client/CPlayerInterface.h
  5. 3 9
      client/CServerHandler.cpp
  6. 85 56
      client/adventureMap/CAdvMapInt.cpp
  7. 5 2
      client/adventureMap/CAdvMapInt.h
  8. 8 11
      client/adventureMap/CInGameConsole.cpp
  9. 3 3
      client/adventureMap/CInGameConsole.h
  10. 3 2
      client/adventureMap/CMinimap.cpp
  11. 1 1
      client/adventureMap/CMinimap.h
  12. 1 0
      client/adventureMap/CResDataBar.cpp
  13. 16 17
      client/adventureMap/CTerrainRect.cpp
  14. 4 4
      client/adventureMap/CTerrainRect.h
  15. 1 0
      client/adventureMap/mapHandler.cpp
  16. 2 2
      client/battle/BattleFieldController.cpp
  17. 1 1
      client/battle/BattleFieldController.h
  18. 4 4
      client/battle/BattleInterfaceClasses.cpp
  19. 2 1
      client/battle/BattleStacksController.cpp
  20. 5 5
      client/battle/BattleWindow.cpp
  21. 1 1
      client/battle/BattleWindow.h
  22. 152 31
      client/gui/CGuiHandler.cpp
  23. 27 5
      client/gui/CGuiHandler.h
  24. 23 12
      client/gui/CIntObject.cpp
  25. 16 18
      client/gui/CIntObject.h
  26. 0 19
      client/gui/CursorHandler.cpp
  27. 0 3
      client/gui/CursorHandler.h
  28. 19 0
      client/gui/MouseButton.h
  29. 1 1
      client/lobby/CBonusSelection.cpp
  30. 2 4
      client/lobby/CSelectionBase.cpp
  31. 1 2
      client/lobby/CSelectionBase.h
  32. 2 7
      client/lobby/SelectionTab.cpp
  33. 2 1
      client/lobby/SelectionTab.h
  34. 21 22
      client/mainmenu/CMainMenu.cpp
  35. 1 0
      client/mainmenu/CPrologEpilogVideo.cpp
  36. 26 0
      client/render/Colors.cpp
  37. 50 0
      client/render/Colors.h
  38. 0 2
      client/render/Graphics.cpp
  39. 2 1
      client/renderSDL/CTrueTypeFont.cpp
  40. 2 1
      client/renderSDL/CursorHardware.cpp
  41. 2 2
      client/renderSDL/CursorSoftware.cpp
  42. 7 93
      client/renderSDL/SDL_Extensions.cpp
  43. 3 47
      client/renderSDL/SDL_Extensions.h
  44. 9 12
      client/widgets/Buttons.cpp
  45. 3 3
      client/widgets/Buttons.h
  46. 1 0
      client/widgets/CArtifactHolder.cpp
  47. 7 14
      client/widgets/CGarrisonInt.cpp
  48. 16 17
      client/widgets/TextControls.cpp
  49. 6 5
      client/widgets/TextControls.h
  50. 6 8
      client/windows/CCastleInterface.cpp
  51. 3 2
      client/windows/CCastleInterface.h
  52. 4 5
      client/windows/CCreatureWindow.cpp
  53. 1 0
      client/windows/CMessage.cpp
  54. 1 0
      client/windows/CQuestLog.cpp
  55. 1 1
      client/windows/CQuestLog.h
  56. 8 10
      client/windows/CSpellWindow.cpp
  57. 2 1
      client/windows/CSpellWindow.h
  58. 28 36
      client/windows/GUIClasses.cpp
  59. 4 2
      client/windows/GUIClasses.h

+ 3 - 3
client/CMT.cpp

@@ -54,7 +54,7 @@
 #include <SDL.h>
 
 #ifdef VCMI_WINDOWS
-#include "SDL_syswm.h"
+#include <SDL_syswm.h>
 #endif
 #ifdef VCMI_ANDROID
 #include "lib/CAndroidVMHelper.h"
@@ -949,7 +949,7 @@ static void handleEvent(SDL_Event & ev)
 	}
 	else if(ev.type == SDL_USEREVENT)
 	{
-		switch(ev.user.code)
+		switch(static_cast<EUserEvent>(ev.user.code))
 		{
 		case EUserEvent::FORCE_QUIT:
 			{
@@ -1050,7 +1050,7 @@ static void handleEvent(SDL_Event & ev)
 static void mainLoop()
 {
 	SettingsListener resChanged = settings.listen["video"]["fullscreen"];
-	resChanged([](const JsonNode &newState){  CGuiHandler::pushSDLEvent(SDL_USEREVENT, EUserEvent::FULLSCREEN_TOGGLED); });
+	resChanged([](const JsonNode &newState){  CGuiHandler::pushUserEvent(EUserEvent::FULLSCREEN_TOGGLED); });
 
 	inGuiThread.reset(new bool(true));
 	GH.mainFPSmng->init();

+ 3 - 0
client/CMakeLists.txt

@@ -54,6 +54,7 @@ set(client_SRCS
 	render/CFadeAnimation.cpp
 	render/Canvas.cpp
 	render/ColorFilter.cpp
+	render/Colors.cpp
 	render/Graphics.cpp
 	render/IFont.cpp
 
@@ -136,6 +137,7 @@ set(client_HEADERS
 	gui/CIntObject.h
 	gui/CursorHandler.h
 	gui/InterfaceObjectConfigurable.h
+	gui/MouseButton.h
 	gui/NotificationHandler.h
 	gui/TextAlignment.h
 
@@ -160,6 +162,7 @@ set(client_HEADERS
 	render/CFadeAnimation.h
 	render/Canvas.h
 	render/ColorFilter.h
+	render/Colors.h
 	render/Graphics.h
 	render/ICursor.h
 	render/IFont.h

+ 7 - 28
client/CPlayerInterface.cpp

@@ -23,6 +23,7 @@
 #include "gui/CursorHandler.h"
 #include "windows/CKingdomInterface.h"
 #include "CGameInfo.h"
+#include "CMT.h"
 #include "windows/CHeroWindow.h"
 #include "windows/CCreatureWindow.h"
 #include "windows/CQuestLog.h"
@@ -87,8 +88,6 @@
 		return;						\
 	RETURN_IF_QUICK_COMBAT
 
-using namespace CSDL_Ext;
-
 extern std::queue<SDL_Event> SDLEventsQueue;
 extern boost::mutex eventsM;
 boost::recursive_mutex * CPlayerInterface::pim = new boost::recursive_mutex;
@@ -1043,7 +1042,7 @@ void CPlayerInterface::showComp(const Component &comp, std::string message)
 void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<Component> & components, int soundID)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if (settings["session"]["autoSkip"].Bool() && !LOCPLINT->shiftPressed())
+	if (settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown())
 	{
 		return;
 	}
@@ -1067,7 +1066,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
 	LOG_TRACE_PARAMS(logGlobal, "player=%s, text=%s, is LOCPLINT=%d", playerID % text % (this==LOCPLINT));
 	waitWhileDialog();
 
-	if (settings["session"]["autoSkip"].Bool() && !LOCPLINT->shiftPressed())
+	if (settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown())
 	{
 		return;
 	}
@@ -1328,16 +1327,6 @@ void CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
 	boost::thread moveHeroTask(std::bind(&CPlayerInterface::doMoveHero,this,h,path));
 }
 
-bool CPlayerInterface::shiftPressed() const
-{
-	return isShiftKeyDown();
-}
-
-bool CPlayerInterface::altPressed() const
-{
-	return isAltKeyDown();
-}
-
 void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
@@ -1558,11 +1547,6 @@ void CPlayerInterface::playerBlocked(int reason, bool start)
 	}
 }
 
-bool CPlayerInterface::ctrlPressed() const
-{
-	return isCtrlKeyDown();
-}
-
 const CArmedInstance * CPlayerInterface::getSelection()
 {
 	return currentSelection;
@@ -1604,7 +1588,7 @@ void CPlayerInterface::update()
 
 	if (!adventureInt || adventureInt->isActive())
 		GH.simpleRedraw();
-	else if((adventureInt->swipeEnabled && adventureInt->swipeMovementRequested) || adventureInt->scrollingDir)
+	else if((adventureInt->swipeEnabled && adventureInt->swipeMovementRequested) || (adventureInt->scrollingDir && GH.isKeyboardCtrlDown()))
 		GH.totalRedraw(); //player forces map scrolling though interface is disabled
 	else
 		GH.simpleRedraw();
@@ -1990,7 +1974,7 @@ void CPlayerInterface::acceptTurn()
 	adventureInt->updateNextHero(nullptr);
 	adventureInt->showAll(screen);
 
-	if(settings["session"]["autoSkip"].Bool() && !LOCPLINT->shiftPressed())
+	if(settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown())
 	{
 		if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt().get()))
 			iw->close();
@@ -2154,12 +2138,7 @@ void CPlayerInterface::requestReturningToMainMenu(bool won)
 	if(won && cb->getStartInfo()->campState)
 		CSH->startCampaignScenario(cb->getStartInfo()->campState);
 	else
-		sendCustomEvent(EUserEvent::RETURN_TO_MAIN_MENU);
-}
-
-void CPlayerInterface::sendCustomEvent( int code )
-{
-	CGuiHandler::pushSDLEvent(SDL_USEREVENT, code);
+		GH.pushUserEvent(EUserEvent::RETURN_TO_MAIN_MENU);
 }
 
 void CPlayerInterface::askToAssembleArtifact(const ArtifactLocation &al)
@@ -2283,7 +2262,7 @@ void CPlayerInterface::waitForAllDialogs(bool unlockPim)
 
 void CPlayerInterface::proposeLoadingGame()
 {
-	showYesNoDialog(CGI->generaltexth->allTexts[68], [this](){ sendCustomEvent(EUserEvent::RETURN_TO_MENU_LOAD); }, nullptr);
+	showYesNoDialog(CGI->generaltexth->allTexts[68], [](){ GH.pushUserEvent(EUserEvent::RETURN_TO_MENU_LOAD); }, nullptr);
 }
 
 CPlayerInterface::SpellbookLastSetting::SpellbookLastSetting()

+ 0 - 4
client/CPlayerInterface.h

@@ -213,9 +213,6 @@ public:
 	void heroKilled(const CGHeroInstance* hero);
 	void waitWhileDialog(bool unlockPim = true);
 	void waitForAllDialogs(bool unlockPim = true);
-	bool shiftPressed() const; //determines if shift key is pressed (left or right or both)
-	bool ctrlPressed() const; //determines if ctrl key is pressed (left or right or both)
-	bool altPressed() const; //determines if alt key is pressed (left or right or both)
 	void redrawHeroWin(const CGHeroInstance * hero);
 	void openTownWindow(const CGTownInstance * town); //shows townscreen
 	void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero
@@ -243,7 +240,6 @@ public:
 	void tryDiggging(const CGHeroInstance *h);
 	void showShipyardDialogOrProblemPopup(const IShipyard *obj); //obj may be town or shipyard;
 	void requestReturningToMainMenu(bool won);
-	void sendCustomEvent(int code);
 	void proposeLoadingGame();
 
 	// Ambient sounds

+ 3 - 9
client/CServerHandler.cpp

@@ -60,8 +60,6 @@
 #include <windows.h>
 #endif
 
-#include <SDL_events.h>
-
 template<typename T> class CApplyOnLobby;
 
 const std::string CServerHandler::localhostAddress{"127.0.0.1"};
@@ -655,14 +653,10 @@ void CServerHandler::endGameplay(bool closeConnection, bool restart)
 
 void CServerHandler::startCampaignScenario(std::shared_ptr<CCampaignState> cs)
 {
-	SDL_Event event;
-	event.type = SDL_USEREVENT;
-	event.user.code = EUserEvent::CAMPAIGN_START_SCENARIO;
 	if(cs)
-		event.user.data1 = CMemorySerializer::deepCopy(*cs.get()).release();
+		GH.pushUserEvent(EUserEvent::CAMPAIGN_START_SCENARIO, CMemorySerializer::deepCopy(*cs.get()).release());
 	else
-		event.user.data1 = CMemorySerializer::deepCopy(*si->campState.get()).release();
-	SDL_PushEvent(&event);
+		GH.pushUserEvent(EUserEvent::CAMPAIGN_START_SCENARIO, CMemorySerializer::deepCopy(*si->campState.get()).release());
 }
 
 void CServerHandler::showServerError(std::string txt)
@@ -824,7 +818,7 @@ void CServerHandler::threadHandleConnection()
 			if(client)
 			{
 				state = EClientState::DISCONNECTING;
-				CGuiHandler::pushSDLEvent(SDL_USEREVENT, EUserEvent::RETURN_TO_MAIN_MENU);
+				CGuiHandler::pushUserEvent(EUserEvent::RETURN_TO_MAIN_MENU);
 			}
 			else
 			{

+ 85 - 56
client/adventureMap/CAdvMapInt.cpp

@@ -30,6 +30,7 @@
 #include "../gui/CGuiHandler.h"
 #include "../widgets/TextControls.h"
 #include "../widgets/Buttons.h"
+#include "../CMT.h"
 
 #include "../../CCallback.h"
 #include "../../lib/CConfigHandler.h"
@@ -43,7 +44,6 @@
 #include "../../lib/TerrainHandler.h"
 
 #include <SDL_surface.h>
-#include <SDL_events.h>
 
 #define ADVOPT (conf.go()->ac)
 
@@ -616,7 +616,7 @@ void CAdvMapInt::handleMapScrollingUpdate()
 	int scrollSpeed = static_cast<int>(settings["adventure"]["scrollSpeed"].Float());
 	//if advmap needs updating AND (no dialog is shown OR ctrl is pressed)
 	if((animValHitCount % (4 / scrollSpeed)) == 0
-	   && ((GH.topInt().get() == this) || CSDL_Ext::isCtrlKeyDown()))
+	   && GH.isKeyboardCtrlDown())
 	{
 		if((scrollingDir & LEFT) && (position.x > -CGI->mh->frameW))
 			position.x--;
@@ -712,21 +712,46 @@ void CAdvMapInt::centerOn(const CGObjectInstance * obj, bool fade)
 	centerOn(obj->getSightCenter(), fade);
 }
 
-void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
+void CAdvMapInt::keyReleased(const SDL_Keycode &key)
 {
+	if (mode == EAdvMapMode::WORLD_VIEW)
+		return;
+
+	switch (key)
+	{
+		case SDLK_s:
+			if(isActive())
+				GH.pushIntT<CSavingScreen>();
+			return;
+		default:
+		{
+			auto direction = keyToMoveDirection(key);
+
+			if (!direction)
+				return;
+
+			ui8 Dir = (direction->x<0 ? LEFT  : 0) |
+				  (direction->x>0 ? RIGHT : 0) |
+				  (direction->y<0 ? UP    : 0) |
+				  (direction->y>0 ? DOWN  : 0) ;
+
+			scrollingDir &= ~Dir;
+		}
+	}
+}
 
+void CAdvMapInt::keyPressed(const SDL_Keycode & key)
+{
 	if (mode == EAdvMapMode::WORLD_VIEW)
 		return;
 
-	ui8 Dir = 0;
-	SDL_Keycode k = key.keysym.sym;
 	const CGHeroInstance *h = curHero(); //selected hero
 	const CGTownInstance *t = curTown(); //selected town
 
-	switch(k)
+	switch(key)
 	{
 	case SDLK_g:
-		if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS)
+		if(GH.topInt()->type & BLOCK_ADV_HOTKEYS)
 			return;
 
 		{
@@ -750,13 +775,9 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
 		if(isActive())
 			LOCPLINT->proposeLoadingGame();
 		return;
-	case SDLK_s:
-		if(isActive() && key.type == SDL_KEYUP)
-			GH.pushIntT<CSavingScreen>();
-		return;
 	case SDLK_d:
 		{
-			if(h && isActive() && LOCPLINT->makingTurn && key.state == SDL_PRESSED)
+			if(h && isActive() && LOCPLINT->makingTurn)
 				LOCPLINT->tryDiggging(h);
 			return;
 		}
@@ -769,17 +790,17 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
 			LOCPLINT->viewWorldMap();
 		return;
 	case SDLK_r:
-		if(isActive() && LOCPLINT->ctrlPressed())
+		if(isActive() && GH.isKeyboardCtrlDown())
 		{
 			LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.adventureMap.confirmRestartGame"),
-				[](){ LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME); }, nullptr);
+				[](){ GH.pushUserEvent(EUserEvent::RESTART_GAME); }, nullptr);
 		}
 		return;
 	case SDLK_SPACE: //space - try to revisit current object with selected hero
 		{
 			if(!isActive())
 				return;
-			if(h && key.state == SDL_PRESSED)
+			if(h)
 			{
 				auto unlockPim = vstd::makeUnlockGuard(*CPlayerInterface::pim);
 				//TODO!!!!!!! possible freeze, when GS mutex is locked and network thread can't apply package
@@ -792,7 +813,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
 		return;
 	case SDLK_RETURN:
 		{
-			if(!isActive() || !selection || key.state != SDL_PRESSED)
+			if(!isActive() || !selection)
 				return;
 			if(h)
 				LOCPLINT->openHeroWindow(h);
@@ -802,7 +823,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
 		}
 	case SDLK_ESCAPE:
 		{
-			if(isActive() || GH.topInt().get() != this || !spellBeingCasted || key.state != SDL_PRESSED)
+			if(isActive() || GH.topInt().get() != this || !spellBeingCasted)
 				return;
 
 			leaveCastingMode();
@@ -811,10 +832,10 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
 	case SDLK_t:
 		{
 			//act on key down if marketplace windows is not already opened
-			if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS)
+			if(GH.topInt()->type & BLOCK_ADV_HOTKEYS)
 				return;
 
-			if(LOCPLINT->ctrlPressed()) //CTRL + T => open marketplace
+			if(GH.isKeyboardCtrlDown()) //CTRL + T => open marketplace
 			{
 				//check if we have any marketplace
 				const CGTownInstance *townWithMarket = nullptr;
@@ -840,37 +861,29 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
 		}
 	default:
 		{
-			static const int3 directions[] = {  int3(-1, +1, 0), int3(0, +1, 0), int3(+1, +1, 0),
-												int3(-1, 0, 0),  int3(0, 0, 0),  int3(+1, 0, 0),
-												int3(-1, -1, 0), int3(0, -1, 0), int3(+1, -1, 0) };
+			auto direction = keyToMoveDirection(key);
 
-			//numpad arrow
-			if(CGuiHandler::isArrowKey(k))
-				k = CGuiHandler::arrowToNum(k);
+			if (!direction)
+				return;
 
-			k -= SDLK_KP_1;
+			ui8 Dir = (direction->x<0 ? LEFT  : 0) |
+				  (direction->x>0 ? RIGHT : 0) |
+				  (direction->y<0 ? UP    : 0) |
+				  (direction->y>0 ? DOWN  : 0) ;
 
-			if(k < 0 || k > 8)
-				return;
+			scrollingDir |= Dir;
 
-			if (!CGI->mh->canStartHeroMovement())
+			//ctrl makes arrow move screen, not hero
+			if(GH.isKeyboardCtrlDown())
 				return;
 
-			int3 dir = directions[k];
-
-			if(!isActive() || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero
-			{
-				Dir = (dir.x<0 ? LEFT  : 0) |
-					  (dir.x>0 ? RIGHT : 0) |
-					  (dir.y<0 ? UP    : 0) |
-					  (dir.y>0 ? DOWN  : 0) ;
-				break;
-			}
+			if(!h || !isActive())
+				return;
 
-			if(!h || key.state != SDL_PRESSED)
-				break;
+			if (!CGI->mh->canStartHeroMovement())
+				return;
 
-			if(k == 4)
+			if(*direction == Point(0,0))
 			{
 				centerOn(h);
 				return;
@@ -878,7 +891,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
 
 			CGPath &path = LOCPLINT->paths[h];
 			terrain.currentPath = &path;
-			int3 dst = h->visitablePos() + dir;
+			int3 dst = h->visitablePos() + int3(direction->x, direction->y, 0);
 			if(dst != verifyPos(dst) || !LOCPLINT->cb->getPathsInfo(h)->getPath(path, dst))
 			{
 				terrain.currentPath = nullptr;
@@ -894,13 +907,29 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
 
 		return;
 	}
-	if(Dir && key.state == SDL_PRESSED //arrow is pressed
-		&& LOCPLINT->ctrlPressed()
-	)
-		scrollingDir |= Dir;
-	else
-		scrollingDir &= ~Dir;
 }
+
+boost::optional<Point> CAdvMapInt::keyToMoveDirection(const SDL_Keycode & key)
+{
+	switch (key) {
+		case SDLK_DOWN:  return Point( 0, +1);
+		case SDLK_LEFT:  return Point(-1,  0);
+		case SDLK_RIGHT: return Point(+1,  0);
+		case SDLK_UP:    return Point( 0, -1);
+
+		case SDLK_KP_1: return Point(-1, +1);
+		case SDLK_KP_2: return Point( 0, +1);
+		case SDLK_KP_3: return Point(+1, +1);
+		case SDLK_KP_4: return Point(-1,  0);
+		case SDLK_KP_5: return Point( 0,  0);
+		case SDLK_KP_6: return Point(+1,  0);
+		case SDLK_KP_7: return Point(-1, -1);
+		case SDLK_KP_8: return Point( 0, -1);
+		case SDLK_KP_9: return Point(+1, -1);
+	}
+	return boost::none;
+}
+
 void CAdvMapInt::handleRightClick(std::string text, tribool down)
 {
 	if(down)
@@ -971,7 +1000,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)
 	heroList.redraw();
 }
 
-void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
+void CAdvMapInt::mouseMoved( const Point & cursorPosition )
 {
 #if defined(VCMI_ANDROID) || defined(VCMI_IOS)
 	if(swipeEnabled)
@@ -980,9 +1009,9 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
 	// adventure map scrolling with mouse
 	// currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed
 	// don't scroll if there is no window in focus - these events don't seem to correspond to the actual mouse movement
-	if(!CSDL_Ext::isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL)
+	if(!GH.isKeyboardCtrlDown() && isActive() && mode == EAdvMapMode::NORMAL)
 	{
-		if(sEvent.x<15)
+		if(cursorPosition.x<15)
 		{
 			scrollingDir |= LEFT;
 		}
@@ -990,7 +1019,7 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
 		{
 			scrollingDir &= ~LEFT;
 		}
-		if(sEvent.x>screen->w-15)
+		if(cursorPosition.x>screen->w-15)
 		{
 			scrollingDir |= RIGHT;
 		}
@@ -998,7 +1027,7 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
 		{
 			scrollingDir &= ~RIGHT;
 		}
-		if(sEvent.y<15)
+		if(cursorPosition.y<15)
 		{
 			scrollingDir |= UP;
 		}
@@ -1006,7 +1035,7 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
 		{
 			scrollingDir &= ~UP;
 		}
-		if(sEvent.y>screen->h-15)
+		if(cursorPosition.y>screen->h-15)
 		{
 			scrollingDir |= DOWN;
 		}
@@ -1245,7 +1274,7 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
 		const CGPathNode * pathNode = LOCPLINT->cb->getPathsInfo(hero)->getPathInfo(mapPos);
 		assert(pathNode);
 
-		if(LOCPLINT->altPressed() && pathNode->reachable()) //overwrite status bar text with movement info
+		if(GH.isKeyboardAltDown() && pathNode->reachable()) //overwrite status bar text with movement info
 		{
 			ShowMoveDetailsInStatusbar(*hero, *pathNode);
 		}

+ 5 - 2
client/adventureMap/CAdvMapInt.h

@@ -56,6 +56,8 @@ class CAdvMapInt : public CIntObject
 	//Return object that must be active at this tile (=clickable)
 	const CGObjectInstance *getActiveObject(const int3 &tile);
 
+	boost::optional<Point> keyToMoveDirection(const SDL_Keycode & key);
+
 public:
 	CAdvMapInt();
 
@@ -158,8 +160,9 @@ public:
 	void centerOn(const CGObjectInstance *obj, bool fade = false);
 	int3 verifyPos(int3 ver);
 	void handleRightClick(std::string text, tribool down);
-	void keyPressed(const SDL_KeyboardEvent & key) override;
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
+	void keyPressed(const SDL_Keycode & key) override;
+	void keyReleased(const SDL_Keycode & key) override;
+	void mouseMoved (const Point & cursorPosition) override;
 	bool isActive();
 
 	bool isHeroSleeping(const CGHeroInstance *hero);

+ 8 - 11
client/adventureMap/CInGameConsole.cpp

@@ -11,7 +11,7 @@
 #include "StdInc.h"
 #include "CInGameConsole.h"
 
-#include "../renderSDL/SDL_Extensions.h"
+#include "../render/Colors.h"
 #include "../CGameInfo.h"
 #include "../CMusicHandler.h"
 #include "../CPlayerInterface.h"
@@ -24,7 +24,6 @@
 #include "../../lib/mapObjects/CArmedInstance.h"
 
 #include <SDL_timer.h>
-#include <SDL_events.h>
 
 CInGameConsole::CInGameConsole()
 	: CIntObject(KEYBOARD | TEXTINPUT),
@@ -91,13 +90,11 @@ void CInGameConsole::print(const std::string &txt)
 	}
 }
 
-void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
+void CInGameConsole::keyPressed (const SDL_Keycode & key)
 {
-	if(key.type != SDL_KEYDOWN) return;
+	if(!captureAllKeys && key != SDLK_TAB) return; //because user is not entering any text
 
-	if(!captureAllKeys && key.keysym.sym != SDLK_TAB) return; //because user is not entering any text
-
-	switch(key.keysym.sym)
+	switch(key)
 	{
 	case SDLK_TAB:
 	case SDLK_ESCAPE:
@@ -106,7 +103,7 @@ void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
 			{
 				endEnteringText(false);
 			}
-			else if(SDLK_TAB == key.keysym.sym)
+			else if(SDLK_TAB == key)
 			{
 				startEnteringText();
 			}
@@ -178,19 +175,19 @@ void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
 	}
 }
 
-void CInGameConsole::textInputed(const SDL_TextInputEvent & event)
+void CInGameConsole::textInputed(const std::string & inputtedText)
 {
 	if(!captureAllKeys || enteredText.size() == 0)
 		return;
 	enteredText.resize(enteredText.size()-1);
 
-	enteredText += event.text;
+	enteredText += inputtedText;
 	enteredText += "_";
 
 	refreshEnteredText();
 }
 
-void CInGameConsole::textEdited(const SDL_TextEditingEvent & event)
+void CInGameConsole::textEdited(const std::string & inputtedText)
 {
  //do nothing here
 }

+ 3 - 3
client/adventureMap/CInGameConsole.h

@@ -26,10 +26,10 @@ public:
 	std::string enteredText;
 	void show(SDL_Surface * to) override;
 	void print(const std::string &txt);
-	void keyPressed (const SDL_KeyboardEvent & key) override; //call-in
+	void keyPressed(const SDL_Keycode & key) override;
 
-	void textInputed(const SDL_TextInputEvent & event) override;
-	void textEdited(const SDL_TextEditingEvent & event) override;
+	void textInputed(const std::string & enteredText) override;
+	void textEdited(const std::string & enteredText) override;
 
 	void startEnteringText();
 	void endEnteringText(bool processEnteredText);

+ 3 - 2
client/adventureMap/CMinimap.cpp

@@ -17,6 +17,7 @@
 #include "../CGameInfo.h"
 #include "../CPlayerInterface.h"
 #include "../gui/CGuiHandler.h"
+#include "../render/Colors.h"
 #include "../renderSDL/SDL_PixelAccess.h"
 
 #include "../../CCallback.h"
@@ -229,9 +230,9 @@ void CMinimap::hover(bool on)
 		GH.statusbar->clear();
 }
 
-void CMinimap::mouseMoved(const SDL_MouseMotionEvent & sEvent)
+void CMinimap::mouseMoved(const Point & cursorPosition)
 {
-	if(mouseState(EIntObjMouseBtnType::LEFT))
+	if(mouseState(MouseButton::LEFT))
 		moveAdvMapSelection();
 }
 

+ 1 - 1
client/adventureMap/CMinimap.h

@@ -53,7 +53,7 @@ protected:
 	void clickLeft(tribool down, bool previousState) override;
 	void clickRight(tribool down, bool previousState) override;
 	void hover (bool on) override;
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
+	void mouseMoved (const Point & cursorPosition) override;
 
 	void moveAdvMapSelection();
 

+ 1 - 0
client/adventureMap/CResDataBar.cpp

@@ -12,6 +12,7 @@
 
 #include "../CGameInfo.h"
 #include "../CPlayerInterface.h"
+#include "../render/Colors.h"
 #include "../renderSDL/SDL_Extensions.h"
 #include "../gui/CGuiHandler.h"
 #include "../widgets/Images.h"

+ 16 - 17
client/adventureMap/CTerrainRect.cpp

@@ -28,7 +28,7 @@
 #include "../../lib/mapping/CMap.h"
 #include "../../lib/CPathfinder.h"
 
-#include <SDL_events.h>
+#include <SDL_surface.h>
 
 #define ADVOPT (conf.go()->ac)
 
@@ -110,32 +110,31 @@ void CTerrainRect::clickMiddle(tribool down, bool previousState)
 	handleSwipeStateChange((bool)down == true);
 }
 
-void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent)
+void CTerrainRect::mouseMoved(const Point & cursorPosition)
 {
-	handleHover(sEvent);
+	handleHover(cursorPosition);
 
 	if(!adventureInt->swipeEnabled)
 		return;
 
-	handleSwipeMove(sEvent);
+	handleSwipeMove(cursorPosition);
 }
 
-void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
+void CTerrainRect::handleSwipeMove(const Point & cursorPosition)
 {
 #if defined(VCMI_ANDROID) || defined(VCMI_IOS)
-	if(sEvent.state == 0 || GH.multifinger) // any "button" is enough on mobile
+	if(!GH.isMouseButtonPressed() || GH.multifinger) // any "button" is enough on mobile
+		return;
 #else
-	if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms
-#endif
-	{
+	if(!GH.isMouseButtonPressed(MouseButton::MIDDLE)) // swipe only works with middle mouse on other platforms
 		return;
-	}
+#endif
 
 	if(!isSwiping)
 	{
 		// try to distinguish if this touch was meant to be a swipe or just fat-fingering press
-		if(abs(sEvent.x - swipeInitialRealPos.x) > SwipeTouchSlop ||
-		   abs(sEvent.y - swipeInitialRealPos.y) > SwipeTouchSlop)
+		if(abs(cursorPosition.x - swipeInitialRealPos.x) > SwipeTouchSlop ||
+		   abs(cursorPosition.y - swipeInitialRealPos.y) > SwipeTouchSlop)
 		{
 			isSwiping = true;
 		}
@@ -144,9 +143,9 @@ void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
 	if(isSwiping)
 	{
 		adventureInt->swipeTargetPosition.x =
-			swipeInitialMapPos.x + static_cast<si32>(swipeInitialRealPos.x - sEvent.x) / 32;
+			swipeInitialMapPos.x + static_cast<si32>(swipeInitialRealPos.x - cursorPosition.x) / 32;
 		adventureInt->swipeTargetPosition.y =
-			swipeInitialMapPos.y + static_cast<si32>(swipeInitialRealPos.y - sEvent.y) / 32;
+			swipeInitialMapPos.y + static_cast<si32>(swipeInitialRealPos.y - cursorPosition.y) / 32;
 		adventureInt->swipeMovementRequested = true;
 	}
 }
@@ -155,7 +154,7 @@ bool CTerrainRect::handleSwipeStateChange(bool btnPressed)
 {
 	if(btnPressed)
 	{
-		swipeInitialRealPos = int3(GH.getCursorPosition().x, GH.getCursorPosition().y, 0);
+		swipeInitialRealPos = Point(GH.getCursorPosition().x, GH.getCursorPosition().y);
 		swipeInitialMapPos = int3(adventureInt->position);
 		return true;
 	}
@@ -167,9 +166,9 @@ bool CTerrainRect::handleSwipeStateChange(bool btnPressed)
 	return false;
 }
 
-void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent)
+void CTerrainRect::handleHover(const Point & cursorPosition)
 {
-	int3 tHovered = whichTileIsIt(sEvent.x, sEvent.y);
+	int3 tHovered = whichTileIsIt(cursorPosition.x, cursorPosition.y);
 	int3 pom = adventureInt->verifyPos(tHovered);
 
 	if(tHovered != pom) //tile outside the map

+ 4 - 4
client/adventureMap/CTerrainRect.h

@@ -27,12 +27,12 @@ class CTerrainRect : public CIntObject
 	std::shared_ptr<CFadeAnimation> fadeAnim;
 
 	int3 swipeInitialMapPos;
-	int3 swipeInitialRealPos;
+	Point swipeInitialRealPos;
 	bool isSwiping;
 	static constexpr float SwipeTouchSlop = 16.0f;
 
-	void handleHover(const SDL_MouseMotionEvent & sEvent);
-	void handleSwipeMove(const SDL_MouseMotionEvent & sEvent);
+	void handleHover(const Point & cursorPosition);
+	void handleSwipeMove(const Point & cursorPosition);
 	/// handles start/finish of swipe (press/release of corresponding button); returns true if state change was handled
 	bool handleSwipeStateChange(bool btnPressed);
 public:
@@ -48,7 +48,7 @@ public:
 	void clickRight(tribool down, bool previousState) override;
 	void clickMiddle(tribool down, bool previousState) override;
 	void hover(bool on) override;
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
+	void mouseMoved (const Point & cursorPosition) override;
 	void show(SDL_Surface * to) override;
 	void showAll(SDL_Surface * to) override;
 	void showAnim(SDL_Surface * to);

+ 1 - 0
client/adventureMap/mapHandler.cpp

@@ -13,6 +13,7 @@
 
 #include "../render/CAnimation.h"
 #include "../render/CFadeAnimation.h"
+#include "../render/Colors.h"
 #include "../renderSDL/SDL_Extensions.h"
 #include "../CGameInfo.h"
 #include "../render/Graphics.h"

+ 2 - 2
client/battle/BattleFieldController.cpp

@@ -98,9 +98,9 @@ void BattleFieldController::createHeroes()
 		owner.defendingHero = std::make_shared<BattleHero>(owner, owner.defendingHeroInstance, true);
 }
 
-void BattleFieldController::mouseMoved(const SDL_MouseMotionEvent &event)
+void BattleFieldController::mouseMoved(const Point & cursorPosition)
 {
-	if (!pos.isInside(event.x, event.y))
+	if (!pos.isInside(cursorPosition))
 	{
 		owner.actionsController->onHoverEnded();
 		return;

+ 1 - 1
client/battle/BattleFieldController.h

@@ -62,7 +62,7 @@ class BattleFieldController : public CIntObject
 
 	BattleHex::EDir selectAttackDirection(BattleHex myNumber, const Point & point);
 
-	void mouseMoved(const SDL_MouseMotionEvent &event) override;
+	void mouseMoved(const Point & cursorPosition) override;
 	void clickLeft(tribool down, bool previousState) override;
 	void clickRight(tribool down, bool previousState) override;
 

+ 4 - 4
client/battle/BattleInterfaceClasses.cpp

@@ -33,6 +33,7 @@
 #include "../windows/CSpellWindow.h"
 #include "../render/CAnimation.h"
 #include "../adventureMap/CInGameConsole.h"
+#include "../renderSDL/SDL_Extensions.h"
 
 #include "../../CCallback.h"
 #include "../../lib/CStack.h"
@@ -48,7 +49,6 @@
 #include "../../lib/mapObjects/CGTownInstance.h"
 
 #include <SDL_surface.h>
-#include <SDL_events.h>
 
 void BattleConsole::showAll(SDL_Surface * to)
 {
@@ -162,12 +162,12 @@ void BattleConsole::setEnteringMode(bool on)
 	if (on)
 	{
 		assert(enteringText == false);
-		CSDL_Ext::startTextInput(pos);
+		GH.startTextInput(pos);
 	}
 	else
 	{
 		assert(enteringText == true);
-		CSDL_Ext::stopTextInput();
+		GH.stopTextInput();
 	}
 	enteringText = on;
 	redraw();
@@ -738,7 +738,7 @@ boost::optional<uint32_t> StackQueue::getHoveredUnitIdIfAny() const
 {
 	for(const auto & stackBox : stackBoxes)
 	{
-		if(stackBox->hovered || stackBox->mouseState(EIntObjMouseBtnType::RIGHT))
+		if(stackBox->hovered || stackBox->mouseState(MouseButton::RIGHT))
 		{
 			return stackBox->getBoundUnitID();
 		}

+ 2 - 1
client/battle/BattleStacksController.cpp

@@ -26,8 +26,9 @@
 #include "../CMusicHandler.h"
 #include "../CGameInfo.h"
 #include "../gui/CGuiHandler.h"
-#include "../renderSDL/SDL_Extensions.h"
+#include "../render/Colors.h"
 #include "../render/Canvas.h"
+#include "../renderSDL/SDL_Extensions.h"
 
 #include "../../CCallback.h"
 #include "../../lib/spells/ISpellMechanics.h"

+ 5 - 5
client/battle/BattleWindow.cpp

@@ -28,6 +28,7 @@
 #include "../render/CAnimation.h"
 #include "../render/Canvas.h"
 #include "../adventureMap/CInGameConsole.h"
+#include "../CMT.h"
 
 #include "../../CCallback.h"
 #include "../../lib/CGeneralTextHandler.h"
@@ -37,7 +38,6 @@
 #include "../../lib/filesystem/ResourceID.h"
 
 #include <SDL_surface.h>
-#include <SDL_events.h>
 
 BattleWindow::BattleWindow(BattleInterface & owner):
 	owner(owner)
@@ -165,9 +165,9 @@ void BattleWindow::deactivate()
 	LOCPLINT->cingconsole->deactivate();
 }
 
-void BattleWindow::keyPressed(const SDL_KeyboardEvent & key)
+void BattleWindow::keyPressed(const SDL_Keycode & key)
 {
-	if(key.keysym.sym == SDLK_q && key.state == SDL_PRESSED)
+	if(key == SDLK_q)
 	{
 		if(settings["battle"]["showQueue"].Bool()) //hide queue
 			hideQueue();
@@ -175,11 +175,11 @@ void BattleWindow::keyPressed(const SDL_KeyboardEvent & key)
 			showQueue();
 
 	}
-	else if(key.keysym.sym == SDLK_f && key.state == SDL_PRESSED)
+	else if(key == SDLK_f)
 	{
 		owner.actionsController->enterCreatureCastingMode();
 	}
-	else if(key.keysym.sym == SDLK_ESCAPE)
+	else if(key == SDLK_ESCAPE)
 	{
 		if(owner.getAnimationCondition(EAnimationEvents::OPENING) == true)
 			CCS->soundh->stopSound(owner.battleIntroSoundChannel);

+ 1 - 1
client/battle/BattleWindow.h

@@ -79,7 +79,7 @@ public:
 
 	void activate() override;
 	void deactivate() override;
-	void keyPressed(const SDL_KeyboardEvent & key) override;
+	void keyPressed(const SDL_Keycode & key) override;
 	void clickRight(tribool down, bool previousState) override;
 	void show(SDL_Surface *to) override;
 	void showAll(SDL_Surface *to) override;

+ 152 - 31
client/gui/CGuiHandler.cpp

@@ -15,6 +15,7 @@
 #include "CursorHandler.h"
 
 #include "../CGameInfo.h"
+#include "../render/Colors.h"
 #include "../renderSDL/SDL_Extensions.h"
 #include "../CMT.h"
 #include "../CPlayerInterface.h"
@@ -27,6 +28,14 @@
 #include <SDL_timer.h>
 #include <SDL_events.h>
 
+#ifdef VCMI_APPLE
+#include <dispatch/dispatch.h>
+#endif
+
+#ifdef VCMI_IOS
+#include "ios/utils.h"
+#endif
+
 extern std::queue<SDL_Event> SDLEventsQueue;
 extern boost::mutex eventsM;
 
@@ -118,7 +127,7 @@ void CGuiHandler::popInt(std::shared_ptr<IShowActivatable> top)
 		listInt.front()->activate();
 	totalRedraw();
 
-	pushSDLEvent(SDL_USEREVENT, EUserEvent::INTERFACE_CHANGED);
+	pushUserEvent(EUserEvent::INTERFACE_CHANGED);
 }
 
 void CGuiHandler::pushInt(std::shared_ptr<IShowActivatable> newInt)
@@ -137,7 +146,7 @@ void CGuiHandler::pushInt(std::shared_ptr<IShowActivatable> newInt)
 	objsToBlit.push_back(newInt);
 	totalRedraw();
 
-	pushSDLEvent(SDL_USEREVENT, EUserEvent::INTERFACE_CHANGED);
+	pushUserEvent(EUserEvent::INTERFACE_CHANGED);
 }
 
 void CGuiHandler::popInts(int howMany)
@@ -160,7 +169,7 @@ void CGuiHandler::popInts(int howMany)
 	}
 	fakeMouseMove();
 
-	pushSDLEvent(SDL_USEREVENT, EUserEvent::INTERFACE_CHANGED);
+	pushUserEvent(EUserEvent::INTERFACE_CHANGED);
 }
 
 std::shared_ptr<IShowActivatable> CGuiHandler::topInt()
@@ -203,7 +212,12 @@ void CGuiHandler::handleEvents()
 	{
 		continueEventHandling = true;
 		SDL_Event currentEvent = SDLEventsQueue.front();
-		cursorPosition = Point(currentEvent.motion.x, currentEvent.motion.y);
+
+		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.
@@ -257,6 +271,59 @@ void CGuiHandler::fakeMouseMove()
 	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
+}
+
+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;
@@ -280,9 +347,9 @@ void CGuiHandler::fakeMouseButtonEventRelativeMode(bool down, bool right)
 	SDL_RenderGetScale(mainRenderer, &xScale, &yScale);
 
 	SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
-	CSDL_Ext::warpMouse(
+	moveCursorToPosition( Point(
 		(int)(sme.x * xScale) + (w - rLogicalWidth * xScale) / 2,
-		(int)(sme.y * yScale + (h - rLogicalHeight * yScale) / 2));
+		(int)(sme.y * yScale + (h - rLogicalHeight * yScale) / 2)));
 	SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
 
 	event.button = sme;
@@ -345,7 +412,7 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
 		bool keysCaptured = false;
 		for(auto i = keyinterested.begin(); i != keyinterested.end() && continueEventHandling; i++)
 		{
-			if((*i)->captureThisEvent(key))
+			if((*i)->captureThisKey(key.keysym.sym))
 			{
 				keysCaptured = true;
 				break;
@@ -354,8 +421,13 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
 
 		std::list<CIntObject*> miCopy = keyinterested;
 		for(auto i = miCopy.begin(); i != miCopy.end() && continueEventHandling; i++)
-			if(vstd::contains(keyinterested,*i) && (!keysCaptured || (*i)->captureThisEvent(key)))
-				(**i).keyPressed(key);
+			if(vstd::contains(keyinterested,*i) && (!keysCaptured || (*i)->captureThisKey(key.keysym.sym)))
+			{
+				if (key.state == SDL_PRESSED)
+					(**i).keyPressed(key.keysym.sym);
+				if (key.state == SDL_RELEASED)
+					(**i).keyReleased(key.keysym.sym);
+			}
 	}
 	else if(current.type == SDL_MOUSEMOTION)
 	{
@@ -387,14 +459,14 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
 			lastClickTime = SDL_GetTicks();
 
 			if(!doubleClicked)
-				handleMouseButtonClick(lclickable, EIntObjMouseBtnType::LEFT, true);
+				handleMouseButtonClick(lclickable, MouseButton::LEFT, true);
 			break;
 		}
 		case SDL_BUTTON_RIGHT:
-			handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, true);
+			handleMouseButtonClick(rclickable, MouseButton::RIGHT, true);
 			break;
 		case SDL_BUTTON_MIDDLE:
-			handleMouseButtonClick(mclickable, EIntObjMouseBtnType::MIDDLE, true);
+			handleMouseButtonClick(mclickable, MouseButton::MIDDLE, true);
 			break;
 		default:
 			break;
@@ -416,14 +488,14 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
 	{
 		for(auto it : textInterested)
 		{
-			it->textInputed(current.text);
+			it->textInputed(current.text.text);
 		}
 	}
 	else if(current.type == SDL_TEXTEDITING)
 	{
 		for(auto it : textInterested)
 		{
-			it->textEdited(current.edit);
+			it->textEdited(current.edit.text);
 		}
 	}
 	else if(current.type == SDL_MOUSEBUTTONUP)
@@ -433,13 +505,13 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
 			switch(current.button.button)
 			{
 			case SDL_BUTTON_LEFT:
-				handleMouseButtonClick(lclickable, EIntObjMouseBtnType::LEFT, false);
+				handleMouseButtonClick(lclickable, MouseButton::LEFT, false);
 				break;
 			case SDL_BUTTON_RIGHT:
-				handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false);
+				handleMouseButtonClick(rclickable, MouseButton::RIGHT, false);
 				break;
 			case SDL_BUTTON_MIDDLE:
-				handleMouseButtonClick(mclickable, EIntObjMouseBtnType::MIDDLE, false);
+				handleMouseButtonClick(mclickable, MouseButton::MIDDLE, false);
 				break;
 			}
 		}
@@ -471,7 +543,7 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
 		{
 			convertTouchToMouse(&current);
 			handleMouseMotion(current);
-			handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, true);
+			handleMouseButtonClick(rclickable, MouseButton::RIGHT, true);
 		}
 #endif //VCMI_IOS
 	}
@@ -495,14 +567,14 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
 		{
 			convertTouchToMouse(&current);
 			handleMouseMotion(current);
-			handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false);
+			handleMouseButtonClick(rclickable, MouseButton::RIGHT, false);
 			multifinger = fingerCount != 0;
 		}
 #endif //VCMI_IOS
 	}
 } //event end
 
-void CGuiHandler::handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed)
+void CGuiHandler::handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed)
 {
 	auto hlp = interestedObjs;
 	for(auto i = hlp.begin(); i != hlp.end() && continueEventHandling; i++)
@@ -546,7 +618,9 @@ void CGuiHandler::handleMouseMotion(const SDL_Event & current)
 		elem->hovered = true;
 	}
 
-	handleMoveInterested(current.motion);
+	// do not send motion events for events outside our window
+	//if (current.motion.windowID == 0)
+		handleMoveInterested(current.motion);
 }
 
 void CGuiHandler::simpleRedraw()
@@ -566,7 +640,7 @@ void CGuiHandler::handleMoveInterested(const SDL_MouseMotionEvent & motion)
 	{
 		if(elem->strongInterest || Rect::createAround(elem->pos, 1).isInside( motion.x, motion.y)) //checking bounds including border fixes bug #2476
 		{
-			(elem)->mouseMoved(motion);
+			(elem)->mouseMoved(Point(motion.x, motion.y));
 		}
 	}
 }
@@ -612,13 +686,16 @@ void CGuiHandler::renderFrame()
 
 
 CGuiHandler::CGuiHandler()
-	: lastClick(-500, -500),lastClickTime(0), defActionsDef(0), captureChildren(false),
-    multifinger(false)
+	: lastClick(-500, -500)
+	, lastClickTime(0)
+	, defActionsDef(0)
+	, captureChildren(false)
+	, multifinger(false)
+	, mouseButtonsMask(0)
+	, continueEventHandling(true)
+	, curInt(nullptr)
+	, statusbar(nullptr)
 {
-	continueEventHandling = true;
-	curInt = nullptr;
-	statusbar = nullptr;
-
 	// Creates the FPS manager and sets the framerate to 48 which is doubled the value of the original Heroes 3 FPS rate
 	mainFPSmng = new CFramerateManager(60);
 	//do not init CFramerateManager here --AVS
@@ -632,6 +709,27 @@ CGuiHandler::~CGuiHandler()
 	delete terminate_cond;
 }
 
+
+void CGuiHandler::moveCursorToPosition(const Point & position)
+{
+	SDL_WarpMouseInWindow(mainWindow, position.x, position.y);
+}
+
+bool CGuiHandler::isKeyboardCtrlDown() const
+{
+	return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LCTRL] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RCTRL];
+}
+
+bool CGuiHandler::isKeyboardAltDown() const
+{
+	return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LALT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RALT];
+}
+
+bool CGuiHandler::isKeyboardShiftDown() const
+{
+	return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RSHIFT];
+}
+
 void CGuiHandler::breakEventHandling()
 {
 	continueEventHandling = false;
@@ -642,6 +740,23 @@ const Point & CGuiHandler::getCursorPosition() const
 	return cursorPosition;
 }
 
+bool CGuiHandler::isMouseButtonPressed() const
+{
+	return mouseButtonsMask > 0;
+}
+
+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);
+}
+
 void CGuiHandler::drawFPSCounter()
 {
 	static SDL_Rect overlay = { 0, 0, 64, 32};
@@ -719,11 +834,17 @@ bool CGuiHandler::amIGuiThread()
 	return inGuiThread.get() && *inGuiThread;
 }
 
-void CGuiHandler::pushSDLEvent(int type, int usercode)
+void CGuiHandler::pushUserEvent(EUserEvent usercode)
+{
+	pushUserEvent(usercode, nullptr);
+}
+
+void CGuiHandler::pushUserEvent(EUserEvent usercode, void * userdata)
 {
 	SDL_Event event;
-	event.type = type;
-	event.user.code = usercode;	// not necessarily used
+	event.type = SDL_USEREVENT;
+	event.user.code = static_cast<int32_t>(usercode);
+	event.user.data1 = userdata;
 	SDL_PushEvent(&event);
 }
 

+ 27 - 5
client/gui/CGuiHandler.h

@@ -9,12 +9,15 @@
  */
 #pragma once
 
+#include "MouseButton.h"
 #include "../../lib/Point.h"
-#include "SDL_keycode.h"
+
+#include <SDL_keycode.h>
 
 VCMI_LIB_NAMESPACE_BEGIN
 
 template <typename T> struct CondSh;
+class Rect;
 
 VCMI_LIB_NAMESPACE_END
 
@@ -27,10 +30,9 @@ class CIntObject;
 class IUpdateable;
 class IShowActivatable;
 class IShowable;
-enum class EIntObjMouseBtnType;
 
 // TODO: event handling need refactoring
-enum EUserEvent
+enum class EUserEvent
 {
 	/*CHANGE_SCREEN_RESOLUTION = 1,*/
 	RETURN_TO_MAIN_MENU = 2,
@@ -71,6 +73,7 @@ public:
 
 private:
 	Point cursorPosition;
+	uint32_t mouseButtonsMask;
 
 	std::vector<std::shared_ptr<IShowActivatable>> disposed;
 
@@ -90,7 +93,7 @@ private:
 	CIntObjectList textInterested;
 
 
-	void handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed);
+	void handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed);
 	void processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb);
 	void handleCurrentEvent(SDL_Event &current);
 	void handleMouseMotion(const SDL_Event & current);
@@ -107,8 +110,26 @@ public:
 	//objs to blit
 	std::vector<std::shared_ptr<IShowActivatable>> objsToBlit;
 
+	/// returns current position of mouse cursor, relative to vcmi window
 	const Point & getCursorPosition() const;
 
+	/// returns true if at least one mouse button is pressed
+	bool isMouseButtonPressed() const;
+
+	/// returns true if specified mouse button is pressed
+	bool isMouseButtonPressed(MouseButton button) const;
+
+	/// returns true if chosen keyboard key is currently pressed down
+	bool isKeyboardAltDown() const;
+	bool isKeyboardCtrlDown() const;
+	bool isKeyboardShiftDown() const;
+
+	void startTextInput(const Rect & where);
+	void stopTextInput();
+
+	/// moves mouse pointer into specified position inside vcmi window
+	void moveCursorToPosition(const Point & position);
+
 	IUpdateable *curInt;
 
 	Point lastClick;
@@ -155,7 +176,8 @@ public:
 	static bool isNumKey(SDL_Keycode key, bool number = true); //checks if key is on numpad (numbers - check only for numpad digits)
 	static bool isArrowKey(SDL_Keycode key);
 	static bool amIGuiThread();
-	static void pushSDLEvent(int type, int usercode = 0);
+	static void pushUserEvent(EUserEvent usercode);
+	static void pushUserEvent(EUserEvent usercode, void * userdata);
 
 	CondSh<bool> * terminate_cond; // confirm termination
 };

+ 23 - 12
client/gui/CIntObject.cpp

@@ -16,7 +16,6 @@
 
 #include <SDL_pixels.h>
 #include <SDL_surface.h>
-#include <SDL_events.h>
 
 IShowActivatable::IShowActivatable()
 {
@@ -146,18 +145,18 @@ void CIntObject::deactivate(ui16 what)
 	GH.handleElementDeActivate(this, what);
 }
 
-void CIntObject::click(EIntObjMouseBtnType btn, tribool down, bool previousState)
+void CIntObject::click(MouseButton btn, tribool down, bool previousState)
 {
 	switch(btn)
 	{
 	default:
-	case EIntObjMouseBtnType::LEFT:
+	case MouseButton::LEFT:
 		clickLeft(down, previousState);
 		break;
-	case EIntObjMouseBtnType::MIDDLE:
+	case MouseButton::MIDDLE:
 		clickMiddle(down, previousState);
 		break;
-	case EIntObjMouseBtnType::RIGHT:
+	case MouseButton::RIGHT:
 		clickRight(down, previousState);
 		break;
 	}
@@ -325,7 +324,7 @@ const Rect & CIntObject::center(const Point & p, bool propagate)
 	return pos;
 }
 
-bool CIntObject::captureThisEvent(const SDL_KeyboardEvent & key)
+bool CIntObject::captureThisKey(const SDL_Keycode & key)
 {
 	return captureAllKeys;
 }
@@ -343,14 +342,26 @@ CKeyShortcut::CKeyShortcut(std::set<int> Keys)
 	:assignedKeys(Keys)
 {}
 
-void CKeyShortcut::keyPressed(const SDL_KeyboardEvent & key)
+void CKeyShortcut::keyPressed(const SDL_Keycode & key)
 {
-	if(vstd::contains(assignedKeys,key.keysym.sym)
-	 || vstd::contains(assignedKeys, CGuiHandler::numToDigit(key.keysym.sym)))
+	if(vstd::contains(assignedKeys,key)
+	 || vstd::contains(assignedKeys, CGuiHandler::numToDigit(key)))
 	{
-		bool prev = mouseState(EIntObjMouseBtnType::LEFT);
-		updateMouseState(EIntObjMouseBtnType::LEFT, key.state == SDL_PRESSED);
-		clickLeft(key.state == SDL_PRESSED, prev);
+		bool prev = mouseState(MouseButton::LEFT);
+		updateMouseState(MouseButton::LEFT, true);
+		clickLeft(true, prev);
+
+	}
+}
+
+void CKeyShortcut::keyReleased(const SDL_Keycode & key)
+{
+	if(vstd::contains(assignedKeys,key)
+	 || vstd::contains(assignedKeys, CGuiHandler::numToDigit(key)))
+	{
+		bool prev = mouseState(MouseButton::LEFT);
+		updateMouseState(MouseButton::LEFT, false);
+		clickLeft(false, prev);
 
 	}
 }

+ 16 - 18
client/gui/CIntObject.h

@@ -9,17 +9,15 @@
  */
 #pragma once
 
-#include "../../lib/Rect.h"
+#include "MouseButton.h"
 #include "../render/Graphics.h"
+#include "../../lib/Rect.h"
 
 struct SDL_Surface;
 class CGuiHandler;
 class CPicture;
 
-struct SDL_KeyboardEvent;
-struct SDL_TextInputEvent;
-struct SDL_TextEditingEvent;
-struct SDL_MouseMotionEvent;
+typedef int32_t SDL_Keycode;
 
 using boost::logic::tribool;
 
@@ -62,9 +60,6 @@ public:
 	virtual ~IShowActivatable(){};
 };
 
-enum class EIntObjMouseBtnType { LEFT, MIDDLE, RIGHT };
-//typedef ui16 ActivityFlag;
-
 // Base UI element
 class CIntObject : public IShowActivatable //interface object
 {
@@ -74,7 +69,7 @@ class CIntObject : public IShowActivatable //interface object
 	int toNextTick;
 	int timerDelay;
 
-	std::map<EIntObjMouseBtnType, bool> currentMouseState;
+	std::map<MouseButton, bool> currentMouseState;
 
 	void onTimer(int timePassed);
 
@@ -108,10 +103,10 @@ public:
 	CIntObject(int used=0, Point offset=Point());
 	virtual ~CIntObject();
 
-	void updateMouseState(EIntObjMouseBtnType btn, bool state) { currentMouseState[btn] = state; }
-	bool mouseState(EIntObjMouseBtnType btn) const { return currentMouseState.count(btn) ? currentMouseState.at(btn) : false; }
+	void updateMouseState(MouseButton btn, bool state) { currentMouseState[btn] = state; }
+	bool mouseState(MouseButton btn) const { return currentMouseState.count(btn) ? currentMouseState.at(btn) : false; }
 
-	virtual void click(EIntObjMouseBtnType btn, tribool down, bool previousState);
+	virtual void click(MouseButton btn, tribool down, bool previousState);
 	virtual void clickLeft(tribool down, bool previousState) {}
 	virtual void clickRight(tribool down, bool previousState) {}
 	virtual void clickMiddle(tribool down, bool previousState) {}
@@ -122,15 +117,16 @@ public:
 
 	//keyboard handling
 	bool captureAllKeys; //if true, only this object should get info about pressed keys
-	virtual void keyPressed(const SDL_KeyboardEvent & key){}
-	virtual bool captureThisEvent(const SDL_KeyboardEvent & key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
+	virtual void keyPressed(const SDL_Keycode & key){}
+	virtual void keyReleased(const SDL_Keycode & key){}
+	virtual bool captureThisKey(const SDL_Keycode & key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
 
-	virtual void textInputed(const SDL_TextInputEvent & event){};
-	virtual void textEdited(const SDL_TextEditingEvent & event){};
+	virtual void textInputed(const std::string & enteredText){};
+	virtual void textEdited(const std::string & enteredText){};
 
 	//mouse movement handling
 	bool strongInterest; //if true - report all mouse movements, if not - only when hovered
-	virtual void mouseMoved (const SDL_MouseMotionEvent & sEvent){}
+	virtual void mouseMoved (const Point & cursorPosition){}
 
 	//time handling
 	void setTimer(int msToTrigger);//set timer delay and activate timer if needed.
@@ -205,7 +201,9 @@ public:
 	CKeyShortcut();
 	CKeyShortcut(int key);
 	CKeyShortcut(std::set<int> Keys);
-	virtual void keyPressed(const SDL_KeyboardEvent & key) override; //call-in
+	void keyPressed(const SDL_Keycode & key) override;
+	void keyReleased(const SDL_Keycode & key) override;
+
 };
 
 class WindowBase : public CIntObject

+ 0 - 19
client/gui/CursorHandler.cpp

@@ -21,13 +21,6 @@
 
 #include "../../lib/CConfigHandler.h"
 
-#include <SDL_render.h>
-#include <SDL_events.h>
-
-#ifdef VCMI_APPLE
-#include <dispatch/dispatch.h>
-#endif
-
 std::unique_ptr<ICursor> CursorHandler::createCursor()
 {
 	if (settings["video"]["cursor"].String() == "auto")
@@ -254,18 +247,6 @@ std::shared_ptr<IImage> CursorHandler::getCurrentImage()
 	return cursors[static_cast<size_t>(type)]->getImage(frame);
 }
 
-void CursorHandler::centerCursor()
-{
-	Point screenSize {screen->w, screen->h};
-	pos = screenSize / 2 - getPivotOffset();
-
-	SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
-	CSDL_Ext::warpMouse(pos.x, pos.y);
-	SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
-
-	cursor->setCursorPosition(pos);
-}
-
 void CursorHandler::updateSpellcastCursor()
 {
 	static const float frameDisplayDuration = 0.1f; // H3 uses 100 ms per frame

+ 0 - 3
client/gui/CursorHandler.h

@@ -178,7 +178,4 @@ public:
 
 	/// change cursor's positions to (x, y)
 	void cursorMove(const int & x, const int & y);
-	/// Move cursor to screen center
-	void centerCursor();
-
 };

+ 19 - 0
client/gui/MouseButton.h

@@ -0,0 +1,19 @@
+/*
+ * MouseButton.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
+
+enum class MouseButton
+{
+	LEFT   = 1,
+	MIDDLE = 2,
+	RIGHT  = 3,
+	EXTRA1 = 4,
+	EXTRA2 = 5
+};

+ 1 - 1
client/lobby/CBonusSelection.cpp

@@ -454,7 +454,7 @@ void CBonusSelection::restartMap()
 	close();
 	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[67], [=]()
 	{
-		LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME);
+		GH.pushUserEvent(EUserEvent::RESTART_GAME);
 	}, 0);
 }
 

+ 2 - 4
client/lobby/CSelectionBase.cpp

@@ -43,8 +43,6 @@
 #include "../../lib/mapping/CMapInfo.h"
 #include "../../lib/serializer/Connection.h"
 
-#include <SDL_events.h>
-
 ISelectionScreenInfo::ISelectionScreenInfo(ESelectionScreen ScreenType)
 	: screenType(ScreenType)
 {
@@ -320,9 +318,9 @@ CChatBox::CChatBox(const Rect & rect)
 	chatHistory->label->color = Colors::GREEN;
 }
 
-void CChatBox::keyPressed(const SDL_KeyboardEvent & key)
+void CChatBox::keyPressed(const SDL_Keycode & key)
 {
-	if(key.keysym.sym == SDLK_RETURN && key.state == SDL_PRESSED && inputBox->getText().size())
+	if(key == SDLK_RETURN && inputBox->getText().size())
 	{
 		CSH->sendMessage(inputBox->getText());
 		inputBox->setText("");

+ 1 - 2
client/lobby/CSelectionBase.h

@@ -120,8 +120,7 @@ public:
 
 	CChatBox(const Rect & rect);
 
-	void keyPressed(const SDL_KeyboardEvent & key) override;
-
+	void keyPressed(const SDL_Keycode & key) override;
 	void addNewMessage(const std::string & text);
 };
 

+ 2 - 7
client/lobby/SelectionTab.cpp

@@ -35,8 +35,6 @@
 #include "../../lib/mapping/CMapInfo.h"
 #include "../../lib/serializer/Connection.h"
 
-#include <SDL_events.h>
-
 bool mapSorter::operator()(const std::shared_ptr<CMapInfo> aaa, const std::shared_ptr<CMapInfo> bbb)
 {
 	auto a = aaa->mapHeader.get();
@@ -280,13 +278,10 @@ void SelectionTab::clickLeft(tribool down, bool previousState)
 	}
 }
 
-void SelectionTab::keyPressed(const SDL_KeyboardEvent & key)
+void SelectionTab::keyPressed(const SDL_Keycode & key)
 {
-	if(key.state != SDL_PRESSED)
-		return;
-
 	int moveBy = 0;
-	switch(key.keysym.sym)
+	switch(key)
 	{
 	case SDLK_UP:
 		moveBy = -1;

+ 2 - 1
client/lobby/SelectionTab.h

@@ -66,7 +66,8 @@ public:
 	void toggleMode();
 
 	void clickLeft(tribool down, bool previousState) override;
-	void keyPressed(const SDL_KeyboardEvent & key) override;
+	void keyPressed(const SDL_Keycode & key) override;
+
 	void onDoubleClick() override;
 
 	void filter(int size, bool selectFirst = false); //0 - all

+ 21 - 22
client/mainmenu/CMainMenu.cpp

@@ -16,25 +16,9 @@
 #include "../lobby/CBonusSelection.h"
 #include "../lobby/CSelectionBase.h"
 #include "../lobby/CLobbyScreen.h"
-
-#include "../../lib/filesystem/Filesystem.h"
-#include "../../lib/filesystem/CCompressedStream.h"
-
 #include "../gui/CursorHandler.h"
-
-#include "../CGameInfo.h"
-#include "../../lib/CGeneralTextHandler.h"
-#include "../../lib/JsonNode.h"
-#include "../CMusicHandler.h"
-#include "../CVideoHandler.h"
-#include "../../lib/serializer/Connection.h"
-#include "../../lib/serializer/CTypeList.h"
-#include "../../lib/VCMIDirs.h"
-#include "../../lib/mapping/CMap.h"
+#include "../CMT.h"
 #include "../windows/GUIClasses.h"
-#include "../CPlayerInterface.h"
-#include "../../CCallback.h"
-#include "../Client.h"
 #include "../gui/CGuiHandler.h"
 #include "../widgets/CComponent.h"
 #include "../widgets/Buttons.h"
@@ -43,6 +27,23 @@
 #include "../widgets/TextControls.h"
 #include "../windows/InfoWindows.h"
 #include "../CServerHandler.h"
+
+#include "../CGameInfo.h"
+#include "../CMusicHandler.h"
+#include "../CVideoHandler.h"
+#include "../CPlayerInterface.h"
+#include "../Client.h"
+
+#include "../../CCallback.h"
+
+#include "../../lib/CGeneralTextHandler.h"
+#include "../../lib/JsonNode.h"
+#include "../../lib/serializer/Connection.h"
+#include "../../lib/serializer/CTypeList.h"
+#include "../../lib/filesystem/Filesystem.h"
+#include "../../lib/filesystem/CCompressedStream.h"
+#include "../../lib/VCMIDirs.h"
+#include "../../lib/mapping/CMap.h"
 #include "../../lib/CStopWatch.h"
 #include "../../lib/NetPacksLobby.h"
 #include "../../lib/CThreadHelper.h"
@@ -52,7 +53,7 @@
 #include "../../lib/CondSh.h"
 #include "../../lib/mapping/CCampaignHandler.h"
 
-#include <SDL_events.h>
+#include <SDL_surface.h>
 
 namespace fs = boost::filesystem;
 
@@ -61,9 +62,7 @@ ISelectionScreenInfo * SEL;
 
 static void do_quit()
 {
-	SDL_Event event;
-	event.quit.type = SDL_QUIT;
-	SDL_PushEvent(&event);
+	GH.pushUserEvent(EUserEvent::FORCE_QUIT);
 }
 
 CMenuScreen::CMenuScreen(const JsonNode & configNode)
@@ -484,7 +483,7 @@ void CSimpleJoinScreen::connectToServer()
 {
 	textTitle->setText("Connecting...");
 	buttonOk->block(true);
-	CSDL_Ext::stopTextInput();
+	GH.stopTextInput();
 
 	boost::thread(&CSimpleJoinScreen::connectThread, this, inputAddress->getText(), boost::lexical_cast<ui16>(inputPort->getText()));
 }

+ 1 - 0
client/mainmenu/CPrologEpilogVideo.cpp

@@ -16,6 +16,7 @@
 #include "../CVideoHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../widgets/TextControls.h"
+#include "../renderSDL/SDL_Extensions.h"
 
 #include "../../lib/mapping/CCampaignHandler.h"
 

+ 26 - 0
client/render/Colors.cpp

@@ -0,0 +1,26 @@
+/*
+ * IFont.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 "Colors.h"
+
+#include <SDL_pixels.h>
+
+const SDL_Color Colors::YELLOW = { 229, 215, 123, SDL_ALPHA_OPAQUE };
+const SDL_Color Colors::WHITE = { 255, 243, 222, SDL_ALPHA_OPAQUE };
+const SDL_Color Colors::METALLIC_GOLD = { 173, 142, 66, SDL_ALPHA_OPAQUE };
+const SDL_Color Colors::GREEN = { 0, 255, 0, SDL_ALPHA_OPAQUE };
+const SDL_Color Colors::ORANGE = { 232, 184, 32, SDL_ALPHA_OPAQUE };
+const SDL_Color Colors::BRIGHT_YELLOW = { 242, 226, 110, SDL_ALPHA_OPAQUE };
+const SDL_Color Colors::DEFAULT_KEY_COLOR = {0, 255, 255, SDL_ALPHA_OPAQUE};
+const SDL_Color Colors::RED = {255, 0, 0, SDL_ALPHA_OPAQUE};
+const SDL_Color Colors::PURPLE = {255, 75, 125, SDL_ALPHA_OPAQUE};
+const SDL_Color Colors::BLACK = {0, 0, 0, SDL_ALPHA_OPAQUE};
+const SDL_Color Colors::TRANSPARENCY = {0, 0, 0, SDL_ALPHA_TRANSPARENT};

+ 50 - 0
client/render/Colors.h

@@ -0,0 +1,50 @@
+/*
+ * ICursor.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_Color;
+
+/**
+ * The colors class defines color constants of type SDL_Color.
+ */
+class Colors
+{
+public:
+	/** the h3 yellow color, typically used for headlines */
+	static const SDL_Color YELLOW;
+
+	/** the standard h3 white color */
+	static const SDL_Color WHITE;
+
+	/** the metallic gold color used mostly as a border around buttons */
+	static const SDL_Color METALLIC_GOLD;
+
+	/** green color used for in-game console */
+	static const SDL_Color GREEN;
+
+	/** the h3 orange color, used for blocked buttons */
+	static const SDL_Color ORANGE;
+
+	/** the h3 bright yellow color, used for selection border */
+	static const SDL_Color BRIGHT_YELLOW;
+
+	/** default key color for all 8 & 24 bit graphics */
+	static const SDL_Color DEFAULT_KEY_COLOR;
+
+	/// Selected creature card
+	static const SDL_Color RED;
+
+	/// Minimap border
+	static const SDL_Color PURPLE;
+
+	static const SDL_Color BLACK;
+
+	static const SDL_Color TRANSPARENCY;
+};

+ 0 - 2
client/render/Graphics.cpp

@@ -42,8 +42,6 @@
 
 #include <SDL_surface.h>
 
-using namespace CSDL_Ext;
-
 Graphics * graphics = nullptr;
 
 void Graphics::loadPaletteAndColors()

+ 2 - 1
client/renderSDL/CTrueTypeFont.cpp

@@ -10,7 +10,8 @@
 #include "StdInc.h"
 #include "CTrueTypeFont.h"
 
-#include "SDL_Extensions.h"
+#include "../render/Colors.h"
+#include "../renderSDL/SDL_Extensions.h"
 
 #include "../../lib/JsonNode.h"
 #include "../../lib/CGeneralTextHandler.h"

+ 2 - 1
client/renderSDL/CursorHardware.cpp

@@ -11,8 +11,9 @@
 #include "StdInc.h"
 #include "CursorHardware.h"
 
-#include "SDL_Extensions.h"
+#include "../render/Colors.h"
 #include "../render/IImage.h"
+#include "SDL_Extensions.h"
 
 #include <SDL_render.h>
 #include <SDL_events.h>

+ 2 - 2
client/renderSDL/CursorSoftware.cpp

@@ -11,9 +11,9 @@
 #include "StdInc.h"
 #include "CursorSoftware.h"
 
-#include "SDL_Extensions.h"
-
+#include "../render/Colors.h"
 #include "../render/IImage.h"
+#include "SDL_Extensions.h"
 
 #include <SDL_render.h>
 #include <SDL_events.h>

+ 7 - 93
client/renderSDL/SDL_Extensions.cpp

@@ -13,10 +13,9 @@
 #include "SDL_PixelAccess.h"
 
 #include "../render/Graphics.h"
+#include "../render/Colors.h"
 
 #include <SDL_render.h>
-#include <SDL_video.h>
-#include <SDL_events.h>
 
 #ifdef VCMI_APPLE
 #include <dispatch/dispatch.h>
@@ -26,18 +25,6 @@
 #include "ios/utils.h"
 #endif
 
-const SDL_Color Colors::YELLOW = { 229, 215, 123, SDL_ALPHA_OPAQUE };
-const SDL_Color Colors::WHITE = { 255, 243, 222, SDL_ALPHA_OPAQUE };
-const SDL_Color Colors::METALLIC_GOLD = { 173, 142, 66, SDL_ALPHA_OPAQUE };
-const SDL_Color Colors::GREEN = { 0, 255, 0, SDL_ALPHA_OPAQUE };
-const SDL_Color Colors::ORANGE = { 232, 184, 32, SDL_ALPHA_OPAQUE };
-const SDL_Color Colors::BRIGHT_YELLOW = { 242, 226, 110, SDL_ALPHA_OPAQUE };
-const SDL_Color Colors::DEFAULT_KEY_COLOR = {0, 255, 255, SDL_ALPHA_OPAQUE};
-const SDL_Color Colors::RED = {255, 0, 0, SDL_ALPHA_OPAQUE};
-const SDL_Color Colors::PURPLE = {255, 75, 125, SDL_ALPHA_OPAQUE};
-const SDL_Color Colors::BLACK = {0, 0, 0, SDL_ALPHA_OPAQUE};
-const SDL_Color Colors::TRANSPARENCY = {0, 0, 0, SDL_ALPHA_TRANSPARENT};
-
 Rect CSDL_Ext::genRect(const int & hh, const int & ww, const int & xx, const int & yy)
 {
 	Rect ret;
@@ -79,29 +66,17 @@ SDL_Color CSDL_Ext::toSDL(const ColorRGBA & color)
 	return result;
 }
 
-void CSDL_Ext::setColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors)
-{
-	SDL_SetPaletteColors(surface->format->palette,colors,firstcolor,ncolors);
-}
-
-void CSDL_Ext::warpMouse(int x, int y)
+Rect CSDL_Ext::getDisplayBounds()
 {
-	SDL_WarpMouseInWindow(mainWindow,x,y);
-}
-
-bool CSDL_Ext::isCtrlKeyDown()
-{
-	return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LCTRL] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RCTRL];
-}
+	SDL_Rect displayBounds;
+	SDL_GetDisplayBounds(std::max(0, SDL_GetWindowDisplayIndex(mainWindow)), &displayBounds);
 
-bool CSDL_Ext::isAltKeyDown()
-{
-	return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LALT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RALT];
+	return fromSDL(displayBounds);
 }
 
-bool CSDL_Ext::isShiftKeyDown()
+void CSDL_Ext::setColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors)
 {
-	return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RSHIFT];
+	SDL_SetPaletteColors(surface->format->palette,colors,firstcolor,ncolors);
 }
 
 void CSDL_Ext::setAlpha(SDL_Surface * bg, int value)
@@ -409,14 +384,6 @@ uint32_t CSDL_Ext::colorTouint32_t(const SDL_Color * color)
 	return ret;
 }
 
-void CSDL_Ext::update(SDL_Surface * what)
-{
-	if(!what)
-		return;
-	if(0 !=SDL_UpdateTexture(screenTexture, nullptr, what->pixels, what->pitch))
-		logGlobal->error("%s SDL_UpdateTexture %s", __FUNCTION__, SDL_GetError());
-}
-
 static void drawLineX(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2)
 {
 	for(int x = x1; x <= x2; x++)
@@ -887,59 +854,6 @@ SDL_Color CSDL_Ext::makeColor(ui8 r, ui8 g, ui8 b, ui8 a)
 	return ret;
 }
 
-void CSDL_Ext::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 CSDL_Ext::stopTextInput()
-{
-#ifdef VCMI_APPLE
-	dispatch_async(dispatch_get_main_queue(), ^{
-#endif
-
-	if (SDL_IsTextInputActive() == SDL_TRUE)
-	{
-		SDL_StopTextInput();
-	}
-
-#ifdef VCMI_APPLE
-	});
-#endif
-}
-
 STRONG_INLINE static uint32_t mapColor(SDL_Surface * surface, SDL_Color color)
 {
 	return SDL_MapRGBA(surface->format, color.r, color.g, color.b, color.a);

+ 3 - 47
client/renderSDL/SDL_Extensions.h

@@ -32,44 +32,6 @@ class Point;
 
 VCMI_LIB_NAMESPACE_END
 
-/**
- * The colors class defines color constants of type SDL_Color.
- */
-class Colors
-{
-public:
-	/** the h3 yellow color, typically used for headlines */
-	static const SDL_Color YELLOW;
-
-	/** the standard h3 white color */
-	static const SDL_Color WHITE;
-
-	/** the metallic gold color used mostly as a border around buttons */
-	static const SDL_Color METALLIC_GOLD;
-
-	/** green color used for in-game console */
-	static const SDL_Color GREEN;
-
-	/** the h3 orange color, used for blocked buttons */
-	static const SDL_Color ORANGE;
-
-	/** the h3 bright yellow color, used for selection border */
-	static const SDL_Color BRIGHT_YELLOW;
-
-	/** default key color for all 8 & 24 bit graphics */
-	static const SDL_Color DEFAULT_KEY_COLOR;
-
-	/// Selected creature card
-	static const SDL_Color RED;
-
-	/// Minimap border
-	static const SDL_Color PURPLE;
-
-	static const SDL_Color BLACK;
-
-	static const SDL_Color TRANSPARENCY;
-};
-
 namespace CSDL_Ext
 {
 
@@ -86,10 +48,6 @@ ColorRGBA fromSDL(const SDL_Color & color);
 SDL_Color toSDL(const ColorRGBA & color);
 
 void setColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors);
-void warpMouse(int x, int y);
-bool isCtrlKeyDown();
-bool isAltKeyDown();
-bool isShiftKeyDown();
 void setAlpha(SDL_Surface * bg, int value);
 
 template<typename IntType>
@@ -150,7 +108,9 @@ typedef void (*TColorPutterAlpha)(uint8_t *&ptr, const uint8_t & R, const uint8_
 	uint32_t colorTouint32_t(const SDL_Color * color); //little endian only
 	SDL_Color makeColor(ui8 r, ui8 g, ui8 b, ui8 a);
 
-	void update(SDL_Surface * what = screen); //updates whole surface (default - main screen)
+	/// returns dimensions of display on which VCMI window is located
+	Rect getDisplayBounds();
+
 	void drawLine(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2);
 	void drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const SDL_Color &color, int depth = 1);
 	void drawBorder(SDL_Surface * sur, const Rect &r, const SDL_Color &color, int depth = 1);
@@ -173,14 +133,10 @@ typedef void (*TColorPutterAlpha)(uint8_t *&ptr, const uint8_t & R, const uint8_
 	void applyEffectBpp( SDL_Surface * surf, const Rect & rect, int mode );
 	void applyEffect(SDL_Surface * surf, const Rect & rect, int mode); //mode: 0 - sepia, 1 - grayscale
 
-	void startTextInput(const Rect & where);
-	void stopTextInput();
-
 	void setColorKey(SDL_Surface * surface, SDL_Color color);
 
 	///set key-color to 0,255,255
 	void setDefaultColorKey(SDL_Surface * surface);
-
 	///set key-color to 0,255,255 only if it exactly mapped
 	void setDefaultColorKeyPresize(SDL_Surface * surface);
 

+ 9 - 12
client/widgets/Buttons.cpp

@@ -21,12 +21,11 @@
 #include "../gui/CGuiHandler.h"
 #include "../windows/InfoWindows.h"
 #include "../render/CAnimation.h"
+#include "../renderSDL/SDL_Extensions.h"
 
 #include "../../lib/CConfigHandler.h"
 #include "../../lib/CGeneralTextHandler.h"
 
-#include <SDL_events.h>
-
 void CButton::update()
 {
 	if (overlay)
@@ -555,22 +554,22 @@ void CSlider::sliderClicked()
 		addUsedEvents(MOVE);
 }
 
-void CSlider::mouseMoved (const SDL_MouseMotionEvent & sEvent)
+void CSlider::mouseMoved (const Point & cursorPosition)
 {
 	double v = 0;
 	if(horizontal)
 	{
-		if(	std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2+40  ||  std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2  )
+		if(	std::abs(cursorPosition.y-(pos.y+pos.h/2)) > pos.h/2+40  ||  std::abs(cursorPosition.x-(pos.x+pos.w/2)) > pos.w/2  )
 			return;
-		v = sEvent.x - pos.x - 24;
+		v = cursorPosition.x - pos.x - 24;
 		v *= positions;
 		v /= (pos.w - 48);
 	}
 	else
 	{
-		if(std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2+40  ||  std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2  )
+		if(std::abs(cursorPosition.x-(pos.x+pos.w/2)) > pos.w/2+40  ||  std::abs(cursorPosition.y-(pos.y+pos.h/2)) > pos.h/2  )
 			return;
-		v = sEvent.y - pos.y - 24;
+		v = cursorPosition.y - pos.y - 24;
 		v *= positions;
 		v /= (pos.h - 48);
 	}
@@ -679,7 +678,7 @@ void CSlider::clickLeft(tribool down, bool previousState)
 			return;
 		// 		if (rw>1) return;
 		// 		if (rw<0) return;
-		slider->clickLeft(true, slider->mouseState(EIntObjMouseBtnType::LEFT));
+		slider->clickLeft(true, slider->mouseState(MouseButton::LEFT));
 		moveTo((int)(rw * positions  +  0.5));
 		return;
 	}
@@ -780,12 +779,10 @@ void CSlider::wheelScrolled(bool down, bool in)
 	moveTo(value + 3 * (down ? +scrollStep : -scrollStep));
 }
 
-void CSlider::keyPressed(const SDL_KeyboardEvent & key)
+void CSlider::keyPressed(const SDL_Keycode & key)
 {
-	if(key.state != SDL_PRESSED) return;
-
 	int moveDest = value;
-	switch(key.keysym.sym)
+	switch(key)
 	{
 	case SDLK_UP:
 		if (!horizontal)

+ 3 - 3
client/widgets/Buttons.h

@@ -10,7 +10,7 @@
 #pragma once
 
 #include "../gui/CIntObject.h"
-#include "../renderSDL/SDL_Extensions.h"
+#include "../render/Colors.h"
 #include "../../lib/FunctionList.h"
 
 #include <SDL_pixels.h>
@@ -270,10 +270,10 @@ public:
 
 	void addCallback(std::function<void(int)> callback);
 
-	void keyPressed(const SDL_KeyboardEvent & key) override;
+	void keyPressed(const SDL_Keycode & key) override;
 	void wheelScrolled(bool down, bool in) override;
 	void clickLeft(tribool down, bool previousState) override;
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
+	void mouseMoved (const Point & cursorPosition) override;
 	void showAll(SDL_Surface * to) override;
 
 	 /// @param position coordinates of slider

+ 1 - 0
client/widgets/CArtifactHolder.cpp

@@ -19,6 +19,7 @@
 #include "../windows/CHeroWindow.h"
 #include "../windows/CSpellWindow.h"
 #include "../windows/GUIClasses.h"
+#include "../renderSDL/SDL_Extensions.h"
 #include "../CPlayerInterface.h"
 #include "../CGameInfo.h"
 

+ 7 - 14
client/widgets/CGarrisonInt.cpp

@@ -14,11 +14,11 @@
 #include "TextControls.h"
 
 #include "../gui/CGuiHandler.h"
-
-#include "../CGameInfo.h"
-#include "../CPlayerInterface.h"
+#include "../renderSDL/SDL_Extensions.h"
 #include "../windows/CCreatureWindow.h"
 #include "../windows/GUIClasses.h"
+#include "../CGameInfo.h"
+#include "../CPlayerInterface.h"
 
 #include "../../CCallback.h"
 
@@ -28,12 +28,6 @@
 
 #include "../../lib/CGameState.h"
 
-#ifdef VCMI_MAC
-#define SDL_SCANCODE_LCTRL SDL_SCANCODE_LGUI
-#endif
-
-#include <SDL_keyboard.h>
-
 void CGarrisonSlot::setHighlight(bool on)
 {
 	if (on)
@@ -336,7 +330,7 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
 				lastHeroStackSelected = true;
 			}
 
-			if((owner->getSplittingMode() || LOCPLINT->shiftPressed()) // split window
+			if((owner->getSplittingMode() || GH.isKeyboardShiftDown()) // split window
 				&& (!creature || creature == selection->creature))
 			{
 				refr = split();
@@ -439,10 +433,9 @@ void CGarrisonSlot::splitIntoParts(CGarrisonSlot::EGarrisonType type, int amount
 
 bool CGarrisonSlot::handleSplittingShortcuts()
 {
-	const uint8_t * state = SDL_GetKeyboardState(NULL);
-	const bool isAlt = !!state[SDL_SCANCODE_LALT];
-	const bool isLShift = !!state[SDL_SCANCODE_LSHIFT];
-	const bool isLCtrl = !!state[SDL_SCANCODE_LCTRL];
+	const bool isAlt = GH.isKeyboardAltDown();
+	const bool isLShift = GH.isKeyboardShiftDown();
+	const bool isLCtrl = GH.isKeyboardCtrlDown();
 
 	if(!isAlt && !isLShift && !isLCtrl)
 		return false; // This is only case when return false

+ 16 - 17
client/widgets/TextControls.cpp

@@ -17,14 +17,14 @@
 #include "../gui/CGuiHandler.h"
 #include "../windows/CMessage.h"
 #include "../adventureMap/CInGameConsole.h"
+#include "../renderSDL/SDL_Extensions.h"
+
 #include "../../lib/CGeneralTextHandler.h"
 
 #ifdef VCMI_ANDROID
 #include "lib/CAndroidVMHelper.h"
 #endif
 
-#include <SDL_events.h>
-
 std::list<CFocusable*> CFocusable::focusables;
 CFocusable * CFocusable::inputWithFocus;
 
@@ -353,14 +353,14 @@ void CGStatusBar::setEnteringMode(bool on)
 	{
 		assert(enteringText == false);
 		alignment = ETextAlignment::TOPLEFT;
-		CSDL_Ext::startTextInput(pos);
+		GH.startTextInput(pos);
 		setText(consoleText);
 	}
 	else
 	{
 		assert(enteringText == true);
 		alignment = ETextAlignment::CENTER;
-		CSDL_Ext::stopTextInput();
+		GH.stopTextInput();
 		setText(hoverText);
 	}
 	enteringText = on;
@@ -526,7 +526,7 @@ CKeyboardFocusListener::CKeyboardFocusListener(CTextInput * textInput)
 
 void CKeyboardFocusListener::focusGot()
 {
-	CSDL_Ext::startTextInput(textInput->pos);
+	GH.startTextInput(textInput->pos);
 	usageIndex++;
 }
 
@@ -534,7 +534,7 @@ void CKeyboardFocusListener::focusLost()
 {
 	if(0 == --usageIndex)
 	{
-		CSDL_Ext::stopTextInput();
+		GH.stopTextInput();
 	}
 }
 
@@ -549,13 +549,12 @@ void CTextInput::clickLeft(tribool down, bool previousState)
 		giveFocus();
 }
 
-void CTextInput::keyPressed(const SDL_KeyboardEvent & key)
+void CTextInput::keyPressed(const SDL_Keycode & key)
 {
-
-	if(!focus || key.state != SDL_PRESSED)
+	if(!focus)
 		return;
 
-	if(key.keysym.sym == SDLK_TAB)
+	if(key == SDLK_TAB)
 	{
 		moveFocus();
 		GH.breakEventHandling();
@@ -564,7 +563,7 @@ void CTextInput::keyPressed(const SDL_KeyboardEvent & key)
 
 	bool redrawNeeded = false;
 
-	switch(key.keysym.sym)
+	switch(key)
 	{
 	case SDLK_DELETE: // have index > ' ' so it won't be filtered out by default section
 		return;
@@ -603,21 +602,21 @@ void CTextInput::setText(const std::string & nText, bool callCb)
 		cb(text);
 }
 
-bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key)
+bool CTextInput::captureThisKey(const SDL_Keycode & key)
 {
-	if(key.keysym.sym == SDLK_RETURN || key.keysym.sym == SDLK_KP_ENTER || key.keysym.sym == SDLK_ESCAPE)
+	if(key == SDLK_RETURN || key == SDLK_KP_ENTER || key == SDLK_ESCAPE)
 		return false;
 
 	return true;
 }
 
-void CTextInput::textInputed(const SDL_TextInputEvent & event)
+void CTextInput::textInputed(const std::string & enteredText)
 {
 	if(!focus)
 		return;
 	std::string oldText = text;
 
-	text += event.text;
+	text += enteredText;
 
 	filters(text, oldText);
 	if(text != oldText)
@@ -628,12 +627,12 @@ void CTextInput::textInputed(const SDL_TextInputEvent & event)
 	newText.clear();
 }
 
-void CTextInput::textEdited(const SDL_TextEditingEvent & event)
+void CTextInput::textEdited(const std::string & enteredText)
 {
 	if(!focus)
 		return;
 
-	newText = event.text;
+	newText = enteredText;
 	redraw();
 	cb(text + newText);
 }

+ 6 - 5
client/widgets/TextControls.h

@@ -11,7 +11,7 @@
 
 #include "../gui/CIntObject.h"
 #include "../gui/TextAlignment.h"
-#include "../renderSDL/SDL_Extensions.h"
+#include "../render/Colors.h"
 #include "../render/Graphics.h"
 #include "../../lib/FunctionList.h"
 
@@ -225,11 +225,12 @@ public:
 	CTextInput(const Rect & Pos, std::shared_ptr<IImage> srf);
 
 	void clickLeft(tribool down, bool previousState) override;
-	void keyPressed(const SDL_KeyboardEvent & key) override;
-	bool captureThisEvent(const SDL_KeyboardEvent & key) override;
+	void keyPressed(const SDL_Keycode & key) override;
 
-	void textInputed(const SDL_TextInputEvent & event) override;
-	void textEdited(const SDL_TextEditingEvent & event) override;
+	bool captureThisKey(const SDL_Keycode & key) override;
+
+	void textInputed(const std::string & enteredText) override;
+	void textEdited(const std::string & enteredText) override;
 
 	//Filter that will block all characters not allowed in filenames
 	static void filenameFilter(std::string & text, const std::string & oldText);

+ 6 - 8
client/windows/CCastleInterface.cpp

@@ -43,7 +43,7 @@
 #include "../../lib/mapObjects/CGHeroInstance.h"
 #include "../../lib/mapObjects/CGTownInstance.h"
 
-#include <SDL_events.h>
+#include <SDL_surface.h>
 
 CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance * Town, const CStructure * Str)
 	: CShowableAnim(0, 0, Str->defName, CShowableAnim::BASE, BUILDING_FRAME_TIME),
@@ -241,11 +241,11 @@ std::string CBuildingRect::getSubtitle()//hover text for building
 	}
 }
 
-void CBuildingRect::mouseMoved (const SDL_MouseMotionEvent & sEvent)
+void CBuildingRect::mouseMoved (const Point & cursorPosition)
 {
-	if(area && pos.isInside(sEvent.x, sEvent.y))
+	if(area && pos.isInside(cursorPosition.x, cursorPosition.y))
 	{
-		if(area->isTransparent(GH.getCursorPosition() - pos.topLeft())) //hovered pixel is inside this building
+		if(area->isTransparent(cursorPosition - pos.topLeft())) //hovered pixel is inside this building
 		{
 			if(parent->selectedBuilding == this)
 			{
@@ -1255,11 +1255,9 @@ void CCastleInterface::recreateIcons()
 		creainfo.push_back(std::make_shared<CCreaInfo>(Point(14+55*(int)i, 507), town, (int)i+4));
 }
 
-void CCastleInterface::keyPressed(const SDL_KeyboardEvent & key)
+void CCastleInterface::keyPressed(const SDL_Keycode & key)
 {
-	if(key.state != SDL_PRESSED) return;
-
-	switch(key.keysym.sym)
+	switch(key)
 	{
 	case SDLK_UP:
 		townlist->selectPrev();

+ 3 - 2
client/windows/CCastleInterface.h

@@ -68,7 +68,7 @@ public:
 	void hover(bool on) override;
 	void clickLeft(tribool down, bool previousState) override;
 	void clickRight(tribool down, bool previousState) override;
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
+	void mouseMoved (const Point & cursorPosition) override;
 	void show(SDL_Surface * to) override;
 	void showAll(SDL_Surface * to) override;
 };
@@ -245,7 +245,8 @@ public:
 
 	void castleTeleport(int where);
 	void townChange();
-	void keyPressed(const SDL_KeyboardEvent & key) override;
+	void keyPressed(const SDL_Keycode & key) override;
+
 	void close();
 	void addBuilding(BuildingID bid);
 	void removeBuilding(BuildingID bid);

+ 4 - 5
client/windows/CCreatureWindow.cpp

@@ -22,6 +22,7 @@
 #include "../widgets/TextControls.h"
 #include "../widgets/ObjectLists.h"
 #include "../gui/CGuiHandler.h"
+#include "../renderSDL/SDL_Extensions.h"
 
 #include "../../CCallback.h"
 #include "../../lib/CStack.h"
@@ -31,8 +32,6 @@
 #include "../../lib/CHeroHandler.h"
 #include "../../lib/CGameState.h"
 
-using namespace CSDL_Ext;
-
 class CCreatureArtifactInstance;
 class CSelectableSkill;
 
@@ -518,8 +517,8 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
 
 	const CStack * battleStack = parent->info->stack;
 
-	morale = std::make_shared<MoraleLuckBox>(true, genRect(42, 42, 321, 110));
-	luck = std::make_shared<MoraleLuckBox>(false, genRect(42, 42, 375, 110));
+	morale = std::make_shared<MoraleLuckBox>(true, CSDL_Ext::genRect(42, 42, 321, 110));
+	luck = std::make_shared<MoraleLuckBox>(false, CSDL_Ext::genRect(42, 42, 375, 110));
 
 	if(battleStack != nullptr) // in battle
 	{
@@ -583,7 +582,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
 		}
 		expLabel = std::make_shared<CLabel>(
 				pos.x + 21, pos.y + 52, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE,
-				makeNumberShort<TExpType>(stack->experience, 6));
+				CSDL_Ext::makeNumberShort<TExpType>(stack->experience, 6));
 	}
 
 	if(showArt)

+ 1 - 0
client/windows/CMessage.cpp

@@ -20,6 +20,7 @@
 #include "../widgets/TextControls.h"
 #include "../render/CAnimation.h"
 #include "../render/IImage.h"
+#include "../renderSDL/SDL_Extensions.h"
 
 #include <SDL_surface.h>
 

+ 1 - 0
client/windows/CQuestLog.cpp

@@ -18,6 +18,7 @@
 #include "../adventureMap/CAdvMapInt.h"
 #include "../widgets/Buttons.h"
 #include "../adventureMap/CMinimap.h"
+#include "../renderSDL/SDL_Extensions.h"
 
 #include "../../CCallback.h"
 #include "../../lib/CArtHandler.h"

+ 1 - 1
client/windows/CQuestLog.h

@@ -66,7 +66,7 @@ class CQuestMinimap : public CMinimap
 
 	void clickLeft(tribool down, bool previousState) override{}; //minimap ignores clicking on its surface
 	void iconClicked();
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override{};
+	void mouseMoved (const Point & cursorPosition) override{};
 
 public:
 	const QuestInfo * currentQuest;

+ 8 - 10
client/windows/CSpellWindow.cpp

@@ -28,6 +28,7 @@
 #include "../widgets/TextControls.h"
 #include "../adventureMap/CAdvMapInt.h"
 #include "../render/CAnimation.h"
+#include "../renderSDL/SDL_Extensions.h"
 
 #include "../../CCallback.h"
 
@@ -39,8 +40,6 @@
 
 #include "../../lib/mapObjects/CGHeroInstance.h"
 
-#include <SDL_events.h>
-
 CSpellWindow::InteractiveArea::InteractiveArea(const Rect & myRect, std::function<void()> funcL, int helpTextId, CSpellWindow * _owner)
 {
 	addUsedEvents(LCLICK | RCLICK | HOVER);
@@ -422,17 +421,16 @@ void CSpellWindow::turnPageRight()
 		CCS->videoh->openAndPlayVideo("PGTRNRGH.SMK", pos.x+13, pos.y+15);
 }
 
-void CSpellWindow::keyPressed(const SDL_KeyboardEvent & key)
+void CSpellWindow::keyPressed(const SDL_Keycode & key)
 {
-	if(key.keysym.sym == SDLK_ESCAPE ||  key.keysym.sym == SDLK_RETURN)
+	if(key == SDLK_ESCAPE ||  key == SDLK_RETURN)
 	{
 		fexitb();
 		return;
 	}
-
-	if(key.state == SDL_PRESSED)
+	else
 	{
-		switch(key.keysym.sym)
+		switch(key)
 		{
 		case SDLK_LEFT:
 			fLcornerb();
@@ -443,7 +441,7 @@ void CSpellWindow::keyPressed(const SDL_KeyboardEvent & key)
 		case SDLK_UP:
 		case SDLK_DOWN:
 		{
-			bool down = key.keysym.sym == SDLK_DOWN;
+			bool down = key == SDLK_DOWN;
 			static const int schoolsOrder[] = { 0, 3, 1, 2, 4 };
 			int index = -1;
 			while(schoolsOrder[++index] != selectedTab);
@@ -464,9 +462,9 @@ void CSpellWindow::keyPressed(const SDL_KeyboardEvent & key)
 		}
 
 		//alt + 1234567890-= casts spell from 1 - 12 slot
-		if(myInt->altPressed())
+		if(GH.isKeyboardAltDown())
 		{
-			SDL_Keycode hlpKey = key.keysym.sym;
+			SDL_Keycode hlpKey = key;
 			if(CGuiHandler::isNumKey(hlpKey, false))
 			{
 				if(hlpKey == SDLK_KP_PLUS)

+ 2 - 1
client/windows/CSpellWindow.h

@@ -112,6 +112,7 @@ public:
 	void selectSchool(int school); //schools: 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic, 4 - all schools
 	int pagesWithinCurrentTab();
 
-	void keyPressed(const SDL_KeyboardEvent & key) override;
+	void keyPressed(const SDL_Keycode & key) override;
+
 	void show(SDL_Surface * to) override;
 };

+ 28 - 36
client/windows/GUIClasses.cpp

@@ -63,10 +63,6 @@
 #include "../lib/NetPacksBase.h"
 #include "../lib/StartInfo.h"
 
-#include <SDL_events.h>
-
-using namespace CSDL_Ext;
-
 CRecruitmentWindow::CCreatureCard::CCreatureCard(CRecruitmentWindow * window, const CCreature * crea, int totalAmount)
 	: CIntObject(LCLICK | RCLICK),
 	parent(window),
@@ -103,9 +99,9 @@ void CRecruitmentWindow::CCreatureCard::showAll(SDL_Surface * to)
 {
 	CIntObject::showAll(to);
 	if(selected)
-		drawBorder(to, pos, Colors::RED);
+		CSDL_Ext::drawBorder(to, pos, Colors::RED);
 	else
-		drawBorder(to, pos, Colors::YELLOW);
+		CSDL_Ext::drawBorder(to, pos, Colors::YELLOW);
 }
 
 void CRecruitmentWindow::select(std::shared_ptr<CCreatureCard> card)
@@ -180,17 +176,17 @@ void CRecruitmentWindow::showAll(SDL_Surface * to)
 	CWindowObject::showAll(to);
 
 	// recruit\total values
-	drawBorder(to, pos.x + 172, pos.y + 222, 67, 42, Colors::YELLOW);
-	drawBorder(to, pos.x + 246, pos.y + 222, 67, 42, Colors::YELLOW);
+	CSDL_Ext::drawBorder(to, pos.x + 172, pos.y + 222, 67, 42, Colors::YELLOW);
+	CSDL_Ext::drawBorder(to, pos.x + 246, pos.y + 222, 67, 42, Colors::YELLOW);
 
 	//cost boxes
-	drawBorder(to, pos.x + 64,  pos.y + 222, 99, 76, Colors::YELLOW);
-	drawBorder(to, pos.x + 322, pos.y + 222, 99, 76, Colors::YELLOW);
+	CSDL_Ext::drawBorder(to, pos.x + 64,  pos.y + 222, 99, 76, Colors::YELLOW);
+	CSDL_Ext::drawBorder(to, pos.x + 322, pos.y + 222, 99, 76, Colors::YELLOW);
 
 	//buttons borders
-	drawBorder(to, pos.x + 133, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
-	drawBorder(to, pos.x + 211, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
-	drawBorder(to, pos.x + 289, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
+	CSDL_Ext::drawBorder(to, pos.x + 133, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
+	CSDL_Ext::drawBorder(to, pos.x + 211, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
+	CSDL_Ext::drawBorder(to, pos.x + 289, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
 }
 
 CRecruitmentWindow::CRecruitmentWindow(const CGDwelling * Dwelling, int Level, const CArmedInstance * Dst, const std::function<void(CreatureID,int)> & Recruit, int y_offset):
@@ -561,8 +557,7 @@ void CSystemOptionsWindow::selectGameRes()
 	std::vector<std::string> items;
 
 #ifndef VCMI_IOS
-	SDL_Rect displayBounds;
-	SDL_GetDisplayBounds(std::max(0, SDL_GetWindowDisplayIndex(mainWindow)), &displayBounds);
+	Rect displayBounds = CSDL_Ext::getDisplayBounds();
 #endif
 
 	size_t currentResolutionIndex = 0;
@@ -610,7 +605,7 @@ void CSystemOptionsWindow::setGameRes(int index)
 
 void CSystemOptionsWindow::bquitf()
 {
-	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[578], [this](){ closeAndPushEvent(SDL_USEREVENT, EUserEvent::FORCE_QUIT); }, 0);
+	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[578], [this](){ closeAndPushEvent(EUserEvent::FORCE_QUIT); }, 0);
 }
 
 void CSystemOptionsWindow::breturnf()
@@ -620,7 +615,7 @@ void CSystemOptionsWindow::breturnf()
 
 void CSystemOptionsWindow::bmainmenuf()
 {
-	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[578], [this](){ closeAndPushEvent(SDL_USEREVENT, EUserEvent::RETURN_TO_MAIN_MENU); }, 0);
+	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[578], [this](){ closeAndPushEvent(EUserEvent::RETURN_TO_MAIN_MENU); }, 0);
 }
 
 void CSystemOptionsWindow::bloadf()
@@ -637,13 +632,13 @@ void CSystemOptionsWindow::bsavef()
 
 void CSystemOptionsWindow::brestartf()
 {
-	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[67], [this](){ closeAndPushEvent(SDL_USEREVENT, EUserEvent::RESTART_GAME); }, 0);
+	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[67], [this](){ closeAndPushEvent(EUserEvent::RESTART_GAME); }, 0);
 }
 
-void CSystemOptionsWindow::closeAndPushEvent(int eventType, int code)
+void CSystemOptionsWindow::closeAndPushEvent(EUserEvent code)
 {
 	close();
-	GH.pushSDLEvent(eventType, code);
+	GH.pushUserEvent(code);
 }
 
 CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj)
@@ -1140,9 +1135,9 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
 	{
 		primSkillAreas.push_back(std::make_shared<LRClickableAreaWTextComp>());
 		if (qeLayout)
-			primSkillAreas[g]->pos = genRect(22, 152, pos.x + 324, pos.y + 12 + 26 * g);
+			primSkillAreas[g]->pos = CSDL_Ext::genRect(22, 152, pos.x + 324, pos.y + 12 + 26 * g);
 		else
-			primSkillAreas[g]->pos = genRect(32, 140, pos.x + 329, pos.y + 19 + 36 * g);
+			primSkillAreas[g]->pos = CSDL_Ext::genRect(32, 140, pos.x + 329, pos.y + 19 + 36 * g);
 		primSkillAreas[g]->text = CGI->generaltexth->arraytxt[2+g];
 		primSkillAreas[g]->type = g;
 		primSkillAreas[g]->bonusValue = -1;
@@ -1162,7 +1157,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
 			int skill = hero->secSkills[g].first,
 				level = hero->secSkills[g].second; // <1, 3>
 			secSkillAreas[b].push_back(std::make_shared<LRClickableAreaWTextComp>());
-			secSkillAreas[b][g]->pos = genRect(32, 32, pos.x + 32 + g*36 + b*454 , pos.y + (qeLayout ? 83 : 88));
+			secSkillAreas[b][g]->pos = CSDL_Ext::genRect(32, 32, pos.x + 32 + g*36 + b*454 , pos.y + (qeLayout ? 83 : 88));
 			secSkillAreas[b][g]->baseType = 1;
 
 			secSkillAreas[b][g]->type = skill;
@@ -1177,12 +1172,12 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
 		heroAreas[b] = std::make_shared<CHeroArea>(257 + 228*b, 13, hero);
 
 		specialtyAreas[b] = std::make_shared<LRClickableAreaWText>();
-		specialtyAreas[b]->pos = genRect(32, 32, pos.x + 69 + 490*b, pos.y + (qeLayout ? 41 : 45));
+		specialtyAreas[b]->pos = CSDL_Ext::genRect(32, 32, pos.x + 69 + 490*b, pos.y + (qeLayout ? 41 : 45));
 		specialtyAreas[b]->hoverText = CGI->generaltexth->heroscrn[27];
 		specialtyAreas[b]->text = hero->type->getSpecialtyDescriptionTranslated();
 
 		experienceAreas[b] = std::make_shared<LRClickableAreaWText>();
-		experienceAreas[b]->pos = genRect(32, 32, pos.x + 105 + 490*b, pos.y + (qeLayout ? 41 : 45));
+		experienceAreas[b]->pos = CSDL_Ext::genRect(32, 32, pos.x + 105 + 490*b, pos.y + (qeLayout ? 41 : 45));
 		experienceAreas[b]->hoverText = CGI->generaltexth->heroscrn[9];
 		experienceAreas[b]->text = CGI->generaltexth->allTexts[2];
 		boost::algorithm::replace_first(experienceAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->level));
@@ -1190,15 +1185,15 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
 		boost::algorithm::replace_first(experienceAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->exp));
 
 		spellPointsAreas[b] = std::make_shared<LRClickableAreaWText>();
-		spellPointsAreas[b]->pos = genRect(32, 32, pos.x + 141 + 490*b, pos.y + (qeLayout ? 41 : 45));
+		spellPointsAreas[b]->pos = CSDL_Ext::genRect(32, 32, pos.x + 141 + 490*b, pos.y + (qeLayout ? 41 : 45));
 		spellPointsAreas[b]->hoverText = CGI->generaltexth->heroscrn[22];
 		spellPointsAreas[b]->text = CGI->generaltexth->allTexts[205];
 		boost::algorithm::replace_first(spellPointsAreas[b]->text, "%s", hero->getNameTranslated());
 		boost::algorithm::replace_first(spellPointsAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->mana));
 		boost::algorithm::replace_first(spellPointsAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->manaLimit()));
 
-		morale[b] = std::make_shared<MoraleLuckBox>(true, genRect(32, 32, 176 + 490 * b, 39), true);
-		luck[b] = std::make_shared<MoraleLuckBox>(false, genRect(32, 32, 212 + 490 * b, 39), true);
+		morale[b] = std::make_shared<MoraleLuckBox>(true, CSDL_Ext::genRect(32, 32, 176 + 490 * b, 39), true);
+		luck[b] = std::make_shared<MoraleLuckBox>(false, CSDL_Ext::genRect(32, 32, 212 + 490 * b, 39), true);
 	}
 
 	quit = std::make_shared<CButton>(Point(732, 567), "IOKAY.DEF", CGI->generaltexth->zelp[600], std::bind(&CExchangeWindow::close, this), SDLK_RETURN);
@@ -1286,8 +1281,8 @@ void CExchangeWindow::updateWidgets()
 			secSkillIcons[leftRight][m]->setFrame(2 + id * 3 + level);
 		}
 
-		expValues[leftRight]->setText(makeNumberShort(hero->exp));
-		manaValues[leftRight]->setText(makeNumberShort(hero->mana));
+		expValues[leftRight]->setText(CSDL_Ext::makeNumberShort(hero->exp));
+		manaValues[leftRight]->setText(CSDL_Ext::makeNumberShort(hero->mana));
 
 		morale[leftRight]->set(hero);
 		luck[leftRight]->set(hero);
@@ -1380,7 +1375,7 @@ CPuzzleWindow::CPuzzleWindow(const int3 & GrailPos, double discoveredRatio)
 void CPuzzleWindow::showAll(SDL_Surface * to)
 {
 	int3 moveInt = int3(8, 9, 0);
-	Rect mapRect = genRect(544, 591, pos.x + 8, pos.y + 7);
+	Rect mapRect = CSDL_Ext::genRect(544, 591, pos.x + 8, pos.y + 7);
 	int3 topTile = grailPos - moveInt;
 
 	MapDrawingInfo info(topTile, LOCPLINT->cb->getVisibilityMap(), mapRect);
@@ -2170,14 +2165,11 @@ void CObjectListWindow::changeSelection(size_t which)
 	selected = which;
 }
 
-void CObjectListWindow::keyPressed (const SDL_KeyboardEvent & key)
+void CObjectListWindow::keyPressed (const SDL_Keycode & key)
 {
-	if(key.state != SDL_PRESSED)
-		return;
-
 	int sel = static_cast<int>(selected);
 
-	switch(key.keysym.sym)
+	switch(key)
 	{
 	break; case SDLK_UP:
 		sel -=1;

+ 4 - 2
client/windows/GUIClasses.h

@@ -43,6 +43,8 @@ class CTextBox;
 class CResDataBar;
 class CHeroWithMaybePickedArtifact;
 
+enum class EUserEvent;
+
 /// Recruitment window where you can recruit creatures
 class CRecruitmentWindow : public CStatusbarWindow
 {
@@ -193,7 +195,7 @@ public:
 	std::shared_ptr<CIntObject> genItem(size_t index);
 	void elementSelected();//call callback and close this window
 	void changeSelection(size_t which);
-	void keyPressed (const SDL_KeyboardEvent & key) override;
+	void keyPressed(const SDL_Keycode & key) override;
 };
 
 class CSystemOptionsWindow : public CWindowObject
@@ -234,7 +236,7 @@ private:
 
 	void selectGameRes();
 	void setGameRes(int index);
-	void closeAndPushEvent(int eventType, int code = 0);
+	void closeAndPushEvent(EUserEvent code);
 
 public:
 	CSystemOptionsWindow();