From a075db180ec2808e1ef23a4fa14d9463a607ed2a Mon Sep 17 00:00:00 2001 From: Mariotaku Date: Wed, 1 May 2024 11:20:14 +0900 Subject: [PATCH] System Key Capture (#425) * allows capture of webOS home key * keyboard grab for non-webOS platforms --- i18n/messages.pot | 62 ++++++++++++--------- src/app/app.c | 8 +++ src/app/app_settings.c | 3 + src/app/lvgl/input/lv_drv_sdl_key.c | 16 ++++-- src/app/platform/webos/app_webos.c | 6 ++ src/app/platform/webos/app_webos.h | 21 +++++++ src/app/platform/webos/keyboard_webos.c | 9 ++- src/app/stream/input/session_keyboard.c | 4 +- src/app/ui/settings/panes/input.pane.c | 3 + src/app/ui/streaming/streaming.controller.c | 11 ++++ third_party/ss4s | 2 +- 11 files changed, 110 insertions(+), 35 deletions(-) create mode 100644 src/app/platform/webos/app_webos.h diff --git a/i18n/messages.pot b/i18n/messages.pot index d6b67611d..881183a52 100644 --- a/i18n/messages.pot +++ b/i18n/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-21 09:37+0900\n" +"POT-Creation-Date: 2024-05-01 00:23+0900\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,17 +17,17 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: src/app/app.c:79 +#: src/app/app.c:83 msgid "[Localized Language]" msgstr "" -#: src/app/app.c:263 src/app/ui/launcher/add.dialog.c:42 +#: src/app/app.c:267 src/app/ui/launcher/add.dialog.c:42 #: src/app/ui/launcher/apps.controller.c:736 #: src/app/ui/launcher/server.context_menu.c:89 msgid "Cancel" msgstr "" -#: src/app/app.c:263 src/app/ui/launcher/add.dialog.c:42 +#: src/app/app.c:267 src/app/ui/launcher/add.dialog.c:42 #: src/app/ui/launcher/apps.controller.c:662 #: src/app/ui/launcher/apps.controller.c:769 #: src/app/ui/launcher/launcher.controller.c:467 @@ -37,7 +37,7 @@ msgstr "" msgid "OK" msgstr "" -#: src/app/app.c:264 +#: src/app/app.c:268 msgid "Quit Moonlight?" msgstr "" @@ -367,65 +367,73 @@ msgid "Don't send mouse, keyboard or gamepad input to host computer." msgstr "" #: src/app/ui/settings/panes/input.pane.c:49 -msgid "Mouse" +msgid "Capture system keys" +msgstr "" + +#: src/app/ui/settings/panes/input.pane.c:50 +msgid "Capture and send system keys (e.g. Meta/Win key) to host computer." msgstr "" #: src/app/ui/settings/panes/input.pane.c:52 -msgid "Use mouse hardware" +msgid "Mouse" msgstr "" #: src/app/ui/settings/panes/input.pane.c:55 +msgid "Use mouse hardware" +msgstr "" + +#: src/app/ui/settings/panes/input.pane.c:58 msgid "" "Use plugged mouse device only when streaming. This will have better " "performance, but absolute mouse mode will not be enabled." msgstr "" -#: src/app/ui/settings/panes/input.pane.c:60 +#: src/app/ui/settings/panes/input.pane.c:63 msgid "Absolute mouse mode" msgstr "" -#: src/app/ui/settings/panes/input.pane.c:62 -#: src/app/ui/settings/panes/input.pane.c:101 +#: src/app/ui/settings/panes/input.pane.c:65 +#: src/app/ui/settings/panes/input.pane.c:104 msgid "" "Better for remote desktop. For some games, mouse will not work properly." msgstr "" -#: src/app/ui/settings/panes/input.pane.c:65 +#: src/app/ui/settings/panes/input.pane.c:68 msgid "Gamepad" msgstr "" -#: src/app/ui/settings/panes/input.pane.c:67 -#: src/app/ui/settings/panes/input.pane.c:108 +#: src/app/ui/settings/panes/input.pane.c:70 +#: src/app/ui/settings/panes/input.pane.c:111 msgid "Analog stick deadzone" msgstr "" -#: src/app/ui/settings/panes/input.pane.c:71 +#: src/app/ui/settings/panes/input.pane.c:74 msgid "" "Note: Some games can enforce a larger deadzone than what Moonlight is " "configured to use." msgstr "" -#: src/app/ui/settings/panes/input.pane.c:74 +#: src/app/ui/settings/panes/input.pane.c:77 msgid "Virtual mouse" msgstr "" -#: src/app/ui/settings/panes/input.pane.c:75 +#: src/app/ui/settings/panes/input.pane.c:78 msgid "" "Press LB + RS to move mouse cursor with sticks. LT/RT for left/right mouse " "buttons." msgstr "" -#: src/app/ui/settings/panes/input.pane.c:78 +#: src/app/ui/settings/panes/input.pane.c:81 msgid "Swap ABXY buttons" msgstr "" -#: src/app/ui/settings/panes/input.pane.c:79 +#: src/app/ui/settings/panes/input.pane.c:82 msgid "" "Swap A/B and X/Y gamepad buttons. Useful when you prefer Nintendo-like " "layouts." msgstr "" -#: src/app/ui/settings/panes/input.pane.c:97 +#: src/app/ui/settings/panes/input.pane.c:100 msgid "Absolute mouse mode can't be used when \"Use mouse hardware\" enabled." msgstr "" @@ -517,35 +525,35 @@ msgstr "" msgid "Some settings require a restart to take effect." msgstr "" -#: src/app/ui/streaming/streaming.controller.c:143 +#: src/app/ui/streaming/streaming.controller.c:147 msgid "Connecting..." msgstr "" -#: src/app/ui/streaming/streaming.controller.c:163 +#: src/app/ui/streaming/streaming.controller.c:167 msgid "Disconnecting..." msgstr "" -#: src/app/ui/streaming/streaming.view.c:26 +#: src/app/ui/streaming/streaming.view.c:27 #, c-format msgid "Hint: %s" msgstr "" -#: src/app/ui/streaming/streaming.view.c:75 +#: src/app/ui/streaming/streaming.view.c:76 msgid "Soft keyboard" msgstr "" -#: src/app/ui/streaming/streaming.view.c:84 +#: src/app/ui/streaming/streaming.view.c:85 msgid "Virtual Mouse" msgstr "" -#: src/app/ui/streaming/streaming.view.c:97 +#: src/app/ui/streaming/streaming.view.c:98 msgid "Disconnect" msgstr "" -#: src/app/ui/streaming/streaming.view.c:106 +#: src/app/ui/streaming/streaming.view.c:107 msgid "Quit game" msgstr "" -#: src/app/ui/streaming/streaming.view.c:121 +#: src/app/ui/streaming/streaming.view.c:122 msgid "Performance" msgstr "" diff --git a/src/app/app.c b/src/app/app.c index c5c944994..952cf5029 100644 --- a/src/app/app.c +++ b/src/app/app.c @@ -68,6 +68,14 @@ int app_init(app_t *app, app_settings_loader *settings_loader, int argc, char *a SDL_SetHint(SDL_HINT_WEBOS_CURSOR_FREQUENCY, "60"); SDL_SetHint(SDL_HINT_WEBOS_CURSOR_CALIBRATION_DISABLE, "true"); SDL_SetHint(SDL_HINT_WEBOS_HIDAPI_IGNORE_BLUETOOTH_DEVICES, "0x057e/0x0000"); + if (app->settings.syskey_capture) { + SDL_SetHint(SDL_HINT_WEBOS_ACCESS_POLICY_KEYS_HOME, "true"); + SDL_SetHint(SDL_HINT_WEBOS_ACCESS_POLICY_RIBBON, "false"); + } +#else + if (app->settings.syskey_capture) { + SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); + } #endif // DO not init video subsystem before NDL/LGNC initialization if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { diff --git a/src/app/app_settings.c b/src/app/app_settings.c index 87ff89d78..90e4128ee 100644 --- a/src/app/app_settings.c +++ b/src/app/app_settings.c @@ -116,6 +116,7 @@ bool settings_save(app_settings_t *config) { #endif ini_write_bool(fp, "swap_abxy", config->swap_abxy); ini_write_int(fp, "stick_deadzone", config->stick_deadzone); + ini_write_bool(fp, "syskey_capture", config->syskey_capture); ini_write_section(fp, "video"); ini_write_string(fp, "decoder", config->decoder); @@ -265,6 +266,8 @@ static int settings_parse(app_settings_t *config, const char *section, const cha } } else if (INI_NAME_MATCH("swap_abxy")) { config->swap_abxy = INI_IS_TRUE(value); + } else if (INI_NAME_MATCH("syskey_capture")) { + config->syskey_capture = INI_IS_TRUE(value); } else if (INI_FULL_MATCH("video", "decoder")) { set_string(&config->decoder, value); } else if (INI_FULL_MATCH("audio", "backend")) { diff --git a/src/app/lvgl/input/lv_drv_sdl_key.c b/src/app/lvgl/input/lv_drv_sdl_key.c index 0f8fc8e4d..44097a71d 100644 --- a/src/app/lvgl/input/lv_drv_sdl_key.c +++ b/src/app/lvgl/input/lv_drv_sdl_key.c @@ -9,18 +9,20 @@ #include "lv_drv_sdl_key.h" #include "stream/session_events.h" -static bool read_event(const SDL_Event *event, lv_drv_sdl_key_t *state); - -static bool read_keyboard(app_ui_input_t *input, const SDL_KeyboardEvent *event, lv_drv_sdl_key_t *state); - #if TARGET_WEBOS +#include "platform/webos/app_webos.h" + static bool read_webos_key(app_ui_input_t *input, const SDL_KeyboardEvent *event, lv_drv_sdl_key_t *state); static void webos_key_input_mode(app_ui_input_t *input, const SDL_KeyboardEvent *event); #endif +static bool read_event(const SDL_Event *event, lv_drv_sdl_key_t *state); + +static bool read_keyboard(app_ui_input_t *input, const SDL_KeyboardEvent *event, lv_drv_sdl_key_t *state); + static void sdl_input_read(lv_indev_drv_t *drv, lv_indev_data_t *data); int lv_sdl_init_key_input(lv_drv_sdl_key_t *drv, app_ui_input_t *input) { @@ -218,8 +220,14 @@ static bool read_webos_key(app_ui_input_t *input, const SDL_KeyboardEvent *event if (app->session == NULL) { app_request_exit(); } + return false; } + case SDL_SCANCODE_WEBOS_HOME: { + if (app->session == NULL) { + app_webos_open_ribbon(); + } return false; + } case SDL_SCANCODE_WEBOS_RED: case SDL_SCANCODE_WEBOS_GREEN: case SDL_SCANCODE_WEBOS_YELLOW: diff --git a/src/app/platform/webos/app_webos.c b/src/app/platform/webos/app_webos.c index 35d1bed50..13fbb2a14 100644 --- a/src/app/platform/webos/app_webos.c +++ b/src/app/platform/webos/app_webos.c @@ -1,4 +1,5 @@ #include "app.h" +#include "app_webos.h" #include "app_launch.h" #include @@ -79,4 +80,9 @@ app_launch_params_t *app_handle_launch(app_t *app, int argc, char *argv[]) { } jdomparser_release(&parser); return params; +} + +void app_webos_open_ribbon() { + static const char *payload = "{\"id\":\"com.webos.app.home\",\"params\":{\"launchType\":\"homeKey\"}}"; + HLunaServiceCallSync("luna://com.webos.applicationManager/launch", payload, true, NULL); } \ No newline at end of file diff --git a/src/app/platform/webos/app_webos.h b/src/app/platform/webos/app_webos.h new file mode 100644 index 000000000..19d9f7325 --- /dev/null +++ b/src/app/platform/webos/app_webos.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Mariotaku . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ + +#pragma once + +void app_webos_open_ribbon(); \ No newline at end of file diff --git a/src/app/platform/webos/keyboard_webos.c b/src/app/platform/webos/keyboard_webos.c index a39447e35..a74ddbfcf 100644 --- a/src/app/platform/webos/keyboard_webos.c +++ b/src/app/platform/webos/keyboard_webos.c @@ -13,10 +13,11 @@ #include "util/bus.h" #include "util/user_event.h" #include "logging.h" +#include "app_webos.h" #define TV_REMOTE_TOGGLE_SOFT_INPUT 0 -bool webos_intercept_remote_keys(stream_input_t *input, const SDL_KeyboardEvent *event, short *keyCode) { +bool stream_input_webos_intercept_remote_keys(stream_input_t *input, const SDL_KeyboardEvent *event, short *keyCode) { session_t *session = input->session; app_t *app = session->app; switch ((unsigned int) event->keysym.scancode) { @@ -26,6 +27,12 @@ bool webos_intercept_remote_keys(stream_input_t *input, const SDL_KeyboardEvent } return true; } + case SDL_SCANCODE_WEBOS_HOME: { + if (event->state == SDL_RELEASED) { + app_webos_open_ribbon(); + } + return true; + } case SDL_SCANCODE_WEBOS_BACK: *keyCode = VK_ESCAPE /* SDL_SCANCODE_ESCAPE */; return false; diff --git a/src/app/stream/input/session_keyboard.c b/src/app/stream/input/session_keyboard.c index 2aa7e2fb3..17ed5793a 100644 --- a/src/app/stream/input/session_keyboard.c +++ b/src/app/stream/input/session_keyboard.c @@ -66,7 +66,7 @@ static int keydown_count = 0; #if TARGET_WEBOS -bool webos_intercept_remote_keys(stream_input_t *input, const SDL_KeyboardEvent *event, short *keyCode); +bool stream_input_webos_intercept_remote_keys(stream_input_t *input, const SDL_KeyboardEvent *event, short *keyCode); #endif @@ -128,7 +128,7 @@ void performPendingSpecialKeyCombo(stream_input_t *input) { void stream_input_handle_key(stream_input_t *input, const SDL_KeyboardEvent *event) { short keyCode = 0; #if TARGET_WEBOS - if (webos_intercept_remote_keys(input, event, &keyCode)) { + if (stream_input_webos_intercept_remote_keys(input, event, &keyCode)) { return; } #endif diff --git a/src/app/ui/settings/panes/input.pane.c b/src/app/ui/settings/panes/input.pane.c index 23e226ea9..68f9be894 100644 --- a/src/app/ui/settings/panes/input.pane.c +++ b/src/app/ui/settings/panes/input.pane.c @@ -46,6 +46,9 @@ static lv_obj_t *create_obj(lv_fragment_t *self, lv_obj_t *container) { pref_checkbox(view, locstr("View-only mode"), &app_configuration->viewonly, false); pref_desc_label(view, locstr("Don't send mouse, keyboard or gamepad input to host computer."), false); + pref_checkbox(view, locstr("Capture system keys"), &app_configuration->syskey_capture, false); + pref_desc_label(view, locstr("Capture and send system keys (e.g. Meta/Win key) to host computer."), false); + pref_header(view, locstr("Mouse")); #if FEATURE_INPUT_EVMOUSE diff --git a/src/app/ui/streaming/streaming.controller.c b/src/app/ui/streaming/streaming.controller.c index 62a502b46..dafd3c238 100644 --- a/src/app/ui/streaming/streaming.controller.c +++ b/src/app/ui/streaming/streaming.controller.c @@ -221,6 +221,13 @@ static void on_view_created(lv_fragment_t *self, lv_obj_t *view) { controller->notice = notice; controller->notice_label = notice_label; + +#if !defined(TARGET_WEBOS) + const app_settings_t *settings = &controller->global->settings; + if (settings->syskey_capture) { + SDL_SetWindowGrab(controller->global->ui.window, SDL_TRUE); + } +#endif } static void on_delete_obj(lv_fragment_t *self, lv_obj_t *view) { @@ -234,6 +241,10 @@ static void on_delete_obj(lv_fragment_t *self, lv_obj_t *view) { } app_input_set_group(&controller->global->ui.input, NULL); lv_group_del(controller->group); + +#if !defined(TARGET_WEBOS) + SDL_SetWindowGrab(controller->global->ui.window, SDL_FALSE); +#endif } static void on_obj_deleted(lv_fragment_t *self, lv_obj_t *view) { diff --git a/third_party/ss4s b/third_party/ss4s index cf5fe23d1..b2f7879a8 160000 --- a/third_party/ss4s +++ b/third_party/ss4s @@ -1 +1 @@ -Subproject commit cf5fe23d1cf6a2d941d4b6100780252e38758904 +Subproject commit b2f7879a88d18d800ce06d366e82de2e6b68fa35