From: kgv Date: Fri, 16 Apr 2021 10:01:17 +0000 (+0300) Subject: 0032306: Draw Harness, ViewerTest - move window message processing to TKService X-Git-Tag: V7_6_0_beta~174 X-Git-Url: http://git.dev.opencascade.org/gitweb/?p=occt.git;a=commitdiff_plain;h=e8e157df453a19d564ebfebdc5c67ecc5912885a 0032306: Draw Harness, ViewerTest - move window message processing to TKService Aspect_WindowInputListener - basic mouse/keyboard/expose input methods have been moved out from AIS_ViewController to dedicated base interface. Added WNT_Window::ProcessMessage()/Xw_Window::ProcessMessage() methods redirecting Win32/X11 message to Aspect_WindowInputListener. --- diff --git a/src/AIS/AIS_ViewController.cxx b/src/AIS/AIS_ViewController.cxx index 0c0399723b..f93aeb93a8 100644 --- a/src/AIS/AIS_ViewController.cxx +++ b/src/AIS/AIS_ViewController.cxx @@ -82,8 +82,6 @@ AIS_ViewController::AIS_ViewController() myMouseActiveGesture (AIS_MouseGesture_NONE), myMouseActiveIdleRotation (false), myMouseClickCounter (0), - myMousePressed (Aspect_VKeyMouse_NONE), - myMouseModifiers (Aspect_VKeyFlags_NONE), myMouseSingleButton (-1), myMouseStopDragOnUnclick (false), // @@ -99,16 +97,8 @@ AIS_ViewController::AIS_ViewController() myUpdateStartPointRot (true), myUpdateStartPointZRot (true), // - my3dMouseNoRotate (false, false, false), - my3dMouseToReverse (true, false, false), - my3dMouseAccelTrans (2.0f), - my3dMouseAccelRotate (4.0f), - my3dMouseIsQuadric (true), - // myPanPnt3d (Precision::Infinite(), 0.0, 0.0) { - memset(my3dMouseButtonState, 0, sizeof(my3dMouseButtonState)); - myEventTimer.Start(); myViewAnimation->SetOwnDuration (0.5); myAnchorPointPrs1 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0)); @@ -1119,104 +1109,11 @@ bool AIS_ViewController::Update3dMouse (const WNT_HIDSpaceMouse& theEvent) { bool toUpdate = false; toUpdate = update3dMouseTranslation (theEvent) || toUpdate; - toUpdate = update3dMouseRotation (theEvent) || toUpdate; + toUpdate = (myToAllowRotation && update3dMouseRotation (theEvent)) || toUpdate; toUpdate = update3dMouseKeys (theEvent) || toUpdate; return toUpdate; } -// ======================================================================= -// function : update3dMouseTranslation -// purpose : -// ======================================================================= -bool AIS_ViewController::update3dMouseTranslation (const WNT_HIDSpaceMouse& theEvent) -{ - if (!theEvent.IsTranslation()) - { - return false; - } - - bool isIdle = true; - const double aTimeStamp = EventTime(); - const Graphic3d_Vec3d aTrans = theEvent.Translation (isIdle, my3dMouseIsQuadric) * my3dMouseAccelTrans; - myKeys.KeyFromAxis (Aspect_VKey_NavSlideLeft, Aspect_VKey_NavSlideRight, aTimeStamp, aTrans.x()); - myKeys.KeyFromAxis (Aspect_VKey_NavForward, Aspect_VKey_NavBackward, aTimeStamp, aTrans.y()); - myKeys.KeyFromAxis (Aspect_VKey_NavSlideUp, Aspect_VKey_NavSlideDown, aTimeStamp, aTrans.z()); - return true; -} - -// ======================================================================= -// function : update3dMouseRotation -// purpose : -// ======================================================================= -bool AIS_ViewController::update3dMouseRotation (const WNT_HIDSpaceMouse& theEvent) -{ - if (!theEvent.IsRotation() - || !myToAllowRotation) - { - return false; - } - - bool isIdle = true, toUpdate = false; - const double aTimeStamp = EventTime(); - const Graphic3d_Vec3d aRot3 = theEvent.Rotation (isIdle, my3dMouseIsQuadric) * my3dMouseAccelRotate; - if (!my3dMouseNoRotate.x()) - { - KeyFromAxis (Aspect_VKey_NavLookUp, Aspect_VKey_NavLookDown, aTimeStamp, !my3dMouseToReverse.x() ? aRot3.x() : -aRot3.x()); - toUpdate = true; - } - if (!my3dMouseNoRotate.y()) - { - KeyFromAxis (Aspect_VKey_NavRollCW, Aspect_VKey_NavRollCCW, aTimeStamp, !my3dMouseToReverse.y() ? aRot3.y() : -aRot3.y()); - toUpdate = true; - } - if (!my3dMouseNoRotate.z()) - { - KeyFromAxis (Aspect_VKey_NavLookLeft, Aspect_VKey_NavLookRight, aTimeStamp, !my3dMouseToReverse.z() ? aRot3.z() : -aRot3.z()); - toUpdate = true; - } - return toUpdate; -} - -// ======================================================================= -// function : update3dMouseKeys -// purpose : -// ======================================================================= -bool AIS_ViewController::update3dMouseKeys (const WNT_HIDSpaceMouse& theEvent) -{ - bool toUpdate = false; - const double aTimeStamp = EventTime(); - if (theEvent.IsKeyState()) - { - const uint32_t aKeyState = theEvent.KeyState(); - for (unsigned short aKeyBit = 0; aKeyBit < 32; ++aKeyBit) - { - const bool isPressed = (aKeyState & (1 << aKeyBit)) != 0; - const bool isReleased = my3dMouseButtonState[aKeyBit] && !isPressed; - //const bool isRepeated = my3dMouseButtonState[aKeyBit] && isPressed; - my3dMouseButtonState[aKeyBit] = isPressed; - if (!isReleased && !isPressed) - { - continue; - } - - const Aspect_VKey aVKey = theEvent.HidToSpaceKey (aKeyBit); - if (aVKey != Aspect_VKey_UNKNOWN) - { - toUpdate = true; - if (isPressed) - { - KeyDown (aVKey, aTimeStamp); - } - else - { - KeyUp (aVKey, aTimeStamp); - } - } - } - } - return toUpdate; -} - // ======================================================================= // function : SetNavigationMode // purpose : @@ -1240,7 +1137,7 @@ void AIS_ViewController::KeyDown (Aspect_VKey theKey, double theTime, double thePressure) { - myKeys.KeyDown (theKey, theTime, thePressure); + Aspect_WindowInputListener::KeyDown (theKey, theTime, thePressure); } // ======================================================================= @@ -1250,7 +1147,7 @@ void AIS_ViewController::KeyDown (Aspect_VKey theKey, void AIS_ViewController::KeyUp (Aspect_VKey theKey, double theTime) { - myKeys.KeyUp (theKey, theTime); + Aspect_WindowInputListener::KeyUp (theKey, theTime); } // ======================================================================= @@ -1262,7 +1159,7 @@ void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative, double theTime, double thePressure) { - myKeys.KeyFromAxis (theNegative, thePositive, theTime, thePressure); + Aspect_WindowInputListener::KeyFromAxis (theNegative, thePositive, theTime, thePressure); } // ======================================================================= diff --git a/src/AIS/AIS_ViewController.hxx b/src/AIS/AIS_ViewController.hxx index 7cfcfbcf24..747e8bf468 100644 --- a/src/AIS/AIS_ViewController.hxx +++ b/src/AIS/AIS_ViewController.hxx @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -51,7 +52,7 @@ class WNT_HIDSpaceMouse; //! - Mapping mouse/multi-touch input to View camera manipulations (panning/rotating/zooming). //! - Input events are not applied immediately but queued for separate processing from two working threads //! UI thread receiving user input and Rendering thread for OCCT 3D Viewer drawing. -class AIS_ViewController +class AIS_ViewController : public Aspect_WindowInputListener { public: @@ -221,30 +222,30 @@ public: //! @name global parameters public: //! @name keyboard input - //! Return keyboard state. - const Aspect_VKeySet& Keys() const { return myKeys; } - - //! Return keyboard state. - Aspect_VKeySet& ChangeKeys() { return myKeys; } + using Aspect_WindowInputListener::Keys; + using Aspect_WindowInputListener::ChangeKeys; //! Press key. + //! Default implementation updates internal cache. //! @param theKey key pressed //! @param theTime event timestamp Standard_EXPORT virtual void KeyDown (Aspect_VKey theKey, double theTime, - double thePressure = 1.0); + double thePressure = 1.0) Standard_OVERRIDE; //! Release key. + //! Default implementation updates internal cache. //! @param theKey key pressed //! @param theTime event timestamp Standard_EXPORT virtual void KeyUp (Aspect_VKey theKey, - double theTime); + double theTime) Standard_OVERRIDE; //! Simulate key up/down events from axis value. + //! Default implementation updates internal cache. Standard_EXPORT virtual void KeyFromAxis (Aspect_VKey theNegative, Aspect_VKey thePositive, double theTime, - double thePressure); + double thePressure) Standard_OVERRIDE; //! Fetch active navigation actions. Standard_EXPORT AIS_WalkDelta FetchNavigationKeys (Standard_Real theCrouchRatio, @@ -313,7 +314,7 @@ public: //! @name mouse input //! This method is expected to be called from UI thread. //! @param theDelta mouse cursor position and delta //! @return TRUE if new event has been created or FALSE if existing one has been updated - Standard_EXPORT virtual bool UpdateMouseScroll (const Aspect_ScrollDelta& theDelta); + Standard_EXPORT virtual bool UpdateMouseScroll (const Aspect_ScrollDelta& theDelta) Standard_OVERRIDE; //! Handle mouse button press/release event. //! This method is expected to be called from UI thread. @@ -326,7 +327,7 @@ public: //! @name mouse input Standard_EXPORT virtual bool UpdateMouseButtons (const Graphic3d_Vec2i& thePoint, Aspect_VKeyMouse theButtons, Aspect_VKeyFlags theModifiers, - bool theIsEmulated); + bool theIsEmulated) Standard_OVERRIDE; //! Handle mouse cursor movement event. //! This method is expected to be called from UI thread. @@ -339,40 +340,7 @@ public: //! @name mouse input Standard_EXPORT virtual bool UpdateMousePosition (const Graphic3d_Vec2i& thePoint, Aspect_VKeyMouse theButtons, Aspect_VKeyFlags theModifiers, - bool theIsEmulated); - - //! Handle mouse button press event. - //! This method is expected to be called from UI thread. - //! @param thePoint mouse cursor position - //! @param theButton pressed button - //! @param theModifiers key modifiers - //! @param theIsEmulated if TRUE then mouse event comes NOT from real mouse - //! but emulated from non-precise input like touch on screen - //! @return TRUE if View should be redrawn - bool PressMouseButton (const Graphic3d_Vec2i& thePoint, - Aspect_VKeyMouse theButton, - Aspect_VKeyFlags theModifiers, - bool theIsEmulated) - { - return UpdateMouseButtons (thePoint, myMousePressed | theButton, theModifiers, theIsEmulated); - } - - //! Handle mouse button release event. - //! This method is expected to be called from UI thread. - //! @param thePoint mouse cursor position - //! @param theButton released button - //! @param theModifiers key modifiers - //! @param theIsEmulated if TRUE then mouse event comes NOT from real mouse - //! but emulated from non-precise input like touch on screen - //! @return TRUE if View should be redrawn - bool ReleaseMouseButton (const Graphic3d_Vec2i& thePoint, - Aspect_VKeyMouse theButton, - Aspect_VKeyFlags theModifiers, - bool theIsEmulated) - { - Aspect_VKeyMouse aButtons = myMousePressed & (~theButton); - return UpdateMouseButtons (thePoint, aButtons, theModifiers, theIsEmulated); - } + bool theIsEmulated) Standard_OVERRIDE; //! Handle mouse button click event (emulated by UpdateMouseButtons() while releasing single button). //! Note that as this method is called by UpdateMouseButtons(), it should be executed from UI thread. @@ -388,14 +356,12 @@ public: //! @name mouse input Aspect_VKeyFlags theModifiers, bool theIsDoubleClick); - //! Return currently pressed mouse buttons. - Aspect_VKeyMouse PressedMouseButtons() const { return myMousePressed; } + using Aspect_WindowInputListener::PressMouseButton; + using Aspect_WindowInputListener::ReleaseMouseButton; - //! Return active key modifiers passed with last mouse event. - Aspect_VKeyFlags LastMouseFlags() const { return myMouseModifiers; } - - //! Return last mouse position. - const Graphic3d_Vec2i& LastMousePosition() const { return myMousePositionLast; } + using Aspect_WindowInputListener::PressedMouseButtons; + using Aspect_WindowInputListener::LastMouseFlags; + using Aspect_WindowInputListener::LastMousePosition; public: //! @name multi-touch input @@ -436,52 +402,40 @@ public: //! @name multi-touch input public: //! @name 3d mouse input - //! Return acceleration ratio for translation event; 2.0 by default. - float Get3dMouseTranslationScale() const { return my3dMouseAccelTrans; } - - //! Set acceleration ratio for translation event. - void Set3dMouseTranslationScale (float theScale) { my3dMouseAccelTrans = theScale; } - - //! Return acceleration ratio for rotation event; 4.0 by default. - float Get3dMouseRotationScale() const { return my3dMouseAccelRotate; } - - //! Set acceleration ratio for rotation event. - void Set3dMouseRotationScale (float theScale) { my3dMouseAccelRotate = theScale; } - - //! Return quadric acceleration flag; TRUE by default. - bool To3dMousePreciseInput() const { return my3dMouseIsQuadric; } - - //! Set quadric acceleration flag. - void Set3dMousePreciseInput (bool theIsQuadric) { my3dMouseIsQuadric = theIsQuadric; } - - //! Return 3d mouse rotation axes (tilt/roll/spin) ignore flag; (FALSE, FALSE, FALSE) by default. - const NCollection_Vec3& Get3dMouseIsNoRotate() const { return my3dMouseNoRotate; } - - //! Return 3d mouse rotation axes (tilt/roll/spin) ignore flag; (FALSE, FALSE, FALSE) by default. - NCollection_Vec3& Change3dMouseIsNoRotate() { return my3dMouseNoRotate; } + //! Process 3d mouse input event (redirects to translation, rotation and keys). + Standard_EXPORT virtual bool Update3dMouse (const WNT_HIDSpaceMouse& theEvent) Standard_OVERRIDE; - //! Return 3d mouse rotation axes (tilt/roll/spin) reverse flag; (TRUE, FALSE, FALSE) by default. - const NCollection_Vec3& Get3dMouseToReverse() const { return my3dMouseToReverse; } +public: //! @name resize events - //! Return 3d mouse rotation axes (tilt/roll/spin) reverse flag; (TRUE, FALSE, FALSE) by default. - NCollection_Vec3& Change3dMouseToReverse() { return my3dMouseToReverse; } + //! Handle expose event (window content has been invalidation and should be redrawn). + //! Default implementation does nothing. + virtual void ProcessExpose() Standard_OVERRIDE {} - //! Process 3d mouse input event (redirects to translation, rotation and keys). - Standard_EXPORT virtual bool Update3dMouse (const WNT_HIDSpaceMouse& theEvent); + //! Handle window resize event. + //! Default implementation does nothing. + virtual void ProcessConfigure (bool theIsResized) Standard_OVERRIDE + { + (void )theIsResized; + } - //! Process 3d mouse input translation event. - Standard_EXPORT virtual bool update3dMouseTranslation (const WNT_HIDSpaceMouse& theEvent); + //! Handle window input event immediately. + //! Default implementation does nothing - input events are accumulated in internal buffer until explicit FlushViewEvents() call. + virtual void ProcessInput() Standard_OVERRIDE {} - //! Process 3d mouse input rotation event. - Standard_EXPORT virtual bool update3dMouseRotation (const WNT_HIDSpaceMouse& theEvent); + //! Handle focus event. + //! Default implementation does nothing. + virtual void ProcessFocus (bool theIsActivated) + { + (void )theIsActivated; + } - //! Process 3d mouse input keys event. - Standard_EXPORT virtual bool update3dMouseKeys (const WNT_HIDSpaceMouse& theEvent); + //! Handle window close event. + //! Default implementation does nothing. + virtual void ProcessClose() {} public: - //! Return event time (e.g. current time). - double EventTime() const { return myEventTimer.ElapsedTime(); } + using Aspect_WindowInputListener::EventTime; //! Reset input state (pressed keys, mouse buttons, etc.) e.g. on window focus loss. //! This method is expected to be called from UI thread. @@ -712,7 +666,6 @@ protected: AIS_ViewInputBuffer myUI; //!< buffer for UI thread AIS_ViewInputBuffer myGL; //!< buffer for rendering thread - OSD_Timer myEventTimer; //!< timer for timestamping events Standard_Real myLastEventsTime; //!< last fetched events timer value for computing delta/progress Standard_Boolean myToAskNextFrame; //!< flag indicating that another frame should be drawn right after this one @@ -764,10 +717,6 @@ protected: //! @name XR input variables Standard_Boolean myToDisplayXRAuxDevices; //!< flag to display auxiliary tracked XR devices Standard_Boolean myToDisplayXRHands; //!< flag to display XR hands -protected: //! @name keyboard input variables - - Aspect_VKeySet myKeys; //!< keyboard state - protected: //! @name mouse input variables Standard_Real myMouseClickThreshold; //!< mouse click threshold in pixels; 3 by default @@ -779,13 +728,10 @@ protected: //! @name mouse input variables AIS_MouseSelectionSchemeMap myMouseSelectionSchemes; //!< map defining selection schemes bound to mouse + modifiers Standard_Boolean myMouseActiveIdleRotation; //!< flag indicating view idle rotation state - Graphic3d_Vec2i myMousePositionLast; //!< last mouse position Graphic3d_Vec2i myMousePressPoint; //!< mouse position where active gesture was been initiated Graphic3d_Vec2i myMouseProgressPoint; //!< gesture progress OSD_Timer myMouseClickTimer; //!< timer for handling double-click event Standard_Integer myMouseClickCounter; //!< counter for handling double-click event - Aspect_VKeyMouse myMousePressed; //!< active mouse buttons - Aspect_VKeyFlags myMouseModifiers; //!< active key modifiers passed with last mouse event Standard_Integer myMouseSingleButton; //!< index of mouse button pressed alone (>0) Standard_Boolean myMouseStopDragOnUnclick; //!< queue stop dragging even with at next mouse unclick @@ -806,15 +752,6 @@ protected: //! @name multi-touch input variables Standard_Boolean myUpdateStartPointRot; //!< flag indicating that new gravity point should be picked for starting rotation gesture Standard_Boolean myUpdateStartPointZRot; //!< flag indicating that new gravity point should be picked for starting Z-rotation gesture -protected: //! @name 3d mouse input variables - - bool my3dMouseButtonState[32];//!< cached button state - NCollection_Vec3 my3dMouseNoRotate; //!< ignore 3d mouse rotation axes - NCollection_Vec3 my3dMouseToReverse; //!< reverse 3d mouse rotation axes - float my3dMouseAccelTrans; //!< acceleration ratio for translation event - float my3dMouseAccelRotate; //!< acceleration ratio for rotation event - bool my3dMouseIsQuadric; //!< quadric acceleration - protected: //! @name rotation/panning transient state variables Handle(AIS_Point) myAnchorPointPrs1; //!< anchor point presentation (Graphic3d_ZLayerId_Top) diff --git a/src/Aspect/Aspect_WindowInputListener.cxx b/src/Aspect/Aspect_WindowInputListener.cxx new file mode 100644 index 0000000000..ed6478b812 --- /dev/null +++ b/src/Aspect/Aspect_WindowInputListener.cxx @@ -0,0 +1,168 @@ +// Copyright (c) 2021 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include + +// ======================================================================= +// function : Aspect_WindowInputListener +// purpose : +// ======================================================================= +Aspect_WindowInputListener::Aspect_WindowInputListener() +: myMousePressed (Aspect_VKeyMouse_NONE), + myMouseModifiers (Aspect_VKeyFlags_NONE), + // + my3dMouseNoRotate (false, false, false), + my3dMouseToReverse (true, false, false), + my3dMouseAccelTrans (2.0f), + my3dMouseAccelRotate (4.0f), + my3dMouseIsQuadric (true) +{ + memset(my3dMouseButtonState, 0, sizeof(my3dMouseButtonState)); + myEventTimer.Start(); +} + +// ======================================================================= +// function : ~Aspect_WindowInputListener +// purpose : +// ======================================================================= +Aspect_WindowInputListener::~Aspect_WindowInputListener() +{ + // +} + +// ======================================================================= +// function : KeyDown +// purpose : +// ======================================================================= +void Aspect_WindowInputListener::KeyDown (Aspect_VKey theKey, + double theTime, + double thePressure) +{ + myKeys.KeyDown (theKey, theTime, thePressure); +} + +// ======================================================================= +// function : KeyUp +// purpose : +// ======================================================================= +void Aspect_WindowInputListener::KeyUp (Aspect_VKey theKey, + double theTime) +{ + myKeys.KeyUp (theKey, theTime); +} + +// ======================================================================= +// function : KeyFromAxis +// purpose : +// ======================================================================= +void Aspect_WindowInputListener::KeyFromAxis (Aspect_VKey theNegative, + Aspect_VKey thePositive, + double theTime, + double thePressure) +{ + myKeys.KeyFromAxis (theNegative, thePositive, theTime, thePressure); +} + +// ======================================================================= +// function : update3dMouseTranslation +// purpose : +// ======================================================================= +bool Aspect_WindowInputListener::update3dMouseTranslation (const WNT_HIDSpaceMouse& theEvent) +{ + if (!theEvent.IsTranslation()) + { + return false; + } + + bool isIdle = true; + const double aTimeStamp = EventTime(); + const Graphic3d_Vec3d aTrans = theEvent.Translation (isIdle, my3dMouseIsQuadric) * my3dMouseAccelTrans; + myKeys.KeyFromAxis (Aspect_VKey_NavSlideLeft, Aspect_VKey_NavSlideRight, aTimeStamp, aTrans.x()); + myKeys.KeyFromAxis (Aspect_VKey_NavForward, Aspect_VKey_NavBackward, aTimeStamp, aTrans.y()); + myKeys.KeyFromAxis (Aspect_VKey_NavSlideUp, Aspect_VKey_NavSlideDown, aTimeStamp, aTrans.z()); + return true; +} + +// ======================================================================= +// function : update3dMouseRotation +// purpose : +// ======================================================================= +bool Aspect_WindowInputListener::update3dMouseRotation (const WNT_HIDSpaceMouse& theEvent) +{ + if (!theEvent.IsRotation()) + { + return false; + } + + bool isIdle = true, toUpdate = false; + const double aTimeStamp = EventTime(); + const Graphic3d_Vec3d aRot3 = theEvent.Rotation (isIdle, my3dMouseIsQuadric) * my3dMouseAccelRotate; + if (!my3dMouseNoRotate.x()) + { + KeyFromAxis (Aspect_VKey_NavLookUp, Aspect_VKey_NavLookDown, aTimeStamp, !my3dMouseToReverse.x() ? aRot3.x() : -aRot3.x()); + toUpdate = true; + } + if (!my3dMouseNoRotate.y()) + { + KeyFromAxis (Aspect_VKey_NavRollCW, Aspect_VKey_NavRollCCW, aTimeStamp, !my3dMouseToReverse.y() ? aRot3.y() : -aRot3.y()); + toUpdate = true; + } + if (!my3dMouseNoRotate.z()) + { + KeyFromAxis (Aspect_VKey_NavLookLeft, Aspect_VKey_NavLookRight, aTimeStamp, !my3dMouseToReverse.z() ? aRot3.z() : -aRot3.z()); + toUpdate = true; + } + return toUpdate; +} + +// ======================================================================= +// function : update3dMouseKeys +// purpose : +// ======================================================================= +bool Aspect_WindowInputListener::update3dMouseKeys (const WNT_HIDSpaceMouse& theEvent) +{ + bool toUpdate = false; + const double aTimeStamp = EventTime(); + if (theEvent.IsKeyState()) + { + const uint32_t aKeyState = theEvent.KeyState(); + for (unsigned short aKeyBit = 0; aKeyBit < 32; ++aKeyBit) + { + const bool isPressed = (aKeyState & (1 << aKeyBit)) != 0; + const bool isReleased = my3dMouseButtonState[aKeyBit] && !isPressed; + //const bool isRepeated = my3dMouseButtonState[aKeyBit] && isPressed; + my3dMouseButtonState[aKeyBit] = isPressed; + if (!isReleased && !isPressed) + { + continue; + } + + const Aspect_VKey aVKey = theEvent.HidToSpaceKey (aKeyBit); + if (aVKey != Aspect_VKey_UNKNOWN) + { + toUpdate = true; + if (isPressed) + { + KeyDown (aVKey, aTimeStamp); + } + else + { + KeyUp (aVKey, aTimeStamp); + } + } + } + } + return toUpdate; +} diff --git a/src/Aspect/Aspect_WindowInputListener.hxx b/src/Aspect/Aspect_WindowInputListener.hxx new file mode 100644 index 0000000000..88e8825e71 --- /dev/null +++ b/src/Aspect/Aspect_WindowInputListener.hxx @@ -0,0 +1,236 @@ +// Copyright (c) 2021 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Aspect_WindowInputListener_HeaderFile +#define _Aspect_WindowInputListener_HeaderFile + +#include +#include +#include +#include + +struct Aspect_ScrollDelta; +class WNT_HIDSpaceMouse; + +//! Defines a listener for window input events. +class Aspect_WindowInputListener +{ +public: + ///DEFINE_STANDARD_ALLOC +public: + + //! Destructor. + Standard_EXPORT virtual ~Aspect_WindowInputListener(); + + //! Return event time (e.g. current time). + double EventTime() const { return myEventTimer.ElapsedTime(); } + + //! Handle expose event (window content has been invalidation and should be redrawn). + virtual void ProcessExpose() = 0; + + //! Handle window resize event. + virtual void ProcessConfigure (bool theIsResized) = 0; + + //! Handle window input event immediately (flush input buffer or ignore). + virtual void ProcessInput() = 0; + + //! Handle focus event. + virtual void ProcessFocus (bool theIsActivated) = 0; + + //! Handle window close event. + virtual void ProcessClose() = 0; + +public: //! @name keyboard input + + //! Return keyboard state. + const Aspect_VKeySet& Keys() const { return myKeys; } + + //! Return keyboard state. + Aspect_VKeySet& ChangeKeys() { return myKeys; } + + //! Press key. + //! Default implementation updates internal cache. + //! @param theKey key pressed + //! @param theTime event timestamp + Standard_EXPORT virtual void KeyDown (Aspect_VKey theKey, + double theTime, + double thePressure = 1.0) = 0; + + //! Release key. + //! Default implementation updates internal cache. + //! @param theKey key pressed + //! @param theTime event timestamp + Standard_EXPORT virtual void KeyUp (Aspect_VKey theKey, + double theTime) = 0; + + //! Simulate key up/down events from axis value. + //! Default implementation updates internal cache. + Standard_EXPORT virtual void KeyFromAxis (Aspect_VKey theNegative, + Aspect_VKey thePositive, + double theTime, + double thePressure) = 0; + +public: //! @name mouse input + + //! Update mouse scroll event. + //! This method is expected to be called from UI thread. + //! @param theDelta mouse cursor position and delta + //! @return TRUE if new event has been created or FALSE if existing one has been updated + virtual bool UpdateMouseScroll (const Aspect_ScrollDelta& theDelta) = 0; + + //! Handle mouse button press/release event. + //! This method is expected to be called from UI thread. + //! @param thePoint mouse cursor position + //! @param theButtons pressed buttons + //! @param theModifiers key modifiers + //! @param theIsEmulated if TRUE then mouse event comes NOT from real mouse + //! but emulated from non-precise input like touch on screen + //! @return TRUE if window content should be redrawn + virtual bool UpdateMouseButtons (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButtons, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated) = 0; + + //! Handle mouse cursor movement event. + //! This method is expected to be called from UI thread. + //! Default implementation does nothing. + //! @param thePoint mouse cursor position + //! @param theButtons pressed buttons + //! @param theModifiers key modifiers + //! @param theIsEmulated if TRUE then mouse event comes NOT from real mouse + //! but emulated from non-precise input like touch on screen + //! @return TRUE if window content should be redrawn + virtual bool UpdateMousePosition (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButtons, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated) = 0; + + //! Handle mouse button press event. + //! This method is expected to be called from UI thread. + //! Default implementation redirects to UpdateMousePosition(). + //! @param thePoint mouse cursor position + //! @param theButton pressed button + //! @param theModifiers key modifiers + //! @param theIsEmulated if TRUE then mouse event comes NOT from real mouse + //! but emulated from non-precise input like touch on screen + //! @return TRUE if window content should be redrawn + bool PressMouseButton (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButton, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated) + { + return UpdateMouseButtons (thePoint, myMousePressed | theButton, theModifiers, theIsEmulated); + } + + //! Handle mouse button release event. + //! This method is expected to be called from UI thread. + //! Default implementation redirects to UpdateMousePosition(). + //! @param thePoint mouse cursor position + //! @param theButton released button + //! @param theModifiers key modifiers + //! @param theIsEmulated if TRUE then mouse event comes NOT from real mouse + //! but emulated from non-precise input like touch on screen + //! @return TRUE if window content should be redrawn + bool ReleaseMouseButton (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButton, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated) + { + Aspect_VKeyMouse aButtons = myMousePressed & (~theButton); + return UpdateMouseButtons (thePoint, aButtons, theModifiers, theIsEmulated); + } + + //! Return currently pressed mouse buttons. + Aspect_VKeyMouse PressedMouseButtons() const { return myMousePressed; } + + //! Return active key modifiers passed with last mouse event. + Aspect_VKeyFlags LastMouseFlags() const { return myMouseModifiers; } + + //! Return last mouse position. + const Graphic3d_Vec2i& LastMousePosition() const { return myMousePositionLast; } + +public: //! @name 3d mouse input + + //! Return acceleration ratio for translation event; 2.0 by default. + float Get3dMouseTranslationScale() const { return my3dMouseAccelTrans; } + + //! Set acceleration ratio for translation event. + void Set3dMouseTranslationScale (float theScale) { my3dMouseAccelTrans = theScale; } + + //! Return acceleration ratio for rotation event; 4.0 by default. + float Get3dMouseRotationScale() const { return my3dMouseAccelRotate; } + + //! Set acceleration ratio for rotation event. + void Set3dMouseRotationScale (float theScale) { my3dMouseAccelRotate = theScale; } + + //! Return quadric acceleration flag; TRUE by default. + bool To3dMousePreciseInput() const { return my3dMouseIsQuadric; } + + //! Set quadric acceleration flag. + void Set3dMousePreciseInput (bool theIsQuadric) { my3dMouseIsQuadric = theIsQuadric; } + + //! Return 3d mouse rotation axes (tilt/roll/spin) ignore flag; (FALSE, FALSE, FALSE) by default. + const NCollection_Vec3& Get3dMouseIsNoRotate() const { return my3dMouseNoRotate; } + + //! Return 3d mouse rotation axes (tilt/roll/spin) ignore flag; (FALSE, FALSE, FALSE) by default. + NCollection_Vec3& Change3dMouseIsNoRotate() { return my3dMouseNoRotate; } + + //! Return 3d mouse rotation axes (tilt/roll/spin) reverse flag; (TRUE, FALSE, FALSE) by default. + const NCollection_Vec3& Get3dMouseToReverse() const { return my3dMouseToReverse; } + + //! Return 3d mouse rotation axes (tilt/roll/spin) reverse flag; (TRUE, FALSE, FALSE) by default. + NCollection_Vec3& Change3dMouseToReverse() { return my3dMouseToReverse; } + + //! Process 3d mouse input event (redirects to translation, rotation and keys). + virtual bool Update3dMouse (const WNT_HIDSpaceMouse& theEvent) = 0; + + //! Process 3d mouse input translation event. + Standard_EXPORT virtual bool update3dMouseTranslation (const WNT_HIDSpaceMouse& theEvent); + + //! Process 3d mouse input rotation event. + Standard_EXPORT virtual bool update3dMouseRotation (const WNT_HIDSpaceMouse& theEvent); + + //! Process 3d mouse input keys event. + Standard_EXPORT virtual bool update3dMouseKeys (const WNT_HIDSpaceMouse& theEvent); + +protected: + + //! Empty constructor. + Standard_EXPORT Aspect_WindowInputListener(); + +protected: + + OSD_Timer myEventTimer; //!< timer for timestamping events + +protected: //! @name keyboard input variables + + Aspect_VKeySet myKeys; //!< keyboard state + +protected: //! @name mouse input variables + + Graphic3d_Vec2i myMousePositionLast; //!< last mouse position + Aspect_VKeyMouse myMousePressed; //!< active mouse buttons + Aspect_VKeyFlags myMouseModifiers; //!< active key modifiers passed with last mouse event + +protected: //! @name 3d mouse input variables + + bool my3dMouseButtonState[32];//!< cached button state + NCollection_Vec3 my3dMouseNoRotate; //!< ignore 3d mouse rotation axes + NCollection_Vec3 my3dMouseToReverse; //!< reverse 3d mouse rotation axes + float my3dMouseAccelTrans; //!< acceleration ratio for translation event + float my3dMouseAccelRotate; //!< acceleration ratio for rotation event + bool my3dMouseIsQuadric; //!< quadric acceleration + +}; + +#endif // _Aspect_WindowInputListener_HeaderFile diff --git a/src/Aspect/FILES b/src/Aspect/FILES index 8f18be03e9..112a2d4207 100755 --- a/src/Aspect/FILES +++ b/src/Aspect/FILES @@ -66,6 +66,8 @@ Aspect_Window.cxx Aspect_Window.hxx Aspect_WindowDefinitionError.hxx Aspect_WindowError.hxx +Aspect_WindowInputListener.cxx +Aspect_WindowInputListener.hxx Aspect_XAtom.hxx Aspect_XRAction.hxx Aspect_XRActionSet.hxx diff --git a/src/ViewerTest/ViewerTest_EventManager.cxx b/src/ViewerTest/ViewerTest_EventManager.cxx index a1e5837ce3..2a2ed2f2f0 100644 --- a/src/ViewerTest/ViewerTest_EventManager.cxx +++ b/src/ViewerTest/ViewerTest_EventManager.cxx @@ -167,15 +167,36 @@ void ViewerTest_EventManager::handleViewRedraw (const Handle(AIS_InteractiveCont //function : ProcessConfigure //purpose : //============================================================================== -void ViewerTest_EventManager::ProcessConfigure() +void ViewerTest_EventManager::ProcessConfigure (bool theIsResized) { if (!myView.IsNull()) { + if (!theIsResized + // track window moves to reverse stereo pair + && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_RowInterlaced + && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_ColumnInterlaced + && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_ChessBoard) + { + return; + } + myView->MustBeResized(); FlushViewEvents (myCtx, myView, true); } } +//============================================================================== +//function : ProcessInput +//purpose : +//============================================================================== +void ViewerTest_EventManager::ProcessInput() +{ + if (!myView.IsNull()) + { + FlushViewEvents (myCtx, myView, true); + } +} + // ======================================================================= // function : navigationKeyModifierSwitch // purpose : diff --git a/src/ViewerTest/ViewerTest_EventManager.hxx b/src/ViewerTest/ViewerTest_EventManager.hxx index 2f1fc87d8c..4b545988ce 100644 --- a/src/ViewerTest/ViewerTest_EventManager.hxx +++ b/src/ViewerTest/ViewerTest_EventManager.hxx @@ -91,14 +91,17 @@ public: double theTime) Standard_OVERRIDE; //! Redraw the View on an Expose Event - Standard_EXPORT virtual void ProcessExpose(); + Standard_EXPORT virtual void ProcessExpose() Standard_OVERRIDE; //! Handle redraw. Standard_EXPORT virtual void handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx, const Handle(V3d_View)& theView) Standard_OVERRIDE; //! Resize View. - Standard_EXPORT virtual void ProcessConfigure(); + Standard_EXPORT virtual void ProcessConfigure (bool theIsResized = true) Standard_OVERRIDE; + + //! Handle window input event immediately (flush input buffer). + Standard_EXPORT virtual void ProcessInput() Standard_OVERRIDE; //! Handle KeyPress event. Standard_EXPORT void ProcessKeyPress (Aspect_VKey theKey); diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index e67e667bba..ee7db32660 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -1390,19 +1390,9 @@ namespace //============================================================================== #ifdef _WIN32 -static LRESULT WINAPI ViewerWindowProc( - HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam ); -static LRESULT WINAPI AdvViewerWindowProc( - HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam ); +static LRESULT WINAPI AdvViewerWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); #endif - //============================================================================== //function : WClass //purpose : @@ -3247,7 +3237,7 @@ static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle, { if (ViewerTest_myViews.IsEmpty()) { - return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam); + return DefWindowProcW (theWinHandle, theMsg, wParam, lParam); } switch (theMsg) @@ -3271,215 +3261,32 @@ static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle, ActivateView (FindViewIdByWindowHandle (theWinHandle)); } } - break; - } - default: - { - return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam); - } - } - return 0; -} - -static LRESULT WINAPI ViewerWindowProc (HWND theWinHandle, - UINT theMsg, - WPARAM wParam, - LPARAM lParam) -{ - const Handle(V3d_View)& aView = ViewerTest::CurrentView(); - if (aView.IsNull()) - { - return DefWindowProcW (theWinHandle, theMsg, wParam, lParam); - } - - switch (theMsg) - { - case WM_PAINT: - { - PAINTSTRUCT aPaint; - BeginPaint(theWinHandle, &aPaint); - EndPaint (theWinHandle, &aPaint); - ViewerTest::CurrentEventManager()->ProcessExpose(); - break; - } - case WM_SIZE: - { - ViewerTest::CurrentEventManager()->ProcessConfigure(); - break; - } - case WM_MOVE: - case WM_MOVING: - case WM_SIZING: - { - switch (aView->RenderingParams().StereoMode) - { - case Graphic3d_StereoMode_RowInterlaced: - case Graphic3d_StereoMode_ColumnInterlaced: - case Graphic3d_StereoMode_ChessBoard: - { - // track window moves to reverse stereo pair - aView->MustBeResized(); - aView->Update(); - break; - } - default: - break; - } - break; - } - case WM_KEYUP: - case WM_KEYDOWN: - { - const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )wParam); - if (aVKey != Aspect_VKey_UNKNOWN) - { - const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime(); - if (theMsg == WM_KEYDOWN) - { - ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp); - } - else - { - ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp); - } - ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); - } - break; + return 0; } - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: { - const Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam)); - const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam); - Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE; - switch (theMsg) - { - case WM_LBUTTONUP: - case WM_LBUTTONDOWN: - aButton = Aspect_VKeyMouse_LeftButton; - break; - case WM_MBUTTONUP: - case WM_MBUTTONDOWN: - aButton = Aspect_VKeyMouse_MiddleButton; - break; - case WM_RBUTTONUP: - case WM_RBUTTONDOWN: - aButton = Aspect_VKeyMouse_RightButton; - break; - } - if (theMsg == WM_LBUTTONDOWN - || theMsg == WM_MBUTTONDOWN - || theMsg == WM_RBUTTONDOWN) - { - if (aButton == Aspect_VKeyMouse_LeftButton) - { - TheIsAnimating = Standard_False; - } - - SetFocus (theWinHandle); - SetCapture(theWinHandle); - ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false); - } - else - { - ReleaseCapture(); - ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false); - } - ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); - break; + TheIsAnimating = Standard_False; } - case WM_MOUSEWHEEL: - { - const int aDelta = GET_WHEEL_DELTA_WPARAM (wParam); - const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA); - const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam); - Graphic3d_Vec2i aPos (int(short(LOWORD(lParam))), int(short(HIWORD(lParam)))); - POINT aCursorPnt = { aPos.x(), aPos.y() }; - if (ScreenToClient (theWinHandle, &aCursorPnt)) - { - aPos.SetValues (aCursorPnt.x, aCursorPnt.y); - } - - ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags)); - ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); - break; - } - case WM_MOUSEMOVE: + Standard_FALLTHROUGH + default: { - Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam)); - Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (wParam); - Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent(wParam); - - // don't make a slide-show from input events - fetch the actual mouse cursor position - CURSORINFO aCursor; - aCursor.cbSize = sizeof(aCursor); - if (::GetCursorInfo (&aCursor) != FALSE) + const Handle(V3d_View)& aView = ViewerTest::CurrentView(); + if (!aView.IsNull() + && !VT_GetWindow().IsNull()) { - POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y }; - if (ScreenToClient (theWinHandle, &aCursorPnt)) + MSG aMsg = {}; + aMsg.hwnd = theWinHandle; + aMsg.message = theMsg; + aMsg.wParam = wParam; + aMsg.lParam = lParam; + if (VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aMsg)) { - // as we override mouse position, we need overriding also mouse state - aPos.SetValues (aCursorPnt.x, aCursorPnt.y); - aButtons = WNT_Window::MouseButtonsAsync(); - aFlags = WNT_Window::MouseKeyFlagsAsync(); + return 0; } } - - if (VT_GetWindow().IsNull() - || (HWND )VT_GetWindow()->HWindow() != theWinHandle) - { - // mouse move events come also for inactive windows - break; - } - - ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false); - ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true); - break; - } - case WM_INPUT: - { - UINT aSize = 0; - ::GetRawInputData ((HRAWINPUT )lParam, RID_INPUT, NULL, &aSize, sizeof(RAWINPUTHEADER)); - NCollection_LocalArray aRawData (aSize); - if (aSize == 0 || ::GetRawInputData ((HRAWINPUT )lParam, RID_INPUT, aRawData, &aSize, sizeof(RAWINPUTHEADER)) != aSize) - { - break; - } - - const RAWINPUT* aRawInput = (RAWINPUT* )(BYTE* )aRawData; - if (aRawInput->header.dwType != RIM_TYPEHID) - { - break; - } - - RID_DEVICE_INFO aDevInfo; - aDevInfo.cbSize = sizeof(RID_DEVICE_INFO); - UINT aDevInfoSize = sizeof(RID_DEVICE_INFO); - if (::GetRawInputDeviceInfoW (aRawInput->header.hDevice, RIDI_DEVICEINFO, &aDevInfo, &aDevInfoSize) != sizeof(RID_DEVICE_INFO) - || (aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_LOGITECH - && aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_3DCONNEXION)) - { - break; - } - - WNT_HIDSpaceMouse aSpaceData (aDevInfo.hid.dwProductId, aRawInput->data.hid.bRawData, aRawInput->data.hid.dwSizeHid); - if (ViewerTest::CurrentEventManager()->Update3dMouse (aSpaceData) - && !VT_GetWindow().IsNull()) - { - VT_GetWindow()->InvalidateContent(); - } - break; - } - default: - { - return DefWindowProcW (theWinHandle, theMsg, wParam, lParam); } } - return 0L; + return DefWindowProcW (theWinHandle, theMsg, wParam, lParam); } //============================================================================== @@ -3518,22 +3325,6 @@ int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec) #elif !defined(__APPLE__) || defined(MACOSX_USE_GLX) -int min( int a, int b ) -{ - if( ab ) - return a; - else - return b; -} - int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec) { static XEvent aReport; @@ -3573,170 +3364,22 @@ int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec) } break; } - case Expose: - { - Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0; - if (anXWindow == aReport.xexpose.window) - { - ViewerTest::CurrentEventManager()->ProcessExpose(); - } - - // remove all the ExposureMask and process them at once - for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents) - { - if (!XCheckWindowEvent (aDisplay, anXWindow, ExposureMask, &aReport)) - { - break; - } - } - - break; - } - case ConfigureNotify: - { - // remove all the StructureNotifyMask and process them at once - Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0; - for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents) - { - if (!XCheckWindowEvent (aDisplay, anXWindow, StructureNotifyMask, &aReport)) - { - break; - } - } - - if (anXWindow == aReport.xconfigure.window) - { - ViewerTest::CurrentEventManager()->ProcessConfigure(); - } - break; - } - case KeyPress: - case KeyRelease: - { - XKeyEvent* aKeyEvent = (XKeyEvent* )&aReport; - const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0); - const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym); - if (aVKey != Aspect_VKey_UNKNOWN) - { - const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime(); - if (aReport.type == KeyPress) - { - ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp); - } - else - { - ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp); - } - ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); - } - break; - } case ButtonPress: - case ButtonRelease: { - const Graphic3d_Vec2i aPos (aReport.xbutton.x, aReport.xbutton.y); - Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; - Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE; if (aReport.xbutton.button == Button1) { - aButton = Aspect_VKeyMouse_LeftButton; + TheIsAnimating = Standard_False; } - if (aReport.xbutton.button == Button2) - { - aButton = Aspect_VKeyMouse_MiddleButton; - } - if (aReport.xbutton.button == Button3) - { - aButton = Aspect_VKeyMouse_RightButton; - } - - if (aReport.xbutton.state & ControlMask) - { - aFlags |= Aspect_VKeyFlags_CTRL; - } - if (aReport.xbutton.state & ShiftMask) - { - aFlags |= Aspect_VKeyFlags_SHIFT; - } - if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt)) - { - aFlags |= Aspect_VKeyFlags_ALT; - } - - if (aReport.xbutton.button == Button4 - || aReport.xbutton.button == Button5) - { - if (aReport.type != ButtonPress) - { - break; - } - - const double aDeltaF = (aReport.xbutton.button == Button4 ? 1.0 : -1.0); - ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags)); - } - else if (aReport.type == ButtonPress) - { - if (aButton == Aspect_VKeyMouse_LeftButton) - { - TheIsAnimating = Standard_False; - } - ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false); - } - else - { - ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false); - } - ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); - break; } - case MotionNotify: + Standard_FALLTHROUGH + default: { - Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0; - if (anXWindow != aReport.xmotion.window) - { - break; - } - - // remove all the ButtonMotionMask and process them at once - for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents) - { - if (!XCheckWindowEvent (aDisplay, anXWindow, ButtonMotionMask | PointerMotionMask, &aReport)) - { - break; - } - } - - Graphic3d_Vec2i aPos (aReport.xmotion.x, aReport.xmotion.y); - Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE; - Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; - if ((aReport.xmotion.state & Button1Mask) != 0) + const Handle(V3d_View)& aView = ViewerTest::CurrentView(); + if (!aView.IsNull() + && !VT_GetWindow().IsNull()) { - aButtons |= Aspect_VKeyMouse_LeftButton; + VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aReport); } - else if ((aReport.xmotion.state & Button2Mask) != 0) - { - aButtons |= Aspect_VKeyMouse_MiddleButton; - } - else if ((aReport.xmotion.state & Button3Mask) != 0) - { - aButtons |= Aspect_VKeyMouse_RightButton; - } - - if (aReport.xmotion.state & ControlMask) - { - aFlags |= Aspect_VKeyFlags_CTRL; - } - if (aReport.xmotion.state & ShiftMask) - { - aFlags |= Aspect_VKeyFlags_SHIFT; - } - if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt)) - { - aFlags |= Aspect_VKeyFlags_ALT; - } - - ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false); - ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); break; } } diff --git a/src/WNT/FILES b/src/WNT/FILES index 0d1163e4ef..e323ce0ef5 100755 --- a/src/WNT/FILES +++ b/src/WNT/FILES @@ -7,5 +7,4 @@ WNT_WClass.cxx WNT_WClass.hxx WNT_Window.cxx WNT_Window.hxx -WNT_Window.lxx WNT_WindowPtr.hxx diff --git a/src/WNT/WNT_Window.cxx b/src/WNT/WNT_Window.cxx index 64086200a9..8f9ed39f2a 100644 --- a/src/WNT/WNT_Window.cxx +++ b/src/WNT/WNT_Window.cxx @@ -22,12 +22,15 @@ #if defined(_WIN32) && !defined(OCCT_UWP) #include +#include #include #include +#include #include -#include +#include #include #include +#include IMPLEMENT_STANDARD_RTTIEXT(WNT_Window, Aspect_Window) @@ -47,11 +50,13 @@ WNT_Window::WNT_Window (const Standard_CString theTitle, const Aspect_Handle theMenu, const Standard_Address theClientStruct) : Aspect_Window(), - aXLeft (thePxLeft), - aYTop (thePxTop), - aXRight (thePxLeft + thePxWidth), - aYBottom (thePxTop + thePxHeight), myWClass (theClass), + myHWindow (NULL), + myHParentWindow (NULL), + myXLeft (thePxLeft), + myYTop (thePxTop), + myXRight (thePxLeft + thePxWidth), + myYBottom (thePxTop + thePxHeight), myIsForeign (Standard_False) { if (thePxWidth <= 0 || thePxHeight <= 0) @@ -71,22 +76,22 @@ WNT_Window::WNT_Window (const Standard_CString theTitle, // include decorations in the window dimensions to reproduce same behavior of Xw_Window RECT aRect; - aRect.top = aYTop; - aRect.bottom = aYBottom; - aRect.left = aXLeft; - aRect.right = aXRight; + aRect.top = myYTop; + aRect.bottom = myYBottom; + aRect.left = myXLeft; + aRect.right = myXRight; AdjustWindowRect (&aRect, aStyle, theMenu != NULL ? TRUE : FALSE); - aXLeft = aRect.left; - aYTop = aRect.top; - aXRight = aRect.right; - aYBottom = aRect.bottom; + myXLeft = aRect.left; + myYTop = aRect.top; + myXRight = aRect.right; + myYBottom = aRect.bottom; const TCollection_ExtendedString aTitleW (theTitle); const TCollection_ExtendedString aClassNameW (myWClass->Name()); myHWindow = CreateWindowW (aClassNameW.ToWideString(), aTitleW.ToWideString(), aStyle, - aXLeft, aYTop, - (aXRight - aXLeft), (aYBottom - aYTop), + myXLeft, myYTop, + (myXRight - myXLeft), (myYBottom - myYTop), (HWND )theParent, (HMENU )theMenu, (HINSTANCE )myWClass->Instance(), @@ -106,21 +111,24 @@ WNT_Window::WNT_Window (const Standard_CString theTitle, // ======================================================================= WNT_Window::WNT_Window (const Aspect_Handle theHandle, const Quantity_NameOfColor theBackColor) -: myIsForeign (Standard_True) +: myHWindow (theHandle), + myHParentWindow (GetParent ((HWND )theHandle)), + myXLeft (0), + myYTop (0), + myXRight (0), + myYBottom (0), + myIsForeign (Standard_True) { - myHWindow = theHandle; - myHParentWindow = GetParent ((HWND )theHandle); - SetBackground (theBackColor); - WINDOWPLACEMENT aPlace; - aPlace.length = sizeof (WINDOWPLACEMENT); + WINDOWPLACEMENT aPlace = {}; + aPlace.length = sizeof(WINDOWPLACEMENT); ::GetWindowPlacement ((HWND )myHWindow, &aPlace); - aXLeft = aPlace.rcNormalPosition.left; - aYTop = aPlace.rcNormalPosition.top; - aXRight = aPlace.rcNormalPosition.right; - aYBottom = aPlace.rcNormalPosition.bottom; + myXLeft = aPlace.rcNormalPosition.left; + myYTop = aPlace.rcNormalPosition.top; + myXRight = aPlace.rcNormalPosition.right; + myYBottom = aPlace.rcNormalPosition.bottom; } // ======================================================================= @@ -159,8 +167,8 @@ Standard_Boolean WNT_Window::IsMapped() const return Standard_True; } - WINDOWPLACEMENT aPlace; - aPlace.length = sizeof (WINDOWPLACEMENT); + WINDOWPLACEMENT aPlace = {}; + aPlace.length = sizeof(WINDOWPLACEMENT); ::GetWindowPlacement ((HWND )myHWindow, &aPlace); return !(aPlace.showCmd == SW_HIDE || aPlace.showCmd == SW_MINIMIZE); @@ -213,60 +221,37 @@ Aspect_TypeOfResize WNT_Window::DoResize() return Aspect_TOR_UNKNOWN; } - int mask = 0; - Aspect_TypeOfResize mode = Aspect_TOR_UNKNOWN; - WINDOWPLACEMENT wp; - - wp.length = sizeof ( WINDOWPLACEMENT ); - GetWindowPlacement ( ( HWND )myHWindow, &wp ); - - if (wp.showCmd != SW_SHOWMINIMIZED) + WINDOWPLACEMENT aPlace = {}; + aPlace.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement ((HWND )myHWindow, &aPlace); + if (aPlace.showCmd == SW_SHOWMINIMIZED) { - if (Abs ((int )wp.rcNormalPosition.left - aXLeft ) > 2) mask |= 1; - if (Abs ((int )wp.rcNormalPosition.right - aXRight ) > 2) mask |= 2; - if (Abs ((int )wp.rcNormalPosition.top - aYTop ) > 2) mask |= 4; - if (Abs ((int )wp.rcNormalPosition.bottom - aYBottom) > 2) mask |= 8; + return Aspect_TOR_UNKNOWN; + } - switch (mask) - { - case 0: - mode = Aspect_TOR_NO_BORDER; - break; - case 1: - mode = Aspect_TOR_LEFT_BORDER; - break; - case 2: - mode = Aspect_TOR_RIGHT_BORDER; - break; - case 4: - mode = Aspect_TOR_TOP_BORDER; - break; - case 5: - mode = Aspect_TOR_LEFT_AND_TOP_BORDER; - break; - case 6: - mode = Aspect_TOR_TOP_AND_RIGHT_BORDER; - break; - case 8: - mode = Aspect_TOR_BOTTOM_BORDER; - break; - case 9: - mode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER; - break; - case 10: - mode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER; - break; - default: - break; - } // end switch - - aXLeft = wp.rcNormalPosition.left; - aXRight = wp.rcNormalPosition.right; - aYTop = wp.rcNormalPosition.top; - aYBottom = wp.rcNormalPosition.bottom; - } - - return mode; + int aMask = 0; + if (Abs ((int )aPlace.rcNormalPosition.left - myXLeft ) > 2) { aMask |= 1; } + if (Abs ((int )aPlace.rcNormalPosition.right - myXRight ) > 2) { aMask |= 2; } + if (Abs ((int )aPlace.rcNormalPosition.top - myYTop ) > 2) { aMask |= 4; } + if (Abs ((int )aPlace.rcNormalPosition.bottom - myYBottom) > 2) { aMask |= 8; } + + myXLeft = aPlace.rcNormalPosition.left; + myXRight = aPlace.rcNormalPosition.right; + myYTop = aPlace.rcNormalPosition.top; + myYBottom = aPlace.rcNormalPosition.bottom; + switch (aMask) + { + case 0: return Aspect_TOR_NO_BORDER; + case 1: return Aspect_TOR_LEFT_BORDER; + case 2: return Aspect_TOR_RIGHT_BORDER; + case 4: return Aspect_TOR_TOP_BORDER; + case 5: return Aspect_TOR_LEFT_AND_TOP_BORDER; + case 6: return Aspect_TOR_TOP_AND_RIGHT_BORDER; + case 8: return Aspect_TOR_BOTTOM_BORDER; + case 9: return Aspect_TOR_BOTTOM_AND_LEFT_BORDER; + case 10: return Aspect_TOR_RIGHT_AND_BOTTOM_BORDER; + } + return Aspect_TOR_UNKNOWN; } // ======================================================================= @@ -277,10 +262,10 @@ Standard_Real WNT_Window::Ratio() const { if (IsVirtual()) { - return Standard_Real(aXRight - aXLeft)/ Standard_Real(aYBottom - aYTop); + return Standard_Real(myXRight - myXLeft)/ Standard_Real(myYBottom - myYTop); } - RECT aRect; + RECT aRect = {}; GetClientRect ((HWND )myHWindow, &aRect); return Standard_Real(aRect.right - aRect.left) / Standard_Real(aRect.bottom - aRect.top); } @@ -294,14 +279,14 @@ void WNT_Window::Position (Standard_Integer& theX1, Standard_Integer& theY1, { if (IsVirtual()) { - theX1 = aXLeft; - theX2 = aXRight; - theY1 = aYTop; - theY2 = aYBottom; + theX1 = myXLeft; + theX2 = myXRight; + theY1 = myYTop; + theY2 = myYBottom; return; } - RECT aRect; + RECT aRect = {}; ::GetClientRect ((HWND )myHWindow, &aRect); POINT aPntLeft, aPntRight; @@ -332,12 +317,12 @@ void WNT_Window::Size (Standard_Integer& theWidth, { if (IsVirtual()) { - theWidth = aXRight - aXLeft; - theHeight = aYBottom - aYTop; + theWidth = myXRight - myXLeft; + theHeight = myYBottom - myYTop; return; } - RECT aRect; + RECT aRect = {}; ::GetClientRect ((HWND )myHWindow, &aRect); theWidth = aRect.right; theHeight = aRect.bottom; @@ -350,10 +335,10 @@ void WNT_Window::Size (Standard_Integer& theWidth, void WNT_Window::SetPos (const Standard_Integer theX, const Standard_Integer theY, const Standard_Integer theX1, const Standard_Integer theY1) { - aXLeft = theX; - aYTop = theY; - aXRight = theX1; - aYBottom = theY1; + myXLeft = theX; + myYTop = theY; + myXRight = theX1; + myYBottom = theY1; } // ======================================================================= @@ -699,4 +684,197 @@ int WNT_Window::RegisterRawInputDevices (unsigned int theRawDeviceMask) return 0; } +// ======================================================================= +// function : ProcessMessage +// purpose : +// ======================================================================= +bool WNT_Window::ProcessMessage (Aspect_WindowInputListener& theListener, + MSG& theMsg) +{ + switch (theMsg.message) + { + case WM_CLOSE: + { + if (theMsg.hwnd == (HWND )myHWindow) + { + theListener.ProcessClose(); + return true; + } + return false; + } + case WM_ACTIVATE: + { + if (theMsg.hwnd == (HWND )myHWindow) + { + theListener.ProcessFocus (LOWORD(theMsg.wParam) == WA_CLICKACTIVE + || LOWORD(theMsg.wParam) == WA_ACTIVE); + return true; + } + return false; + } + case WM_PAINT: + { + PAINTSTRUCT aPaint; + BeginPaint(theMsg.hwnd, &aPaint); + EndPaint (theMsg.hwnd, &aPaint); + theListener.ProcessExpose(); + return true; + } + case WM_SIZE: + case WM_MOVE: + case WM_MOVING: + case WM_SIZING: + { + theListener.ProcessConfigure (theMsg.message == WM_SIZE); + return true; + } + case WM_KEYUP: + case WM_KEYDOWN: + { + const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )theMsg.wParam); + if (aVKey != Aspect_VKey_UNKNOWN) + { + const double aTimeStamp = theListener.EventTime(); + if (theMsg.message == WM_KEYDOWN) + { + theListener.KeyDown (aVKey, aTimeStamp); + } + else + { + theListener.KeyUp (aVKey, aTimeStamp); + } + theListener.ProcessInput(); + } + return true; + } + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { + const Graphic3d_Vec2i aPos (LOWORD(theMsg.lParam), HIWORD(theMsg.lParam)); + const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (theMsg.wParam); + Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE; + switch (theMsg.message) + { + case WM_LBUTTONUP: + case WM_LBUTTONDOWN: + aButton = Aspect_VKeyMouse_LeftButton; + break; + case WM_MBUTTONUP: + case WM_MBUTTONDOWN: + aButton = Aspect_VKeyMouse_MiddleButton; + break; + case WM_RBUTTONUP: + case WM_RBUTTONDOWN: + aButton = Aspect_VKeyMouse_RightButton; + break; + } + if (theMsg.message == WM_LBUTTONDOWN + || theMsg.message == WM_MBUTTONDOWN + || theMsg.message == WM_RBUTTONDOWN) + { + SetFocus (theMsg.hwnd); + SetCapture(theMsg.hwnd); + theListener.PressMouseButton (aPos, aButton, aFlags, false); + } + else + { + ReleaseCapture(); + theListener.ReleaseMouseButton (aPos, aButton, aFlags, false); + } + theListener.ProcessInput(); + return true; + } + case WM_MOUSEWHEEL: + { + const int aDelta = GET_WHEEL_DELTA_WPARAM (theMsg.wParam); + const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA); + const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (theMsg.wParam); + Graphic3d_Vec2i aPos (int(short(LOWORD(theMsg.lParam))), int(short(HIWORD(theMsg.lParam)))); + POINT aCursorPnt = { aPos.x(), aPos.y() }; + if (ScreenToClient (theMsg.hwnd, &aCursorPnt)) + { + aPos.SetValues (aCursorPnt.x, aCursorPnt.y); + } + + if (theMsg.hwnd != (HWND )myHWindow) + { + return false; + } + + theListener.UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags)); + theListener.ProcessInput(); + return true; + } + case WM_MOUSEMOVE: + { + Graphic3d_Vec2i aPos (LOWORD(theMsg.lParam), HIWORD(theMsg.lParam)); + Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (theMsg.wParam); + Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent(theMsg.wParam); + + // don't make a slide-show from input events - fetch the actual mouse cursor position + CURSORINFO aCursor; + aCursor.cbSize = sizeof(aCursor); + if (::GetCursorInfo (&aCursor) != FALSE) + { + POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y }; + if (ScreenToClient (theMsg.hwnd, &aCursorPnt)) + { + // as we override mouse position, we need overriding also mouse state + aPos.SetValues (aCursorPnt.x, aCursorPnt.y); + aButtons = WNT_Window::MouseButtonsAsync(); + aFlags = WNT_Window::MouseKeyFlagsAsync(); + } + } + + if (theMsg.hwnd != (HWND )myHWindow) + { + // mouse move events come also for inactive windows + return false; + } + + theListener.UpdateMousePosition (aPos, aButtons, aFlags, false); + theListener.ProcessInput(); + return true; + } + case WM_INPUT: + { + UINT aSize = 0; + ::GetRawInputData ((HRAWINPUT )theMsg.lParam, RID_INPUT, NULL, &aSize, sizeof(RAWINPUTHEADER)); + NCollection_LocalArray aRawData (aSize); + if (aSize == 0 || ::GetRawInputData ((HRAWINPUT )theMsg.lParam, RID_INPUT, aRawData, &aSize, sizeof(RAWINPUTHEADER)) != aSize) + { + return true; + } + + const RAWINPUT* aRawInput = (RAWINPUT* )(BYTE* )aRawData; + if (aRawInput->header.dwType != RIM_TYPEHID) + { + return true; + } + + RID_DEVICE_INFO aDevInfo; + aDevInfo.cbSize = sizeof(RID_DEVICE_INFO); + UINT aDevInfoSize = sizeof(RID_DEVICE_INFO); + if (::GetRawInputDeviceInfoW (aRawInput->header.hDevice, RIDI_DEVICEINFO, &aDevInfo, &aDevInfoSize) != sizeof(RID_DEVICE_INFO) + || (aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_LOGITECH + && aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_3DCONNEXION)) + { + return true; + } + + WNT_HIDSpaceMouse aSpaceData (aDevInfo.hid.dwProductId, aRawInput->data.hid.bRawData, aRawInput->data.hid.dwSizeHid); + if (theListener.Update3dMouse (aSpaceData)) + { + InvalidateContent (Handle(Aspect_DisplayConnection)()); + } + return true; + } + } + return false; +} + #endif // _WIN32 diff --git a/src/WNT/WNT_Window.hxx b/src/WNT/WNT_Window.hxx index c056a5ef14..530ece407f 100644 --- a/src/WNT/WNT_Window.hxx +++ b/src/WNT/WNT_Window.hxx @@ -24,16 +24,18 @@ #include #include #include -#include #include +class Aspect_WindowInputListener; class WNT_WClass; +typedef struct tagMSG MSG; DEFINE_STANDARD_HANDLE(WNT_Window, Aspect_Window) //! This class defines Windows NT window class WNT_Window : public Aspect_Window { + DEFINE_STANDARD_RTTIEXT(WNT_Window, Aspect_Window) public: //! Convert WInAPI virtual key (VK_ enumeration) into Aspect_VKey. @@ -53,42 +55,45 @@ public: public: - //! Creates a Window defined by his position and size - //! in pixles from the Parent Window. - //! Trigger: Raises WindowDefinitionError if the Position out of the - //! Screen Space or the window creation failed. - Standard_EXPORT WNT_Window(const Standard_CString theTitle, const Handle(WNT_WClass)& theClass, const WNT_Dword& theStyle, const Standard_Integer thePxLeft, const Standard_Integer thePxTop, const Standard_Integer thePxWidth, const Standard_Integer thePxHeight, const Quantity_NameOfColor theBackColor = Quantity_NOC_MATRAGRAY, const Aspect_Handle theParent = 0, const Aspect_Handle theMenu = 0, const Standard_Address theClientStruct = 0); - + //! Creates a Window defined by his position and size in pixels from the Parent Window. + //! Trigger: Raises WindowDefinitionError if the Position out of the Screen Space or the window creation failed. + Standard_EXPORT WNT_Window (const Standard_CString theTitle, + const Handle(WNT_WClass)& theClass, + const WNT_Dword& theStyle, + const Standard_Integer thePxLeft, const Standard_Integer thePxTop, + const Standard_Integer thePxWidth, const Standard_Integer thePxHeight, + const Quantity_NameOfColor theBackColor = Quantity_NOC_MATRAGRAY, + const Aspect_Handle theParent = 0, + const Aspect_Handle theMenu = 0, + const Standard_Address theClientStruct = 0); + //! Creates a Window based on the existing window handle. - //! This handle equals ( aPart1 << 16 ) + aPart2. - Standard_EXPORT WNT_Window(const Aspect_Handle aHandle, const Quantity_NameOfColor aBackColor = Quantity_NOC_MATRAGRAY); - - //! Destroys the Window and all resourses attached to it. - Standard_EXPORT ~WNT_Window(); - - //! Sets cursor for ENTIRE WINDOW CLASS to which - //! the Window belongs. - Standard_EXPORT void SetCursor (const Aspect_Handle aCursor) const; - + Standard_EXPORT WNT_Window (const Aspect_Handle theHandle, + const Quantity_NameOfColor theBackColor = Quantity_NOC_MATRAGRAY); + + //! Destroys the Window and all resources attached to it. + Standard_EXPORT virtual ~WNT_Window(); + + //! Sets cursor for ENTIRE WINDOW CLASS to which the Window belongs. + Standard_EXPORT void SetCursor (const Aspect_Handle theCursor) const; + //! Opens the window . Standard_EXPORT virtual void Map() const Standard_OVERRIDE; - //! Opens a window according to . + //! Opens a window according to the map mode. //! This method is specific to Windows NT. - //! can be one of SW_xxx constants defined - //! in . See documentation. - Standard_EXPORT void Map (const Standard_Integer aMapMode) const; - + //! @param theMapMode [in] can be one of SW_xxx constants defined in + Standard_EXPORT void Map (const Standard_Integer theMapMode) const; + //! Closes the window . Standard_EXPORT virtual void Unmap() const Standard_OVERRIDE; //! Applies the resizing to the window . Standard_EXPORT virtual Aspect_TypeOfResize DoResize() Standard_OVERRIDE; - //! Apply the mapping change to the window - //! and returns TRUE if the window is mapped at screen. - virtual Standard_Boolean DoMapping() const Standard_OVERRIDE; - + //! Does nothing on Windows. + virtual Standard_Boolean DoMapping() const Standard_OVERRIDE { return Standard_True; } + //! Changes variables due to window position. Standard_EXPORT void SetPos (const Standard_Integer X, const Standard_Integer Y, const Standard_Integer X1, const Standard_Integer Y1); @@ -106,17 +111,11 @@ public: //! Returns The Window SIZE in PIXEL Standard_EXPORT virtual void Size (Standard_Integer& Width, Standard_Integer& Height) const Standard_OVERRIDE; - //! Returns the Windows NT handle of the created window . - Aspect_Handle HWindow() const; - - //! Returns the Windows NT handle parent of the created window . - Aspect_Handle HParentWindow() const; - //! Returns native Window handle (HWND) - virtual Aspect_Drawable NativeHandle() const Standard_OVERRIDE; + virtual Aspect_Drawable NativeHandle() const Standard_OVERRIDE { return (Aspect_Drawable )myHWindow; } - //! Returns parent of native Window handle (HWND on Windows, Window with Xlib, and so on) - virtual Aspect_Drawable NativeParentHandle() const Standard_OVERRIDE; + //! Returns parent of native Window handle (HWND on Windows). + virtual Aspect_Drawable NativeParentHandle() const Standard_OVERRIDE { return (Aspect_Drawable )myHParentWindow; } //! Returns nothing on Windows virtual Aspect_FBConfig NativeFBConfig() const Standard_OVERRIDE { return NULL; } @@ -126,7 +125,15 @@ public: //! Invalidate entire window content by calling InvalidateRect() WinAPI function, resulting in WM_PAINT event put into window message loop. //! Method can be called from non-window thread, and system will also automatically aggregate multiple events into single one. - Standard_EXPORT virtual void InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp = NULL) Standard_OVERRIDE; + Standard_EXPORT virtual void InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp = Handle(Aspect_DisplayConnection)()) Standard_OVERRIDE; + +public: + + //! Returns the Windows NT handle of the created window . + Aspect_Handle HWindow() const { return myHWindow; } + + //! Returns the Windows NT handle parent of the created window . + Aspect_Handle HParentWindow() const { return myHParentWindow; } //! Raw input flags. enum RawInputMask @@ -140,22 +147,25 @@ public: //! @return number of actually registered device types Standard_EXPORT int RegisterRawInputDevices (unsigned int theRawDeviceMask); - DEFINE_STANDARD_RTTIEXT(WNT_Window,Aspect_Window) + //! Process a single window message. + //! @param theListener [in][out] listener to redirect message + //! @param theMsg [in][out] message to process + //! @return TRUE if message has been processed + Standard_EXPORT virtual bool ProcessMessage (Aspect_WindowInputListener& theListener, + MSG& theMsg); protected: - Standard_Integer aXLeft; - Standard_Integer aYTop; - Standard_Integer aXRight; - Standard_Integer aYBottom; Handle(WNT_WClass) myWClass; - Aspect_Handle myHWindow; - Aspect_Handle myHParentWindow; + Aspect_Handle myHWindow; + Aspect_Handle myHParentWindow; + Standard_Integer myXLeft; + Standard_Integer myYTop; + Standard_Integer myXRight; + Standard_Integer myYBottom; Standard_Boolean myIsForeign; }; -#include - #endif // _WIN32 #endif // _WNT_Window_HeaderFile diff --git a/src/WNT/WNT_Window.lxx b/src/WNT/WNT_Window.lxx deleted file mode 100644 index ca2184d52d..0000000000 --- a/src/WNT/WNT_Window.lxx +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 1996-1999 Matra Datavision -// Copyright (c) 1999-2014 OPEN CASCADE SAS -// -// This file is part of Open CASCADE Technology software library. -// -// This library is free software; you can redistribute it and/or modify it under -// the terms of the GNU Lesser General Public License version 2.1 as published -// by the Free Software Foundation, with special exception defined in the file -// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT -// distribution for complete text of the license and disclaimer of any warranty. -// -// Alternatively, this file may be used under the terms of Open CASCADE -// commercial license or contractual agreement. - -inline Standard_Boolean WNT_Window::DoMapping() const -{ - // DO nothing on WNT - return Standard_True; -} - -inline Aspect_Handle WNT_Window::HWindow() const -{ - return myHWindow; -} - -inline Aspect_Handle WNT_Window::HParentWindow() const -{ - return myHParentWindow; -} - -inline Aspect_Drawable WNT_Window::NativeHandle() const -{ - return (Aspect_Drawable )myHWindow; -} - -inline Aspect_Drawable WNT_Window::NativeParentHandle() const -{ - return (Aspect_Drawable )myHParentWindow; -} diff --git a/src/Xw/Xw_Window.cxx b/src/Xw/Xw_Window.cxx index c3d9de7016..47d93dc608 100644 --- a/src/Xw/Xw_Window.cxx +++ b/src/Xw/Xw_Window.cxx @@ -18,7 +18,9 @@ #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__) #include +#include #include +#include #include #include @@ -531,4 +533,168 @@ Aspect_VKey Xw_Window::VirtualKeyFromNative (unsigned long theKey) return Aspect_VKey_UNKNOWN; } +// ======================================================================= +// function : ProcessMessage +// purpose : +// ======================================================================= +bool Xw_Window::ProcessMessage (Aspect_WindowInputListener& theListener, + XEvent& theMsg) +{ + Display* aDisplay = myDisplay->GetDisplay(); + + // Handle event for the chosen display connection + switch (theMsg.type) + { + case ClientMessage: + { + if ((Atom)theMsg.xclient.data.l[0] == myDisplay->GetAtom (Aspect_XA_DELETE_WINDOW) + && theMsg.xclient.window == myXWindow) + { + theListener.ProcessClose(); + return true; + } + return false; + } + case FocusIn: + case FocusOut: + { + if (theMsg.xfocus.window == myXWindow) + { + theListener.ProcessFocus (theMsg.type == FocusIn); + } + return true; + } + case Expose: + { + if (theMsg.xexpose.window == myXWindow) + { + theListener.ProcessExpose(); + } + + // remove all the ExposureMask and process them at once + for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents) + { + if (!XCheckWindowEvent (aDisplay, myXWindow, ExposureMask, &theMsg)) + { + break; + } + } + + return true; + } + case ConfigureNotify: + { + // remove all the StructureNotifyMask and process them at once + for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents) + { + if (!XCheckWindowEvent (aDisplay, myXWindow, StructureNotifyMask, &theMsg)) + { + break; + } + } + + if (theMsg.xconfigure.window == myXWindow) + { + theListener.ProcessConfigure (true); + } + return true; + } + case KeyPress: + case KeyRelease: + { + XKeyEvent* aKeyEvent = (XKeyEvent* )&theMsg; + const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0); + const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym); + if (aVKey != Aspect_VKey_UNKNOWN) + { + const double aTimeStamp = theListener.EventTime(); + if (theMsg.type == KeyPress) + { + theListener.KeyDown (aVKey, aTimeStamp); + } + else + { + theListener.KeyUp (aVKey, aTimeStamp); + } + theListener.ProcessInput(); + } + return true; + } + case ButtonPress: + case ButtonRelease: + { + const Graphic3d_Vec2i aPos (theMsg.xbutton.x, theMsg.xbutton.y); + Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; + Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE; + if (theMsg.xbutton.button == Button1) { aButton = Aspect_VKeyMouse_LeftButton; } + if (theMsg.xbutton.button == Button2) { aButton = Aspect_VKeyMouse_MiddleButton; } + if (theMsg.xbutton.button == Button3) { aButton = Aspect_VKeyMouse_RightButton; } + + if ((theMsg.xbutton.state & ControlMask) != 0) { aFlags |= Aspect_VKeyFlags_CTRL; } + if ((theMsg.xbutton.state & ShiftMask) != 0) { aFlags |= Aspect_VKeyFlags_SHIFT; } + if (theListener.Keys().IsKeyDown (Aspect_VKey_Alt)) + { + aFlags |= Aspect_VKeyFlags_ALT; + } + + if (theMsg.xbutton.button == Button4 + || theMsg.xbutton.button == Button5) + { + if (theMsg.type != ButtonPress) + { + return true; + } + + const double aDeltaF = (theMsg.xbutton.button == Button4 ? 1.0 : -1.0); + theListener.UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags)); + } + else if (theMsg.type == ButtonPress) + { + theListener.PressMouseButton (aPos, aButton, aFlags, false); + } + else + { + theListener.ReleaseMouseButton (aPos, aButton, aFlags, false); + } + theListener.ProcessInput(); + return true; + } + case MotionNotify: + { + if (theMsg.xmotion.window != myXWindow) + { + return false; + } + + // remove all the ButtonMotionMask and process them at once + for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents) + { + if (!XCheckWindowEvent (aDisplay, myXWindow, ButtonMotionMask | PointerMotionMask, &theMsg)) + { + break; + } + } + + Graphic3d_Vec2i aPos (theMsg.xmotion.x, theMsg.xmotion.y); + Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE; + Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; + if ((theMsg.xmotion.state & Button1Mask) != 0) { aButtons |= Aspect_VKeyMouse_LeftButton; } + if ((theMsg.xmotion.state & Button2Mask) != 0) { aButtons |= Aspect_VKeyMouse_MiddleButton; } + if ((theMsg.xmotion.state & Button3Mask) != 0) { aButtons |= Aspect_VKeyMouse_RightButton; } + + if ((theMsg.xmotion.state & ControlMask) != 0) { aFlags |= Aspect_VKeyFlags_CTRL; } + if ((theMsg.xmotion.state & ShiftMask) != 0) { aFlags |= Aspect_VKeyFlags_SHIFT; } + if (theListener.Keys().IsKeyDown (Aspect_VKey_Alt)) + { + aFlags |= Aspect_VKeyFlags_ALT; + } + + theListener.UpdateMousePosition (aPos, aButtons, aFlags, false); + theListener.ProcessInput(); + return true; + } + } + return false; +} + #endif // Win32 or Mac OS X diff --git a/src/Xw/Xw_Window.hxx b/src/Xw/Xw_Window.hxx index 0ba84ddddd..bda1c4d557 100644 --- a/src/Xw/Xw_Window.hxx +++ b/src/Xw/Xw_Window.hxx @@ -32,6 +32,7 @@ class Aspect_WindowDefinitionError; class Aspect_WindowError; +class Aspect_WindowInputListener; class Aspect_Background; class Quantity_Color; class Aspect_GradientBackground; @@ -125,6 +126,13 @@ public: //! for this working thread to avoid race conditions, since Xlib display connection is not thread-safe by default. Standard_EXPORT virtual void InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp) Standard_OVERRIDE; + //! Process a single window message. + //! @param theListener [in][out] listener to redirect message + //! @param theMsg [in][out] message to process + //! @return TRUE if message has been processed + Standard_EXPORT virtual bool ProcessMessage (Aspect_WindowInputListener& theListener, + XEvent& theMsg); + protected: Handle(Aspect_DisplayConnection) myDisplay; //!< X Display connection