// For the nested case, reads input from the SDL window and send to wayland #include #include #include #include "main.hpp" #include "wlserver.hpp" #include "sdlwindow.hpp" #include "rendervulkan.hpp" #include "steamcompmgr.hpp" #include "sdlscancodetable.hpp" bool g_bSDLInitOK = false; std::mutex g_SDLInitLock; bool g_bWindowShown = false; int g_nOldNestedRefresh = 0; bool g_bWindowFocused = true; SDL_Window *g_SDLWindow; uint32_t g_unSDLUserEventID; SDL_Event g_SDLUserEvent; //----------------------------------------------------------------------------- // Purpose: Convert from the remote scancode to a Linux event keycode //----------------------------------------------------------------------------- static inline uint32_t SDLScancodeToLinuxKey( uint32_t nScancode ) { if ( nScancode < sizeof( s_ScancodeTable ) / sizeof( s_ScancodeTable[0] ) ) { return s_ScancodeTable[ nScancode ]; } return KEY_RESERVED; } static inline int SDLButtonToLinuxButton( int SDLButton ) { switch ( SDLButton ) { case SDL_BUTTON_LEFT: return BTN_LEFT; case SDL_BUTTON_MIDDLE: return BTN_MIDDLE; case SDL_BUTTON_RIGHT: return BTN_RIGHT; case SDL_BUTTON_X1: return BTN_FORWARD; case SDL_BUTTON_X2: return BTN_BACK; default: return 0; } } void updateOutputRefresh( void ) { int display_index = 0; SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; display_index = SDL_GetWindowDisplayIndex( g_SDLWindow ); if ( SDL_GetDesktopDisplayMode( display_index, &mode ) == 0 ) { g_nOutputRefresh = mode.refresh_rate; } } void inputSDLThreadRun( void ) { SDL_Event event; SDL_Keymod mod; uint32_t key; if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_EVENTS ) != 0 ) { fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); g_SDLInitLock.unlock(); return; } g_unSDLUserEventID = SDL_RegisterEvents( 1 ); g_SDLUserEvent.type = g_unSDLUserEventID; g_SDLUserEvent.user.code = 32; uint32_t nSDLWindowFlags = SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN; if ( g_bBorderlessOutputWindow == true ) { nSDLWindowFlags |= SDL_WINDOW_BORDERLESS; } if ( g_bFullscreen == true ) { nSDLWindowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } g_SDLWindow = SDL_CreateWindow( "gamescope", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, g_nOutputWidth, g_nOutputHeight, nSDLWindowFlags ); if ( g_SDLWindow == nullptr ) { fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); g_SDLInitLock.unlock(); return; } unsigned int extCount = 0; SDL_Vulkan_GetInstanceExtensions( g_SDLWindow, &extCount, nullptr ); g_vecSDLInstanceExts.resize( extCount ); SDL_Vulkan_GetInstanceExtensions( g_SDLWindow, &extCount, g_vecSDLInstanceExts.data() ); SDL_SetRelativeMouseMode(SDL_TRUE); g_nOldNestedRefresh = g_nNestedRefresh; g_bSDLInitOK = true; g_SDLInitLock.unlock(); while( SDL_WaitEvent( &event ) ) { switch( event.type ) { case SDL_MOUSEMOTION: wlserver_lock(); wlserver_mousemotion( event.motion.xrel, event.motion.yrel, event.motion.timestamp ); wlserver_unlock(); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: wlserver_lock(); wlserver_mousebutton( SDLButtonToLinuxButton( event.button.button ), event.button.state == SDL_PRESSED, event.button.timestamp ); wlserver_unlock(); break; case SDL_MOUSEWHEEL: wlserver_lock(); wlserver_mousewheel( -event.wheel.x, -event.wheel.y, event.wheel.timestamp ); wlserver_unlock(); break; case SDL_KEYDOWN: case SDL_KEYUP: mod = SDL_GetModState(); key = SDLScancodeToLinuxKey( event.key.keysym.scancode ); if ( event.type == SDL_KEYUP && mod & KMOD_LGUI ) { switch ( key ) { case KEY_F: g_bFullscreen = !g_bFullscreen; SDL_SetWindowFullscreen( g_SDLWindow, g_bFullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0 ); break; case KEY_N: g_bFilterGameWindow = !g_bFilterGameWindow; break; case KEY_S: g_bTakeScreenshot = true; break; default: goto client; } break; } client: wlserver_lock(); wlserver_key( key, event.type == SDL_KEYDOWN, event.key.timestamp ); wlserver_unlock(); break; case SDL_WINDOWEVENT: switch( event.window.event ) { default: break; case SDL_WINDOWEVENT_MOVED: case SDL_WINDOWEVENT_SHOWN: updateOutputRefresh(); break; case SDL_WINDOWEVENT_SIZE_CHANGED: g_nOutputWidth = event.window.data1; g_nOutputHeight = event.window.data2; updateOutputRefresh(); break; case SDL_WINDOWEVENT_FOCUS_LOST: g_nNestedRefresh = g_nNestedUnfocusedRefresh; g_bWindowFocused = false; break; case SDL_WINDOWEVENT_FOCUS_GAINED: g_nNestedRefresh = g_nOldNestedRefresh; g_bWindowFocused = true; break; } break; default: if ( event.type == g_unSDLUserEventID ) { sdlwindow_update(); } break; } } } bool sdlwindow_init( void ) { g_SDLInitLock.lock(); std::thread inputSDLThread( inputSDLThreadRun ); inputSDLThread.detach(); // When this returns SDL_Init should be over g_SDLInitLock.lock(); return g_bSDLInitOK; } void sdlwindow_update( void ) { if ( g_bWindowShown != hasFocusWindow ) { g_bWindowShown = hasFocusWindow; if ( g_bWindowShown ) { SDL_ShowWindow( g_SDLWindow ); } else { SDL_HideWindow( g_SDLWindow ); } } } void sdlwindow_pushupdate( void ) { SDL_PushEvent( &g_SDLUserEvent ); }