aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Zhu <lisp_25689@163.com>2023-10-16 14:59:48 +0000
committerRobert Clausecker <fuz@FreeBSD.org>2023-10-19 07:07:28 +0000
commitec671703cada5b2e44de0758dc14199b2fb75596 (patch)
tree6d277327363d2f9422e18496f4851116cbe77df0
parent69e85930e200e0ee30f78119063bbd43abe2be3e (diff)
downloadports-ec671703cada5b2e44de0758dc14199b2fb75596.tar.gz
ports-ec671703cada5b2e44de0758dc14199b2fb75596.zip
games/moonlight-embedded: update to 2.6.1
*Security fixes: Fixed CVE-2023-42799, CVE-2023-42800, and CVE-2023-42801 From: https://github.com/moonlight-stream/moonlight-embedded/releases/tag/v2.6.1 *Optimize the experience of grabing the keyboard. Now,Exclusive grab keyboard is the default behavior.But maybe it doesn't work on the Wayland WM. Use Alt+Ctrl+Shift+Z to grab or ungrab keyboard. *Optimize the experience of using the gamepad on FreeBSD. Replace the libevdev drive gamepad with SDL to ensure maximum compatibility. The rumble on the gamepad may not work. *Update man page. Explanation for changed patch files: *patch-src_config.c: *patch-src_config.h: *patch-src_main.c: *patch-src_input_sdl.c: *patch-src_input_sdl.h: Add -nosdl option and replace the libevdev drive gamepad with SDL. *patch-src_input_evdev.c: *patch-src_input_x11.c: *patch-src_video_x11.c: Add the way to ungrab the keyboard for x11* platform. *patch-src_sdl.c: *patch-src_sdl.h: *patch-src_input_sdl.c: Add the way to ungrab the keyboard for SDL platform. PR: 274452 MFH: 2023Q4 Security: f8c2f741-6be1-11ee-b33a-a04a5edf46d9
-rw-r--r--games/moonlight-embedded/Makefile7
-rw-r--r--games/moonlight-embedded/distinfo6
-rw-r--r--games/moonlight-embedded/files/patch-docs_README.pod77
-rw-r--r--games/moonlight-embedded/files/patch-src_config.c28
-rw-r--r--games/moonlight-embedded/files/patch-src_config.h10
-rw-r--r--games/moonlight-embedded/files/patch-src_input_evdev.c195
-rw-r--r--games/moonlight-embedded/files/patch-src_input_sdl.c309
-rw-r--r--games/moonlight-embedded/files/patch-src_input_sdl.h8
-rw-r--r--games/moonlight-embedded/files/patch-src_input_x11.c185
-rw-r--r--games/moonlight-embedded/files/patch-src_main.c59
-rw-r--r--games/moonlight-embedded/files/patch-src_sdl.c64
-rw-r--r--games/moonlight-embedded/files/patch-src_sdl.h19
-rw-r--r--games/moonlight-embedded/files/patch-src_video_x11.c42
-rw-r--r--games/moonlight-embedded/files/patch-third__party_moonlight-common-c_enet_CMakeLists.txt30
14 files changed, 966 insertions, 73 deletions
diff --git a/games/moonlight-embedded/Makefile b/games/moonlight-embedded/Makefile
index cb5234b0b748..62846f1b23f9 100644
--- a/games/moonlight-embedded/Makefile
+++ b/games/moonlight-embedded/Makefile
@@ -1,5 +1,5 @@
PORTNAME= moonlight-embedded
-DISTVERSION= 2.6.0
+DISTVERSION= 2.6.1
CATEGORIES= games
MASTER_SITES= https://github.com/moonlight-stream/moonlight-embedded/releases/download/v${DISTVERSION}/
@@ -34,9 +34,8 @@ NO_WRKSUBDIR= yes
CFLAGS+= -DHAS_SOCKLEN_T=1 -I${LOCALBASE}/include/libepoll-shim/
LDFLAGS+= -lepoll-shim
-pre-configure:
- @${REINPLACE_CMD} -e 's@/etc/moonlight/moonlight.conf@${PREFIX}/etc/moonlight.conf@' \
- -e 's@moonligt@moonlight@g' \
+post-patch:
+ @${REINPLACE_CMD} -e 's@/usr/local@${PREFIX}@' \
${WRKSRC}/docs/README.pod
post-install:
diff --git a/games/moonlight-embedded/distinfo b/games/moonlight-embedded/distinfo
index 40634ce7451a..d28e65f19dbf 100644
--- a/games/moonlight-embedded/distinfo
+++ b/games/moonlight-embedded/distinfo
@@ -1,3 +1,3 @@
-TIMESTAMP = 1695536824
-SHA256 (moonlight-embedded-2.6.0.tar.xz) = 71c883e10c65085c82a75c9affaef5e63f43d9074df74d48039d8c9b83120df7
-SIZE (moonlight-embedded-2.6.0.tar.xz) = 324572
+TIMESTAMP = 1697067500
+SHA256 (moonlight-embedded-2.6.1.tar.xz) = 1a252e18ac637e0ad7180238fa868e04629a3d8e43232097d5ccaa3b4142fded
+SIZE (moonlight-embedded-2.6.1.tar.xz) = 327632
diff --git a/games/moonlight-embedded/files/patch-docs_README.pod b/games/moonlight-embedded/files/patch-docs_README.pod
index f19916d281e1..4763811ca71f 100644
--- a/games/moonlight-embedded/files/patch-docs_README.pod
+++ b/games/moonlight-embedded/files/patch-docs_README.pod
@@ -1,18 +1,26 @@
---- docs/README.pod.orig 2023-09-01 23:40:56 UTC
+--- docs/README.pod.orig 2023-10-11 15:50:11 UTC
+++ docs/README.pod
-@@ -27,6 +27,11 @@ Stream game from host to this computer.
+@@ -13,7 +13,10 @@ Usage: I<moonlight> E<lt>actionE<gt> [options] [host]
- List all available games and application on host.
+ =item B<pair>
-+=item B<discover>
-+
-+Discover moonlight server host.Need start avahi-daemon first.
-+NOTE:It's not work under wifibox.
-+
- =item B<quit>
+-Pair this computer with the host.
++ Pair this computer with the host.
++ If [host] is not specified here,moonlight will auto discover host first.
++ It's need start avahi-daemon first.
++ NOTE:It's not work under wifibox.
+
+ =item B<unpair>
+
+@@ -22,6 +25,7 @@ Unpair this computer with the host.
+ =item B<stream>
- Quit the current running game or application on host.
-@@ -99,9 +104,9 @@ By default, 1392 is used on LAN and 1024 on WAN.
+ Stream game from host to this computer.
++If [host] is not specified here,moonlight will auto discover host first.
+
+ =item B<list>
+
+@@ -99,9 +103,9 @@ By default, 1392 is used on LAN and 1024 on WAN.
=item B<-codec> [I<CODEC>]
Select codec to use.
@@ -25,7 +33,7 @@
=item B<-remote> [I<yes/no/auto>]
-@@ -138,8 +143,10 @@ By default the gamecontrollerdb.txt provided by Moonli
+@@ -138,8 +142,10 @@ By default the gamecontrollerdb.txt provided by Moonli
=item B<-platform> [I<PLATFORM>]
Select platform for audio and video output and input.
@@ -37,19 +45,22 @@
=item B<-nounsupported>
Don't stream if resolution is not officially supported by the server
-@@ -170,11 +177,6 @@ Enable the I<INPUT> device.
+@@ -170,10 +176,11 @@ Enable the I<INPUT> device.
By default all available input devices are enabled.
Only evdev devices /dev/input/event* are supported.
-=item B<-audio> [I<DEVICE>]
--
++=item B<-nosdl>
+
-Use <DEVICE> as audio output device.
-The default value is 'sysdefault' for ALSA and 'hdmi' for OMX on the Raspberry Pi.
--
++Use libevdev to drive game controller instead.
++SDL controller module have better compatibility for gamepad.
++So it's not recommended.
+
=item B<-windowed>
- Display the stream in a window instead of fullscreen.
-@@ -182,22 +184,48 @@ Only available when X11 or SDL platform is used.
+@@ -182,22 +189,51 @@ Only available when X11 or SDL platform is used.
=back
@@ -74,32 +85,36 @@
If no user specified configuration file is available the configuration will be loaded from:
- /etc/moonlight/moonlight.conf
+- /etc/moonlight/moonlight.conf
++ /usr/local/etc/moonlight.conf
-A documented example configuration file can be found at /etc/moonlight/moonlight.conf.
+A documented example configuration file can be found at /usr/local/etc/moonlight.conf.
--=head1 COMMENTS
+=head1 KEYBOARD SHORTCUTS
-
- Use Ctrl+Alt+Shift+Q or Play+Back+LeftShoulder+RightShoulder to quit the streaming session.
-
++
++ Use Ctrl+Alt+Shift+Q or Play+Back+LeftShoulder+RightShoulder to quit the streaming session.
++ Use Ctrl+Alt+Shift+Z to Grab/Ungrab keyboard.
++ It may not grab the keyboard Using sdl platform under wayland.
++
+=head1 GAMEPAD
+
+FreeBSD supports fewer controllers.Please see hgame(4) xb360gp(4) ps4dshock(4) and FreeBSD forums...
+SDL platforms have better compatibility for gamepad.
+
-+=head1 COMMENTS
-+
-+Platform 'sdl' and 'x11' is soft decoding.
-+Platform 'x11_vaapi' and 'x11_vdpau' is hard decoding.
-+If you want to use GPU decoding,you must meet 3 conditions:
-+ 1.Use platform 'x11_vaapi' or 'x11_vdpau'.
-+ 2.Use Intel or AMD(not test) GPU driver in xorg.conf
+ =head1 COMMENTS
+
+-Use Ctrl+Alt+Shift+Q or Play+Back+LeftShoulder+RightShoulder to quit the streaming session.
++Platform 'sdl' and 'x11' is soft decoding.'x11' is deprecated.
++Platform 'x11_vaapi' and 'x11_vdpau' is hard accel decoding.
++If you want to use GPU decoding for intel gpu,you must meet 3 conditions:
++ 1.Use platform 'x11_vaapi'
++ 2.Use intel GPU driver in xorg.conf but not modesetting.
+ 3.Install package:libva-intel-driver/libva-intel-media-driver or libva-vdpau-driver.
+
+
=head1 AUTHOR
-Iwan Timmer E<lt>irtimmer@gmail.comE<gt>
-+Thanks Iwan Timmer and every contributor!
-+Armin Zhu E<lt>lisp_25689@163.comE<gt>
++ Thanks Iwan Timmer and every contributor!
++ Armin Zhu E<lt>lisp_25689@163.comE<gt>.
diff --git a/games/moonlight-embedded/files/patch-src_config.c b/games/moonlight-embedded/files/patch-src_config.c
new file mode 100644
index 000000000000..58b295aad0f0
--- /dev/null
+++ b/games/moonlight-embedded/files/patch-src_config.c
@@ -0,0 +1,28 @@
+--- src/config.c.orig 2023-10-11 15:50:11 UTC
++++ src/config.c
+@@ -42,6 +42,7 @@
+ #define write_config_bool(fd, key, value) fprintf(fd, "%s = %s\n", key, value ? "true":"false")
+
+ bool inputAdded = false;
++bool isNoSdl = false;
+
+ static struct option long_options[] = {
+ {"720", no_argument, NULL, 'a'},
+@@ -49,6 +50,7 @@ static struct option long_options[] = {
+ {"4k", no_argument, NULL, '0'},
+ {"width", required_argument, NULL, 'c'},
+ {"height", required_argument, NULL, 'd'},
++ {"nosdl", no_argument, NULL, 'e'},
+ {"bitrate", required_argument, NULL, 'g'},
+ {"packetsize", required_argument, NULL, 'h'},
+ {"app", required_argument, NULL, 'i'},
+@@ -149,6 +151,9 @@ static void parse_argument(int c, char* value, PCONFIG
+ break;
+ case 'd':
+ config->stream.height = atoi(value);
++ break;
++ case 'e':
++ isNoSdl = true;
+ break;
+ case 'g':
+ config->stream.bitrate = atoi(value);
diff --git a/games/moonlight-embedded/files/patch-src_config.h b/games/moonlight-embedded/files/patch-src_config.h
new file mode 100644
index 000000000000..f7b36617a241
--- /dev/null
+++ b/games/moonlight-embedded/files/patch-src_config.h
@@ -0,0 +1,10 @@
+--- src/config.h.orig 2023-10-11 15:50:11 UTC
++++ src/config.h
+@@ -51,6 +51,7 @@ typedef struct _CONFIGURATION {
+ } CONFIGURATION, *PCONFIGURATION;
+
+ extern bool inputAdded;
++extern bool isNoSdl;
+
+ bool config_file_parse(char* filename, PCONFIGURATION config);
+ void config_parse(int argc, char* argv[], PCONFIGURATION config);
diff --git a/games/moonlight-embedded/files/patch-src_input_evdev.c b/games/moonlight-embedded/files/patch-src_input_evdev.c
index 5daa32c63111..b93c258415f6 100644
--- a/games/moonlight-embedded/files/patch-src_input_evdev.c
+++ b/games/moonlight-embedded/files/patch-src_input_evdev.c
@@ -1,6 +1,6 @@
---- src/input/evdev.c.orig 2023-09-01 23:40:56 UTC
+--- src/input/evdev.c.orig 2023-10-11 15:50:11 UTC
+++ src/input/evdev.c
-@@ -38,10 +38,12 @@
+@@ -38,10 +38,16 @@
#include <limits.h>
#include <unistd.h>
#include <pthread.h>
@@ -9,13 +9,17 @@
#include <math.h>
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-+bool iskeyboardgrab = true;
++extern bool isNoSdl;
++bool iskeyboardgrab = false;
++void grab_window(bool grabstat);
++static bool waitingToSwitchGrabOnModifierUp = false;
++static bool isgrabkeyrelease = false;
+
+#if _BYTE_ORDER == _LITTLE_ENDIAN
#define int16_to_le(val) val
#else
#define int16_to_le(val) ((((val) >> 8) & 0x00FF) | (((val) << 8) & 0xFF00))
-@@ -66,8 +68,8 @@ struct input_device {
+@@ -66,8 +72,8 @@ struct input_device {
int hats_state[3][2];
int fd;
char modifiers;
@@ -26,7 +30,38 @@
struct timeval touchDownTime;
struct timeval btnDownTime;
short controllerId;
-@@ -343,7 +345,7 @@ static bool evdev_handle_event(struct input_event *ev,
+@@ -127,6 +133,7 @@ int evdev_gamepads = 0;
+
+ #define ACTION_MODIFIERS (MODIFIER_SHIFT|MODIFIER_ALT|MODIFIER_CTRL)
+ #define QUIT_KEY KEY_Q
++#define GRAB_KEY KEY_Z
+ #define QUIT_BUTTONS (PLAY_FLAG|BACK_FLAG|LB_FLAG|RB_FLAG)
+
+ static bool (*handler) (struct input_event*, struct input_device*);
+@@ -139,6 +146,22 @@ static int evdev_get_map(int* map, int length, int val
+ return -1;
+ }
+
++static short keystatlist[0xFF];
++static void keyrelease(int keycode) {
++ keystatlist[keycode] = 0;
++}
++static void keypress(int keycode) {
++ keystatlist[keycode] = 1;
++}
++static void freeallkey () {
++ for (int i=0;i<0xFF;i++) {
++ if (keystatlist[i] == 1) {
++ keystatlist[i] = 0;
++ LiSendKeyboardEvent(0x80 << 8 | keyCodes[i], KEY_ACTION_UP, 0);
++ }
++ }
++}
++
+ static bool evdev_init_parms(struct input_device *dev, struct input_abs_parms *parms, int code) {
+ int abs = evdev_get_map(dev->abs_map, ABS_MAX, code);
+
+@@ -343,7 +366,7 @@ static bool evdev_handle_event(struct input_event *ev,
if (dev->mouseHScroll != 0) {
LiSendHScrollEvent(dev->mouseHScroll);
dev->mouseHScroll = 0;
@@ -35,26 +70,142 @@
if (dev->gamepadModified) {
if (dev->controllerId < 0) {
for (int i = 0; i < MAX_GAMEPADS; i++) {
-@@ -813,7 +815,7 @@ void evdev_create(const char* device, struct mapping*
- if (mappings == NULL && strstr(name, "Xbox 360 Wireless Receiver") != NULL)
- mappings = xwc_mapping;
+@@ -398,15 +421,41 @@ static bool evdev_handle_event(struct input_event *ev,
+ }
+
+ // After the quit key combo is pressed, quit once all keys are raised
+- if ((dev->modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS &&
+- ev->code == QUIT_KEY && ev->value != 0) {
+- waitingToExitOnModifiersUp = true;
+- return true;
+- } else if (waitingToExitOnModifiersUp && dev->modifiers == 0)
++ if ((dev->modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && ev->value != 0) {
++ if (ev->code == QUIT_KEY) {
++ waitingToExitOnModifiersUp = true;
++ return true;
++ } else if (ev->code == GRAB_KEY && iskeyboardgrab) {
++ waitingToSwitchGrabOnModifierUp = true;
++ return true;
++ }
++ }
++ if (waitingToSwitchGrabOnModifierUp) {
++ if (ev->code == GRAB_KEY && ev->value == 0) {
++ isgrabkeyrelease = true;
++ if (dev->modifiers != 0)
++ return true;
++ }
++ if (dev->modifiers == 0 && isgrabkeyrelease) {
++ waitingToSwitchGrabOnModifierUp = false;
++ isgrabkeyrelease = false;
++ freeallkey();
++ grab_window(!iskeyboardgrab);
++ return true;
++ }
++ } else if (waitingToExitOnModifiersUp && dev->modifiers == 0) {
++ freeallkey();
++ grab_window(false);
+ return false;
++ }
-- bool is_keyboard = libevdev_has_event_code(evdev, EV_KEY, KEY_Q);
-+ bool is_keyboard = libevdev_has_event_code(evdev, EV_KEY, KEY_Q) && libevdev_get_id_version(evdev) < 500;
- bool is_mouse = libevdev_has_event_type(evdev, EV_REL) || libevdev_has_event_code(evdev, EV_KEY, BTN_LEFT);
- bool is_touchscreen = libevdev_has_event_code(evdev, EV_KEY, BTN_TOUCH);
++ if (ev->value)
++ keypress(ev->code);
++ else
++ keyrelease(ev->code);
+ short code = 0x80 << 8 | keyCodes[ev->code];
+ LiSendKeyboardEvent(code, ev->value?KEY_ACTION_DOWN:KEY_ACTION_UP, dev->modifiers);
++
+ } else {
+ int mouseCode = 0;
+ int gamepadCode = 0;
+@@ -749,8 +798,10 @@ static int evdev_handle(int fd) {
+ struct input_event ev;
+ while ((rc = libevdev_next_event(devices[i].dev, LIBEVDEV_READ_FLAG_NORMAL, &ev)) >= 0) {
+ if (rc == LIBEVDEV_READ_STATUS_SYNC)
+- fprintf(stderr, "Error: cannot keep up\n");
++ fprintf(stderr, "Error:%s(%d) cannot keep up\n", libevdev_get_name(devices[i].dev), i);
+ else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
++ if (!iskeyboardgrab)
++ break;
+ if (!handler(&ev, &devices[i]))
+ return LOOP_RETURN;
+ }
+@@ -840,7 +891,28 @@ void evdev_create(const char* device, struct mapping*
+ libevdev_has_event_code(evdev, EV_ABS, ABS_WHEEL) ||
+ libevdev_has_event_code(evdev, EV_ABS, ABS_GAS) ||
+ libevdev_has_event_code(evdev, EV_ABS, ABS_BRAKE));
++ bool is_acpibutton =
++ is_keyboard &&
++ (strcmp(libevdev_get_name(evdev), "Sleep Button") == 0 ||
++ strcmp(libevdev_get_name(evdev), "Power Button") == 0);
++ bool is_likekeyboard =
++ is_keyboard &&
++ (libevdev_get_id_version(evdev) > 1000 ||
++ libevdev_get_id_bustype(evdev) <= 3);
-@@ -1055,8 +1057,12 @@ void evdev_start() {
++ // In some cases,acpibutton can be mistaken for a keyboard and freeze the keyboard when tring grab.
++ if (is_acpibutton) {
++ if (verbose)
++ printf("Do Not grab acpibutton: %s\n", libevdev_get_name(evdev));
++ is_keyboard = false;
++ }
++ // In some cases,tring grab "Logitech USB Receiver Keyboard" will freeze the keyboard.
++ if (is_likekeyboard) {
++ if (verbose)
++ printf("Do Not grab likekeyboard: %s,version: %d,bustype: %d\n", libevdev_get_name(evdev), libevdev_get_id_version(evdev), libevdev_get_id_bustype(evdev));
++ is_keyboard = false;
++ }
++
+ if (is_accelerometer) {
+ if (verbose)
+ printf("Ignoring accelerometer: %s\n", name);
+@@ -850,6 +922,13 @@ void evdev_create(const char* device, struct mapping*
+ }
+
+ if (is_gamepad) {
++ if (!isNoSdl) {
++ if (verbose)
++ printf("Gamepad %s ignored,use sdl instead.\n", name);
++ libevdev_free(evdev);
++ close(fd);
++ return;
++ }
+ evdev_gamepads++;
+
+ if (mappings == NULL) {
+@@ -1054,11 +1133,7 @@ void evdev_start() {
+ // code looks for. For this reason, we wait to grab until
// we're ready to take input events. Ctrl+C works up until
// this point.
- for (int i = 0; i < numDevices; i++) {
+- for (int i = 0; i < numDevices; i++) {
- if ((devices[i].is_keyboard || devices[i].is_mouse || devices[i].is_touchscreen) && ioctl(devices[i].fd, EVIOCGRAB, 1) < 0) {
-+ if ((devices[i].is_mouse || devices[i].is_touchscreen) && ioctl(devices[i].fd, EVIOCGRAB, 1) < 0) {
- fprintf(stderr, "EVIOCGRAB failed with error %d\n", errno);
-+ }
-+ if (devices[i].is_keyboard && libevdev_get_id_bustype(devices[i].dev) > 3) {
-+ if (ioctl(devices[i].fd, EVIOCGRAB, 1) < 0)
-+ fprintf(stderr, "EVIOCGRAB failed with error %d\n", errno);
- }
- }
+- fprintf(stderr, "EVIOCGRAB failed with error %d\n", errno);
+- }
+- }
++ grab_window(true);
+ // Any new input devices detected after this point will be grabbed immediately
+ grabbingDevices = true;
+@@ -1111,4 +1186,23 @@ void evdev_rumble(unsigned short controller_id, unsign
+ event.value = 1;
+ write(device->fd, (const void*) &event, sizeof(event));
+ device->haptic_effect_id = effect.id;
++}
++
++void grab_window(bool grabstat) {
++ if (grabstat != iskeyboardgrab) {
++ int grabnum;
++ if (iskeyboardgrab) {
++ grabnum = 0;
++ iskeyboardgrab = false;
++ } else {
++ grabnum = 1;
++ iskeyboardgrab = true;
++ }
++ for (int i = 0; i < numDevices; i++) {
++ if (devices[i].is_keyboard || devices[i].is_mouse || devices[i].is_touchscreen) {
++ if (ioctl(devices[i].fd, EVIOCGRAB, grabnum) < 0)
++ fprintf(stderr, "EVIOCGRAB failed with error %d\n", errno);
++ }
++ }
++ }
+ }
diff --git a/games/moonlight-embedded/files/patch-src_input_sdl.c b/games/moonlight-embedded/files/patch-src_input_sdl.c
new file mode 100644
index 000000000000..6b6278d8109e
--- /dev/null
+++ b/games/moonlight-embedded/files/patch-src_input_sdl.c
@@ -0,0 +1,309 @@
+--- src/input/sdl.c.orig 2023-10-08 02:12:37 UTC
++++ src/input/sdl.c
+@@ -19,15 +19,23 @@
+
+ #include "sdl.h"
+ #include "../sdl.h"
++#include "../loop.h"
+
++#include <poll.h>
++#include <fcntl.h>
++#include <unistd.h>
+ #include <Limelight.h>
+
+ #define ACTION_MODIFIERS (MODIFIER_SHIFT|MODIFIER_ALT|MODIFIER_CTRL)
+ #define QUIT_KEY SDLK_q
+ #define QUIT_BUTTONS (PLAY_FLAG|BACK_FLAG|LB_FLAG|RB_FLAG)
+ #define FULLSCREEN_KEY SDLK_f
+-#define UNGRAB_KEY SDLK_z
++#define UNGRAB_MOUSE_KEY SDLK_m
++#define UNGRAB_WINDOW_KEY SDLK_z
+
++static bool isx11sdlcall = false;
++static int x11_sdl_event_handle(int fd);
++
+ static const int SDL_TO_LI_BUTTON_MAP[] = {
+ A_FLAG, B_FLAG, X_FLAG, Y_FLAG,
+ BACK_FLAG, SPECIAL_FLAG, PLAY_FLAG,
+@@ -51,6 +59,8 @@ typedef struct _GAMEPAD_STATE {
+ int haptic_effect_id;
+ #endif
+ short id;
++ int fd;
++ bool fdadded;
+ bool initialized;
+ } GAMEPAD_STATE, *PGAMEPAD_STATE;
+
+@@ -62,6 +72,22 @@ static GAMEPAD_STATE gamepads[MAX_GAMEPADS];
+ static int keyboard_modifiers;
+ static int activeGamepadMask = 0;
+
++static short keystatlist[0xFF];
++static void keyrelease(int keycode) {
++ keystatlist[keycode] = 0;
++}
++static void keypress(int keycode) {
++ keystatlist[keycode] = 1;
++}
++static void freeallkey () {
++ for (int i=0;i<0xFF;i++) {
++ if (keystatlist[i] == 1) {
++ keystatlist[i] = 0;
++ LiSendKeyboardEvent(0x80 << 8 | i, KEY_ACTION_UP, 0);
++ }
++ }
++}
++
+ int sdl_gamepads = 0;
+
+ static void send_controller_arrival(PGAMEPAD_STATE state) {
+@@ -142,12 +168,22 @@ static PGAMEPAD_STATE get_gamepad(SDL_JoystickID sdl_i
+ }
+
+ static void add_gamepad(int joystick_index) {
++ int fd;
+ SDL_GameController* controller = SDL_GameControllerOpen(joystick_index);
+ if (!controller) {
+ fprintf(stderr, "Could not open gamecontroller %i: %s\n", joystick_index, SDL_GetError());
+ return;
+ }
+-
++ if (isx11sdlcall) {
++ char* controllerpath = SDL_GameControllerPath(controller);
++ fd = open(controllerpath, O_RDWR|O_NONBLOCK);
++ if (fd == -1) {
++ close(fd);
++ fprintf(stderr, "Could not open gamecontroller from path: %s\n", controllerpath);
++ return;
++ }
++ }
++
+ SDL_Joystick* joystick = SDL_GameControllerGetJoystick(controller);
+ SDL_JoystickID joystick_id = SDL_JoystickInstanceID(joystick);
+
+@@ -166,10 +202,15 @@ static void add_gamepad(int joystick_index) {
+ // Create a new gamepad state
+ state = get_gamepad(joystick_id, true);
+ state->controller = controller;
++ if (isx11sdlcall) {
++ state->fd = fd;
++ loop_add_fd(state->fd, &x11_sdl_event_handle, POLLIN);
++ state->fdadded = true;
++ }
+
+ #if !SDL_VERSION_ATLEAST(2, 0, 9)
+ state->haptic = SDL_HapticOpenFromJoystick(joystick);
+- if (haptic && (SDL_HapticQuery(state->haptic) & SDL_HAPTIC_LEFTRIGHT) == 0) {
++ if (state->haptic && (SDL_HapticQuery(state->haptic) & SDL_HAPTIC_LEFTRIGHT) == 0) {
+ SDL_HapticClose(state->haptic);
+ state->haptic = NULL;
+ }
+@@ -182,6 +223,11 @@ static void add_gamepad(int joystick_index) {
+ sdl_gamepads++;
+ }
+
++static void x11_add_gamepad(int joystick_index) {
++ isx11sdlcall = true;
++ add_gamepad(joystick_index);
++}
++
+ static void remove_gamepad(SDL_JoystickID sdl_id) {
+ for (int i = 0;i<MAX_GAMEPADS;i++) {
+ if (gamepads[i].initialized && gamepads[i].sdl_id == sdl_id) {
+@@ -208,6 +254,20 @@ static void remove_gamepad(SDL_JoystickID sdl_id) {
+ }
+ }
+
++static void x11_remove_gamepad(SDL_JoystickID sdl_id) {
++ for (int i=0;i<MAX_GAMEPADS;i++) {
++ if (gamepads[i].initialized && gamepads[i].sdl_id == sdl_id) {
++ if (gamepads[i].fdadded) {
++ loop_remove_fd(gamepads[i].fd);
++ gamepads[i].fdadded = false;
++ close(gamepads[i].fd);
++ }
++ remove_gamepad(gamepads[i].sdl_id);
++ return;
++ }
++ }
++}
++
+ void sdlinput_init(char* mappings) {
+ memset(gamepads, 0, sizeof(gamepads));
+
+@@ -317,15 +377,28 @@ int sdlinput_handle_event(SDL_Window* window, SDL_Even
+ keyboard_modifiers &= ~modifier;
+ }
+
+- LiSendKeyboardEvent(0x80 << 8 | button, event->type==SDL_KEYDOWN?KEY_ACTION_DOWN:KEY_ACTION_UP, keyboard_modifiers);
+-
+ // Quit the stream if all the required quit keys are down
+- if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == QUIT_KEY && event->type==SDL_KEYUP)
++ if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == QUIT_KEY && event->type==SDL_KEYUP) {
++ freeallkey();
+ return SDL_QUIT_APPLICATION;
+- else if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == FULLSCREEN_KEY && event->type==SDL_KEYUP)
++ } else if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == FULLSCREEN_KEY && event->type==SDL_KEYUP) {
++ freeallkey();
+ return SDL_TOGGLE_FULLSCREEN;
+- else if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == UNGRAB_KEY && event->type==SDL_KEYUP)
++ } else if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == UNGRAB_MOUSE_KEY && event->type==SDL_KEYUP) {
++ freeallkey();
+ return SDL_GetRelativeMouseMode() ? SDL_MOUSE_UNGRAB : SDL_MOUSE_GRAB;
++ } else if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == UNGRAB_WINDOW_KEY && event->type==SDL_KEYUP) {
++ freeallkey();
++ return iskeyboardgrab ? SDL_WINDOW_UNGRAB : SDL_WINDOW_GRAB;
++ }
++
++ if (event->type==SDL_KEYDOWN)
++ keypress(button);
++ else
++ keyrelease(button);
++
++
++ LiSendKeyboardEvent(0x80 << 8 | button, event->type==SDL_KEYDOWN?KEY_ACTION_DOWN:KEY_ACTION_UP, keyboard_modifiers);
+ break;
+ case SDL_FINGERDOWN:
+ case SDL_FINGERMOTION:
+@@ -524,4 +597,139 @@ void sdlinput_set_controller_led(unsigned short contro
+ #if SDL_VERSION_ATLEAST(2, 0, 14)
+ SDL_GameControllerSetLED(state->controller, r, g, b);
+ #endif
+-}
+\ No newline at end of file
++}
++
++static int x11_sdlinput_handle_event(SDL_Event* event) {
++ int button = 0;
++ unsigned char touchEventType;
++ PGAMEPAD_STATE gamepad;
++ switch (event->type) {
++ case SDL_CONTROLLERAXISMOTION:
++ gamepad = get_gamepad(event->caxis.which, false);
++ if (!gamepad)
++ return SDL_NOTHING;
++ switch (event->caxis.axis) {
++ case SDL_CONTROLLER_AXIS_LEFTX:
++ gamepad->leftStickX = event->caxis.value;
++ break;
++ case SDL_CONTROLLER_AXIS_LEFTY:
++ gamepad->leftStickY = -SDL_max(event->caxis.value, (short)-32767);
++ break;
++ case SDL_CONTROLLER_AXIS_RIGHTX:
++ gamepad->rightStickX = event->caxis.value;
++ break;
++ case SDL_CONTROLLER_AXIS_RIGHTY:
++ gamepad->rightStickY = -SDL_max(event->caxis.value, (short)-32767);
++ break;
++ case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
++ gamepad->leftTrigger = (unsigned char)(event->caxis.value * 255UL / 32767);
++ break;
++ case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
++ gamepad->rightTrigger = (unsigned char)(event->caxis.value * 255UL / 32767);
++ break;
++ default:
++ return SDL_NOTHING;
++ }
++ LiSendMultiControllerEvent(gamepad->id, activeGamepadMask, gamepad->buttons, gamepad->leftTrigger, gamepad->rightTrigger, gamepad->leftStickX, gamepad->leftStickY, gamepad->rightStickX, gamepad->rightStickY);
++ break;
++ case SDL_CONTROLLERBUTTONDOWN:
++ case SDL_CONTROLLERBUTTONUP:
++ gamepad = get_gamepad(event->cbutton.which, false);
++ if (!gamepad)
++ return SDL_NOTHING;
++ if (event->cbutton.button >= SDL_arraysize(SDL_TO_LI_BUTTON_MAP))
++ return SDL_NOTHING;
++
++ if (event->type == SDL_CONTROLLERBUTTONDOWN)
++ gamepad->buttons |= SDL_TO_LI_BUTTON_MAP[event->cbutton.button];
++ else
++ gamepad->buttons &= ~SDL_TO_LI_BUTTON_MAP[event->cbutton.button];
++
++ if ((gamepad->buttons & QUIT_BUTTONS) == QUIT_BUTTONS)
++ return SDL_QUIT_APPLICATION;
++
++ LiSendMultiControllerEvent(gamepad->id, activeGamepadMask, gamepad->buttons, gamepad->leftTrigger, gamepad->rightTrigger, gamepad->leftStickX, gamepad->leftStickY, gamepad->rightStickX, gamepad->rightStickY);
++ break;
++ case SDL_CONTROLLERDEVICEADDED:
++ x11_add_gamepad(event->cdevice.which);
++ break;
++ case SDL_CONTROLLERDEVICEREMOVED:
++ x11_remove_gamepad(event->cdevice.which);
++ break;
++#if SDL_VERSION_ATLEAST(2, 0, 14)
++ case SDL_CONTROLLERSENSORUPDATE:
++ gamepad = get_gamepad(event->csensor.which, false);
++ if (!gamepad)
++ return SDL_NOTHING;
++ switch (event->csensor.sensor) {
++ case SDL_SENSOR_ACCEL:
++ LiSendControllerMotionEvent(gamepad->id, LI_MOTION_TYPE_ACCEL, event->csensor.data[0], event->csensor.data[1], event->csensor.data[2]);
++ break;
++ case SDL_SENSOR_GYRO:
++ // Convert rad/s to deg/s
++ LiSendControllerMotionEvent(gamepad->id, LI_MOTION_TYPE_GYRO,
++ event->csensor.data[0] * 57.2957795f,
++ event->csensor.data[1] * 57.2957795f,
++ event->csensor.data[2] * 57.2957795f);
++ break;
++ }
++ break;
++ case SDL_CONTROLLERTOUCHPADDOWN:
++ case SDL_CONTROLLERTOUCHPADUP:
++ case SDL_CONTROLLERTOUCHPADMOTION:
++ gamepad = get_gamepad(event->ctouchpad.which, false);
++ if (!gamepad)
++ return SDL_NOTHING;
++ switch (event->type) {
++ case SDL_CONTROLLERTOUCHPADDOWN:
++ touchEventType = LI_TOUCH_EVENT_DOWN;
++ break;
++ case SDL_CONTROLLERTOUCHPADUP:
++ touchEventType = LI_TOUCH_EVENT_UP;
++ break;
++ case SDL_CONTROLLERTOUCHPADMOTION:
++ touchEventType = LI_TOUCH_EVENT_MOVE;
++ break;
++ default:
++ return SDL_NOTHING;
++ }
++ LiSendControllerTouchEvent(gamepad->id, touchEventType, event->ctouchpad.finger,
++ event->ctouchpad.x, event->ctouchpad.y, event->ctouchpad.pressure);
++ break;
++#endif
++ }
++
++ return SDL_NOTHING;
++}
++
++static int x11_sdl_event_handle(int fd) {
++ SDL_Event event;
++ for (int i=0;i<MAX_GAMEPADS;i++) {
++ if (gamepads[i].fd == fd) {
++ int rc;
++ while (SDL_PollEvent(&event)) {
++ rc = x11_sdlinput_handle_event(&event);
++ if (rc == SDL_QUIT_APPLICATION)
++ return LOOP_RETURN;
++ }
++ }
++ }
++ return LOOP_OK;
++}
++
++void x11_sdl_init(char* mappings) {
++ isx11sdlcall = true;
++ sdlinput_init(mappings);
++}
++
++void x11_sdl_stop() {
++ for (int i=0;i<MAX_GAMEPADS;i++) {
++ if (gamepads[i].initialized && gamepads[i].fdadded) {
++ loop_remove_fd(gamepads[i].fd);
++ gamepads[i].fdadded = false;
++ close(gamepads[i].fd);
++ remove_gamepad(gamepads[i].sdl_id);
++ }
++ }
++ SDL_Quit();
++}
diff --git a/games/moonlight-embedded/files/patch-src_input_sdl.h b/games/moonlight-embedded/files/patch-src_input_sdl.h
new file mode 100644
index 000000000000..5ccc7cf8b321
--- /dev/null
+++ b/games/moonlight-embedded/files/patch-src_input_sdl.h
@@ -0,0 +1,8 @@
+--- src/input/sdl.h.orig 2023-10-11 15:50:11 UTC
++++ src/input/sdl.h
+@@ -105,3 +105,5 @@ void sdlinput_rumble(unsigned short controller_id, uns
+ void sdlinput_rumble_triggers(unsigned short controller_id, unsigned short left_trigger, unsigned short right_trigger);
+ void sdlinput_set_motion_event_state(unsigned short controller_id, unsigned char motion_type, unsigned short report_rate_hz);
+ void sdlinput_set_controller_led(unsigned short controller_id, unsigned char r, unsigned char g, unsigned char b);
++void x11_sdl_init(char* mappings);
++void x11_sdl_stop();
diff --git a/games/moonlight-embedded/files/patch-src_input_x11.c b/games/moonlight-embedded/files/patch-src_input_x11.c
new file mode 100644
index 000000000000..582b15b405cd
--- /dev/null
+++ b/games/moonlight-embedded/files/patch-src_input_x11.c
@@ -0,0 +1,185 @@
+--- src/input/x11.c.orig 2023-10-08 02:12:37 UTC
++++ src/input/x11.c
+@@ -33,6 +33,8 @@
+
+ #define ACTION_MODIFIERS (MODIFIER_SHIFT|MODIFIER_ALT|MODIFIER_CTRL)
+ #define QUIT_KEY 0x18 /* KEY_Q */
++#define GRAB_KEY 0x34 /* KEY_Z */
++#define TAB_KEY 0x17 /* KEY_Tab */
+
+ static Display *display;
+ static Window window;
+@@ -46,6 +48,35 @@ static const char data[1] = {0};
+ static Cursor cursor;
+ static bool grabbed = True;
+
++static bool isgrabkeyrelease = false;
++static bool waitingToSwitchGrabOnModifierUp = false;
++static bool waitingToExitOnModifiersUp = false;
++extern bool iskeyboardgrab;
++extern void grab_window(bool grabstat);
++
++static short keystatlist[0xFF];
++static void keyrelease(int keycode) {
++ keystatlist[keycode] = 0;
++}
++static void keypress(int keycode) {
++ keystatlist[keycode] = 1;
++}
++static void freeallkey () {
++ for (int i=0;i<0xFF;i++) {
++ if (keystatlist[i] == 1) {
++ keystatlist[i] = 0;
++ LiSendKeyboardEvent(0x80 << 8 | keyCodes[i - 8], KEY_ACTION_UP, 0);
++ }
++ }
++}
++static void clearallkey () {
++ for (int i=0;i<0xFF;i++) {
++ if (keystatlist[i] == 1) {
++ keystatlist[i] = 0;
++ }
++ }
++}
++
+ static int x11_handler(int fd) {
+ XEvent event;
+ int button = 0;
+@@ -54,18 +85,24 @@ static int x11_handler(int fd) {
+ while (XPending(display)) {
+ XNextEvent(display, &event);
+ switch (event.type) {
++ case FocusIn:
++ case FocusOut:
++ if (event.type == FocusIn) {
++ clearallkey();
++ keyboard_modifiers = 0;
++ grabbed = true;
++ } else {
++ if (iskeyboardgrab)
++ break;
++ freeallkey();
++ keyboard_modifiers = 0;
++ grabbed = false;
++ }
++ XDefineCursor(display, window, grabbed ? cursor : 0);
++ break;
+ case KeyPress:
+ case KeyRelease:
+ if (event.xkey.keycode >= 8 && event.xkey.keycode < (sizeof(keyCodes)/sizeof(keyCodes[0]) + 8)) {
+- if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event.type == KeyRelease) {
+- if (event.xkey.keycode == QUIT_KEY)
+- return LOOP_RETURN;
+- else {
+- grabbed = !grabbed;
+- XDefineCursor(display, window, grabbed ? cursor : 0);
+- }
+- }
+-
+ int modifier = 0;
+ switch (event.xkey.keycode) {
+ case 0x32:
+@@ -89,8 +126,58 @@ static int x11_handler(int fd) {
+ keyboard_modifiers &= ~modifier;
+ }
+
++ if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event.type == KeyPress) {
++ if (event.xkey.keycode == QUIT_KEY) {
++ waitingToExitOnModifiersUp = true;
++ break;
++ } else if (event.xkey.keycode == GRAB_KEY) {
++ if (event.type == KeyPress) {
++ waitingToSwitchGrabOnModifierUp = true;
++ break;
++ }
++ }
++ }
++ if (waitingToSwitchGrabOnModifierUp) {
++ if (event.xkey.keycode == GRAB_KEY && event.type == KeyRelease) {
++ isgrabkeyrelease = true;
++ if (keyboard_modifiers != 0)
++ break;
++ }
++ if (keyboard_modifiers == 0 && isgrabkeyrelease) {
++ waitingToSwitchGrabOnModifierUp = false;
++ isgrabkeyrelease = false;
++ XDefineCursor(display, window, cursor);
++ freeallkey();
++ grab_window(true);
++ break;
++ }
++ } else if (waitingToExitOnModifiersUp) {
++ if (event.xkey.keycode == QUIT_KEY) {
++ if (keyboard_modifiers != 0)
++ break;
++ }
++ if (keyboard_modifiers == 0) {
++ freeallkey();
++ waitingToExitOnModifiersUp = false;
++ return LOOP_RETURN;
++ }
++ }
++ if (event.xkey.keycode == TAB_KEY && keyboard_modifiers == MODIFIER_ALT) {
++ freeallkey();
++ keyboard_modifiers = 0;
++ break;
++ }
++ if (event.xkey.keycode == 0x40 || event.xkey.keycode == 0x6c)
++ break;
++
++ if (event.type == KeyPress)
++ keypress(event.xkey.keycode);
++ else
++ keyrelease(event.xkey.keycode);
++
+ short code = 0x80 << 8 | keyCodes[event.xkey.keycode - 8];
+- LiSendKeyboardEvent(code, event.type == KeyPress ? KEY_ACTION_DOWN : KEY_ACTION_UP, keyboard_modifiers);
++ if (!iskeyboardgrab)
++ LiSendKeyboardEvent(code, event.type == KeyPress ? KEY_ACTION_DOWN : KEY_ACTION_UP, keyboard_modifiers);
+ }
+ break;
+ case ButtonPress:
+@@ -106,16 +193,20 @@ static int x11_handler(int fd) {
+ button = BUTTON_RIGHT;
+ break;
+ case Button4:
+- LiSendScrollEvent(1);
++ if (!iskeyboardgrab)
++ LiSendScrollEvent(1);
+ break;
+ case Button5:
+- LiSendScrollEvent(-1);
++ if (!iskeyboardgrab)
++ LiSendScrollEvent(-1);
+ break;
+ case 6:
+- LiSendHScrollEvent(-1);
++ if (!iskeyboardgrab)
++ LiSendHScrollEvent(-1);
+ break;
+ case 7:
+- LiSendHScrollEvent(1);
++ if (!iskeyboardgrab)
++ LiSendHScrollEvent(1);
+ break;
+ case 8:
+ button = BUTTON_X1;
+@@ -125,14 +216,16 @@ static int x11_handler(int fd) {
+ break;
+ }
+
+- if (button != 0)
++ if (button != 0 && !iskeyboardgrab)
+ LiSendMouseButtonEvent(event.type==ButtonPress ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE, button);
+ break;
+ case MotionNotify:
++ if (!grabbed)
++ break;
+ motion_x = event.xmotion.x - last_x;
+ motion_y = event.xmotion.y - last_y;
+ if (abs(motion_x) > 0 || abs(motion_y) > 0) {
+- if (last_x >= 0 && last_y >= 0)
++ if (last_x >= 0 && last_y >= 0 && !iskeyboardgrab)
+ LiSendMouseMoveEvent(motion_x, motion_y);
+
+ if (grabbed)
diff --git a/games/moonlight-embedded/files/patch-src_main.c b/games/moonlight-embedded/files/patch-src_main.c
index 6589a8ab876a..32131dc18e63 100644
--- a/games/moonlight-embedded/files/patch-src_main.c
+++ b/games/moonlight-embedded/files/patch-src_main.c
@@ -1,4 +1,4 @@
---- src/main.c.orig 2023-09-01 23:40:56 UTC
+--- src/main.c.orig 2023-10-11 15:50:11 UTC
+++ src/main.c
@@ -42,6 +42,7 @@
#include <client.h>
@@ -16,7 +16,18 @@
static void applist(PSERVER_DATA server) {
PAPP_LIST list = NULL;
-@@ -202,7 +202,6 @@ static void help() {
+@@ -149,6 +149,10 @@ static void stream(PSERVER_DATA server, PCONFIGURATION
+ if (!config->viewonly)
+ evdev_start();
+ loop_main();
++ #ifdef HAVE_SDL
++ if (!isNoSdl)
++ x11_sdl_stop();
++ #endif
+ if (!config->viewonly)
+ evdev_stop();
+ }
+@@ -202,7 +206,6 @@ static void help() {
printf("\t-bitrate <bitrate>\tSpecify the bitrate in Kbps\n");
printf("\t-packetsize <size>\tSpecify the maximum packetsize in bytes\n");
printf("\t-codec <codec>\t\tSelect used codec: auto/h264/h265/av1 (default auto)\n");
@@ -24,7 +35,19 @@
printf("\t-remote <yes/no/auto>\t\t\tEnable optimizations for WAN streaming (default auto)\n");
printf("\t-app <app>\t\tName of app to stream\n");
printf("\t-nosops\t\t\tDon't allow GFE to modify game settings\n");
-@@ -322,19 +321,19 @@ int main(int argc, char* argv[]) {
+@@ -238,7 +241,10 @@ static void pair_check(PSERVER_DATA server) {
+ int main(int argc, char* argv[]) {
+ CONFIGURATION config;
+ config_parse(argc, argv, &config);
+-
++ #ifndef HAVE_SDL
++ isNoSdl = true;
++ #endif
++
+ if (config.action == NULL || strcmp("help", config.action) == 0)
+ help();
+
+@@ -322,19 +328,19 @@ int main(int argc, char* argv[]) {
config.stream.supportedVideoFormats = VIDEO_FORMAT_H264;
if (config.codec == CODEC_HEVC || (config.codec == CODEC_UNSPECIFIED && platform_prefers_codec(system, CODEC_HEVC))) {
config.stream.supportedVideoFormats |= VIDEO_FORMAT_H265;
@@ -52,7 +75,27 @@
#ifdef HAVE_SDL
if (system == SDL)
-@@ -398,7 +397,8 @@ int main(int argc, char* argv[]) {
+@@ -371,7 +377,19 @@ int main(int argc, char* argv[]) {
+
+ udev_init(!inputAdded, mappings, config.debug_level > 0, config.rotate);
+ evdev_init(config.mouse_emulation);
++ #ifdef HAVE_SDL
++ if (isNoSdl)
++ rumble_handler = evdev_rumble;
++ else {
++ x11_sdl_init(config.mapping);
++ rumble_handler = sdlinput_rumble;
++ rumble_triggers_handler = sdlinput_rumble_triggers;
++ set_motion_event_state_handler = sdlinput_set_motion_event_state;
++ set_controller_led_handler = sdlinput_set_controller_led;
++ }
++ #else
+ rumble_handler = evdev_rumble;
++ #endif
+ #ifdef HAVE_LIBCEC
+ cec_init();
+ #endif /* HAVE_LIBCEC */
+@@ -398,7 +416,8 @@ int main(int argc, char* argv[]) {
if (config.pin > 0 && config.pin <= 9999) {
sprintf(pin, "%04d", config.pin);
} else {
@@ -62,3 +105,11 @@
}
printf("Please enter the following PIN on the target PC: %s\n", pin);
fflush(stdout);
+@@ -406,6 +425,7 @@ int main(int argc, char* argv[]) {
+ fprintf(stderr, "Failed to pair to server: %s\n", gs_error);
+ } else {
+ printf("Succesfully paired\n");
++ printf("Note: Use Ctrl+Alt+Shift+Q to quit streaming.\n");
+ }
+ } else if (strcmp("unpair", config.action) == 0) {
+ if (gs_unpair(&server) != GS_OK) {
diff --git a/games/moonlight-embedded/files/patch-src_sdl.c b/games/moonlight-embedded/files/patch-src_sdl.c
new file mode 100644
index 000000000000..849b82b2e379
--- /dev/null
+++ b/games/moonlight-embedded/files/patch-src_sdl.c
@@ -0,0 +1,64 @@
+--- src/sdl.c.orig 2023-10-11 15:50:11 UTC
++++ src/sdl.c
+@@ -42,6 +42,10 @@ void sdl_init(int width, int height, bool fullscreen)
+ fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
+ exit(1);
+ }
++ if(!SDL_SetHint(SDL_HINT_GRAB_KEYBOARD,"1"))
++ printf("Override SDL_HINT_GRAB_KEYBOARD to 1 failed.\n");
++ if(!SDL_SetHint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED,"0"))
++ printf("Override SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED to 0 failed.\n");
+
+ fullscreen_flags = fullscreen?SDL_WINDOW_FULLSCREEN:0;
+ window = SDL_CreateWindow("Moonlight", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_OPENGL | fullscreen_flags);
+@@ -72,8 +76,19 @@ void sdl_init(int width, int height, bool fullscreen)
+ void sdl_loop() {
+ SDL_Event event;
+
++ iskeyboardgrab = true;
+ SDL_SetRelativeMouseMode(SDL_TRUE);
++#if SDL_VERSION_ATLEAST(2, 0, 15)
++ // On SDL 2.0.15+, we can get keyboard-only grab on Win32, X11, and Wayland.
++ // SDL 2.0.18 adds keyboard grab on macOS (if built with non-AppStore APIs).
++ SDL_SetWindowKeyboardGrab(window, SDL_TRUE);
++ if(!SDL_GetWindowKeyboardGrab(window))
++ printf("Try to grab window failed.\n");
++#else
++ SDL_SetWindowGrab(window, SDL_TRUE);
++#endif
+
++
+ while(!done && SDL_WaitEvent(&event)) {
+ switch (sdlinput_handle_event(window, &event)) {
+ case SDL_QUIT_APPLICATION:
+@@ -90,6 +105,30 @@ void sdl_loop() {
+ case SDL_MOUSE_UNGRAB:
+ SDL_SetRelativeMouseMode(SDL_FALSE);
+ SDL_ShowCursor(SDL_DISABLE);
++ break;
++ case SDL_WINDOW_GRAB:
++ if(!SDL_SetHintWithPriority(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED,"0",SDL_HINT_OVERRIDE))
++ printf("Override SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED to 0 failed.\n");
++ SDL_ShowCursor(SDL_ENABLE);
++ SDL_SetRelativeMouseMode(SDL_TRUE);
++ iskeyboardgrab = true;
++#if SDL_VERSION_ATLEAST(2, 0, 15)
++ SDL_SetWindowKeyboardGrab(window, SDL_TRUE);
++#else
++ SDL_SetWindowGrab(window, SDL_TRUE);
++#endif
++ break;
++ case SDL_WINDOW_UNGRAB:
++ if(!SDL_SetHintWithPriority(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED,"1",SDL_HINT_OVERRIDE))
++ printf("Override SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED to 1 failed.\n");
++ SDL_SetRelativeMouseMode(SDL_FALSE);
++ SDL_ShowCursor(SDL_DISABLE);
++ iskeyboardgrab = false;
++#if SDL_VERSION_ATLEAST(2, 0, 15)
++ SDL_SetWindowKeyboardGrab(window, SDL_FALSE);
++#else
++ SDL_SetWindowGrab(window, SDL_FALSE);
++#endif
+ break;
+ default:
+ if (event.type == SDL_QUIT)
diff --git a/games/moonlight-embedded/files/patch-src_sdl.h b/games/moonlight-embedded/files/patch-src_sdl.h
new file mode 100644
index 000000000000..f2410ccc5a54
--- /dev/null
+++ b/games/moonlight-embedded/files/patch-src_sdl.h
@@ -0,0 +1,19 @@
+--- src/sdl.h.orig 2023-10-11 15:50:11 UTC
++++ src/sdl.h
+@@ -28,6 +28,8 @@
+ #define SDL_MOUSE_GRAB 2
+ #define SDL_MOUSE_UNGRAB 3
+ #define SDL_TOGGLE_FULLSCREEN 4
++#define SDL_WINDOW_GRAB 5
++#define SDL_WINDOW_UNGRAB 6
+
+ #define SDL_CODE_FRAME 0
+
+@@ -36,6 +38,7 @@
+ void sdl_init(int width, int height, bool fullscreen);
+ void sdl_loop();
+
++extern bool iskeyboardgrab;
+ extern SDL_mutex *mutex;
+ extern int sdlCurrentFrame, sdlNextFrame;
+
diff --git a/games/moonlight-embedded/files/patch-src_video_x11.c b/games/moonlight-embedded/files/patch-src_video_x11.c
new file mode 100644
index 000000000000..8c9079fc91fe
--- /dev/null
+++ b/games/moonlight-embedded/files/patch-src_video_x11.c
@@ -0,0 +1,42 @@
+--- src/video/x11.c.orig 2023-10-08 02:12:37 UTC
++++ src/video/x11.c
+@@ -53,6 +53,16 @@ static int pipefd[2];
+ static int display_width;
+ static int display_height;
+
++static void resetcursor() {
++ XColor dummy;
++ Cursor cursor;
++ const char data[1] = {0};
++ Pixmap blank = XCreateBitmapFromData(display, window, data, 1, 1);
++ cursor = XCreatePixmapCursor(display, blank, blank, &dummy, &dummy, 0, 0);
++ XFreePixmap(display, blank);
++ XDefineCursor(display, window, cursor);
++}
++
+ static int frame_handle(int pipefd) {
+ AVFrame* frame = NULL;
+ while (read(pipefd, &frame, sizeof(void*)) > 0);
+@@ -75,7 +85,7 @@ int x11_init(bool vdpau, bool vaapi) {
+ return 0;
+
+ #ifdef HAVE_VAAPI
+- if (vaapi && vaapi_init_lib(display) == 0)
++ if (vaapi && vaapi_init_lib() == 0)
+ return INIT_VAAPI;
+ #endif
+
+@@ -100,10 +110,12 @@ int x11_setup(int videoFormat, int width, int height,
+ }
+
+ Window root = DefaultRootWindow(display);
+- XSetWindowAttributes winattr = { .event_mask = PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask };
++ XSetWindowAttributes winattr = { .event_mask = PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | FocusChangeMask };
+ window = XCreateWindow(display, root, 0, 0, display_width, display_height, 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask, &winattr);
+ XMapWindow(display, window);
+ XStoreName(display, window, "Moonlight");
++ // Fix the bug that the default cursor keep in screen when streaming.
++ resetcursor();
+
+ if (drFlags & DISPLAY_FULLSCREEN) {
+ Atom wm_state = XInternAtom(display, "_NET_WM_STATE", False);
diff --git a/games/moonlight-embedded/files/patch-third__party_moonlight-common-c_enet_CMakeLists.txt b/games/moonlight-embedded/files/patch-third__party_moonlight-common-c_enet_CMakeLists.txt
index 2569c15301b0..f2550dd2c585 100644
--- a/games/moonlight-embedded/files/patch-third__party_moonlight-common-c_enet_CMakeLists.txt
+++ b/games/moonlight-embedded/files/patch-third__party_moonlight-common-c_enet_CMakeLists.txt
@@ -1,14 +1,26 @@
---- third_party/moonlight-common-c/enet/CMakeLists.txt.orig 2023-07-30 18:58:58 UTC
+--- third_party/moonlight-common-c/enet/CMakeLists.txt.orig 2023-09-21 01:51:32 UTC
+++ third_party/moonlight-common-c/enet/CMakeLists.txt
-@@ -107,11 +107,3 @@ target_include_directories(enet SYSTEM PUBLIC include)
+@@ -2,8 +2,6 @@ cmake_minimum_required(VERSION 2.8.12...3.20)
+
+ project(enet)
+
+-option(ENET_NO_INSTALL "Disable installation of headers and libraries" OFF)
+-
+ # The "configure" step.
+ include(CheckFunctionExists)
+ include(CheckStructHasMember)
+@@ -108,14 +106,4 @@ target_include_directories(enet SYSTEM PUBLIC include)
+
if (MINGW)
target_link_libraries(enet winmm ws2_32)
- endif()
+-endif()
-
--install(TARGETS enet
-- RUNTIME DESTINATION bin
-- ARCHIVE DESTINATION lib/static
-- LIBRARY DESTINATION lib)
+-if(NOT ENET_NO_INSTALL)
+- install(TARGETS enet
+- RUNTIME DESTINATION bin
+- ARCHIVE DESTINATION lib/static
+- LIBRARY DESTINATION lib)
-
--install(DIRECTORY include/
-- DESTINATION include)
+- install(DIRECTORY include/
+- DESTINATION include)
+ endif()