Skip to content
Open
65 changes: 56 additions & 9 deletions src/Backends/SDLBackend.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// For the nested case, reads input from the SDL window and send to wayland

#include <X11/Xlib.h>
#include <linux/input.h>
#include <thread>
#include <mutex>
#include <string>
Expand All @@ -21,6 +22,8 @@
#include "Utils/Defer.h"
#include "refresh_rate.h"

#include "LibInputHandler.h"

#include "sdlscancodetable.hpp"

static int g_nOldNestedRefresh = 0;
Expand Down Expand Up @@ -191,6 +194,10 @@ namespace gamescope
uint32_t m_uUserEventIdBase = 0u;
std::vector<const char *> m_pszInstanceExtensions;


std::shared_ptr<CLibInputHandler> m_pLibInput;
CAsyncWaiter<CRawPointer<IWaitable>, 16> m_LibInputWaiter;

std::thread m_SDLThread;
std::atomic<SDLInitState> m_eSDLInit = { SDLInitState::SDLInit_Waiting };

Expand Down Expand Up @@ -394,12 +401,24 @@ namespace gamescope
////////////////

CSDLBackend::CSDLBackend()
: m_SDLThread{ [this](){ this->SDLThreadFunc(); } }
: m_LibInputWaiter{ "gamescope-libinput" }
, m_SDLThread{ [this](){ this->SDLThreadFunc(); } }
{
}

bool CSDLBackend::Init()
{
if (g_libinputSelectedDevices.size() > 0) {
std::unique_ptr<CLibInputHandler> pLibInput = std::make_unique<CLibInputHandler>();
if ( pLibInput->Init() ) {
m_pLibInput = std::move( pLibInput );
m_LibInputWaiter.AddWaitable( m_pLibInput.get() );
} else {
fprintf(stderr, "CSDLBackend::Init failed: Unable to register LIBINPUT devices");
return false;
}
}

m_eSDLInit.wait( SDLInitState::SDLInit_Waiting );

return m_eSDLInit == SDLInitState::SDLInit_Success;
Expand Down Expand Up @@ -664,6 +683,7 @@ namespace gamescope

case SDL_MOUSEMOTION:
{
if (g_bMouseDisabled) break;
if ( m_bApplicationGrabbed )
{
if ( g_bWindowFocused )
Expand All @@ -689,6 +709,7 @@ namespace gamescope
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
if (g_bMouseDisabled) break;
wlserver_lock();
wlserver_mousebutton( SDLButtonToLinuxButton( event.button.button ),
event.button.state == SDL_PRESSED,
Expand All @@ -699,6 +720,7 @@ namespace gamescope

case SDL_MOUSEWHEEL:
{
if (g_bMouseDisabled) break;
wlserver_lock();
wlserver_mousewheel( -event.wheel.x, -event.wheel.y, fake_timestamp );
wlserver_unlock();
Expand Down Expand Up @@ -731,6 +753,7 @@ namespace gamescope

case SDL_KEYDOWN:
{
if (g_bKeyboardDisabled) break;
// If this keydown event is super + one of the shortcut keys, consume the keydown event, since the corresponding keyup
// event will be consumed by the next case statement when the user releases the key
if ( event.key.keysym.mod & KMOD_LGUI )
Expand All @@ -747,7 +770,39 @@ namespace gamescope
[[fallthrough]];
case SDL_KEYUP:
{
if (g_bKeyboardDisabled) break;
uint32_t key = SDLScancodeToLinuxKey( event.key.keysym.scancode );
static std::bitset<KEY_MAX+1> held_keys;
static bool toggle_grab_on_all_keys_up;

if (key <= KEY_MAX) {
held_keys[key] = (event.type == SDL_KEYUP); // Toggle the pressed button
}
if (held_keys[KEY_G] && held_keys[KEY_LEFTMETA]) toggle_grab_on_all_keys_up = true;

if (toggle_grab_on_all_keys_up && held_keys.none()) {
toggle_grab_on_all_keys_up = false;
g_bGrabbed = !g_bGrabbed;

for (int dev_fd : g_libinputSelectedDevices_grabbed_fds) {
if (g_bGrabbed) {
if (ioctl(dev_fd, EVIOCGRAB, 1) < 0) {
fprintf( stderr,"SDL: Failed to grab exclusive lock on device: %d\n", dev_fd);
}
} else {
if (ioctl(dev_fd, EVIOCGRAB, 0) < 0) {
fprintf( stderr,"SDL: Failed to release exclusive grab on device: %d\n", dev_fd);
}
}
}

SDL_SetWindowKeyboardGrab( m_Connector.GetSDLWindow(), g_bGrabbed ? SDL_TRUE : SDL_FALSE );

SDL_Event event;
event.type = GetUserEventIndex( GAMESCOPE_SDL_EVENT_TITLE );
SDL_PushEvent( &event );
}


if ( event.type == SDL_KEYUP && ( event.key.keysym.mod & KMOD_LGUI ) )
{
Expand Down Expand Up @@ -781,14 +836,6 @@ namespace gamescope
case KEY_S:
gamescope::CScreenshotManager::Get().TakeScreenshot( true );
break;
case KEY_G:
g_bGrabbed = !g_bGrabbed;
SDL_SetWindowKeyboardGrab( m_Connector.GetSDLWindow(), g_bGrabbed ? SDL_TRUE : SDL_FALSE );

SDL_Event event;
event.type = GetUserEventIndex( GAMESCOPE_SDL_EVENT_TITLE );
SDL_PushEvent( &event );
break;
default:
handled = false;
}
Expand Down
69 changes: 69 additions & 0 deletions src/Backends/WaylandBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "Utils/TempFiles.h"

#include <cstring>
#include <linux/input.h>
#include <unordered_map>
#include <unordered_set>
#include <csignal>
Expand All @@ -37,6 +38,8 @@
#include <xdg-toplevel-icon-v1-client-protocol.h>
#include "wlr_end.hpp"

#include "LibInputHandler.h"

#include "drm_include.h"

#define WL_FRACTIONAL_SCALE_DENOMINATOR 120
Expand Down Expand Up @@ -808,6 +811,11 @@ namespace gamescope
wl_surface *m_pCursorSurface = nullptr;
std::shared_ptr<INestedHints::CursorInfo> m_pDefaultCursorInfo;
wl_surface *m_pDefaultCursorSurface = nullptr;


std::shared_ptr<CLibInputHandler> m_pLibInput;
CAsyncWaiter<CRawPointer<IWaitable>, 16> m_LibInputWaiter;

};
const wl_registry_listener CWaylandBackend::s_RegistryListener =
{
Expand Down Expand Up @@ -1922,11 +1930,24 @@ namespace gamescope
};

CWaylandBackend::CWaylandBackend()
: m_LibInputWaiter{ "gamescope-libinput" }
{
}

bool CWaylandBackend::Init()
{
if (g_libinputSelectedDevices.size() > 0) {
std::unique_ptr<CLibInputHandler> pLibInput = std::make_unique<CLibInputHandler>();
if ( pLibInput->Init() ) {
m_pLibInput = std::move( pLibInput );
m_LibInputWaiter.AddWaitable( m_pLibInput.get() );
} else {
xdg_log.errorf( "CWaylandBackend::Init failed: Unable to register LIBINPUT devices" );
return false;
}
}


g_nOutputWidth = g_nPreferredOutputWidth;
g_nOutputHeight = g_nPreferredOutputHeight;
g_nOutputRefresh = g_nNestedRefresh;
Expand Down Expand Up @@ -2836,8 +2857,36 @@ namespace gamescope

void CWaylandInputThread::HandleKey( uint32_t uKey, bool bPressed )
{
if (g_bKeyboardDisabled) return;

if ( m_uKeyModifiers & m_uModMask[ GAMESCOPE_WAYLAND_MOD_META ] )
{

static std::bitset<KEY_MAX+1> held_keys;
static bool toggle_grab_on_all_keys_up;

if (uKey <= KEY_MAX) {
held_keys[uKey] = bPressed; // Toggle the pressed button
}
if (held_keys[KEY_G] && held_keys[KEY_LEFTMETA]) toggle_grab_on_all_keys_up = true;

if (toggle_grab_on_all_keys_up && held_keys.none()) {
toggle_grab_on_all_keys_up = false;
g_bGrabbed = !g_bGrabbed;

for (int dev_fd : g_libinputSelectedDevices_grabbed_fds) {
if (g_bGrabbed) {
if (ioctl(dev_fd, EVIOCGRAB, 1) < 0) {
fprintf( stderr,"Wayland: Failed to grab exclusive lock on device: %d\n", dev_fd);
}
} else {
if (ioctl(dev_fd, EVIOCGRAB, 0) < 0) {
fprintf( stderr,"Wayland: Failed to release exclusive grab on device: %d\n", dev_fd);
}
}
}
}

switch ( uKey )
{
case KEY_F:
Expand Down Expand Up @@ -2981,6 +3030,8 @@ namespace gamescope

void CWaylandInputThread::Wayland_Pointer_Enter( wl_pointer *pPointer, uint32_t uSerial, wl_surface *pSurface, wl_fixed_t fSurfaceX, wl_fixed_t fSurfaceY )
{
if (g_bMouseDisabled) return;

if ( !IsSurfacePlane( pSurface ) )
return;

Expand All @@ -2995,6 +3046,8 @@ namespace gamescope
}
void CWaylandInputThread::Wayland_Pointer_Leave( wl_pointer *pPointer, uint32_t uSerial, wl_surface *pSurface )
{
if (g_bMouseDisabled) return;

if ( !IsSurfacePlane( pSurface ) )
return;

Expand All @@ -3008,6 +3061,8 @@ namespace gamescope
}
void CWaylandInputThread::Wayland_Pointer_Motion( wl_pointer *pPointer, uint32_t uTime, wl_fixed_t fSurfaceX, wl_fixed_t fSurfaceY )
{
if (g_bMouseDisabled) return;

if ( m_pRelativePointer.load() != nullptr )
return;

Expand Down Expand Up @@ -3037,6 +3092,8 @@ namespace gamescope
}
void CWaylandInputThread::Wayland_Pointer_Button( wl_pointer *pPointer, uint32_t uSerial, uint32_t uTime, uint32_t uButton, uint32_t uState )
{
if (g_bMouseDisabled) return;

// Don't do any motion/movement stuff if we don't have kb focus
if ( !cv_wayland_mouse_warp_without_keyboard_focus && !m_bKeyboardEntered )
return;
Expand All @@ -3060,6 +3117,8 @@ namespace gamescope
}
void CWaylandInputThread::Wayland_Pointer_Axis_Value120( wl_pointer *pPointer, uint32_t uAxis, int32_t nValue120 )
{
if (g_bMouseDisabled) return;

if ( !cv_wayland_mouse_warp_without_keyboard_focus && !m_bKeyboardEntered )
return;

Expand All @@ -3070,6 +3129,8 @@ namespace gamescope
}
void CWaylandInputThread::Wayland_Pointer_Frame( wl_pointer *pPointer )
{
if (g_bMouseDisabled) return;

defer( m_uAxisSource = WL_POINTER_AXIS_SOURCE_WHEEL );
double flX = m_flScrollAccum[0];
double flY = m_flScrollAccum[1];
Expand Down Expand Up @@ -3124,6 +3185,8 @@ namespace gamescope
}
void CWaylandInputThread::Wayland_Keyboard_Enter( wl_keyboard *pKeyboard, uint32_t uSerial, wl_surface *pSurface, wl_array *pKeys )
{
if (g_bKeyboardDisabled) return;

m_bKeyboardEntered = true;
m_uScancodesHeld.clear();

Expand All @@ -3147,6 +3210,8 @@ namespace gamescope
}
void CWaylandInputThread::Wayland_Keyboard_Leave( wl_keyboard *pKeyboard, uint32_t uSerial, wl_surface *pSurface )
{
if (g_bKeyboardDisabled) return;

m_bKeyboardEntered = false;
m_uKeyModifiers = 0;

Expand All @@ -3157,6 +3222,8 @@ namespace gamescope
}
void CWaylandInputThread::Wayland_Keyboard_Key( wl_keyboard *pKeyboard, uint32_t uSerial, uint32_t uTime, uint32_t uKey, uint32_t uState )
{
if (g_bKeyboardDisabled) return;

if ( !m_bKeyboardEntered )
return;

Expand Down Expand Up @@ -3184,6 +3251,8 @@ namespace gamescope

void CWaylandInputThread::Wayland_RelativePointer_RelativeMotion( zwp_relative_pointer_v1 *pRelativePointer, uint32_t uTimeHi, uint32_t uTimeLo, wl_fixed_t fDx, wl_fixed_t fDy, wl_fixed_t fDxUnaccel, wl_fixed_t fDyUnaccel )
{
if (g_bMouseDisabled) return;

// Don't do any motion/movement stuff if we don't have kb focus
if ( !cv_wayland_mouse_relmotion_without_keyboard_focus && !m_bKeyboardEntered )
return;
Expand Down
Loading