Browse Source

Use the "click to focus" mechanism on all desktop platforms in windowed & mouse-hidden mode. Code cleanup in Input.

Lasse Öörni 10 years ago
parent
commit
03602fbd1c
1 changed files with 55 additions and 33 deletions
  1. 55 33
      Source/Urho3D/Input/Input.cpp

+ 55 - 33
Source/Urho3D/Input/Input.cpp

@@ -48,6 +48,11 @@
 
 extern "C" int SDL_AddTouch(SDL_TouchID touchID, const char *name);
 
+// Use a "click inside window to focus" mechanism on desktop platforms when the mouse cursor is hidden
+#if defined(WIN32) || (defined(__APPLE__) && !defined(IOS)) || (defined(__linux__) && !defined(ANDROID) && !defined(RPI))
+#define REQUIRE_CLICK_TO_FOCUS
+#endif
+
 namespace Urho3D
 {
 
@@ -208,10 +213,10 @@ Input::Input(Context* context) :
     lastMouseVisible_(false),
     mouseGrabbed_(false),
     mouseMode_(MM_ABSOLUTE),
-#ifdef EMSCRIPTEN
+    #ifdef EMSCRIPTEN
     emscriptenExitingPointerLock_(false),
     emscriptenEnteredPointerLock_(false),
-#endif
+    #endif
     touchEmulation_(false),
     inputFocus_(false),
     minimized_(false),
@@ -267,15 +272,6 @@ void Input::Update()
         state.delta_ = IntVector2::ZERO;
     }
 
-    // Check and handle SDL events
-
-    if (!inputFocus_)
-    {
-        // While there is no input focus, don't process key, mouse, touch or joystick events.
-        SDL_PumpEvents();
-        SDL_FlushEvents(SDL_KEYDOWN, SDL_MULTIGESTURE);
-    }
-
     SDL_Event evt;
     while (SDL_PollEvent(&evt))
         HandleSDLEvent(&evt);
@@ -283,10 +279,15 @@ void Input::Update()
     // Check for focus change this frame
     SDL_Window* window = graphics_->GetImpl()->GetWindow();
     unsigned flags = window ? SDL_GetWindowFlags(window) & (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS) : 0;
-#ifndef EMSCRIPTEN
+    #ifndef EMSCRIPTEN
     if (window)
     {
+        #ifdef REQUIRE_CLICK_TO_FOCUS
+        // When using the "click to focus" mechanism, only focus automatically in fullscreen or non-hidden mouse mode
+        if (!inputFocus_ && (mouseVisible_ || graphics_->GetFullscreen()) && (flags & SDL_WINDOW_INPUT_FOCUS))
+        #else
         if (!inputFocus_ && (flags & SDL_WINDOW_INPUT_FOCUS))
+        #endif
             focusedThisFrame_ = true;
 
         if (focusedThisFrame_)
@@ -374,9 +375,7 @@ void Input::Update()
         }
         #else
         if (mouseMode_ == MM_ABSOLUTE)
-        {
             lastMousePosition_ = mousePosition;
-        }
         #endif
         // Send mouse move event if necessary
         if (mouseMove_ != IntVector2::ZERO)
@@ -560,9 +559,7 @@ void Input::SetMouseMode(MouseMode mode)
         }
         #ifndef EMSCRIPTEN
         else if (previousMode == MM_WRAP)
-        {
             SDL_SetWindowGrab(window, SDL_FALSE);
-        }
         #endif
 
         // Handle changing to new mode
@@ -947,18 +944,18 @@ unsigned Input::LoadGestures(Deserializer& source)
 
 bool Input::RemoveGesture(unsigned gestureID)
 {
-#if defined(EMSCRIPTEN)
+    #ifdef EMSCRIPTEN
     return false;
-#else
+    #else
     return SDL_RemoveDollarTemplate(gestureID) != 0;
-#endif
+    #endif
 }
 
 void Input::RemoveAllGestures()
 {
-#if !defined(EMSCRIPTEN)
+    #ifndef EMSCRIPTEN
     SDL_RemoveAllDollarTemplates();
-#endif
+    #endif
 }
 
 SDL_JoystickID Input::OpenJoystick(unsigned index)
@@ -1181,15 +1178,15 @@ void Input::Initialize()
 
     // Set the initial activation
     initialized_ = true;
-#ifndef EMSCRIPTEN
+    #ifndef EMSCRIPTEN
     focusedThisFrame_ = true;
-#else
+    #else
     // Note: Page visibility and focus are slightly different, however we can't query last focus with Emscripten (1.29.0)
     if (emscriptenInput_->IsVisible())
         GainFocus();
     else
         LoseFocus();
-#endif
+    #endif
 
     ResetJoysticks();
     ResetState();
@@ -1368,7 +1365,7 @@ void Input::SendInputFocusEvent()
 
 void Input::SetMouseButton(int button, bool newState)
 {
-#ifdef EMSCRIPTEN
+    #ifdef EMSCRIPTEN
     if (emscriptenEnteredPointerLock_)
     {
         // Suppress mouse jump on initial Pointer Lock
@@ -1378,7 +1375,7 @@ void Input::SetMouseButton(int button, bool newState)
         suppressNextMouseMove_ = true;
         emscriptenEnteredPointerLock_ = false;
     }
-#endif
+    #endif
 
     if (newState)
     {
@@ -1474,23 +1471,46 @@ void Input::HandleSDLEvent(void* sdlEvent)
 {
     SDL_Event& evt = *static_cast<SDL_Event*>(sdlEvent);
 
+    // While not having input focus, skip key/mouse/touch/joystick events, except for the "click to focus" mechanism
+    if (!inputFocus_ && evt.type >= SDL_KEYDOWN && evt.type <= SDL_MULTIGESTURE)
+    {
+        #ifdef REQUIRE_CLICK_TO_FOCUS
+        // Require the click to be at least 1 pixel inside the window to disregard clicks in the title bar
+        if (evt.type == SDL_MOUSEBUTTONDOWN && evt.button.x > 0 && evt.button.y > 0 && evt.button.x < graphics_->GetWidth() - 1 &&
+            evt.button.y < graphics_->GetHeight() - 1)
+        {
+            focusedThisFrame_ = true;
+            // Do not cause the click to actually go through
+            return;
+        }
+        else if (evt.type == SDL_FINGERDOWN)
+        {
+            // When focusing by touch, call GainFocus() immediately as it resets the state; a touch has sustained state
+            // which should be kept
+            GainFocus();
+        }
+        else
+        #endif
+            return;
+    }
+
     switch (evt.type)
     {
     case SDL_KEYDOWN:
         // Convert to uppercase to match Win32 virtual key codes
-#if defined (EMSCRIPTEN)
+        #ifdef EMSCRIPTEN
         SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), evt.key.keysym.scancode, 0, true);
-#else
+        #else
         SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), evt.key.keysym.scancode, evt.key.keysym.raw, true);
-#endif
+        #endif
         break;
 
     case SDL_KEYUP:
-#if defined(EMSCRIPTEN)
+        #ifdef EMSCRIPTEN
         SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), evt.key.keysym.scancode, 0, false);
-#else
+        #else
         SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), evt.key.keysym.scancode, evt.key.keysym.raw, false);
-#endif
+        #endif
         break;
 
     case SDL_TEXTINPUT:
@@ -1976,6 +1996,7 @@ void Input::HandleScreenMode(StringHash eventType, VariantMap& eventData)
         IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
         SetMousePosition(center);
         lastMousePosition_ = center;
+        focusedThisFrame_ = true;
     }
     else
         lastMousePosition_ = GetMousePosition();
@@ -1988,7 +2009,8 @@ void Input::HandleScreenMode(StringHash eventType, VariantMap& eventData)
             screenjoystick->SetSize(graphics_->GetWidth(), graphics_->GetHeight());
     }
 
-    focusedThisFrame_ = true;
+    if (graphics_->GetFullscreen())
+        focusedThisFrame_ = true;
 
     // After setting a new screen mode we should not be minimized
     minimized_ = (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) != 0;