Sfoglia il codice sorgente

SDL relative pointer for android

Andrii Danylchenko 2 anni fa
parent
commit
6c843bce0b
4 ha cambiato i file con 127 aggiunte e 21 eliminazioni
  1. 9 1
      client/CMT.cpp
  2. 89 19
      client/gui/CGuiHandler.cpp
  3. 7 0
      client/gui/CGuiHandler.h
  4. 22 1
      config/schemas/settings.json

+ 9 - 1
client/CMT.cpp

@@ -374,7 +374,8 @@ int main(int argc, char * argv[])
 		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
 		#endif // VCMI_ANDROID
 
-		GH.mainFPSmng->init(); //(!)init here AFTER SDL_Init() while using SDL for FPS management
+		//(!)init here AFTER SDL_Init() while using SDL for FPS management
+		GH.init();
 
 		SDL_LogSetOutputFunction(&SDLLogCallback, nullptr);
 
@@ -430,11 +431,18 @@ int main(int argc, char * argv[])
 		CCS->musich->setVolume((ui32)settings["general"]["music"].Float());
 		logGlobal->info("Initializing screen and sound handling: %d ms", pomtime.getDiff());
 	}
+
 #ifdef VCMI_MAC
 	// Ctrl+click should be treated as a right click on Mac OS X
 	SDL_SetHint(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, "1");
 #endif
 
+	if(GH.isPointerRelativeMode)
+	{
+		SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
+		SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
+	}
+
 #ifndef VCMI_NO_THREADED_LOAD
 	//we can properly play intro only in the main thread, so we have to move loading to the separate thread
 	boost::thread loading(init);

+ 89 - 19
client/gui/CGuiHandler.cpp

@@ -78,6 +78,13 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::function<void (std:
 	processList(CIntObject::TEXTINPUT,activityFlag,&textInterested,cb);
 }
 
+void CGuiHandler::init()
+{
+	mainFPSmng->init();
+	isPointerRelativeMode = settings["general"]["userRelativePointer"].Bool();
+	pointerSpeedMultiplier = settings["general"]["relativePointerSpeedMultiplier"].Float();
+}
+
 void CGuiHandler::handleElementActivate(CIntObject * elem, ui16 activityFlag)
 {
 	processLists(activityFlag,[&](std::list<CIntObject*> * lst){
@@ -206,7 +213,7 @@ void CGuiHandler::handleEvents()
 	}
 }
 
-void convertTouch(SDL_Event * current)
+void CGuiHandler::convertTouchToMouse(SDL_Event * current)
 {
 	int rLogicalWidth, rLogicalHeight;
 
@@ -221,6 +228,58 @@ void convertTouch(SDL_Event * current)
 	current->motion.y = adjustedMouseY;
 }
 
+void CGuiHandler::fakeMoveCursor(float dx, float dy)
+{
+	int x, y, w, h;
+
+	SDL_Event event;
+	SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0};
+
+	sme.state = SDL_GetMouseState(&x, &y);
+	SDL_GetWindowSize(mainWindow, &w, &h);
+
+	sme.x = CCS->curh->xpos + (int)(GH.pointerSpeedMultiplier * w * dx);
+	sme.y = CCS->curh->ypos + (int)(GH.pointerSpeedMultiplier * h * dy);
+
+	vstd::abetween(sme.x, 0, w);
+	vstd::abetween(sme.y, 0, h);
+
+	event.motion = sme;
+	SDL_PushEvent(&event);
+}
+
+void CGuiHandler::fakeMouseMove()
+{
+	fakeMoveCursor(0, 0);
+}
+
+void CGuiHandler::fakeMouseButtonEventRelativeMode(bool down, bool right)
+{
+	SDL_Event event;
+	SDL_MouseButtonEvent sme = {SDL_MOUSEBUTTONDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+	if(!down)
+	{
+		sme.type = SDL_MOUSEBUTTONUP;
+	}
+
+	sme.button = right ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT;
+
+	sme.x = CCS->curh->xpos;
+	sme.y = CCS->curh->ypos;
+
+	int windowX, windowY;
+
+	SDL_RenderLogicalToWindow(mainRenderer, sme.x, sme.y, &windowX, &windowY);
+
+	SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
+	SDL_WarpMouse(windowX, windowY);
+	SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
+
+	event.button = sme;
+	SDL_PushEvent(&event);
+}
+
 void CGuiHandler::handleCurrentEvent()
 {
 	if(current->type == SDL_KEYDOWN || current->type == SDL_KEYUP)
@@ -372,15 +431,31 @@ void CGuiHandler::handleCurrentEvent()
 		}
 	}
 #ifndef VCMI_IOS
+	else if(current->type == SDL_FINGERMOTION)
+	{
+		if(isPointerRelativeMode)
+		{
+			fakeMoveCursor(current->tfinger.dx, current->tfinger.dy);
+		}
+	}
 	else if(current->type == SDL_FINGERDOWN)
 	{
 		auto fingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId);
 
 		multifinger = fingerCount > 1;
 
-		if(fingerCount == 2)
+		if(isPointerRelativeMode)
 		{
-			convertTouch(current);
+			if(current->tfinger.x > 0.5)
+			{
+				bool isRightClick = current->tfinger.y < 0.5;
+
+				fakeMouseButtonEventRelativeMode(true, isRightClick);
+			}
+		}
+		else if(fingerCount == 2)
+		{
+			convertTouchToMouse(current);
 			handleMouseMotion();
 			handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, true);
 		}
@@ -389,9 +464,18 @@ void CGuiHandler::handleCurrentEvent()
 	{
 		auto fingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId);
 
-		if(multifinger)
+		if(isPointerRelativeMode)
 		{
-			convertTouch(current);
+			if(current->tfinger.x > 0.5)
+			{
+				bool isRightClick = current->tfinger.y < 0.5;
+
+				fakeMouseButtonEventRelativeMode(false, isRightClick);
+			}
+		}
+		else if(multifinger)
+		{
+			convertTouchToMouse(current);
 			handleMouseMotion();
 			handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false);
 			multifinger = fingerCount != 0;
@@ -471,20 +555,6 @@ void CGuiHandler::handleMoveInterested(const SDL_MouseMotionEvent & motion)
 	}
 }
 
-void CGuiHandler::fakeMouseMove()
-{
-	SDL_Event event;
-	SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0};
-	int x, y;
-
-	sme.state = SDL_GetMouseState(&x, &y);
-	sme.x = x;
-	sme.y = y;
-
-	event.motion = sme;
-	SDL_PushEvent(&event);
-}
-
 void CGuiHandler::renderFrame()
 {
 

+ 7 - 0
client/gui/CGuiHandler.h

@@ -88,6 +88,10 @@ private:
 
 	void handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed);
 	void processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb);
+	void convertTouchToMouse(SDL_Event * current);
+	void fakeMoveCursor(float dx, float dy);
+	void fakeMouseButtonEventRelativeMode(bool down, bool right);
+
 public:
 	void handleElementActivate(CIntObject * elem, ui16 activityFlag);
 	void handleElementDeActivate(CIntObject * elem, ui16 activityFlag);
@@ -102,6 +106,8 @@ public:
 	Point lastClick;
 	unsigned lastClickTime;
 	bool multifinger;
+	bool isPointerRelativeMode;
+	float pointerSpeedMultiplier;
 
 	ui8 defActionsDef; //default auto actions
 	bool captureChildren; //all newly created objects will get their parents from stack and will be added to parents children list
@@ -110,6 +116,7 @@ public:
 	CGuiHandler();
 	~CGuiHandler();
 
+	void init();
 	void renderFrame();
 
 	void totalRedraw(); //forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering

+ 22 - 1
config/schemas/settings.json

@@ -17,7 +17,20 @@
 			"type" : "object",
 			"default": {},
 			"additionalProperties" : false,
-			"required" : [ "playerName", "showfps", "music", "sound", "encoding", "swipe", "saveRandomMaps", "saveFrequency", "notifications", "extraDump" ],
+			"required" : [
+				"playerName",
+				"showfps",
+				"music",
+				"sound",
+				"encoding",
+				"swipe",
+				"saveRandomMaps",
+				"saveFrequency",
+				"notifications",
+				"extraDump",
+				"userRelativePointer",
+				"relativePointerSpeedMultiplier"
+			],
 			"properties" : {
 				"playerName" : {
 					"type":"string",
@@ -70,6 +83,14 @@
 				"extraDump" : {
 					"type" : "boolean",
 					"default" : false
+				},
+				"userRelativePointer" : {
+					"type" : "boolean",
+					"default" : false
+				},
+				"relativePointerSpeedMultiplier" : {
+					"type" : "number",
+					"default" : 1
 				}
 			}
 		},