From d6fbb2aba4ba93e07f93d2540cb23a2397e1f8d6 Mon Sep 17 00:00:00 2001 From: kgv Date: Fri, 26 Jun 2020 09:58:50 +0300 Subject: [PATCH] 0031632: Draw Harness - handle 3d mouse Raw HID input on Windows WNT_HIDSpaceMouse - added auxiliary class for processing 3d mouse Raw HID input. AIS_ViewController::Update3dMouse() - added default processor for 3d mouse input event. ViewerTest now redirects WM_INPUT to AIS_ViewController::Update3dMouse(). Aspect_VKey enumeration has been extended by 3D view buttons. WNT_Window::RegisterRawInputDevices() has beend added as a small wrapper over WinAPI RegisterRawInputDevices() for common HID input devices. AIS_ViewCube now stores animation duration within AIS_AnimationCamera instead of dedicated duplicating class property. --- adm/cmake/occt_toolkit.cmake | 213 ++++++------ adm/genproj.tcl | 26 +- src/AIS/AIS_ViewController.cxx | 247 +++++++++++++- src/AIS/AIS_ViewController.hxx | 69 +++- src/AIS/AIS_ViewCube.cxx | 23 +- src/AIS/AIS_ViewCube.hxx | 5 +- src/Aspect/Aspect_VKey.hxx | 14 + src/Aspect/Aspect_VKeySet.hxx | 5 + src/ViewerTest/ViewerTest_EventManager.cxx | 1 + src/ViewerTest/ViewerTest_ViewerCommands.cxx | 37 +++ src/WNT/FILES | 2 + src/WNT/WNT_HIDSpaceMouse.cxx | 320 +++++++++++++++++++ src/WNT/WNT_HIDSpaceMouse.hxx | 167 ++++++++++ src/WNT/WNT_Window.cxx | 56 ++++ src/WNT/WNT_Window.hxx | 12 + 15 files changed, 1054 insertions(+), 143 deletions(-) create mode 100644 src/WNT/WNT_HIDSpaceMouse.cxx create mode 100644 src/WNT/WNT_HIDSpaceMouse.hxx diff --git a/adm/cmake/occt_toolkit.cmake b/adm/cmake/occt_toolkit.cmake index f59b1639d2..38c39ae0c1 100644 --- a/adm/cmake/occt_toolkit.cmake +++ b/adm/cmake/occt_toolkit.cmake @@ -57,117 +57,110 @@ foreach (OCCT_PACKAGE ${USED_PACKAGES}) set (OCCT_PACKAGE_NAME "${OCCT_PACKAGE}") endif() - # TKService contains platform-dependent packages: Xw and WNT - if ((WIN32 AND "${OCCT_PACKAGE}" STREQUAL "Xw") OR (NOT WIN32 AND "${OCCT_PACKAGE}" STREQUAL "WNT")) - # do nothing - else() - - if (WIN32) - list (APPEND PRECOMPILED_DEFS "-D__${OCCT_PACKAGE_NAME}_DLL") - endif() - - set (SOURCE_FILES) - set (HEADER_FILES) - - # Generate Flex and Bison files - if (${BUILD_YACCLEX}) - - # flex files - OCCT_ORIGIN_AND_PATCHED_FILES ("${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}" "*[.]lex" SOURCE_FILES_FLEX) - list (LENGTH SOURCE_FILES_FLEX SOURCE_FILES_FLEX_LEN) - - # bison files - OCCT_ORIGIN_AND_PATCHED_FILES ("${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}" "*[.]yacc" SOURCE_FILES_BISON) - list (LENGTH SOURCE_FILES_BISON SOURCE_FILES_BISON_LEN) - - if (${SOURCE_FILES_FLEX_LEN} EQUAL ${SOURCE_FILES_BISON_LEN} AND NOT ${SOURCE_FILES_FLEX_LEN} EQUAL 0) - - list (SORT SOURCE_FILES_FLEX) - list (SORT SOURCE_FILES_BISON) - - math (EXPR SOURCE_FILES_FLEX_LEN "${SOURCE_FILES_FLEX_LEN} - 1") - foreach (FLEX_FILE_INDEX RANGE ${SOURCE_FILES_FLEX_LEN}) - - list (GET SOURCE_FILES_FLEX ${FLEX_FILE_INDEX} CURRENT_FLEX_FILE) - get_filename_component (CURRENT_FLEX_FILE_NAME ${CURRENT_FLEX_FILE} NAME_WE) - - list (GET SOURCE_FILES_BISON ${FLEX_FILE_INDEX} CURRENT_BISON_FILE) - get_filename_component (CURRENT_BISON_FILE_NAME ${CURRENT_BISON_FILE} NAME_WE) - - string (COMPARE EQUAL ${CURRENT_FLEX_FILE_NAME} ${CURRENT_BISON_FILE_NAME} ARE_FILES_EQUAL) - - if (EXISTS "${CURRENT_FLEX_FILE}" AND EXISTS "${CURRENT_BISON_FILE}" AND ${ARE_FILES_EQUAL}) - set (BISON_OUTPUT_FILE ${CURRENT_BISON_FILE_NAME}.tab.c) - set (FLEX_OUTPUT_FILE lex.${CURRENT_FLEX_FILE_NAME}.c) - BISON_TARGET (Parser_${CURRENT_BISON_FILE_NAME} ${CURRENT_BISON_FILE} ${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${BISON_OUTPUT_FILE} COMPILE_FLAGS "-p ${CURRENT_BISON_FILE_NAME}") - FLEX_TARGET (Scanner_${CURRENT_FLEX_FILE_NAME} ${CURRENT_FLEX_FILE} ${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${FLEX_OUTPUT_FILE} COMPILE_FLAGS "-P${CURRENT_FLEX_FILE_NAME}") - ADD_FLEX_BISON_DEPENDENCY (Scanner_${CURRENT_FLEX_FILE_NAME} Parser_${CURRENT_BISON_FILE_NAME}) - - list (APPEND SOURCE_FILES ${BISON_OUTPUT_FILE} ${FLEX_OUTPUT_FILE}) - endif() - endforeach() - endif() - endif() - - # header files - if (BUILD_PATCH AND EXISTS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES") - file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_M REGEX ".+[.]h") - file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_LXX REGEX ".+[.]lxx") - file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_GXX REGEX ".+[.]gxx") - - file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_C REGEX ".+[.]c") - if(APPLE) - file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_M REGEX ".+[.]mm") - endif() - else() - file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_M REGEX ".+[.]h") - file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_LXX REGEX ".+[.]lxx") - file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_GXX REGEX ".+[.]gxx") - - file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_C REGEX ".+[.]c") - if(APPLE) - file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_M REGEX ".+[.]mm") - endif() - endif() - - list (APPEND HEADER_FILES ${HEADER_FILES_M} ${HEADER_FILES_LXX} ${SOURCE_FILES_GXX}) - list (APPEND SOURCE_FILES ${SOURCE_FILES_C}) - if(APPLE) - list (APPEND SOURCE_FILES ${SOURCE_FILES_M}) - endif() - - foreach(HEADER_FILE ${HEADER_FILES}) - if (BUILD_PATCH AND EXISTS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") - message (STATUS "Info: consider patched file: ${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") - list (APPEND USED_INCFILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") - SOURCE_GROUP ("Header Files\\${OCCT_PACKAGE_NAME}" FILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") - else() - list (APPEND USED_INCFILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") - SOURCE_GROUP ("Header Files\\${OCCT_PACKAGE_NAME}" FILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") - endif() - endforeach() - - foreach(SOURCE_FILE ${SOURCE_FILES}) - if (BUILD_PATCH AND EXISTS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") - message (STATUS "Info: consider patched file: ${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") - list (APPEND USED_SRCFILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") - SOURCE_GROUP ("Source Files\\${OCCT_PACKAGE_NAME}" FILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") - else() - list (APPEND USED_SRCFILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") - SOURCE_GROUP ("Source Files\\${OCCT_PACKAGE_NAME}" FILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") - endif() - endforeach() - - if (USE_QT) - FIND_AND_INSTALL_QT_RESOURCES (${OCCT_PACKAGE} RESOURCE_FILES) - #message("Qt Resource files are: ${QT_RESOURCE_FILES} in ${OCCT_PACKAGE}") - endif(USE_QT) - - #message("Resource files are: ${RESOURCE_FILES} in ${OCCT_PACKAGE}") - foreach(RESOURCE_FILE ${RESOURCE_FILES}) - SOURCE_GROUP ("Resource Files\\${OCCT_PACKAGE_NAME}" FILES "${RESOURCE_FILE}") - endforeach() + if (WIN32) + list (APPEND PRECOMPILED_DEFS "-D__${OCCT_PACKAGE_NAME}_DLL") endif() + + set (SOURCE_FILES) + set (HEADER_FILES) + + # Generate Flex and Bison files + if (${BUILD_YACCLEX}) + # flex files + OCCT_ORIGIN_AND_PATCHED_FILES ("${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}" "*[.]lex" SOURCE_FILES_FLEX) + list (LENGTH SOURCE_FILES_FLEX SOURCE_FILES_FLEX_LEN) + + # bison files + OCCT_ORIGIN_AND_PATCHED_FILES ("${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}" "*[.]yacc" SOURCE_FILES_BISON) + list (LENGTH SOURCE_FILES_BISON SOURCE_FILES_BISON_LEN) + + if (${SOURCE_FILES_FLEX_LEN} EQUAL ${SOURCE_FILES_BISON_LEN} AND NOT ${SOURCE_FILES_FLEX_LEN} EQUAL 0) + + list (SORT SOURCE_FILES_FLEX) + list (SORT SOURCE_FILES_BISON) + + math (EXPR SOURCE_FILES_FLEX_LEN "${SOURCE_FILES_FLEX_LEN} - 1") + foreach (FLEX_FILE_INDEX RANGE ${SOURCE_FILES_FLEX_LEN}) + + list (GET SOURCE_FILES_FLEX ${FLEX_FILE_INDEX} CURRENT_FLEX_FILE) + get_filename_component (CURRENT_FLEX_FILE_NAME ${CURRENT_FLEX_FILE} NAME_WE) + + list (GET SOURCE_FILES_BISON ${FLEX_FILE_INDEX} CURRENT_BISON_FILE) + get_filename_component (CURRENT_BISON_FILE_NAME ${CURRENT_BISON_FILE} NAME_WE) + + string (COMPARE EQUAL ${CURRENT_FLEX_FILE_NAME} ${CURRENT_BISON_FILE_NAME} ARE_FILES_EQUAL) + + if (EXISTS "${CURRENT_FLEX_FILE}" AND EXISTS "${CURRENT_BISON_FILE}" AND ${ARE_FILES_EQUAL}) + set (BISON_OUTPUT_FILE ${CURRENT_BISON_FILE_NAME}.tab.c) + set (FLEX_OUTPUT_FILE lex.${CURRENT_FLEX_FILE_NAME}.c) + BISON_TARGET (Parser_${CURRENT_BISON_FILE_NAME} ${CURRENT_BISON_FILE} ${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${BISON_OUTPUT_FILE} COMPILE_FLAGS "-p ${CURRENT_BISON_FILE_NAME}") + FLEX_TARGET (Scanner_${CURRENT_FLEX_FILE_NAME} ${CURRENT_FLEX_FILE} ${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${FLEX_OUTPUT_FILE} COMPILE_FLAGS "-P${CURRENT_FLEX_FILE_NAME}") + ADD_FLEX_BISON_DEPENDENCY (Scanner_${CURRENT_FLEX_FILE_NAME} Parser_${CURRENT_BISON_FILE_NAME}) + + list (APPEND SOURCE_FILES ${BISON_OUTPUT_FILE} ${FLEX_OUTPUT_FILE}) + endif() + endforeach() + endif() + endif() + + # header files + if (BUILD_PATCH AND EXISTS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES") + file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_M REGEX ".+[.]h") + file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_LXX REGEX ".+[.]lxx") + file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_GXX REGEX ".+[.]gxx") + + file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_C REGEX ".+[.]c") + if(APPLE) + file (STRINGS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_M REGEX ".+[.]mm") + endif() + else() + file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_M REGEX ".+[.]h") + file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_LXX REGEX ".+[.]lxx") + file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" HEADER_FILES_GXX REGEX ".+[.]gxx") + + file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_C REGEX ".+[.]c") + if(APPLE) + file (STRINGS "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/FILES" SOURCE_FILES_M REGEX ".+[.]mm") + endif() + endif() + + list (APPEND HEADER_FILES ${HEADER_FILES_M} ${HEADER_FILES_LXX} ${SOURCE_FILES_GXX}) + list (APPEND SOURCE_FILES ${SOURCE_FILES_C}) + if(APPLE) + list (APPEND SOURCE_FILES ${SOURCE_FILES_M}) + endif() + + foreach(HEADER_FILE ${HEADER_FILES}) + if (BUILD_PATCH AND EXISTS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") + message (STATUS "Info: consider patched file: ${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") + list (APPEND USED_INCFILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") + SOURCE_GROUP ("Header Files\\${OCCT_PACKAGE_NAME}" FILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") + else() + list (APPEND USED_INCFILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") + SOURCE_GROUP ("Header Files\\${OCCT_PACKAGE_NAME}" FILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${HEADER_FILE}") + endif() + endforeach() + + foreach(SOURCE_FILE ${SOURCE_FILES}) + if (BUILD_PATCH AND EXISTS "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") + message (STATUS "Info: consider patched file: ${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") + list (APPEND USED_SRCFILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") + SOURCE_GROUP ("Source Files\\${OCCT_PACKAGE_NAME}" FILES "${BUILD_PATCH}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") + else() + list (APPEND USED_SRCFILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") + SOURCE_GROUP ("Source Files\\${OCCT_PACKAGE_NAME}" FILES "${CMAKE_SOURCE_DIR}/${RELATIVE_SOURCES_DIR}/${OCCT_PACKAGE}/${SOURCE_FILE}") + endif() + endforeach() + + if (USE_QT) + FIND_AND_INSTALL_QT_RESOURCES (${OCCT_PACKAGE} RESOURCE_FILES) + #message("Qt Resource files are: ${QT_RESOURCE_FILES} in ${OCCT_PACKAGE}") + endif(USE_QT) + + #message("Resource files are: ${RESOURCE_FILES} in ${OCCT_PACKAGE}") + foreach(RESOURCE_FILE ${RESOURCE_FILES}) + SOURCE_GROUP ("Resource Files\\${OCCT_PACKAGE_NAME}" FILES "${RESOURCE_FILE}") + endforeach() endforeach() string (REGEX REPLACE ";" " " PRECOMPILED_DEFS "${PRECOMPILED_DEFS}") diff --git a/adm/genproj.tcl b/adm/genproj.tcl index 501bf1cc75..8a077ae8d5 100644 --- a/adm/genproj.tcl +++ b/adm/genproj.tcl @@ -1596,11 +1596,6 @@ proc osutils:tk:units { tkloc theSrcDir } { return $l } -proc osutils:justwnt { listloc } { - set goaway [list Xw] - return [osutils:juststation $goaway $listloc] -} - # remove from listloc OpenCascade units indesirables on NT proc osutils:juststation {goaway listloc} { global path @@ -2267,17 +2262,6 @@ proc wokUtils:FILES:mkdir { d } { } } -# remove from listloc OpenCascade units indesirables on Unix -proc osutils:justunix { listloc } { - if { "$::tcl_platform(os)" == "Darwin" } { - set goaway [list Xw WNT] - } else { - set goaway [list WNT] - } - return [osutils:juststation $goaway $listloc] -} - - ####### CODEBLOCK ################################################################### # Function to generate Code Blocks workspace and project files proc OS:MKCBP { theOutDir theModules theAllSolution thePlatform theCmpl } { @@ -2333,13 +2317,8 @@ proc osutils:cbptk { theCmpl theOutDir theToolKit thePlatform} { set listloc $theToolKit } - if { $thePlatform == "wnt" || $thePlatform == "uwp" } { - set resultloc [osutils:justwnt $listloc] - } else { - set resultloc [osutils:justunix $listloc] - } if [array exists written] { unset written } - foreach fxlo $resultloc { + foreach fxlo $listloc { set xlo $fxlo set aSrcFiles [osutils:tk:cxxfiles $xlo $thePlatform "src"] foreach aSrcFile [lsort $aSrcFiles] { @@ -2928,9 +2907,8 @@ proc osutils:xcdtk:sources {theToolKit theTargetType theSrcFileRefSection theGro upvar $theIncPaths anIncPaths set listloc [osutils:tk:units $theToolKit "src"] - set resultloc [osutils:justunix $listloc] set aBuildFileSection "" - set aPackages [lsort -nocase $resultloc] + set aPackages [lsort -nocase $listloc] if { "$theTargetType" == "executable" } { set aPackages [list "$theToolKit"] } diff --git a/src/AIS/AIS_ViewController.cxx b/src/AIS/AIS_ViewController.cxx index 736f0acb5d..17a5425e2d 100644 --- a/src/AIS/AIS_ViewController.cxx +++ b/src/AIS/AIS_ViewController.cxx @@ -28,6 +28,7 @@ #include #include #include +#include // ======================================================================= // function : AIS_ViewController @@ -98,9 +99,17 @@ 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)); myAnchorPointPrs1->SetZLayer (Graphic3d_ZLayerId_Top); @@ -1092,6 +1101,112 @@ void AIS_ViewController::UpdateTouchPoint (Standard_Size theId, } } +// ======================================================================= +// function : Update3dMouse +// purpose : +// ======================================================================= +bool AIS_ViewController::Update3dMouse (const WNT_HIDSpaceMouse& theEvent) +{ + bool toUpdate = false; + toUpdate = update3dMouseTranslation (theEvent) || toUpdate; + toUpdate = 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 : @@ -1755,6 +1870,135 @@ gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& t return theCtx ->GravityPoint (theView); } +// ======================================================================= +// function : FitAllAuto +// purpose : +// ======================================================================= +void AIS_ViewController::FitAllAuto (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView) +{ + const Bnd_Box aBoxSel = theCtx->BoundingBoxOfSelection(); + const double aFitMargin = 0.01; + if (aBoxSel.IsVoid()) + { + theView->FitAll (aFitMargin, false); + return; + } + + // fit all algorithm is not 100% stable - so compute some precision to compare equal camera values + const double aFitTol = (aBoxSel.CornerMax().XYZ() - aBoxSel.CornerMin().XYZ()).Modulus() * 0.000001; + const Bnd_Box aBoxAll = theView->View()->MinMaxValues(); + + const Handle(Graphic3d_Camera)& aCam = theView->Camera(); + Handle(Graphic3d_Camera) aCameraSel = new Graphic3d_Camera (aCam); + Handle(Graphic3d_Camera) aCameraAll = new Graphic3d_Camera (aCam); + theView->FitMinMax (aCameraSel, aBoxSel, aFitMargin); + theView->FitMinMax (aCameraAll, aBoxAll, aFitMargin); + if (aCameraSel->Center().IsEqual (aCam->Center(), aFitTol) + && Abs (aCameraSel->Scale() - aCam->Scale()) < aFitTol + && Abs (aCameraSel->Distance() - aCam->Distance()) < aFitTol) + { + // fit all entire view on second FitALL request + aCam->Copy (aCameraAll); + } + else + { + aCam->Copy (aCameraSel); + } +} + +// ======================================================================= +// function : handleViewOrientationKeys +// purpose : +// ======================================================================= +void AIS_ViewController::handleViewOrientationKeys (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView) +{ + if (myNavigationMode == AIS_NavigationMode_FirstPersonWalk) + { + return; + } + + Handle(Graphic3d_Camera) aCameraBack; + struct ViewKeyAction + { + Aspect_VKey Key; + V3d_TypeOfOrientation Orientation; + }; + static const ViewKeyAction THE_VIEW_KEYS[] = + { + { Aspect_VKey_ViewTop, V3d_TypeOfOrientation_Zup_Top }, + { Aspect_VKey_ViewBottom, V3d_TypeOfOrientation_Zup_Bottom }, + { Aspect_VKey_ViewLeft, V3d_TypeOfOrientation_Zup_Left }, + { Aspect_VKey_ViewRight, V3d_TypeOfOrientation_Zup_Right }, + { Aspect_VKey_ViewFront, V3d_TypeOfOrientation_Zup_Front }, + { Aspect_VKey_ViewBack, V3d_TypeOfOrientation_Zup_Back }, + { Aspect_VKey_ViewAxoLeftProj, V3d_TypeOfOrientation_Zup_AxoLeft }, + { Aspect_VKey_ViewAxoRightProj, V3d_TypeOfOrientation_Zup_AxoRight }, + { Aspect_VKey_ViewRoll90CW, (V3d_TypeOfOrientation )-1}, + { Aspect_VKey_ViewRoll90CCW, (V3d_TypeOfOrientation )-1}, + { Aspect_VKey_ViewFitAll, (V3d_TypeOfOrientation )-1} + }; + { + Standard_Mutex::Sentry aLock (myKeys.Mutex()); + const size_t aNbKeys = sizeof(THE_VIEW_KEYS) / sizeof(*THE_VIEW_KEYS); + const double anEventTime = EventTime(); + for (size_t aKeyIter = 0; aKeyIter < aNbKeys; ++aKeyIter) + { + const ViewKeyAction& aKeyAction = THE_VIEW_KEYS[aKeyIter]; + if (!myKeys.IsKeyDown (aKeyAction.Key)) + { + continue; + } + + myKeys.KeyUp (aKeyAction.Key, anEventTime); + if (aCameraBack.IsNull()) + { + aCameraBack = theView->Camera(); + theView->SetCamera (new Graphic3d_Camera (aCameraBack)); + } + if (aKeyAction.Orientation != (V3d_TypeOfOrientation )-1) + { + theView->SetProj (aKeyAction.Orientation); + FitAllAuto (theCtx, theView); + } + else if (aKeyAction.Key == Aspect_VKey_ViewRoll90CW) + { + const double aTwist = theView->Twist() + M_PI / 2.0; + theView->SetTwist (aTwist); + } + else if (aKeyAction.Key == Aspect_VKey_ViewRoll90CCW) + { + const double aTwist = theView->Twist() - M_PI / 2.0; + theView->SetTwist (aTwist); + } + else if (aKeyAction.Key == Aspect_VKey_ViewFitAll) + { + FitAllAuto (theCtx, theView); + } + } + } + + if (aCameraBack.IsNull()) + { + return; + } + + Handle(Graphic3d_Camera) aCameraNew = theView->Camera(); + theView->SetCamera (aCameraBack); + const Graphic3d_Mat4d anOrientMat1 = aCameraBack->OrientationMatrix(); + const Graphic3d_Mat4d anOrientMat2 = aCameraNew ->OrientationMatrix(); + if (anOrientMat1 != anOrientMat2) + { + const Handle(AIS_AnimationCamera)& aCamAnim = myViewAnimation; + aCamAnim->SetView (theView); + aCamAnim->SetStartPts (0.0); + aCamAnim->SetCameraStart (new Graphic3d_Camera (aCameraBack)); + aCamAnim->SetCameraEnd (new Graphic3d_Camera (aCameraNew)); + aCamAnim->StartTimer (0.0, 1.0, true, false); + } +} + // ======================================================================= // function : handleNavigationKeys // purpose : @@ -2763,7 +3007,7 @@ void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& { const Handle(V3d_View)& aView = aViewIter.Value(); if (aView->IsInvalidated() - || myToAskNextFrame) + || (myToAskNextFrame && aView == theView)) { if (aView->ComputedMode()) { @@ -3056,6 +3300,7 @@ void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& { const bool wasImmediateUpdate = theView->SetImmediateUpdate (false); + handleViewOrientationKeys (theCtx, theView); const AIS_WalkDelta aWalk = handleNavigationKeys (theCtx, theView); handleXRInput (theCtx, theView, aWalk); if (theView->View()->IsActiveXR()) diff --git a/src/AIS/AIS_ViewController.hxx b/src/AIS/AIS_ViewController.hxx index eaa12fb137..11a6b6066d 100644 --- a/src/AIS/AIS_ViewController.hxx +++ b/src/AIS/AIS_ViewController.hxx @@ -41,6 +41,7 @@ class AIS_RubberBand; class AIS_XRTrackedDevice; class Graphic3d_Camera; class V3d_View; +class WNT_HIDSpaceMouse; //! Auxiliary structure for handling viewer events between GUI and Rendering threads. //! @@ -428,6 +429,50 @@ public: //! @name multi-touch input Standard_EXPORT virtual void UpdateTouchPoint (Standard_Size theId, const Graphic3d_Vec2d& thePnt); +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). + Standard_EXPORT virtual bool Update3dMouse (const WNT_HIDSpaceMouse& theEvent); + + //! 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); + public: //! Return event time (e.g. current time). @@ -488,14 +533,25 @@ public: Standard_EXPORT virtual gp_Pnt GravityPoint (const Handle(AIS_InteractiveContext)& theCtx, const Handle(V3d_View)& theView); + //! Modify view camera to fit all objects. + //! Default implementation fits either all visible and all selected objects (swapped on each call). + Standard_EXPORT virtual void FitAllAuto (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + public: - //! Perform navigation. + //! Handle hot-keys defining new camera orientation (Aspect_VKey_ViewTop and similar keys). + //! Default implementation starts an animated transaction from the current to the target camera orientation, when specific action key was pressed. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void handleViewOrientationKeys (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + + //! Perform navigation (Aspect_VKey_NavForward and similar keys). //! This method is expected to be called from rendering thread. Standard_EXPORT virtual AIS_WalkDelta handleNavigationKeys (const Handle(AIS_InteractiveContext)& theCtx, const Handle(V3d_View)& theView); - //! Perform camera actions. + //! Perform immediate camera actions (rotate/zoom/pan) on gesture progress. //! This method is expected to be called from rendering thread. Standard_EXPORT virtual void handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx, const Handle(V3d_View)& theView, @@ -742,6 +798,15 @@ 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/AIS/AIS_ViewCube.cxx b/src/AIS/AIS_ViewCube.cxx index dd643a7624..a8c7cef02d 100644 --- a/src/AIS/AIS_ViewCube.cxx +++ b/src/AIS/AIS_ViewCube.cxx @@ -149,12 +149,12 @@ AIS_ViewCube::AIS_ViewCube() myViewAnimation (new AIS_AnimationCamera ("AIS_ViewCube", Handle(V3d_View)())), myStartState(new Graphic3d_Camera()), myEndState (new Graphic3d_Camera()), - myDuration (0.5), myToAutoStartAnim (true), myIsFixedAnimation (true), myToFitSelected (true), myToResetCameraUp (false) { + myViewAnimation->SetOwnDuration (0.5); myInfiniteState = true; myIsMutable = true; myDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost); @@ -824,6 +824,24 @@ void AIS_ViewCube::ComputeSelection (const Handle(SelectMgr_Selection)& theSelec } } +//======================================================================= +//function : Duration +//purpose : +//======================================================================= +Standard_Real AIS_ViewCube::Duration() const +{ + return myViewAnimation->OwnDuration(); +} + +//======================================================================= +//function : SetDuration +//purpose : +//======================================================================= +void AIS_ViewCube::SetDuration (Standard_Real theDurationSec) +{ + myViewAnimation->SetOwnDuration (theDurationSec); +} + //======================================================================= //function : HasAnimation //purpose : @@ -913,7 +931,6 @@ void AIS_ViewCube::StartAnimation (const Handle(AIS_ViewCubeOwner)& theOwner) myViewAnimation->SetView (aView); myViewAnimation->SetCameraStart (myStartState); myViewAnimation->SetCameraEnd (myEndState); - myViewAnimation->SetOwnDuration (myDuration); myViewAnimation->StartTimer (0.0, 1.0, true, false); } @@ -924,7 +941,7 @@ void AIS_ViewCube::StartAnimation (const Handle(AIS_ViewCubeOwner)& theOwner) Standard_Boolean AIS_ViewCube::updateAnimation() { const Standard_Real aPts = myViewAnimation->UpdateTimer(); - if (aPts >= myDuration) + if (aPts >= myViewAnimation->OwnDuration()) { myViewAnimation->Stop(); onAnimationFinished(); diff --git a/src/AIS/AIS_ViewCube.hxx b/src/AIS/AIS_ViewCube.hxx index 757f645e25..4667d194fc 100644 --- a/src/AIS/AIS_ViewCube.hxx +++ b/src/AIS/AIS_ViewCube.hxx @@ -465,11 +465,11 @@ public: public: //! @name animation methods //! Return duration of animation in seconds; 0.5 sec by default - Standard_Real Duration() const { return myDuration; } + Standard_EXPORT Standard_Real Duration() const; //! Set duration of animation. //! @param theValue [in] input value of duration in seconds - void SetDuration (Standard_Real theValue) { myDuration = theValue; } + Standard_EXPORT void SetDuration (Standard_Real theValue); //! Return TRUE if new camera Up direction should be always set to default value for a new camera Direction; FALSE by default. //! When this flag is FALSE, the new camera Up will be set as current Up orthogonalized to the new camera Direction, @@ -675,7 +675,6 @@ protected: //! @name Animation options Handle(AIS_AnimationCamera) myViewAnimation; //!< Camera animation object Handle(Graphic3d_Camera) myStartState; //!< Start state of view camera Handle(Graphic3d_Camera) myEndState; //!< End state of view camera - Standard_Real myDuration; //!< Duration of animation. By default it is half a second Standard_Boolean myToAutoStartAnim; //!< start animation automatically on click Standard_Boolean myIsFixedAnimation; //!< fixed-loop animation Standard_Boolean myToFitSelected; //!< fit selected or fit entire scene diff --git a/src/Aspect/Aspect_VKey.hxx b/src/Aspect/Aspect_VKey.hxx index ff0def5b9c..4b55efa109 100644 --- a/src/Aspect/Aspect_VKey.hxx +++ b/src/Aspect/Aspect_VKey.hxx @@ -139,6 +139,20 @@ enum Aspect_VKeyBasic Aspect_VKey_BrowserFavorites, Aspect_VKey_BrowserHome, + // 3d view keys + Aspect_VKey_ViewTop, + Aspect_VKey_ViewBottom, + Aspect_VKey_ViewLeft, + Aspect_VKey_ViewRight, + Aspect_VKey_ViewFront, + Aspect_VKey_ViewBack, + Aspect_VKey_ViewAxoLeftProj, + Aspect_VKey_ViewAxoRightProj, + Aspect_VKey_ViewFitAll, + Aspect_VKey_ViewRoll90CW, + Aspect_VKey_ViewRoll90CCW, + Aspect_VKey_ViewSwitchRotate, + // modifier keys, @sa Aspect_VKey_ModifiersLower and Aspect_VKey_ModifiersUpper below Aspect_VKey_Shift, Aspect_VKey_Control, diff --git a/src/Aspect/Aspect_VKeySet.hxx b/src/Aspect/Aspect_VKeySet.hxx index bc7b3121be..787279253f 100644 --- a/src/Aspect/Aspect_VKeySet.hxx +++ b/src/Aspect/Aspect_VKeySet.hxx @@ -65,6 +65,11 @@ public: return myKeys[theKey].Status == KeyStatus_Pressed; } + //! Return mutex for thread-safe updates. + //! All operations in class implicitly locks this mutex, + //! so this method could be used only for batch processing of keys. + Standard_Mutex& Mutex() { return myLock; } + public: //! Reset the key state into unpressed state. diff --git a/src/ViewerTest/ViewerTest_EventManager.cxx b/src/ViewerTest/ViewerTest_EventManager.cxx index 2f732e89dd..a1e5837ce3 100644 --- a/src/ViewerTest/ViewerTest_EventManager.cxx +++ b/src/ViewerTest/ViewerTest_EventManager.cxx @@ -35,6 +35,7 @@ IMPLEMENT_STANDARD_RTTIEXT(ViewerTest_EventManager,Standard_Transient) const Handle(AIS_AnimationCamera)& ViewerTest_EventManager::GlobalViewAnimation() { static Handle(AIS_AnimationCamera) THE_CAMERA_ANIM = new AIS_AnimationCamera ("ViewerTest_EventManager_ViewAnimation", Handle(V3d_View)()); + THE_CAMERA_ANIM->SetOwnDuration (0.5); return THE_CAMERA_ANIM; } diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 498ec5542c..b6cf50dadc 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,7 @@ #if defined(_WIN32) #include #include + #include #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX) #include #else @@ -1831,6 +1833,7 @@ TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft aPxLeft, aPxTop, aPxWidth, aPxHeight, Quantity_NOC_BLACK); + VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse); #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX) VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(), aPxLeft, aPxTop, @@ -3258,6 +3261,40 @@ static LRESULT WINAPI ViewerWindowProc (HWND theWinHandle, 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); diff --git a/src/WNT/FILES b/src/WNT/FILES index d604a60823..0d1163e4ef 100755 --- a/src/WNT/FILES +++ b/src/WNT/FILES @@ -1,5 +1,7 @@ WNT_ClassDefinitionError.hxx WNT_Dword.hxx +WNT_HIDSpaceMouse.cxx +WNT_HIDSpaceMouse.hxx WNT_OrientationType.hxx WNT_WClass.cxx WNT_WClass.hxx diff --git a/src/WNT/WNT_HIDSpaceMouse.cxx b/src/WNT/WNT_HIDSpaceMouse.cxx new file mode 100644 index 0000000000..74937a153c --- /dev/null +++ b/src/WNT/WNT_HIDSpaceMouse.cxx @@ -0,0 +1,320 @@ +// Copyright (c) 2019-2020 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 + +namespace +{ + //! Enumeration of known Space Mouse models. + enum SpacePid + { + // VENDOR_ID_LOGITECH + SpacePid_SpaceMouse = 0xC603, + SpacePid_CADMan = 0xC605, + SpacePid_SpaceMouseClassic = 0xC606, + SpacePid_SpaceBall5000 = 0xC621, + SpacePid_SpaceTraveler = 0xC623, + SpacePid_SpacePilot = 0xC625, + SpacePid_SpaceNavigator = 0xC626, //!< has only 2 "menu" buttons (second one is treated as SpaceVKey_Fit) + SpacePid_SpaceExplorer = 0xC627, //!< 15 buttons + SpacePid_NavigatorForNotebooks = 0xC628, //!< has only 2 "menu" buttons (second one is treated as SpaceVKey_Fit) + SpacePid_SpacePilotPro = 0xC629, //!< 31 buttons + SpacePid_SpaceMousePro = 0xC62B, //!< has only 15 buttons, but codes range from 0 to 26 + // VENDOR_ID_3DCONNEXION + SpacePid_SpaceMouseWireless1 = 0xC62E, //!< [plugged in] has only 2 buttons + SpacePid_SpaceMouseWireless2 = 0xC62F, //!< [wireless] has only 2 buttons + SpacePid_SpaceMouseProWireless1 = 0xC631, //!< [plugged in] has only 15 buttons + SpacePid_SpaceMouseProWireless2 = 0xC632, //!< [wireless] has only 15 buttons + SpacePid_SpaceMouseEnterprise = 0xC633, //!< 31 buttons + SpacePid_SpaceMouseCompact = 0xC635 + }; + + //! Enumeration of known keys available on various Space Mouse models. + enum SpaceVKey + { + SpaceVKey_INVALID = 0, + SpaceVKey_Menu = 1, SpaceVKey_Fit, + SpaceVKey_Top, SpaceVKey_Left, SpaceVKey_Right, SpaceVKey_Front, SpaceVKey_Bottom, SpaceVKey_Back, + SpaceVKey_RollCW, SpaceVKey_RollCCW, + SpaceVKey_ISO1, SpaceVKey_ISO2, + SpaceVKey_1, SpaceVKey_2, SpaceVKey_3, SpaceVKey_4, SpaceVKey_5, SpaceVKey_6, SpaceVKey_7, SpaceVKey_8, SpaceVKey_9, SpaceVKey_10, + SpaceVKey_Esc, SpaceVKey_Alt, SpaceVKey_Shift, SpaceVKey_Ctrl, + SpaceVKey_Rotate, SpaceVKey_PanZoom, SpaceVKey_Dominant, + SpaceVKey_Plus, SpaceVKey_Minus, + }; + + //! The raw value range on tested device is [-350; 350]. + enum { THE_RAW_RANGE_350 = 350 }; + + //! Convert key state bit into virtual key. + static SpaceVKey hidToSpaceKey (unsigned long theProductId, + unsigned short theKeyBit) + { + static const SpaceVKey THE_PILOT_KEYS[] = + { + SpaceVKey_1, SpaceVKey_2, SpaceVKey_3, SpaceVKey_4, SpaceVKey_5, SpaceVKey_6, + SpaceVKey_Top, SpaceVKey_Left, SpaceVKey_Right, SpaceVKey_Front, + SpaceVKey_Esc, SpaceVKey_Alt, SpaceVKey_Shift, SpaceVKey_Ctrl, + SpaceVKey_Fit, SpaceVKey_Menu, + SpaceVKey_Plus, SpaceVKey_Minus, + SpaceVKey_Dominant, SpaceVKey_Rotate + }; + const int THE_NB_PILOT_KEYS = sizeof(THE_PILOT_KEYS) / sizeof(SpaceVKey); + + static const SpaceVKey THE_EXPLORER_KEYS[] = + { + SpaceVKey_1, SpaceVKey_2, + SpaceVKey_Top, SpaceVKey_Left, SpaceVKey_Right, SpaceVKey_Front, + SpaceVKey_Esc, SpaceVKey_Alt, SpaceVKey_Shift, SpaceVKey_Ctrl, + SpaceVKey_Fit, SpaceVKey_Menu, + SpaceVKey_Plus, SpaceVKey_Minus, + SpaceVKey_Rotate + }; + const int THE_NB_EXPLORER_KEYS = sizeof(THE_EXPLORER_KEYS) / sizeof(SpaceVKey); + + // shared by latest 3Dconnexion hardware + static const SpaceVKey THE_SPACEMOUSEPRO_KEYS[] = + { + SpaceVKey_Menu, SpaceVKey_Fit, + SpaceVKey_Top, SpaceVKey_Left, SpaceVKey_Right, SpaceVKey_Front, SpaceVKey_Bottom, SpaceVKey_Back, + SpaceVKey_RollCW, SpaceVKey_RollCCW, SpaceVKey_ISO1, SpaceVKey_ISO2, + SpaceVKey_1, SpaceVKey_2, SpaceVKey_3, SpaceVKey_4, + SpaceVKey_5, SpaceVKey_6, SpaceVKey_7, SpaceVKey_8, SpaceVKey_9, SpaceVKey_10, + SpaceVKey_Esc, SpaceVKey_Alt, SpaceVKey_Shift, SpaceVKey_Ctrl, + SpaceVKey_Rotate, + SpaceVKey_PanZoom, SpaceVKey_Dominant, SpaceVKey_Plus, SpaceVKey_Minus + }; + const int THE_NB_SPACEMOUSEPRO_KEYS = sizeof(THE_SPACEMOUSEPRO_KEYS) / sizeof(SpaceVKey); + + switch (theProductId) + { + case SpacePid_SpacePilot: + return theKeyBit < THE_NB_PILOT_KEYS ? THE_PILOT_KEYS[theKeyBit] : SpaceVKey_INVALID; + case SpacePid_SpaceExplorer: + return theKeyBit < THE_NB_EXPLORER_KEYS ? THE_EXPLORER_KEYS[theKeyBit] : SpaceVKey_INVALID; + case SpacePid_SpaceNavigator: + case SpacePid_NavigatorForNotebooks: + case SpacePid_SpacePilotPro: + case SpacePid_SpaceMousePro: + case SpacePid_SpaceMouseWireless1: + case SpacePid_SpaceMouseWireless2: + case SpacePid_SpaceMouseProWireless1: + case SpacePid_SpaceMouseProWireless2: + case SpacePid_SpaceMouseEnterprise: + case SpacePid_SpaceMouseCompact: + return theKeyBit < THE_NB_SPACEMOUSEPRO_KEYS ? THE_SPACEMOUSEPRO_KEYS[theKeyBit] : SpaceVKey_INVALID; + } + return SpaceVKey_INVALID; + } + +} + +// ======================================================================= +// function : WNT_HIDSpaceMouse +// purpose : +// ======================================================================= +WNT_HIDSpaceMouse::WNT_HIDSpaceMouse (unsigned long theProductId, + const Standard_Byte* theData, + Standard_Size theSize) +: myData (theData), + mySize (theSize), + myProductId (theProductId), + myValueRange (THE_RAW_RANGE_350) +{ + // +} + +// ======================================================================= +// function : IsKnownProduct +// purpose : +// ======================================================================= +bool WNT_HIDSpaceMouse::IsKnownProduct (unsigned long theProductId) +{ + switch (theProductId) + { + case SpacePid_SpacePilot: + case SpacePid_SpaceExplorer: + case SpacePid_SpaceNavigator: + case SpacePid_NavigatorForNotebooks: + case SpacePid_SpacePilotPro: + case SpacePid_SpaceMousePro: + case SpacePid_SpaceMouseWireless1: + case SpacePid_SpaceMouseWireless2: + case SpacePid_SpaceMouseProWireless1: + case SpacePid_SpaceMouseProWireless2: + case SpacePid_SpaceMouseEnterprise: + case SpacePid_SpaceMouseCompact: + return true; + } + return false; +} + +// ======================================================================= +// function : Translation +// purpose : +// ======================================================================= +Graphic3d_Vec3d WNT_HIDSpaceMouse::Translation (bool& theIsIdle, + bool theIsQuadric) const +{ + theIsIdle = true; + return myData[0] == SpaceRawInput_Translation + && (mySize == 7 || mySize == 13) + ? fromRawVec3 (theIsIdle, myData + 1, true, theIsQuadric) + : Graphic3d_Vec3d(); +} + +// ======================================================================= +// function : Rotation +// purpose : +// ======================================================================= +Graphic3d_Vec3d WNT_HIDSpaceMouse::Rotation (bool& theIsIdle, + bool theIsQuadric) const +{ + theIsIdle = true; + if (myData[0] == SpaceRawInput_Rotation && mySize == 7) + { + return fromRawVec3 (theIsIdle, myData + 1, false, theIsQuadric); + } + else if (myData[0] == SpaceRawInput_Translation && mySize == 13) + { + return fromRawVec3 (theIsIdle, myData + 7, false, theIsQuadric); + } + return Graphic3d_Vec3d(); +} + +// ======================================================================= +// function : fromRawVec3 +// purpose : +// ======================================================================= +Graphic3d_Vec3d WNT_HIDSpaceMouse::fromRawVec3 (bool& theIsIdle, + const Standard_Byte* theData, + bool theIsTrans, + bool theIsQuadric) const +{ + theIsIdle = true; + const NCollection_Vec3& aRaw16 = *reinterpret_cast*>(theData); + Graphic3d_Vec3d aVec (aRaw16.x(), aRaw16.y(), aRaw16.z()); + if (theIsTrans) + { + static const int16_t THE_MIN_RAW_TRANS = 4; + static const int16_t THE_MIN_RAW_TRANS_Z = 8; + for (int aCompIter = 0; aCompIter < 3; ++aCompIter) + { + if (aRaw16[aCompIter] > -THE_MIN_RAW_TRANS && aRaw16[aCompIter] < THE_MIN_RAW_TRANS) + { + aVec[aCompIter] = 0.0; + } + else + { + theIsIdle = false; + } + } + if (aRaw16.z() > -THE_MIN_RAW_TRANS_Z && aRaw16.z() < THE_MIN_RAW_TRANS_Z) + { + aVec.z() = 0.0; + } + } + else + { + for (int aCompIter = 0; aCompIter < 3; ++aCompIter) + { + if (aRaw16[aCompIter] != 0) + { + theIsIdle = false; + break; + } + } + } + + // determine raw value range + for (int aCompIter = 0; aCompIter < 3; ++aCompIter) + { + if (aRaw16[aCompIter] > myValueRange + || -aRaw16[aCompIter] > myValueRange) + { + myValueRange = 32767; // SHRT_MAX + break; + } + } + + if (!theIsQuadric) + { + return aVec / double(myValueRange); + } + + for (int aCompIter = 0; aCompIter < 3; ++aCompIter) + { + aVec[aCompIter] = aRaw16[aCompIter] > 0 + ? aVec[aCompIter] * aVec[aCompIter] + : -aVec[aCompIter] * aVec[aCompIter]; + } + return aVec / (double(myValueRange) * double(myValueRange)); +} + +// ======================================================================= +// function : HidToSpaceKey +// purpose : +// ======================================================================= +Aspect_VKey WNT_HIDSpaceMouse::HidToSpaceKey (unsigned short theKeyBit) const +{ + const SpaceVKey aKey = hidToSpaceKey (myProductId, theKeyBit); + switch (aKey) + { + case SpaceVKey_1: + case SpaceVKey_2: + case SpaceVKey_3: + case SpaceVKey_4: + case SpaceVKey_5: + case SpaceVKey_6: + case SpaceVKey_7: + case SpaceVKey_8: + case SpaceVKey_9: + case SpaceVKey_10: + return (int(aKey) - int(SpaceVKey_1)) + Aspect_VKey_1; + case SpaceVKey_Esc: + return Aspect_VKey_Escape; + case SpaceVKey_Shift: + return Aspect_VKey_Shift; + case SpaceVKey_Alt: + return Aspect_VKey_Alt; + case SpaceVKey_Ctrl: + return Aspect_VKey_Control; + case SpaceVKey_Top: + return Aspect_VKey_ViewTop; + case SpaceVKey_Bottom: + return Aspect_VKey_ViewBottom; + case SpaceVKey_Left: + return Aspect_VKey_ViewLeft; + case SpaceVKey_Right: + return Aspect_VKey_ViewRight; + case SpaceVKey_Front: + return Aspect_VKey_ViewFront; + case SpaceVKey_Back: + return Aspect_VKey_ViewBack; + case SpaceVKey_ISO1: + return Aspect_VKey_ViewAxoLeftProj; + case SpaceVKey_ISO2: + return Aspect_VKey_ViewAxoRightProj; + case SpaceVKey_Fit: + return Aspect_VKey_ViewFitAll; + case SpaceVKey_RollCW: + return Aspect_VKey_ViewRoll90CW; + case SpaceVKey_RollCCW: + return Aspect_VKey_ViewRoll90CCW; + case SpaceVKey_Rotate: + return Aspect_VKey_ViewSwitchRotate; + default: + break; + } + return Aspect_VKey_UNKNOWN; +} diff --git a/src/WNT/WNT_HIDSpaceMouse.hxx b/src/WNT/WNT_HIDSpaceMouse.hxx new file mode 100644 index 0000000000..ea6a8d8cd4 --- /dev/null +++ b/src/WNT/WNT_HIDSpaceMouse.hxx @@ -0,0 +1,167 @@ +// Copyright (c) 2019-2020 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 _WNT_HIDSpaceMouse_Header +#define _WNT_HIDSpaceMouse_Header + +#include +#include + +//! Wrapper over Space Mouse data chunk within WM_INPUT event (known also as Raw Input in WinAPI). +//! This class predefines specific list of supported devices, which does not depend on 3rdparty library provided by mouse vendor. +//! Supported input chunks: +//! - Rotation (3 directions); +//! - Translation (3 directions); +//! - Pressed buttons. +//! +//! To use the class, register Raw Input device: +//! @code +//! Handle(WNT_Window) theWindow; +//! RAWINPUTDEVICE aRawInDevList[1]; +//! RAWINPUTDEVICE& aRawSpace = aRawInDevList[0]; +//! aRawSpace.usUsagePage = HID_USAGE_PAGE_GENERIC; +//! aRawSpace.usUsage = HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER; +//! aRawSpace.dwFlags = 0; // RIDEV_DEVNOTIFY +//! aRawSpace.hwndTarget = (HWND )theWindow->NativeHandle(); +//! if (!::RegisterRawInputDevices (aRawInDevList, 1, sizeof(aRawInDevList[0]))) { Error; } +//! @endcode +//! +//! Then handle WM_INPUT events within window message loop. +//! @code +//! AIS_ViewController theViewCtrl; +//! case WM_INPUT: +//! { +//! UINT aSize = 0; +//! ::GetRawInputData ((HRAWINPUT )theLParam, RID_INPUT, NULL, &aSize, sizeof(RAWINPUTHEADER)); +//! NCollection_LocalArray aRawData (aSize); // receive Raw Input for any device and process known devices +//! if (aSize == 0 || ::GetRawInputData ((HRAWINPUT )theLParam, 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; +//! } +//! +//! Aspect_VKeySet& aKeys = theViewCtrl.ChangeKeys(); +//! const double aTimeStamp = theViewCtrl.EventTime(); +//! WNT_HIDSpaceMouse aSpaceData (aDevInfo.hid.dwProductId, aRawInput->data.hid.bRawData, aRawInput->data.hid.dwSizeHid); +//! if (aSpaceData.IsTranslation()) +//! { +//! // process translation input +//! bool isIdle = true, isQuadric = true; +//! const Graphic3d_Vec3d aTrans = aSpaceData.Translation (isIdle, isQuadric); +//! aKeys.KeyFromAxis (Aspect_VKey_NavSlideLeft, Aspect_VKey_NavSlideRight, aTimeStamp, aTrans.x()); +//! aKeys.KeyFromAxis (Aspect_VKey_NavForward, Aspect_VKey_NavBackward, aTimeStamp, aTrans.y()); +//! aKeys.KeyFromAxis (Aspect_VKey_NavSlideUp, Aspect_VKey_NavSlideDown, aTimeStamp, aTrans.z()); +//! } +//! if (aSpaceData.IsRotation()) {} // process rotation input +//! if (aSpaceData.IsKeyState()) {} // process keys input +//! break; +//! } +//! @endcode +class WNT_HIDSpaceMouse +{ +public: + //! Vendor HID identifier. + enum { VENDOR_ID_LOGITECH = 0x46D, VENDOR_ID_3DCONNEXION = 0x256F }; + + //! Return if product id is known by this class. + Standard_EXPORT static bool IsKnownProduct (unsigned long theProductId); + +public: + //! Main constructor. + Standard_EXPORT WNT_HIDSpaceMouse (unsigned long theProductId, + const Standard_Byte* theData, + Standard_Size theSize); + + //! Return the raw value range. + int16_t RawValueRange() const { return myValueRange; } + + //! Set the raw value range. + void SetRawValueRange (int16_t theRange) { myValueRange = theRange > myValueRange ? theRange : myValueRange; } + + //! Return TRUE if data chunk defines new translation values. + bool IsTranslation() const + { + return myData[0] == SpaceRawInput_Translation + && (mySize == 7 || mySize == 13); + } + + //! Return new translation values. + //! @param theIsIdle [out] flag indicating idle state (no translation) + //! @param theIsQuadric [in] flag to apply non-linear scale factor + //! @return vector of 3 elements defining translation values within [-1..1] range, 0 meaning idle, + //! .x defining left/right slide, .y defining forward/backward and .z defining up/down slide. + Standard_EXPORT Graphic3d_Vec3d Translation (bool& theIsIdle, + bool theIsQuadric) const; + + //! Return TRUE if data chunk defines new rotation values. + bool IsRotation() const + { + return (myData[0] == SpaceRawInput_Rotation && mySize == 7) + || (myData[0] == SpaceRawInput_Translation && mySize == 13); + } + + //! Return new rotation values. + //! @param theIsIdle [out] flag indicating idle state (no rotation) + //! @param theIsQuadric [in] flag to apply non-linear scale factor + //! @return vector of 3 elements defining rotation values within [-1..1] range, 0 meaning idle, + //! .x defining tilt, .y defining roll and .z defining spin. + Standard_EXPORT Graphic3d_Vec3d Rotation (bool& theIsIdle, + bool theIsQuadric) const; + + //! Return TRUE for key state data chunk. + bool IsKeyState() const { return myData[0] == SpaceRawInput_KeyState; } + + //! Return new keystate. + uint32_t KeyState() const { return *reinterpret_cast(myData + 1); } + + //! Convert key state bit into virtual key. + Standard_EXPORT Aspect_VKey HidToSpaceKey (unsigned short theKeyBit) const; + +private: + + //! Translate raw data chunk of 3 int16 values into normalized vec3. + //! The values are considered within the range [-350; 350], with 0 as neutral state. + Graphic3d_Vec3d fromRawVec3 (bool& theIsIdle, + const Standard_Byte* theData, + bool theIsTrans, + bool theIsQuadric) const; + + //! Data chunk type. + enum + { + SpaceRawInput_Translation = 0x01, //!< translation data chunk + SpaceRawInput_Rotation = 0x02, //!< rotation data chunk + SpaceRawInput_KeyState = 0x03, //!< keystate data chunk + }; + +private: + const Standard_Byte* myData; //!< RAW data chunk + Standard_Size mySize; //!< size of RAW data chunk + unsigned long myProductId; //!< product id + mutable int16_t myValueRange; //!< RAW value range +}; + +#endif // _WNT_HIDSpaceMouse_Header diff --git a/src/WNT/WNT_Window.cxx b/src/WNT/WNT_Window.cxx index 6051a4cecf..64086200a9 100644 --- a/src/WNT/WNT_Window.cxx +++ b/src/WNT/WNT_Window.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -643,4 +644,59 @@ Aspect_VKeyMouse WNT_Window::MouseButtonsAsync() return aButtons; } +// ======================================================================= +// function : RegisterRawInputDevices +// purpose : +// ======================================================================= +int WNT_Window::RegisterRawInputDevices (unsigned int theRawDeviceMask) +{ + if (IsVirtual() + || myHWindow == NULL) + { + return 0; + } + + // hidusage.h + enum HidUsagePage { THE_HID_USAGE_PAGE_GENERIC = 0x01 }; // HID_USAGE_PAGE_GENERIC + enum HidUsage + { + THE_HID_USAGE_GENERIC_MOUSE = 0x02, // HID_USAGE_GENERIC_MOUSE + THE_HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER = 0x08, // HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER + }; + + int aNbDevices = 0; + RAWINPUTDEVICE aRawInDevList[2]; + if ((theRawDeviceMask & RawInputMask_Mouse) != 0) + { + // mouse + RAWINPUTDEVICE& aRawMouse = aRawInDevList[aNbDevices++]; + aRawMouse.usUsagePage = THE_HID_USAGE_PAGE_GENERIC; + aRawMouse.usUsage = THE_HID_USAGE_GENERIC_MOUSE; + aRawMouse.dwFlags = RIDEV_INPUTSINK; + aRawMouse.hwndTarget = (HWND )myHWindow; + } + if ((theRawDeviceMask & RawInputMask_SpaceMouse) != 0) + { + // space mouse + RAWINPUTDEVICE& aRawSpace = aRawInDevList[aNbDevices++]; + aRawSpace.usUsagePage = THE_HID_USAGE_PAGE_GENERIC; + aRawSpace.usUsage = THE_HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER; + aRawSpace.dwFlags = 0; // RIDEV_DEVNOTIFY + aRawSpace.hwndTarget = (HWND )myHWindow; + } + + for (int aTryIter = aNbDevices; aTryIter > 0; --aTryIter) + { + if (::RegisterRawInputDevices (aRawInDevList, aTryIter, sizeof(aRawInDevList[0]))) + { + return aTryIter; + } + + Message::SendTrace (aRawInDevList[aTryIter - 1].usUsage == THE_HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER + ? "Warning: RegisterRawInputDevices() failed to register RAW multi-axis controller input" + : "Warning: RegisterRawInputDevices() failed to register RAW mouse input"); + } + return 0; +} + #endif // _WIN32 diff --git a/src/WNT/WNT_Window.hxx b/src/WNT/WNT_Window.hxx index 4a60acb011..c056a5ef14 100644 --- a/src/WNT/WNT_Window.hxx +++ b/src/WNT/WNT_Window.hxx @@ -128,6 +128,18 @@ public: //! 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; + //! Raw input flags. + enum RawInputMask + { + RawInputMask_Mouse = 0x01, //!< HID_USAGE_GENERIC_MOUSE + RawInputMask_SpaceMouse = 0x02, //!< HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER + }; + + //! RegisterRawInputDevices() wrapper. + //! @param theRawDeviceMask [in] mask of RawInputMask flags + //! @return number of actually registered device types + Standard_EXPORT int RegisterRawInputDevices (unsigned int theRawDeviceMask); + DEFINE_STANDARD_RTTIEXT(WNT_Window,Aspect_Window) protected: