Ver código fonte

cursor state handling improved

Arnis Lielturks 5 anos atrás
pai
commit
5255f847f6
2 arquivos alterados com 113 adições e 27 exclusões
  1. 63 5
      Source/Urho3D/Input/Input.cpp
  2. 50 22
      bin/shell.html

+ 63 - 5
Source/Urho3D/Input/Input.cpp

@@ -47,6 +47,8 @@
 
 
 #ifdef __EMSCRIPTEN__
 #ifdef __EMSCRIPTEN__
 #include <emscripten/html5.h>
 #include <emscripten/html5.h>
+#include <emscripten/emscripten.h>
+#include <emscripten/bind.h>
 #endif
 #endif
 
 
 #include "../DebugNew.h"
 #include "../DebugNew.h"
@@ -109,6 +111,8 @@ public:
 
 
     /// Static callback method for Pointer Lock API. Handles change in Pointer Lock state and sends events for mouse mode change.
     /// Static callback method for Pointer Lock API. Handles change in Pointer Lock state and sends events for mouse mode change.
     static EM_BOOL HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent* keyEvent, void* userData);
     static EM_BOOL HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent* keyEvent, void* userData);
+    /// Static callback method for Pointer Lock API for the custom shell implementation
+    static void HandleCustomPointerLockChange(bool pointerLocked);
     /// Static callback method for tracking focus change events.
     /// Static callback method for tracking focus change events.
     static EM_BOOL HandleFocusChange(int eventType, const EmscriptenFocusEvent* keyEvent, void* userData);
     static EM_BOOL HandleFocusChange(int eventType, const EmscriptenFocusEvent* keyEvent, void* userData);
     /// Static callback method for suppressing mouse jump.
     /// Static callback method for suppressing mouse jump.
@@ -126,7 +130,7 @@ public:
 
 
 private:
 private:
     /// Instance of Input subsystem that constructed this instance.
     /// Instance of Input subsystem that constructed this instance.
-    Input* inputInst_;
+    static Input* inputInst_;
     /// The mouse mode being requested for pointer-lock.
     /// The mouse mode being requested for pointer-lock.
     static MouseMode requestedMouseMode_;
     static MouseMode requestedMouseMode_;
     /// Flag indicating whether to suppress the next mouse mode change event.
     /// Flag indicating whether to suppress the next mouse mode change event.
@@ -138,14 +142,15 @@ private:
     static bool invalidatedSuppressMouseModeEvent_;
     static bool invalidatedSuppressMouseModeEvent_;
 };
 };
 
 
+Input* EmscriptenInput::inputInst_ = nullptr;
 bool EmscriptenInput::suppressMouseModeEvent_ = false;
 bool EmscriptenInput::suppressMouseModeEvent_ = false;
 MouseMode EmscriptenInput::requestedMouseMode_ = MM_INVALID;
 MouseMode EmscriptenInput::requestedMouseMode_ = MM_INVALID;
 bool EmscriptenInput::invalidatedSuppressMouseModeEvent_ = false;
 bool EmscriptenInput::invalidatedSuppressMouseModeEvent_ = false;
 MouseMode EmscriptenInput::invalidatedRequestedMouseMode_ = MM_INVALID;
 MouseMode EmscriptenInput::invalidatedRequestedMouseMode_ = MM_INVALID;
 
 
-EmscriptenInput::EmscriptenInput(Input* inputInst) :
-    inputInst_(inputInst)
+EmscriptenInput::EmscriptenInput(Input* inputInst)
 {
 {
+    inputInst_ = inputInst;
     auto* vInputInst = (void*)inputInst;
     auto* vInputInst = (void*)inputInst;
 
 
     // Handle pointer lock
     // Handle pointer lock
@@ -168,6 +173,10 @@ void EmscriptenInput::RequestPointerLock(MouseMode mode, bool suppressEvent)
     requestedMouseMode_ = mode;
     requestedMouseMode_ = mode;
     suppressMouseModeEvent_ = suppressEvent;
     suppressMouseModeEvent_ = suppressEvent;
     emscripten_request_pointerlock(NULL, true);
     emscripten_request_pointerlock(NULL, true);
+
+    EM_ASM({
+        Module.RequestPointerLock();
+    });
 }
 }
 
 
 void EmscriptenInput::ExitPointerLock(bool suppressEvent)
 void EmscriptenInput::ExitPointerLock(bool suppressEvent)
@@ -185,6 +194,9 @@ void EmscriptenInput::ExitPointerLock(bool suppressEvent)
         inputInst_->emscriptenExitingPointerLock_ = true;
         inputInst_->emscriptenExitingPointerLock_ = true;
         emscripten_exit_pointerlock();
         emscripten_exit_pointerlock();
     }
     }
+    EM_ASM({
+        Module.ExitPointerLock();
+    });
 }
 }
 
 
 bool EmscriptenInput::IsVisible()
 bool EmscriptenInput::IsVisible()
@@ -198,6 +210,51 @@ bool EmscriptenInput::IsVisible()
     return true;
     return true;
 }
 }
 
 
+void EmscriptenInput::HandleCustomPointerLockChange(bool pointerLocked)
+{
+    bool invalid = false;
+    const bool suppress = suppressMouseModeEvent_;
+    if (requestedMouseMode_ == MM_INVALID && invalidatedRequestedMouseMode_ != MM_INVALID)
+    {
+        invalid = true;
+        requestedMouseMode_ = invalidatedRequestedMouseMode_;
+        suppressMouseModeEvent_ = invalidatedSuppressMouseModeEvent_;
+        invalidatedRequestedMouseMode_ = MM_INVALID;
+        invalidatedSuppressMouseModeEvent_ = false;
+    }
+
+    if (pointerLocked >= 1)
+    {
+        // Pointer Lock is now active
+        inputInst_->emscriptenPointerLock_ = true;
+        inputInst_->emscriptenEnteredPointerLock_ = true;
+        inputInst_->SetMouseModeEmscriptenFinal(requestedMouseMode_, suppressMouseModeEvent_);
+    }
+    else
+    {
+        // Pointer Lock is now inactive
+        inputInst_->emscriptenPointerLock_ = false;
+
+        if (inputInst_->mouseMode_ == MM_RELATIVE)
+            inputInst_->SetMouseModeEmscriptenFinal(MM_FREE, suppressMouseModeEvent_);
+        else if (inputInst_->mouseMode_ == MM_ABSOLUTE)
+            inputInst_->SetMouseModeEmscriptenFinal(MM_ABSOLUTE, suppressMouseModeEvent_);
+
+        inputInst_->emscriptenExitingPointerLock_ = false;
+    }
+
+    requestedMouseMode_ = MM_INVALID;
+    suppressMouseModeEvent_ = false;
+
+    invalidatedRequestedMouseMode_ = MM_INVALID;
+    invalidatedSuppressMouseModeEvent_ = false;
+}
+
+using namespace emscripten;
+EMSCRIPTEN_BINDINGS(Module) {
+    function("JSPointerLockChange", &EmscriptenInput::HandleCustomPointerLockChange);
+}
+
 EM_BOOL EmscriptenInput::HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent* keyEvent, void* userData)
 EM_BOOL EmscriptenInput::HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent* keyEvent, void* userData)
 {
 {
     auto* const inputInst = (Input*)userData;
     auto* const inputInst = (Input*)userData;
@@ -594,7 +651,7 @@ void Input::SetMouseVisible(bool enable, bool suppressEvent)
                 if (mouseMode_ == MM_ABSOLUTE)
                 if (mouseMode_ == MM_ABSOLUTE)
                     SetMouseModeAbsolute(SDL_TRUE);
                     SetMouseModeAbsolute(SDL_TRUE);
 #else
 #else
-                if (mouseMode_ == MM_ABSOLUTE && !emscriptenPointerLock_)
+                if (mouseMode_ == MM_ABSOLUTE && !emscriptenPointerLock_ || !enable)
                     emscriptenInput_->RequestPointerLock(MM_ABSOLUTE, suppressEvent);
                     emscriptenInput_->RequestPointerLock(MM_ABSOLUTE, suppressEvent);
 #endif
 #endif
                 SDL_ShowCursor(SDL_FALSE);
                 SDL_ShowCursor(SDL_FALSE);
@@ -633,7 +690,7 @@ void Input::SetMouseVisible(bool enable, bool suppressEvent)
                     }
                     }
                 }
                 }
 #else
 #else
-                if (mouseMode_ == MM_ABSOLUTE && emscriptenPointerLock_)
+                if (mouseMode_ == MM_ABSOLUTE && emscriptenPointerLock_ || enable)
                     emscriptenInput_->ExitPointerLock(suppressEvent);
                     emscriptenInput_->ExitPointerLock(suppressEvent);
 #endif
 #endif
             }
             }
@@ -777,6 +834,7 @@ void Input::SetMouseModeEmscripten(MouseMode mode, bool suppressEvent)
             if (emscriptenPointerLock_)
             if (emscriptenPointerLock_)
             {
             {
                 SetMouseVisibleEmscripten(false, suppressEvent);
                 SetMouseVisibleEmscripten(false, suppressEvent);
+
             }
             }
             else
             else
             {
             {

+ 50 - 22
bin/shell.html

@@ -80,7 +80,7 @@
     </div>
     </div>
     <script>
     <script>
         var canvasElement = document.getElementById('canvas');
         var canvasElement = document.getElementById('canvas');
-        var devicePixelRatio = window.devicePixelRatio || 1;
+        var devicePixelRatio = 1;//window.devicePixelRatio || 1;
         var canvasWidth = 0;
         var canvasWidth = 0;
         var canvasHeight = 0;
         var canvasHeight = 0;
 
 
@@ -94,6 +94,7 @@
         // Detect fullscreen change and resize canvas resolution accordingly
         // Detect fullscreen change and resize canvas resolution accordingly
         function viewportResizeHandler() {
         function viewportResizeHandler() {
             if (document.hidden) {
             if (document.hidden) {
+                unlockPointer();
                 return;
                 return;
             }
             }
 
 
@@ -107,22 +108,31 @@
             }
             }
         }
         }
 
 
+        function unlockPointer() {
+            document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;
+            document.exitPointerLock();
+        }
+
+        function lockPointer() {
+            if (Module.shouldLockPointer && !IsPointerLocked()) {
+                canvasElement.requestPointerLock = canvasElement.requestPointerLock || canvasElement.mozRequestPointerLock;
+                canvasElement.requestPointerLock();
+            }
+        }
+
+        canvasElement.addEventListener('click', lockPointer);
+
         function visibilityChanged() {
         function visibilityChanged() {
             if (document.hidden) {
             if (document.hidden) {
+                unlockPointer();
                 return;
                 return;
             }
             }
 
 
-            // Overwrite some emscripten functions that break the input
-            __registerFocusEventCallback = function() {
-                if (!JSEvents.focusEvent) JSEvents.focusEvent = _malloc(256);
-            };
-            __registerFullscreenChangeEventCallback = function() {
-                if (!JSEvents.fullscreenChangeEvent) JSEvents.fullscreenChangeEvent = _malloc(280);
-            };
-
             setTimeout(() => {
             setTimeout(() => {
                 viewportResizeHandler();
                 viewportResizeHandler();
             }, 100);
             }, 100);
+
+            lockPointer();
         }
         }
 
 
         document.addEventListener('fullscreenchange', viewportResizeHandler, false);
         document.addEventListener('fullscreenchange', viewportResizeHandler, false);
@@ -134,14 +144,10 @@
         document.addEventListener('msvisibilitychange', visibilityChanged, false);
         document.addEventListener('msvisibilitychange', visibilityChanged, false);
         document.addEventListener('webkitvisibilitychange', visibilityChanged, false);
         document.addEventListener('webkitvisibilitychange', visibilityChanged, false);
 
 
-        var resizeTimeout = false;
         // When window size has changed, resize the canvas accordingly
         // When window size has changed, resize the canvas accordingly
         window.addEventListener('resize', function(evt) {
         window.addEventListener('resize', function(evt) {
             // resize event is called before the resizing has finished, we must wait a bit so the new calculations use the new viewport size
             // resize event is called before the resizing has finished, we must wait a bit so the new calculations use the new viewport size
-            if (resizeTimeout) {
-                clearTimeout(resizeTimeout);
-            }
-            resizeTimeout = setTimeout(() => {
+            setTimeout(() => {
                 viewportResizeHandler(evt);
                 viewportResizeHandler(evt);
             }, 1000);
             }, 1000);
         });
         });
@@ -166,26 +172,34 @@
             return !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
             return !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
         }
         }
 
 
+        function IsPointerLocked() {
+            if(document.pointerLockElement === canvasElement || document.mozPointerLockElement === canvasElement) {
+                return true;
+            }
+            return false;
+        }
+        function pointerLockChange() {
+            Module.JSPointerLockChange(IsPointerLocked());
+        }
+        document.addEventListener('pointerlockchange', pointerLockChange);
+        document.addEventListener('mozpointerlockchange', pointerLockChange);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange);
+
+
         // App is ready to launch, make canvas and fullscreen button visible
         // App is ready to launch, make canvas and fullscreen button visible
         function ready() {
         function ready() {
             document.getElementById('canvas').style.display = 'block';
             document.getElementById('canvas').style.display = 'block';
             document.getElementById('fullscreen-button').style.display = 'block';
             document.getElementById('fullscreen-button').style.display = 'block';
 
 
             if (document.hidden) {
             if (document.hidden) {
+                unlockPointer();
                 return;
                 return;
             }
             }
 
 
-            // Overwrite some emscripten functions that break the input
-            __registerFocusEventCallback = function() {
-                if (!JSEvents.focusEvent) JSEvents.focusEvent = _malloc(256);
-            };
-            __registerFullscreenChangeEventCallback = function() {
-                if (!JSEvents.fullscreenChangeEvent) JSEvents.fullscreenChangeEvent = _malloc(280);
-            };
-
             setTimeout(() => {
             setTimeout(() => {
                 viewportResizeHandler();
                 viewportResizeHandler();
             }, 100);
             }, 100);
+            lockPointer();
         }
         }
 
 
         var Module = {
         var Module = {
@@ -193,6 +207,10 @@
             postRun: [],
             postRun: [],
             canvas: canvasElement,
             canvas: canvasElement,
             forcedAspectRatio: false,
             forcedAspectRatio: false,
+            // Disable custom emscripten pointer lock handling
+            elementPointerLock: false,
+            mouseVisible: true,
+            shouldLockPointer: false,
 
 
             print: function (text) {
             print: function (text) {
                 console.log(text);
                 console.log(text);
@@ -252,6 +270,16 @@
                 this.totalDependencies = Math.max(this.totalDependencies, left);
                 this.totalDependencies = Math.max(this.totalDependencies, left);
                 Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
                 Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
             },
             },
+
+            RequestPointerLock: function() {
+                Module.shouldLockPointer = true;
+                lockPointer();
+            },
+
+            ExitPointerLock: function() {
+                Module.shouldLockPointer = false;
+                unlockPointer();
+            }
         };
         };
         Module.setStatus('Downloading...');
         Module.setStatus('Downloading...');
     </script>
     </script>