]> OCCT Git - occt.git/commitdiff
0032638: Draw Harness, ViewerTest - HTML input range misbehavior in WebAssembly
authorkgv <kgv@opencascade.com>
Fri, 22 Oct 2021 12:59:19 +0000 (15:59 +0300)
committersmoskvin <smoskvin@opencascade.com>
Fri, 22 Oct 2021 16:58:16 +0000 (19:58 +0300)
ViewerTest_EventManager - added tracking of EMSCRIPTEN_EVENT_FOCUSOUT event.
onWasmMouseCallback() has been adjusted to return FALSE for EMSCRIPTEN_EVENT_TARGET_WINDOW
target to avoid misbehavior of other HTML controls.

WNT_Window::ProcessMessage() now handles WM_SETFOCUS/WM_KILLFOCUS instead of WM_ACTIVATE to track focus changes.

AIS_ViewController::ProcessFocus() now redirects to AIS_ViewController::ResetViewInput() on focus loss.
This fixes issues when key action (like WASD navigation) keep working even after releasing key if window has been switched.

samples/webgl/WasmOcctView.cpp
samples/webgl/WasmOcctView.h
samples/webgl/occt-webgl-sample.html
src/AIS/AIS_ViewController.hxx
src/ViewerTest/ViewerTest_EventManager.cxx
src/WNT/WNT_Window.cxx
src/Wasm/Wasm_Window.cxx
src/Wasm/Wasm_Window.hxx

index e47f395acbef67e1f736fa8d201212020698f616..53e0096030fdbfbc91beead7e82388018ed82377 100644 (file)
@@ -202,9 +202,12 @@ void WasmOcctView::initWindow()
   emscripten_set_touchmove_callback  (aTargetId, this, toUseCapture, onTouchCallback);
   emscripten_set_touchcancel_callback(aTargetId, this, toUseCapture, onTouchCallback);
 
-  //emscripten_set_keypress_callback   (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onKeyCallback);
-  emscripten_set_keydown_callback    (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onKeyDownCallback);
-  emscripten_set_keyup_callback      (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onKeyUpCallback);
+  //emscripten_set_keypress_callback   (aTargetId, this, toUseCapture, onKeyCallback);
+  emscripten_set_keydown_callback    (aTargetId, this, toUseCapture, onKeyDownCallback);
+  emscripten_set_keyup_callback      (aTargetId, this, toUseCapture, onKeyUpCallback);
+  //emscripten_set_focus_callback    (aTargetId, this, toUseCapture, onFocusCallback);
+  //emscripten_set_focusin_callback  (aTargetId, this, toUseCapture, onFocusCallback);
+  emscripten_set_focusout_callback   (aTargetId, this, toUseCapture, onFocusCallback);
 }
 
 // ================================================================
@@ -513,7 +516,8 @@ EM_BOOL WasmOcctView::onMouseEvent (int theEventType, const EmscriptenMouseEvent
     EmscriptenMouseEvent anEvent = *theEvent;
     anEvent.targetX -= jsGetBoundingClientLeft();
     anEvent.targetY -= jsGetBoundingClientTop();
-    return aWindow->ProcessMouseEvent (*this, theEventType, &anEvent) ? EM_TRUE : EM_FALSE;
+    aWindow->ProcessMouseEvent (*this, theEventType, &anEvent);
+    return EM_FALSE;
   }
 
   return aWindow->ProcessMouseEvent (*this, theEventType, theEvent) ? EM_TRUE : EM_FALSE;
@@ -587,6 +591,24 @@ bool WasmOcctView::navigationKeyModifierSwitch (unsigned int theModifOld,
   return hasActions;
 }
 
+// ================================================================
+// Function : onFocusEvent
+// Purpose  :
+// ================================================================
+EM_BOOL WasmOcctView::onFocusEvent (int theEventType, const EmscriptenFocusEvent* theEvent)
+{
+  if (myView.IsNull()
+   || (theEventType != EMSCRIPTEN_EVENT_FOCUS
+    && theEventType != EMSCRIPTEN_EVENT_FOCUSIN // about to receive focus
+    && theEventType != EMSCRIPTEN_EVENT_FOCUSOUT))
+  {
+    return EM_FALSE;
+  }
+
+  Handle(Wasm_Window) aWindow = Handle(Wasm_Window)::DownCast (myView->Window());
+  return aWindow->ProcessFocusEvent (*this, theEventType, theEvent) ? EM_TRUE : EM_FALSE;
+}
+
 // ================================================================
 // Function : onKeyDownEvent
 // Purpose  :
index 626ba00d8abedd03d4b6c2c7426c472352f0fe02..58921a6bed416912c221a014ae0b9ef461803666 100644 (file)
@@ -181,6 +181,9 @@ private:
   //! Key up event.
   EM_BOOL onKeyUpEvent (int theEventType, const EmscriptenKeyboardEvent* theEvent);
 
+  //! Focus change event.
+  EM_BOOL onFocusEvent (int theEventType, const EmscriptenFocusEvent* theEvent);
+
 //! @name Emscripten callbacks (static functions)
 private:
 
@@ -205,6 +208,9 @@ private:
   static EM_BOOL onKeyUpCallback (int theEventType, const EmscriptenKeyboardEvent* theEvent, void* theView)
   { return ((WasmOcctView* )theView)->onKeyUpEvent (theEventType, theEvent); }
 
+  static EM_BOOL onFocusCallback (int theEventType, const EmscriptenFocusEvent* theEvent, void* theView)
+  { return ((WasmOcctView* )theView)->onFocusEvent (theEventType, theEvent); }
+
 private:
 
   //! Register hot-keys for specified Action.
index a831e3e1f0e3e56edae793d9e55d9dff1f1d509a..7b48a41c23f778997c72646fee2d602245fe54c0 100644 (file)
@@ -42,6 +42,11 @@ function updateCanvasSize()
 window.onresize = updateCanvasSize;
 updateCanvasSize();
 
+// capture keyboard input on mouse click
+occViewerCanvas.tabIndex = -1;
+occViewerCanvas.onclick = (theEvent) => { occViewerCanvas.focus() };
+occViewerCanvas.focus();
+
 //! Check browser support.
 function isWasmSupported()
 {
@@ -78,6 +83,7 @@ fileInput.onchange = function()
     OccViewerModule.openFromMemory (aFile.name, aDataBuffer, aDataArray.length, true);
     //OccViewerModule._free (aDataBuffer); will be freed by called method
     OccViewerModule.displayGround (true);
+    occViewerCanvas.focus();
   };
   aReader.readAsArrayBuffer(aFile);
 };
index 1437b20fda8a645f3a881df54d09f4c8ebc057a3..8ab8fd23a8c399247bd92c9972779ef8bb72992e 100644 (file)
@@ -441,10 +441,13 @@ public: //! @name resize events
   virtual void ProcessInput() Standard_OVERRIDE {}
 
   //! Handle focus event.
-  //! Default implementation does nothing.
+  //! Default implementation resets cached input state (pressed keys).
   virtual void ProcessFocus (bool theIsActivated) Standard_OVERRIDE
   {
-    (void )theIsActivated;
+    if (!theIsActivated)
+    {
+      ResetViewInput();
+    }
   }
 
   //! Handle window close event.
index 7ae3a25c744bd413275c578d8884386e42de9f99..3335af811fceee269ef91f1429f67d59f0d64aab 100644 (file)
@@ -655,7 +655,8 @@ static EM_BOOL onWasmMouseCallback (int theEventType, const EmscriptenMouseEvent
       EmscriptenMouseEvent anEvent = *theEvent;
       anEvent.targetX -= occJSGetBoundingClientLeft();
       anEvent.targetY -= occJSGetBoundingClientTop();
-      return aWindow->ProcessMouseEvent (*aViewCtrl, theEventType, &anEvent) ? EM_TRUE : EM_FALSE;
+      aWindow->ProcessMouseEvent (*aViewCtrl, theEventType, &anEvent);
+      return EM_FALSE;
     }
 
     return aWindow->ProcessMouseEvent (*aViewCtrl, theEventType, theEvent) ? EM_TRUE : EM_FALSE;
@@ -702,6 +703,19 @@ static EM_BOOL onWasmKeyCallback (int theEventType, const EmscriptenKeyboardEven
   }
   return EM_FALSE;
 }
+
+//! Handle focus change event.
+static EM_BOOL onWasmFocusCallback (int theEventType, const EmscriptenFocusEvent* theEvent, void*)
+{
+  Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
+  if (!aViewCtrl.IsNull()
+   && !ViewerTest::CurrentView().IsNull())
+  {
+    Handle(Wasm_Window) aWindow = Handle(Wasm_Window)::DownCast (ViewerTest::CurrentView()->Window());
+    return aWindow->ProcessFocusEvent (*aViewCtrl, theEventType, theEvent) ? EM_TRUE : EM_FALSE;
+  }
+  return EM_FALSE;
+}
 #endif
 
 // ==============================================================================
@@ -777,6 +791,9 @@ void ViewerTest_EventManager::SetupWindowCallbacks (const Handle(Aspect_Window)&
   // keyboard input requires a focusable element or EMSCRIPTEN_EVENT_TARGET_WINDOW
   emscripten_set_keydown_callback    (aTargetId, anOpaque, toUseCapture, onWasmKeyCallback);
   emscripten_set_keyup_callback      (aTargetId, anOpaque, toUseCapture, onWasmKeyCallback);
+  //emscripten_set_focus_callback    (aTargetId, anOpaque, toUseCapture, onWasmFocusCallback);
+  //emscripten_set_focusin_callback  (aTargetId, anOpaque, toUseCapture, onWasmFocusCallback);
+  emscripten_set_focusout_callback   (aTargetId, anOpaque, toUseCapture, onWasmFocusCallback);
 #else
   (void )theWin;
 #endif
index 73ebe522eff47a471c37fe0d1f9a5ccf289e6d30..10edc7a24213668322f3c0dd513742eea937fa9a 100644 (file)
@@ -815,12 +815,12 @@ bool WNT_Window::ProcessMessage (Aspect_WindowInputListener& theListener,
       }
       return false;
     }
-    case WM_ACTIVATE:
+    case WM_SETFOCUS:
+    case WM_KILLFOCUS:
     {
       if (theMsg.hwnd == (HWND )myHWindow)
       {
-        theListener.ProcessFocus (LOWORD(theMsg.wParam) == WA_CLICKACTIVE
-                               || LOWORD(theMsg.wParam) == WA_ACTIVE);
+        theListener.ProcessFocus (theMsg.message == WM_SETFOCUS);
         return true;
       }
       return false;
index 19100a4b7cc59fb9111f1e7a3d91fb2690cba33d..985333b63406ddf7c3fc3ec4616f096955adc593 100644 (file)
@@ -243,6 +243,12 @@ bool Wasm_Window::ProcessMessage (Aspect_WindowInputListener& theListener,
     {
       return ProcessUiEvent (theListener, theEventType, (const EmscriptenUiEvent* )theEvent);
     }
+    case EMSCRIPTEN_EVENT_FOCUS:
+    case EMSCRIPTEN_EVENT_FOCUSIN:
+    case EMSCRIPTEN_EVENT_FOCUSOUT:
+    {
+      return ProcessFocusEvent (theListener, theEventType, (const EmscriptenFocusEvent* )theEvent);
+    }
   }
   return false;
 #else
@@ -536,6 +542,29 @@ bool Wasm_Window::ProcessUiEvent (Aspect_WindowInputListener& theListener,
   return true;
 }
 
+// =======================================================================
+// function : ProcessFocusEvent
+// purpose  :
+// =======================================================================
+bool Wasm_Window::ProcessFocusEvent (Aspect_WindowInputListener& theListener,
+                                     int theEventType, const EmscriptenFocusEvent* )
+{
+  bool isActivated = false;
+#if defined(__EMSCRIPTEN__)
+  if (theEventType != EMSCRIPTEN_EVENT_FOCUS
+   && theEventType != EMSCRIPTEN_EVENT_FOCUSIN // about to receive focus
+   && theEventType != EMSCRIPTEN_EVENT_FOCUSOUT)
+  {
+    return false;
+  }
+  isActivated = theEventType == EMSCRIPTEN_EVENT_FOCUS;
+#else
+  (void )theEventType;
+#endif
+  theListener.ProcessFocus (isActivated);
+  return true;
+}
+
 // =======================================================================
 // function : MouseButtonsFromNative
 // purpose  :
index 62b00b37521790ded8e9b06cbe010b03aebca9c9..5043f83cddcc1694df4b3ff75fb11e831b35b2b5 100644 (file)
@@ -28,6 +28,7 @@ struct EmscriptenWheelEvent;
 struct EmscriptenTouchEvent;
 struct EmscriptenKeyboardEvent;
 struct EmscriptenUiEvent;
+struct EmscriptenFocusEvent;
 
 //! This class defines WebAssembly window (HTML5 canvas) intended for creation of OpenGL (WebGL) context.
 //!
@@ -175,6 +176,14 @@ public:
   Standard_EXPORT virtual bool ProcessUiEvent (Aspect_WindowInputListener& theListener,
                                                int theEventType, const EmscriptenUiEvent* theEvent);
 
+  //! Process a focus input change message.
+  //! @param[in,out] theListener listener to redirect message
+  //! @param[in] theEventType message type to process
+  //! @param[in] theEvent message to process
+  //! @return TRUE if message has been processed
+  Standard_EXPORT virtual bool ProcessFocusEvent (Aspect_WindowInputListener& theListener,
+                                                  int theEventType, const EmscriptenFocusEvent* theEvent);
+
 protected:
 
   TCollection_AsciiString  myCanvasId;