Browse Source

Solved the multiple window input issue

Marko Pintera 12 years ago
parent
commit
c27c0407dc

+ 12 - 4
CamelotCore/Include/CmInput.h

@@ -20,14 +20,24 @@ namespace CamelotFramework
 		boost::signal<void(const MouseEvent&, MouseButton)> onMouseDown;
 		boost::signal<void(const MouseEvent&, MouseButton)> onMouseDown;
 		boost::signal<void(const MouseEvent&, MouseButton)> onMouseUp;
 		boost::signal<void(const MouseEvent&, MouseButton)> onMouseUp;
 
 
-		void initClipRect(Rect& clipRect);
 		void registerInputHandler(InputHandlerPtr inputHandler);
 		void registerInputHandler(InputHandlerPtr inputHandler);
 
 
 		/**
 		/**
-		 * @brief	Called every frame. Should only be called by Application.
+		 * @brief	Called every frame. Dispatches any callbacks resulting from input by the user. Should only be called by Application.
 		 */
 		 */
 		void update();
 		void update();
 
 
+		/**
+		 * @brief	Captures any input between this and last call to capture. MUST be called from the render
+		 * 			thread, because thats the thread that owns the input window.
+		 */
+		void capture();
+
+		/**
+		 * @brief	Should be called any time window in focus changes. Should only be called by Application.
+		 */
+		void inputWindowChanged(const RenderWindow& win);
+
 		/**
 		/**
 		 * @brief	Returns smoothed mouse/joystick input in the horizontal axis.
 		 * @brief	Returns smoothed mouse/joystick input in the horizontal axis.
 		 *
 		 *
@@ -57,8 +67,6 @@ namespace CamelotFramework
 		int	mCurrentBufferIdx;
 		int	mCurrentBufferIdx;
 
 
 		Int2 mMouseLastRel;
 		Int2 mMouseLastRel;
-		Rect mClipRect;
-		bool mUsingClipRect;
 
 
 		bool mMouseButtonState[MB_Count];
 		bool mMouseButtonState[MB_Count];
 		bool mKeyState[KC_Count];
 		bool mKeyState[KC_Count];

+ 5 - 0
CamelotCore/Include/CmInputHandler.h

@@ -226,5 +226,10 @@ namespace CamelotFramework
 		 * @brief	Called every frame by InputManager. Capture input here if needed.
 		 * @brief	Called every frame by InputManager. Capture input here if needed.
 		 */
 		 */
 		virtual void update() {}
 		virtual void update() {}
+
+		/**
+		 * @brief	Called by InputManager whenever window in focus changes.
+		 */
+		virtual void inputWindowChanged(const RenderWindow& win) {}
 	};
 	};
 }
 }

+ 7 - 27
CamelotCore/Source/CmInput.cpp

@@ -12,8 +12,7 @@ namespace CamelotFramework
 	const float Input::WEIGHT_MODIFIER = 0.5f;
 	const float Input::WEIGHT_MODIFIER = 0.5f;
 
 
 	Input::Input()
 	Input::Input()
-		:mSmoothHorizontalAxis(0.0f), mSmoothVerticalAxis(0.0f), mCurrentBufferIdx(0), mMouseLastRel(0, 0),
-		mUsingClipRect(false), mClipRect(0, 0, 0, 0), mInputHandler(nullptr)
+		:mSmoothHorizontalAxis(0.0f), mSmoothVerticalAxis(0.0f), mCurrentBufferIdx(0), mMouseLastRel(0, 0), mInputHandler(nullptr)
 	{ 
 	{ 
 		mHorizontalHistoryBuffer = cm_newN<float>(HISTORY_BUFFER_SIZE);
 		mHorizontalHistoryBuffer = cm_newN<float>(HISTORY_BUFFER_SIZE);
 		mVerticalHistoryBuffer = cm_newN<float>(HISTORY_BUFFER_SIZE);
 		mVerticalHistoryBuffer = cm_newN<float>(HISTORY_BUFFER_SIZE);
@@ -40,13 +39,6 @@ namespace CamelotFramework
 		cm_deleteN(mTimesHistoryBuffer, HISTORY_BUFFER_SIZE);
 		cm_deleteN(mTimesHistoryBuffer, HISTORY_BUFFER_SIZE);
 	}
 	}
 
 
-	void Input::initClipRect(Rect& clipRect)
-	{
-		mClipRect = clipRect;
-
-		mUsingClipRect = (clipRect.width > 0 && clipRect.height > 0);
-	}
-
 	void Input::registerInputHandler(InputHandlerPtr inputHandler)
 	void Input::registerInputHandler(InputHandlerPtr inputHandler)
 	{
 	{
 		if(mInputHandler != inputHandler)
 		if(mInputHandler != inputHandler)
@@ -78,6 +70,12 @@ namespace CamelotFramework
 		updateSmoothInput();
 		updateSmoothInput();
 	}
 	}
 
 
+	void Input::inputWindowChanged(const RenderWindow& win)
+	{
+		if(mInputHandler != nullptr)
+			mInputHandler->inputWindowChanged(win);
+	}
+
 	void Input::keyDown(const KeyEvent& event)
 	void Input::keyDown(const KeyEvent& event)
 	{
 	{
 		mKeyState[event.keyCode] = true;
 		mKeyState[event.keyCode] = true;
@@ -92,36 +90,18 @@ namespace CamelotFramework
 
 
 	void Input::mouseMoved(const MouseEvent& event)
 	void Input::mouseMoved(const MouseEvent& event)
 	{
 	{
-		if(mUsingClipRect)
-		{
-			if(!mClipRect.contains(event.coords))
-				return;
-		}
-
 		onMouseMoved(event);
 		onMouseMoved(event);
 		mMouseLastRel = Int2(-event.relCoords.x, -event.relCoords.y);
 		mMouseLastRel = Int2(-event.relCoords.x, -event.relCoords.y);
 	}
 	}
 
 
 	void Input::mouseDown(const MouseEvent& event, MouseButton buttonID)
 	void Input::mouseDown(const MouseEvent& event, MouseButton buttonID)
 	{
 	{
-		if(mUsingClipRect)
-		{
-			if(!mClipRect.contains(event.coords))
-				return;
-		}
-
 		mMouseButtonState[buttonID] = true;
 		mMouseButtonState[buttonID] = true;
 		onMouseDown(event, buttonID);
 		onMouseDown(event, buttonID);
 	}
 	}
 
 
 	void Input::mouseUp(const MouseEvent& event, MouseButton buttonID)
 	void Input::mouseUp(const MouseEvent& event, MouseButton buttonID)
 	{
 	{
-		if(mUsingClipRect)
-		{
-			if(!mClipRect.contains(event.coords))
-				return;
-		}
-
 		mMouseButtonState[buttonID] = false;
 		mMouseButtonState[buttonID] = false;
 		onMouseUp(event, buttonID);
 		onMouseUp(event, buttonID);
 	}
 	}

+ 3 - 0
CamelotCore/Source/CmWindowEventUtilities.cpp

@@ -30,6 +30,7 @@ THE SOFTWARE.
 #include "CmApplication.h"
 #include "CmApplication.h"
 #include "CmException.h"
 #include "CmException.h"
 #include "CmCursor.h"
 #include "CmCursor.h"
+#include "CmInput.h"
 
 
 #if CM_PLATFORM == CM_PLATFORM_LINUX
 #if CM_PLATFORM == CM_PLATFORM_LINUX
 #include <X11/Xlib.h>
 #include <X11/Xlib.h>
@@ -167,6 +168,8 @@ LRESULT CALLBACK WindowEventUtilities::_WndProc(HWND hWnd, UINT uMsg, WPARAM wPa
 
 
 			if(!win->hasFocus())
 			if(!win->hasFocus())
 				win->setHasFocus(true);
 				win->setHasFocus(true);
+
+			gInput().inputWindowChanged(*win);
         }
         }
         else
         else
         {
         {

+ 1 - 0
CamelotOISInput/Include/CmInputHandlerOIS.h

@@ -28,5 +28,6 @@ namespace CamelotFramework
 		virtual bool mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id);
 		virtual bool mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id);
 
 
 		virtual void update();
 		virtual void update();
+		virtual void inputWindowChanged(const RenderWindow& win);
 	};
 	};
 }
 }

+ 16 - 2
CamelotOISInput/Source/CmInputHandlerOIS.cpp

@@ -1,6 +1,7 @@
 #include "CmInputHandlerOIS.h"
 #include "CmInputHandlerOIS.h"
 #include "CmInt2.h"
 #include "CmInt2.h"
 #include "OIS/OISException.h"
 #include "OIS/OISException.h"
+#include "CmRenderWindow.h"
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
@@ -13,9 +14,9 @@ namespace CamelotFramework
 		pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
 		pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
 
 
 #if defined CM_PLATFORM == CM_PLATFORM_WIN32
 #if defined CM_PLATFORM == CM_PLATFORM_WIN32
-		pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_BACKGROUND" )));
+		pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND" )));
 		pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
 		pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
-		pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_BACKGROUND")));
+		pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_FOREGROUND")));
 		pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE")));
 		pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE")));
 #elif defined CM_PLATFORM == CM_PLATFORM_LINUX || CM_PLATFORM == CM_PLATFORM_APPLE
 #elif defined CM_PLATFORM == CM_PLATFORM_LINUX || CM_PLATFORM == CM_PLATFORM_APPLE
 		pl.insert(std::make_pair(std::string("x11_mouse_grab"), std::string("false")));
 		pl.insert(std::make_pair(std::string("x11_mouse_grab"), std::string("false")));
@@ -60,6 +61,19 @@ namespace CamelotFramework
 		mKeyboard->capture();
 		mKeyboard->capture();
 	}
 	}
 
 
+	void InputHandlerOIS::inputWindowChanged(const RenderWindow& win)
+	{
+		unsigned long long hWnd;
+		win.getCustomAttribute("WINDOW", &hWnd);
+
+		if(hWnd != 0) // DEBUG ONLY
+		{
+			std::string normalString = toString((unsigned long)hWnd).c_str();
+			mKeyboard->setCaptureContext(normalString);
+			mMouse->setCaptureContext(normalString);
+		}
+	}
+
 	bool InputHandlerOIS::keyPressed(const OIS::KeyEvent &arg)
 	bool InputHandlerOIS::keyPressed(const OIS::KeyEvent &arg)
 	{
 	{
 		KeyEvent event;
 		KeyEvent event;

+ 36 - 0
TODO.txt

@@ -21,9 +21,45 @@ MAJOR ISSUE: writeSubresource/readSubresoure doesn't require a shared ptr to Gpu
 I call waitUntilLoaded too many times. Sometimes 5-6 times in a single function. Each of those calls will wait a single frame.
 I call waitUntilLoaded too many times. Sometimes 5-6 times in a single function. Each of those calls will wait a single frame.
 GUIWidget::updateMeshes leaks. If I leave the game running I can see memory continously going up
 GUIWidget::updateMeshes leaks. If I leave the game running I can see memory continously going up
 
 
+/************** INPUT REFACTOR *********************/
+
+Remagine render thread:
+ - Its main loop is in CmApplication
+ - Rename it to CoreThread
+
+Reimagine input:
+ - Text input should come from main loop instead of from OIS. This way I can use key repeat and similar functions
+
+I should separate actual games input and text/cursor input. Key presses used for text and absolute cursor position should be provided separately.
+ - Main loop updates gInput with current text string (mutex protected), which gets flushed character by character when update() is called
+ - Same thing with absolute cursor position
+ - Also it will call focusChange as it does now
+
+Add separate classes:
+ RawInputHandler (transform existing InputHandler) - Called from main thread
+ OSInputHandler (new class) - Called from core thread
+
+AT THE END DONT FORGET:
+ Compile new OIS for all other build types (also update libs and includes)
+
+------------
+
+How to design OSInputHandler and how does it interact with msg loop?
+ - Set up key up/down callbacks, and mouse moved callbacks on the main loop
+
+How do I deal with window focus changes for newly created windows (no HWND)?
+ - Calling setFocus(true) on a window calls WindowManager who registers a focus change
+ - WindowManager::update (called from Application main thread) then triggers actual calls to setFocus and triggers focusChanged events
+   - Potentially remove focus events from RenderWindow (used by GUI) and use WindowManager directly
+ - This also solves a problem that ATM focus changes are actually being called directly from render thread which is WRONG! (setFocus called from msg loop directly)
+
+/*******************************************************/
+
 IMMEDIATE:
 IMMEDIATE:
  - Get rid of querying mouse states on each mouse event - Include button states in each event?
  - Get rid of querying mouse states on each mouse event - Include button states in each event?
  - Handle capital leters - include shift, alt, ctrl, caps states in KeyEvent
  - Handle capital leters - include shift, alt, ctrl, caps states in KeyEvent
+  - GetAsyncKeyState - possibly can be used for querying Caps Lock state. - Hook that to _translateText and update OIS notes (so I know I need that in Linux/Mac as well)
+ - Ignore input when other window has focus - Possibly foreground mode but switch window input? (Will likely need multiple OIS input handlers...) (Possibly just calling SetCooperativeLevel will work)
  - Add window-management command to DeferredRenderContext - I already have resource management commands
  - Add window-management command to DeferredRenderContext - I already have resource management commands
    there, few window related ones won't hurt. I can always split the class if needed.
    there, few window related ones won't hurt. I can always split the class if needed.
      - Possibly add guards to render target classes so they aren't accidentaly accessed from the render thread (similar to how Texture is handled)
      - Possibly add guards to render target classes so they aren't accidentaly accessed from the render thread (similar to how Texture is handled)