@@ -77,12 +77,50 @@ gamescope::ConVar<bool> cv_vr_nudge_to_visible_per_connector( "vr_nudge_to_visib
7777// Maximum interval between polling for VR events (normally paced by frame sync)
7878gamescope::ConVar<uint32_t > cv_vr_poll_rate ( " vr_poll_rate" , 50ul , " Max time between input polls. In milliseconds." );
7979
80+ extern std::atomic<uint64_t > g_FocusedVROverlayMouse;
81+ extern std::atomic<uint64_t > g_FocusedVROverlayKeyboard;
82+
8083// Not in public headers yet.
8184namespace vr
8285{
8386 const EVRButtonId k_EButton_Steam = (EVRButtonId)(50 );
8487 const EVRButtonId k_EButton_QAM = (EVRButtonId)(51 );
88+
89+ constexpr EVREventType VREvent_OverlayInputFocusChanged = ( EVREventType )(564 ); // data is overlayInputFocus
90+
91+
92+ /* * Used in VREvent_OverlayInputFocus_t */
93+ enum EVRInputFocusEventFlags
94+ {
95+ // Indicates the overlay should actively have keyboard focus.
96+ k_EVRInputFocusEventFlags_OverlayShouldShowAffordanceForKeyboardInput = 1 << 0 ,
97+ // Indicates the overlay should actively have gamepad focus.
98+ k_EVRInputFocusEventFlags_OverlayShouldShowAffordanceForGamepadInput = 1 << 1 ,
99+ };
100+ /* * Used for a few events about overlay input focus */
101+ struct VREvent_OverlayInputFocus_t
102+ {
103+ // Overlay that has keyboard and/or gamepad focus. If this is your overlay and its contents is a desktop or a desktop window,
104+ // this event is a great oppportunity to move that window to the foreground so it receives input.
105+ uint64_t overlayHandle; // VROverlayHandle_t
106+ uint32_t flags; // EVRInputFocusEventFlags
107+ };
108+
109+ typedef union
110+ {
111+ VREvent_OverlayInputFocus_t overlayInputFocus;
112+ } VREvent_Data_Gamescope_t;
113+
114+ static inline const VREvent_Data_Gamescope_t &CastToGamescopeEventData ( const VREvent_Data_t &eventData )
115+ {
116+ return reinterpret_cast < const vr::VREvent_Data_Gamescope_t & >( eventData );
117+ }
118+ static inline VREvent_Data_Gamescope_t &CastToGamescopeEventData ( VREvent_Data_t &eventData )
119+ {
120+ return reinterpret_cast < vr::VREvent_Data_Gamescope_t & >( eventData );
121+ }
85122}
123+ //
86124
87125extern std::atomic<uint32_t > g_unCurrentVRSceneAppId;
88126
@@ -740,8 +778,12 @@ namespace gamescope
740778
741779 virtual IBackendConnector *GetCurrentConnector () override
742780 {
743- return m_pFocusConnector ;
781+ return m_pKeyboardFocusConnector ;
744782 }
783+ virtual IBackendConnector *GetCurrentMouseConnector ()
784+ {
785+ return m_pMouseFocusConnector;
786+ }
745787 virtual IBackendConnector *GetConnector ( GamescopeScreenType eScreenType ) override
746788 {
747789 if ( eScreenType == GAMESCOPE_SCREEN_TYPE_INTERNAL )
@@ -832,20 +874,23 @@ namespace gamescope
832874 return TouchClickModes::Trackpad;
833875 }
834876
835- if ( pConnector-> IsTouchForbidden () )
877+ if ( pConnector )
836878 {
837- return TouchClickModes::Left;
838- }
879+ if ( pConnector->IsTouchForbidden () )
880+ {
881+ return TouchClickModes::Left;
882+ }
839883
840- if ( VirtualConnectorKeyIsNonSteamWindow ( pConnector->GetVirtualConnectorKey () ) )
841- {
842- return TouchClickModes::Passthrough;
843- }
884+ if ( VirtualConnectorKeyIsNonSteamWindow ( pConnector->GetVirtualConnectorKey () ) )
885+ {
886+ return TouchClickModes::Passthrough;
887+ }
844888
845- if ( VirtualConnectorInSteamPerAppState () )
846- {
847- if ( !VirtualConnectorKeyIsSteam ( pConnector->GetVirtualConnectorKey () ) )
848- return TouchClickModes::Left;
889+ if ( VirtualConnectorInSteamPerAppState () )
890+ {
891+ if ( !VirtualConnectorKeyIsSteam ( pConnector->GetVirtualConnectorKey () ) )
892+ return TouchClickModes::Left;
893+ }
849894 }
850895
851896 return CBaseBackend::GetTouchClickMode ();
@@ -859,22 +904,23 @@ namespace gamescope
859904 {
860905 std::shared_ptr<COpenVRConnector> pConnector = std::make_shared<COpenVRConnector>( this , ulVirtualConnectorKey );
861906
862- bool bSetCurrentConnector = false ;
907+ if ( !pConnector-> Init () )
863908 {
864- if ( !m_pFocusConnector )
865- {
866- SetFocus ( pConnector.get () );
867- bSetCurrentConnector = true ;
868- }
909+ return nullptr ;
910+ }
911+
912+ {
913+ COpenVRConnector *pExpected = nullptr ;
914+ m_pMouseFocusConnector.compare_exchange_strong ( pExpected, pConnector.get () );
869915 }
870916
871- if ( !pConnector->Init () )
872917 {
873- if ( bSetCurrentConnector )
918+ COpenVRConnector *pExpected = nullptr ;
919+ if ( m_pKeyboardFocusConnector.compare_exchange_strong ( pExpected, pConnector.get () ) )
874920 {
875- SetFocus ( nullptr );
921+ openvr_log.debugf ( " Changed keyboard focus connector to %p " , pConnector.get () );
922+ update_connector_display_info_wl ( NULL );
876923 }
877- return nullptr ;
878924 }
879925
880926 std::scoped_lock lock{ m_mutActiveConnectors };
@@ -998,16 +1044,6 @@ namespace gamescope
9981044 m_nOverlaysVisible.wait ( 0 );
9991045 }
10001046
1001- void SetFocus ( COpenVRConnector *pFocus )
1002- {
1003- COpenVRConnector *pPreviousFocus = m_pFocusConnector.exchange ( pFocus );
1004- if ( pPreviousFocus != pFocus )
1005- {
1006- MakeFocusDirty ();
1007- update_connector_display_info_wl ( NULL );
1008- }
1009- }
1010-
10111047 COpenVRPlane *GetPlaneByOverlayHandle ( vr::VROverlayHandle_t hOverlay )
10121048 {
10131049 COpenVRPlane *pPlane = nullptr ;
@@ -1020,6 +1056,75 @@ namespace gamescope
10201056 return pPlane;
10211057 }
10221058
1059+ void SetMouseFocus ( uint64_t ulFocusOverlay )
1060+ {
1061+ uint64_t oldOverlayHandle = g_FocusedVROverlayMouse.exchange ( ulFocusOverlay );
1062+
1063+ if ( oldOverlayHandle == ulFocusOverlay )
1064+ return ;
1065+
1066+ openvr_log.debugf ( " Changing mouse focus from %lx to %lx" , oldOverlayHandle, ulFocusOverlay );
1067+
1068+ COpenVRConnector *pInputConnector = nullptr ;
1069+ if ( ulFocusOverlay != vr::k_ulOverlayHandleInvalid )
1070+ {
1071+ COpenVRPlane *pInputPlane = GetPlaneByOverlayHandle ( ulFocusOverlay );
1072+ if ( pInputPlane )
1073+ {
1074+ pInputConnector = pInputPlane->GetConnector ();
1075+ }
1076+ }
1077+
1078+ if ( pInputConnector )
1079+ {
1080+ pInputConnector->m_bUsingVRMouse = true ;
1081+
1082+ COpenVRConnector *pOldConnector = m_pMouseFocusConnector.exchange ( pInputConnector );
1083+
1084+ if ( pOldConnector != pInputConnector )
1085+ {
1086+ openvr_log.debugf ( " Changing mouse focus connector to %p" , pInputConnector );
1087+
1088+ // We don't do anything with mouse focus that isn't local,
1089+ // so only dirty focus if the focus connector changed.
1090+ //
1091+ // Unlike with Keyboard where we need to focus for forwarders too!
1092+
1093+ MakeFocusDirty ();
1094+ nudge_steamcompmgr ();
1095+ }
1096+ }
1097+ }
1098+
1099+ void SetKeyboardFocus ( uint64_t ulFocusOverlay )
1100+ {
1101+ uint64_t oldOverlayHandle = g_FocusedVROverlayKeyboard.exchange ( ulFocusOverlay );
1102+
1103+ if ( oldOverlayHandle == ulFocusOverlay )
1104+ return ;
1105+
1106+ openvr_log.debugf ( " Changing keyboard focus from %lx to %lx" , oldOverlayHandle, ulFocusOverlay );
1107+
1108+ COpenVRConnector *pInputConnector = nullptr ;
1109+ if ( ulFocusOverlay != vr::k_ulOverlayHandleInvalid )
1110+ {
1111+ COpenVRPlane *pInputPlane = GetPlaneByOverlayHandle ( ulFocusOverlay );
1112+ if ( pInputPlane )
1113+ {
1114+ pInputConnector = pInputPlane->GetConnector ();
1115+ }
1116+ }
1117+
1118+ if ( pInputConnector )
1119+ {
1120+ openvr_log.debugf ( " Changing keyboard focus connector to %p" , pInputConnector );
1121+ m_pKeyboardFocusConnector.exchange ( pInputConnector );
1122+ }
1123+
1124+ MakeFocusDirty ();
1125+ nudge_steamcompmgr ();
1126+ }
1127+
10231128 void ProcessVRInput ()
10241129 {
10251130 std::scoped_lock lock{m_mutActiveConnectors};
@@ -1161,7 +1266,8 @@ namespace gamescope
11611266 {
11621267 if (pConnector && pConnector->m_bUsingVRMouse )
11631268 {
1164- SetFocus (pConnector);
1269+ SetMouseFocus ( hOverlay );
1270+
11651271 float flX = vrEvent.data .mouse .x / float (g_nOutputWidth);
11661272 float flY = (g_nOutputHeight - vrEvent.data .mouse .y ) / float (g_nOutputHeight);
11671273
@@ -1197,17 +1303,31 @@ namespace gamescope
11971303 break ;
11981304 }
11991305 case vr::VREvent_FocusEnter:
1200- if (pConnector)
12011306 {
1202- pConnector->m_bUsingVRMouse = true ;
1203- SetFocus (pConnector);
1307+ if (pConnector)
1308+ {
1309+ pConnector->m_bUsingVRMouse = true ;
1310+ SetMouseFocus ( hOverlay );
1311+ }
1312+ }
1313+ break ;
1314+
1315+ case vr::VREvent_OverlayFocusChanged:
1316+ {
1317+ SetMouseFocus ( vrEvent.data .overlay .overlayHandle );
1318+ }
1319+ break ;
1320+ case vr::VREvent_OverlayInputFocusChanged:
1321+ {
1322+ const vr::VREvent_Data_Gamescope_t &data = CastToGamescopeEventData ( vrEvent.data );
1323+ SetKeyboardFocus ( data.overlayInputFocus .overlayHandle );
12041324 }
12051325 break ;
12061326 case vr::VREvent_MouseButtonUp:
12071327 case vr::VREvent_MouseButtonDown:
12081328 if (pConnector)
12091329 {
1210- SetFocus (pConnector );
1330+ SetMouseFocus ( hOverlay );
12111331
12121332 if (!pConnector->m_bUsingVRMouse )
12131333 {
@@ -1289,7 +1409,8 @@ namespace gamescope
12891409 case vr::VREvent_ScrollSmooth:
12901410 if (pConnector)
12911411 {
1292- SetFocus (pConnector);
1412+ SetMouseFocus ( hOverlay );
1413+
12931414 float flX = -vrEvent.data .scroll .xdelta * m_flScrollSpeed;
12941415 float flY = -vrEvent.data .scroll .ydelta * m_flScrollSpeed;
12951416 wlserver_lock ();
@@ -1299,24 +1420,6 @@ namespace gamescope
12991420 }
13001421 break ;
13011422
1302- case vr::VREvent_ButtonPress:
1303- if (pConnector)
1304- {
1305- SetFocus (pConnector);
1306- vr::EVRButtonId button = (vr::EVRButtonId)vrEvent.data .controller .button ;
1307-
1308- if (button != vr::k_EButton_Steam && button != vr::k_EButton_QAM)
1309- break ;
1310-
1311- if (button == vr::k_EButton_Steam)
1312- openvr_log.infof (" STEAM button pressed." );
1313- else
1314- openvr_log.infof (" QAM button pressed." );
1315-
1316- wlserver_open_steam_menu (button == vr::k_EButton_QAM);
1317- }
1318- break ;
1319-
13201423 case vr::VREvent_OverlayShown:
13211424 case vr::VREvent_OverlayHidden:
13221425 if (pConnector)
@@ -1419,7 +1522,8 @@ namespace gamescope
14191522 friend COpenVRConnector;
14201523 std::vector<COpenVRConnector*> m_pActiveConnectors;
14211524 std::mutex m_mutActiveConnectors;
1422- std::atomic<COpenVRConnector *> m_pFocusConnector;
1525+ std::atomic<COpenVRConnector *> m_pMouseFocusConnector;
1526+ std::atomic<COpenVRConnector *> m_pKeyboardFocusConnector;
14231527
14241528 std::atomic<bool > m_bInitted = { false };
14251529 std::atomic<bool > m_bRunning = { false };
@@ -1462,9 +1566,10 @@ namespace gamescope
14621566 m_pBackend->m_pActiveConnectors .erase ( iter );
14631567
14641568 COpenVRConnector *pThis = this ;
1465- m_pBackend->m_pFocusConnector .compare_exchange_strong ( pThis, nullptr );
1569+ m_pBackend->m_pMouseFocusConnector .compare_exchange_strong ( pThis, nullptr );
1570+ pThis = this ;
1571+ m_pBackend->m_pKeyboardFocusConnector .compare_exchange_strong ( pThis, nullptr );
14661572 }
1467-
14681573 GamescopeScreenType COpenVRConnector::GetScreenType () const
14691574 {
14701575 return GAMESCOPE_SCREEN_TYPE_INTERNAL;
0 commit comments