Skip to content

Commit fe0b022

Browse files
committed
Added support for SDL_SetWindowKeyboardGrab():
- With SDL_SetWindowKeyboardGrab() function, we are able to replace low level XGrabKeyboard() and XUngrabKeyboard() making the code much more portable. Also it fixes a couple of corner cases where window focus was lost when concurrent X applications tried to grab the keyboard. - Client no longer depends on libx11 directly and with a future commit we can work on Wayland support as mentioned in #7. - Requires SDL >= 2.0.16.
1 parent 9fc9a79 commit fe0b022

File tree

3 files changed

+15
-45
lines changed

3 files changed

+15
-45
lines changed

README.md

+9-10
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,7 @@ without chroma subsampling for sharp and crystal clear text.
113113
* Fully CLI based customization. User can specify all required parameters via
114114
command line switches, allow perfect integration into different window
115115
managers.
116-
* Desktop in window support with [XGrabKeyboard](https://tronche.com/gui/x/xlib/input/XGrabKeyboard.html)
117-
and [XUngrabKeyboard](https://tronche.com/gui/x/xlib/input/XUngrabKeyboard.html)
116+
* Desktop in window support with [SDL_SetWindowKeyboardGrab](https://wiki.libsdl.org/SDL_SetWindowKeyboardGrab)
118117
while leaving mouse pointer ungrabbed. Supporting Alt+Tab and Windows special
119118
keys grab, even if assigned to the window manager.
120119
* SDL window is created without `SDL_WINDOW_RESIZABLE` flag set, so window
@@ -160,14 +159,14 @@ without chroma subsampling for sharp and crystal clear text.
160159
# Building
161160

162161
VDI Stream Client uses GNU Build System to configure, build and install the
163-
application. It requires `sdl2`, `sdl2_ttf`, `libx11`, `libglvnd`, `libusb`,
164-
`usbredir` and the [Parsec SDK](https://github.com/parsec-cloud/parsec-sdk).
165-
The build system will search the SDK first in build directory and use DSO
166-
linking, the resulting binary will be redistributable but you need to ship
167-
Parsec library somehow. If not found, it will search in system-wide include and
168-
library directories and link accordingly, binary may not be redistributable.
169-
For build and install use the commands below and if `--prefix=/usr` is used,
170-
the `make install` command must be run as root user.
162+
application. It requires `sdl2`, `sdl2_ttf`, `libglvnd`, `libusb`, `usbredir`
163+
and the [Parsec SDK](https://github.com/parsec-cloud/parsec-sdk). The build
164+
system will search the SDK first in build directory and use DSO linking, the
165+
resulting binary will be redistributable but you need to ship Parsec library
166+
somehow. If not found, it will search in system-wide include and library
167+
directories and link accordingly, binary may not be redistributable. For build
168+
and install use the commands below and if `--prefix=/usr` is used, the
169+
`make install` command must be run as root user.
171170

172171
```
173172
git clone https://github.com/parsec-cloud/parsec-sdk

configure.ac

+1-4
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,11 @@ PKG_PROG_PKG_CONFIG
2121
AC_CHECK_HEADER([dlfcn.h], [], [AC_MSG_ERROR([*** dlfcn.h is required, install glibc header files])])
2222
AC_CHECK_LIB([dl], [dlopen], [], [AC_MSG_ERROR([*** dlopen is required, install glibc library files])])
2323

24-
# checking for libx11 library.
25-
PKG_CHECK_MODULES([X11], [x11])
26-
2724
# checking for libglvnd library.
2825
PKG_CHECK_MODULES([GL], [gl])
2926

3027
# checking for sdl2 library.
31-
PKG_CHECK_MODULES([SDL2], [sdl2 >= 2.0.5])
28+
PKG_CHECK_MODULES([SDL2], [sdl2 >= 2.0.16])
3229

3330
# checking for sdl2_ttf library.
3431
PKG_CHECK_MODULES([SDL2_TTF], [SDL2_ttf >= 2.0.5])

src/parsec.c

+5-31
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ Sint32 vdi_stream_client__render_text(void *opaque, char *text) {
127127
Sint32 vdi_stream_client__event_loop(vdi_config_s *vdi_config) {
128128
struct parsec_context_s parsec_context = {0};
129129
struct redirect_context_s redirect_context[USB_MAX] = {0};
130-
SDL_bool focus = SDL_FALSE;
131130
SDL_bool grab_forced = SDL_FALSE;
132131
Uint32 wait_time = 0;
133132
Uint32 last_time = 0;
@@ -421,10 +420,6 @@ Sint32 vdi_stream_client__event_loop(vdi_config_s *vdi_config) {
421420
vdi_stream_client__render_text(&parsec_context, "Closing...");
422421
break;
423422
case SDL_KEYUP:
424-
425-
/* TODO: we need to re-grab keyboard later. (workaround for buggy x11 and sdl) */
426-
focus = SDL_FALSE;
427-
428423
pmsg.type = MESSAGE_KEYBOARD;
429424
pmsg.keyboard.code = (ParsecKeycode) msg.key.keysym.scancode;
430425
pmsg.keyboard.mod = msg.key.keysym.mod;
@@ -574,27 +569,15 @@ Sint32 vdi_stream_client__event_loop(vdi_config_s *vdi_config) {
574569
break;
575570
case SDL_WINDOWEVENT:
576571
switch (msg.window.event) {
577-
case SDL_WINDOWEVENT_FOCUS_GAINED:
572+
case SDL_WINDOWEVENT_ENTER:
578573
SDL_EventState(SDL_KEYDOWN, SDL_ENABLE);
579574
SDL_EventState(SDL_KEYUP, SDL_ENABLE);
580-
XGrabKeyboard(wm_info.info.x11.display, wm_info.info.x11.window, False, GrabModeAsync, GrabModeAsync, CurrentTime);
581-
582-
/* TODO: copy client to host clipboard. (workaround for buggy x11 and sdl) */
583-
if (vdi_config->clipboard == 1 && SDL_HasClipboardText() == SDL_TRUE) {
584-
ParsecClientSendUserData(parsec_context.parsec, PARSEC_CLIPBOARD_MSG, SDL_GetClipboardText());
585-
}
586-
575+
SDL_SetWindowKeyboardGrab(parsec_context.window, SDL_TRUE);
587576
break;
588-
case SDL_WINDOWEVENT_FOCUS_LOST:
577+
case SDL_WINDOWEVENT_LEAVE:
589578
SDL_EventState(SDL_KEYDOWN, SDL_DISABLE);
590579
SDL_EventState(SDL_KEYUP, SDL_DISABLE);
591-
XUngrabKeyboard(wm_info.info.x11.display, CurrentTime);
592-
break;
593-
case SDL_WINDOWEVENT_ENTER:
594-
parsec_context.focus = SDL_TRUE;
595-
break;
596-
case SDL_WINDOWEVENT_LEAVE:
597-
parsec_context.focus = SDL_FALSE;
580+
SDL_SetWindowKeyboardGrab(parsec_context.window, SDL_FALSE);
598581
break;
599582
}
600583
break;
@@ -663,9 +646,6 @@ Sint32 vdi_stream_client__event_loop(vdi_config_s *vdi_config) {
663646
default:
664647
break;
665648
}
666-
667-
/* TODO: we need to re-grab keyboard later. (workaround for buggy x11 and sdl) */
668-
focus = SDL_FALSE;
669649
}
670650

671651
/* TODO: check if we need to grab input to force decoder initialization. (workaround for buggy parsec sdk) */
@@ -711,17 +691,11 @@ Sint32 vdi_stream_client__event_loop(vdi_config_s *vdi_config) {
711691
parsec_context.window_height = parsec_context.client_status.decoder->height;
712692
}
713693

714-
/* check if we need to regrab keyboard on modifier keypress. */
715-
if (focus == SDL_FALSE && (SDL_GetWindowFlags(parsec_context.window) & SDL_WINDOW_INPUT_FOCUS) != 0) {
716-
XGrabKeyboard(wm_info.info.x11.display, wm_info.info.x11.window, False, GrabModeAsync, GrabModeAsync, CurrentTime);
717-
focus = SDL_TRUE;
718-
}
719-
720694
SDL_Delay(1);
721695
}
722696

723697
/* already release any grabbed keyboard because thread termination can take some time. */
724-
XUngrabKeyboard(wm_info.info.x11.display, CurrentTime);
698+
SDL_SetWindowGrab(parsec_context.window, SDL_FALSE);
725699

726700
/* stop network threads for usb redirection. */
727701
if (vdi_config->usb_devices[0].vendor != 0) {

0 commit comments

Comments
 (0)