Browse Source

Initial touch emulation.

Lasse Öörni 11 years ago
parent
commit
a317c48beb

+ 104 - 15
Source/Engine/Input/Input.cpp

@@ -44,6 +44,8 @@
 
 
 #include "DebugNew.h"
 #include "DebugNew.h"
 
 
+extern "C" int SDL_AddTouch(SDL_TouchID touchID, const char *name);
+
 // Require a click inside window before re-hiding mouse cursor on OSX, otherwise dragging the window
 // Require a click inside window before re-hiding mouse cursor on OSX, otherwise dragging the window
 // can be incorrectly interpreted as mouse movement inside the window
 // can be incorrectly interpreted as mouse movement inside the window
 #if defined(__APPLE__) && !defined(IOS)
 #if defined(__APPLE__) && !defined(IOS)
@@ -77,6 +79,7 @@ Input::Input(Context* context) :
     toggleFullscreen_(true),
     toggleFullscreen_(true),
     mouseVisible_(false),
     mouseVisible_(false),
     mouseGrabbed_(false),
     mouseGrabbed_(false),
+    touchEmulation_(false),
     inputFocus_(false),
     inputFocus_(false),
     minimized_(false),
     minimized_(false),
     focusedThisFrame_(false),
     focusedThisFrame_(false),
@@ -149,7 +152,7 @@ void Input::Update()
         return;
         return;
 
 
     // Check for relative mode mouse move
     // Check for relative mode mouse move
-    if (graphics_->GetExternalWindow() || (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS)))
+    if (!touchEmulation_ && (graphics_->GetExternalWindow() || (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))))
     {
     {
         IntVector2 mousePosition = GetMousePosition();
         IntVector2 mousePosition = GetMousePosition();
         mouseMove_ = mousePosition - lastMousePosition_;
         mouseMove_ = mousePosition - lastMousePosition_;
@@ -197,6 +200,10 @@ void Input::Update()
 
 
 void Input::SetMouseVisible(bool enable)
 void Input::SetMouseVisible(bool enable)
 {
 {
+    // In touch emulation mode only enabled mouse is allowed
+    if (touchEmulation_)
+        enable = true;
+    
     // SDL Raspberry Pi "video driver" does not have proper OS mouse support yet, so no-op for now
     // SDL Raspberry Pi "video driver" does not have proper OS mouse support yet, so no-op for now
     #ifndef RASPI
     #ifndef RASPI
     if (enable != mouseVisible_)
     if (enable != mouseVisible_)
@@ -513,6 +520,29 @@ void Input::SetScreenKeyboardVisible(bool enable)
     }
     }
 }
 }
 
 
+void Input::SetTouchEmulation(bool enable)
+{
+#if !defined(ANDROID) && !defined(IOS)
+    if (enable != touchEmulation_)
+    {
+        // Touch emulation needs the mouse visible
+        if (enable)
+        {
+            if (!mouseVisible_)
+                SetMouseVisible(true);
+            
+            // Add a virtual touch device the first time we are enabling emulated touch
+            if (enable && !SDL_GetNumTouchDevices())
+                SDL_AddTouch(0, "Emulated Touch");
+        }
+        else
+            ClearTouches();
+        
+        touchEmulation_ = enable;
+    }
+#endif
+}
+
 bool Input::RecordGesture()
 bool Input::RecordGesture()
 {
 {
     // If have no touch devices, fail
     // If have no touch devices, fail
@@ -842,13 +872,28 @@ void Input::ResetState()
     /// \todo Check if this is necessary
     /// \todo Check if this is necessary
     for (HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
     for (HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
     {
     {
+        for (unsigned j = 0; j < i->second_.axes_.Size(); ++j)
+            i->second_.axes_[j] = 0.0f;
         for (unsigned j = 0; j < i->second_.buttons_.Size(); ++j)
         for (unsigned j = 0; j < i->second_.buttons_.Size(); ++j)
             i->second_.buttons_[j] = false;
             i->second_.buttons_[j] = false;
         for (unsigned j = 0; j < i->second_.hats_.Size(); ++j)
         for (unsigned j = 0; j < i->second_.hats_.Size(); ++j)
             i->second_.hats_[j] = HAT_CENTER;
             i->second_.hats_[j] = HAT_CENTER;
     }
     }
 
 
-    // When clearing touch states, send the corresponding touch end events
+    ClearTouches();
+
+    // Use SetMouseButton() to reset the state so that mouse events will be sent properly
+    SetMouseButton(MOUSEB_LEFT, false);
+    SetMouseButton(MOUSEB_RIGHT, false);
+    SetMouseButton(MOUSEB_MIDDLE, false);
+
+    mouseMove_ = IntVector2::ZERO;
+    mouseMoveWheel_ = 0;
+    mouseButtonPress_ = 0;
+}
+
+void Input::ClearTouches()
+{
     for (HashMap<int, TouchState>::Iterator i = touches_.Begin(); i != touches_.End(); ++i)
     for (HashMap<int, TouchState>::Iterator i = touches_.Begin(); i != touches_.End(); ++i)
     {
     {
         TouchState& state = i->second_;
         TouchState& state = i->second_;
@@ -861,15 +906,8 @@ void Input::ResetState()
         eventData[P_Y] = state.position_.y_;
         eventData[P_Y] = state.position_.y_;
         SendEvent(E_TOUCHEND, eventData);
         SendEvent(E_TOUCHEND, eventData);
     }
     }
-
-    // Use SetMouseButton() to reset the state so that mouse events will be sent properly
-    SetMouseButton(MOUSEB_LEFT, false);
-    SetMouseButton(MOUSEB_RIGHT, false);
-    SetMouseButton(MOUSEB_MIDDLE, false);
-
-    mouseMove_ = IntVector2::ZERO;
-    mouseMoveWheel_ = 0;
-    mouseButtonPress_ = 0;
+    
+    touches_.Clear();
 }
 }
 
 
 void Input::SendInputFocusEvent()
 void Input::SendInputFocusEvent()
@@ -1028,15 +1066,49 @@ void Input::HandleSDLEvent(void* sdlEvent)
         break;
         break;
 
 
     case SDL_MOUSEBUTTONDOWN:
     case SDL_MOUSEBUTTONDOWN:
-        SetMouseButton(1 << (evt.button.button - 1), true);
+        if (!touchEmulation_)
+            SetMouseButton(1 << (evt.button.button - 1), true);
+        else if (touchEmulation_ && evt.button.button == 1)
+        {
+            int x, y;
+            SDL_GetMouseState(&x, &y);
+            
+            SDL_Event event;
+            event.type = SDL_FINGERDOWN;
+            event.tfinger.touchId = 0;
+            event.tfinger.fingerId = 0;
+            event.tfinger.pressure = 1.0f;
+            event.tfinger.x = (float)x / (float)graphics_->GetWidth();
+            event.tfinger.y = (float)y / (float)graphics_->GetHeight();
+            event.tfinger.dx = 0;
+            event.tfinger.dy = 0;
+            SDL_PushEvent(&event);
+        }
         break;
         break;
 
 
     case SDL_MOUSEBUTTONUP:
     case SDL_MOUSEBUTTONUP:
-        SetMouseButton(1 << (evt.button.button - 1), false);
+        if (!touchEmulation_)
+            SetMouseButton(1 << (evt.button.button - 1), false);
+        else if (touchEmulation_ && evt.button.button == 1)
+        {
+            int x, y;
+            SDL_GetMouseState(&x, &y);
+            
+            SDL_Event event;
+            event.type = SDL_FINGERUP;
+            event.tfinger.touchId = 0;
+            event.tfinger.fingerId = 0;
+            event.tfinger.pressure = 0.0f;
+            event.tfinger.x = (float)x / (float)graphics_->GetWidth();
+            event.tfinger.y = (float)y / (float)graphics_->GetHeight();
+            event.tfinger.dx = 0;
+            event.tfinger.dy = 0;
+            SDL_PushEvent(&event);
+        }
         break;
         break;
 
 
     case SDL_MOUSEMOTION:
     case SDL_MOUSEMOTION:
-        if (mouseVisible_)
+        if (mouseVisible_ && !touchEmulation_)
         {
         {
             mouseMove_.x_ += evt.motion.xrel;
             mouseMove_.x_ += evt.motion.xrel;
             mouseMove_.y_ += evt.motion.yrel;
             mouseMove_.y_ += evt.motion.yrel;
@@ -1055,10 +1127,27 @@ void Input::HandleSDLEvent(void* sdlEvent)
             eventData[P_QUALIFIERS] = GetQualifiers();
             eventData[P_QUALIFIERS] = GetQualifiers();
             SendEvent(E_MOUSEMOVE, eventData);
             SendEvent(E_MOUSEMOVE, eventData);
         }
         }
+        else if (touchEmulation_ && touches_.Contains(0))
+        {
+            int x, y;
+            SDL_GetMouseState(&x, &y);
+            
+            SDL_Event event;
+            event.type = SDL_FINGERMOTION;
+            event.tfinger.touchId = 0;
+            event.tfinger.fingerId = 0;
+            event.tfinger.pressure = 1.0f;
+            event.tfinger.x = (float)x / (float)graphics_->GetWidth();
+            event.tfinger.y = (float)y / (float)graphics_->GetHeight();
+            event.tfinger.dx = (float)evt.motion.xrel / (float)graphics_->GetWidth();
+            event.tfinger.dy = (float)evt.motion.yrel / (float)graphics_->GetHeight();
+            SDL_PushEvent(&event);
+        }
         break;
         break;
 
 
     case SDL_MOUSEWHEEL:
     case SDL_MOUSEWHEEL:
-        SetMouseWheel(evt.wheel.y);
+        if (!touchEmulation_)
+            SetMouseWheel(evt.wheel.y);
         break;
         break;
 
 
     case SDL_FINGERDOWN:
     case SDL_FINGERDOWN:

+ 8 - 0
Source/Engine/Input/Input.h

@@ -136,6 +136,8 @@ public:
     void SetScreenJoystickVisible(SDL_JoystickID id, bool enable);
     void SetScreenJoystickVisible(SDL_JoystickID id, bool enable);
     /// Show or hide on-screen keyboard on platforms that support it. When shown, keypresses from it are delivered as key events.
     /// Show or hide on-screen keyboard on platforms that support it. When shown, keypresses from it are delivered as key events.
     void SetScreenKeyboardVisible(bool enable);
     void SetScreenKeyboardVisible(bool enable);
+    /// Set touch emulation by mouse. Only available on desktop platforms. When enabled, actual mouse events are no longer sent and the mouse cursor is forced visible.
+    void SetTouchEmulation(bool enable);
     /// Begin recording a touch gesture. Return true if successful. The E_GESTURERECORDED event (which contains the ID for the new gesture) will be sent when recording finishes.
     /// Begin recording a touch gesture. Return true if successful. The E_GESTURERECORDED event (which contains the ID for the new gesture) will be sent when recording finishes.
     bool RecordGesture();
     bool RecordGesture();
     /// Save all in-memory touch gestures. Return true if successful.
     /// Save all in-memory touch gestures. Return true if successful.
@@ -203,6 +205,8 @@ public:
     bool GetScreenKeyboardSupport() const;
     bool GetScreenKeyboardSupport() const;
     /// Return whether on-screen keyboard is being shown.
     /// Return whether on-screen keyboard is being shown.
     bool IsScreenKeyboardVisible() const;
     bool IsScreenKeyboardVisible() const;
+    /// Return whether touch emulation is enabled.
+    bool GetTouchEmulation() const { return touchEmulation_; }
     /// Return whether the operating system mouse cursor is visible.
     /// Return whether the operating system mouse cursor is visible.
     bool IsMouseVisible() const { return mouseVisible_; }
     bool IsMouseVisible() const { return mouseVisible_; }
     /// Return whether the mouse is currently being grabbed by an operation.
     /// Return whether the mouse is currently being grabbed by an operation.
@@ -225,6 +229,8 @@ private:
     void LoseFocus();
     void LoseFocus();
     /// Clear input state.
     /// Clear input state.
     void ResetState();
     void ResetState();
+    /// Clear touch states and send touch end events.
+    void ClearTouches();
     /// Send an input focus or window minimization change event.
     /// Send an input focus or window minimization change event.
     void SendInputFocusEvent();
     void SendInputFocusEvent();
     /// Handle a mouse button change.
     /// Handle a mouse button change.
@@ -278,6 +284,8 @@ private:
     bool mouseVisible_;
     bool mouseVisible_;
     /// Flag to indicate the mouse is being grabbed by an operation. Subsystems like UI that uses mouse should temporarily ignore the mouse hover or click events.
     /// Flag to indicate the mouse is being grabbed by an operation. Subsystems like UI that uses mouse should temporarily ignore the mouse hover or click events.
     bool mouseGrabbed_;
     bool mouseGrabbed_;
+    /// Touch emulation mode flag.
+    bool touchEmulation_;
     /// Input focus flag.
     /// Input focus flag.
     bool inputFocus_;
     bool inputFocus_;
     /// Minimized flag.
     /// Minimized flag.

+ 3 - 0
Source/Engine/LuaScript/pkgs/Input/Input.pkg

@@ -41,6 +41,7 @@ class Input : public Object
     bool RemoveScreenJoystick(int id);
     bool RemoveScreenJoystick(int id);
     void SetScreenJoystickVisible(int id, bool enable);
     void SetScreenJoystickVisible(int id, bool enable);
     void SetScreenKeyboardVisible(bool enable);
     void SetScreenKeyboardVisible(bool enable);
+    void SetTouchEmulation(bool enable);
     bool RecordGesture();
     bool RecordGesture();
     tolua_outside bool InputSaveGestures @ SaveGestures(File* dest);
     tolua_outside bool InputSaveGestures @ SaveGestures(File* dest);
     tolua_outside bool InputSaveGesture @ SaveGesture(File* dest, unsigned gestureID);
     tolua_outside bool InputSaveGesture @ SaveGesture(File* dest, unsigned gestureID);
@@ -78,6 +79,7 @@ class Input : public Object
     bool GetScreenKeyboardSupport() const;
     bool GetScreenKeyboardSupport() const;
     bool IsScreenJoystickVisible(int id) const;
     bool IsScreenJoystickVisible(int id) const;
     bool IsScreenKeyboardVisible() const;
     bool IsScreenKeyboardVisible() const;
+    bool GetTouchEmulation() const;
     bool IsMouseVisible() const;
     bool IsMouseVisible() const;
     bool IsMouseGrabbed() const;
     bool IsMouseGrabbed() const;
     bool HasFocus();
     bool HasFocus();
@@ -94,6 +96,7 @@ class Input : public Object
     tolua_readonly tolua_property__get_set bool toggleFullscreen;
     tolua_readonly tolua_property__get_set bool toggleFullscreen;
     tolua_readonly tolua_property__get_set bool screenKeyboardSupport;
     tolua_readonly tolua_property__get_set bool screenKeyboardSupport;
     tolua_property__is_set bool screenKeyboardVisible;
     tolua_property__is_set bool screenKeyboardVisible;
+    tolua_property__get_set bool touchEmulation;
     tolua_property__is_set bool mouseVisible;
     tolua_property__is_set bool mouseVisible;
     tolua_property__is_set bool mouseGrabbed;
     tolua_property__is_set bool mouseGrabbed;
     tolua_readonly tolua_property__has_set bool focus;
     tolua_readonly tolua_property__has_set bool focus;

+ 2 - 0
Source/Engine/Script/InputAPI.cpp

@@ -491,6 +491,8 @@ static void RegisterInput(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Input", "void set_screenKeyboardVisible(bool)", asMETHOD(Input, SetScreenKeyboardVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "void set_screenKeyboardVisible(bool)", asMETHOD(Input, SetScreenKeyboardVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_screenKeyboardVisible() const", asMETHOD(Input, IsScreenKeyboardVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_screenKeyboardVisible() const", asMETHOD(Input, IsScreenKeyboardVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_screenKeyboardSupport() const", asMETHOD(Input, GetScreenKeyboardSupport), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_screenKeyboardSupport() const", asMETHOD(Input, GetScreenKeyboardSupport), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "void set_touchEmulation(bool)", asMETHOD(Input, SetTouchEmulation), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "bool get_touchEmulation() const", asMETHOD(Input, GetTouchEmulation), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "void set_toggleFullscreen(bool)", asMETHOD(Input, SetToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "void set_toggleFullscreen(bool)", asMETHOD(Input, SetToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_toggleFullscreen() const", asMETHOD(Input, GetToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_toggleFullscreen() const", asMETHOD(Input, GetToggleFullscreen), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_keyDown(int) const", asMETHOD(Input, GetKeyDown), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "bool get_keyDown(int) const", asMETHOD(Input, GetKeyDown), asCALL_THISCALL);

+ 1 - 1
Source/Engine/UI/UI.cpp

@@ -319,7 +319,7 @@ void UI::Update(float timeStep)
 
 
     // Mouse hover
     // Mouse hover
     Input* input = GetSubsystem<Input>();
     Input* input = GetSubsystem<Input>();
-    if (!input->IsMouseGrabbed())
+    if (!input->IsMouseGrabbed() && !input->GetTouchEmulation())
     {
     {
         IntVector2 cursorPos;
         IntVector2 cursorPos;
         bool cursorVisible;
         bool cursorVisible;