diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index a1ad3ba0..e0607e17 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -102,6 +102,7 @@ set(SOURCES src/core.c src/app.c src/config.c + src/keybind.c src/lg-renderer.c src/ll.c src/util.c diff --git a/client/src/core.c b/client/src/core.c index cf762a7b..85bff942 100644 --- a/client/src/core.c +++ b/client/src/core.c @@ -23,6 +23,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "util.h" #include "common/time.h" +#include "common/debug.h" #include @@ -265,3 +266,27 @@ bool core_isValidPointerPos(int x, int y) { return g_state.ds->isValidPointerPos(x, y); } + +bool core_startFrameThread(void) +{ + if (g_state.frameThread) + return true; + + g_state.stopVideo = false; + if (!lgCreateThread("frameThread", main_frameThread, NULL, + &g_state.frameThread)) + { + DEBUG_ERROR("frame create thread failed"); + return false; + } + return true; +} + +void core_stopFrameThread(void) +{ + g_state.stopVideo = true; + if (g_state.frameThread) + lgJoinThread(g_state.frameThread, NULL); + + g_state.frameThread = NULL; +} diff --git a/client/src/core.h b/client/src/core.h index cf15ca71..6b8d0d84 100644 --- a/client/src/core.h +++ b/client/src/core.h @@ -29,5 +29,7 @@ bool core_warpPointer(int x, int y, bool exiting); void core_updatePositionInfo(void); void core_alignToGuest(void); bool core_isValidPointerPos(int x, int y); +bool core_startFrameThread(void); +void core_stopFrameThread(void); #endif diff --git a/client/src/keybind.c b/client/src/keybind.c new file mode 100644 index 00000000..2103abb1 --- /dev/null +++ b/client/src/keybind.c @@ -0,0 +1,153 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2021 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 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 General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "keybind.h" + +#include "main.h" +#include "app.h" +#include "core.h" +#include "kb.h" + +#include "spice/spice.h" + +static void bind_fullscreen(int sc, void * opaque) +{ + SDL_SetWindowFullscreen(g_state.window, g_params.fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP); + g_params.fullscreen = !g_params.fullscreen; +} + +static void bind_video(int sc, void * opaque) +{ + g_state.stopVideo = !g_state.stopVideo; + app_alert( + LG_ALERT_INFO, + g_state.stopVideo ? "Video Stream Disabled" : "Video Stream Enabled" + ); + + if (g_state.stopVideo) + core_stopFrameThread(); + else + core_startFrameThread(); +} + +static void bind_rotate(int sc, void * opaque) +{ + if (g_params.winRotate == LG_ROTATE_MAX-1) + g_params.winRotate = 0; + else + ++g_params.winRotate; + core_updatePositionInfo(); +} + +static void bind_input(int sc, void * opaque) +{ + g_state.ignoreInput = !g_state.ignoreInput; + + if (g_state.ignoreInput) + core_setCursorInView(false); + else + g_state.ds->realignPointer(); + + app_alert( + LG_ALERT_INFO, + g_state.ignoreInput ? "Input Disabled" : "Input Enabled" + ); +} + +static void bind_quit(int sc, void * opaque) +{ + g_state.state = APP_STATE_SHUTDOWN; +} + +static void bind_mouseSens(int sc, void * opaque) +{ + bool inc = (bool)opaque; + + if (inc) + { + if (g_cursor.sens < 9) + ++g_cursor.sens; + } + else + { + if (g_cursor.sens > -9) + --g_cursor.sens; + } + + char msg[20]; + snprintf(msg, sizeof(msg), "Sensitivity: %s%d", + g_cursor.sens > 0 ? "+" : "", g_cursor.sens); + + app_alert( + LG_ALERT_INFO, + msg + ); +} + +static void bind_ctrlAltFn(int sc, void * opaque) +{ + const uint32_t ctrl = xfree86_to_ps2[KEY_LEFTCTRL]; + const uint32_t alt = xfree86_to_ps2[KEY_LEFTALT ]; + const uint32_t fn = xfree86_to_ps2[sc]; + spice_key_down(ctrl); + spice_key_down(alt ); + spice_key_down(fn ); + + spice_key_up(ctrl); + spice_key_up(alt ); + spice_key_up(fn ); +} + +static void bind_passthrough(int sc, void * opaque) +{ + sc = xfree86_to_ps2[sc]; + spice_key_down(sc); + spice_key_up (sc); +} + +void keybind_register(void) +{ + app_registerKeybind(KEY_F, bind_fullscreen, NULL); + app_registerKeybind(KEY_V, bind_video , NULL); + app_registerKeybind(KEY_R, bind_rotate , NULL); + app_registerKeybind(KEY_Q, bind_quit , NULL); + + if (g_params.useSpiceInput) + { + app_registerKeybind(KEY_I , bind_input , NULL); + app_registerKeybind(KEY_INSERT, bind_mouseSens, (void*)true ); + app_registerKeybind(KEY_DELETE, bind_mouseSens, (void*)false); + + app_registerKeybind(KEY_F1 , bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F2 , bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F3 , bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F4 , bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F5 , bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F6 , bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F7 , bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F8 , bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F9 , bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F10, bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F11, bind_ctrlAltFn, NULL); + app_registerKeybind(KEY_F12, bind_ctrlAltFn, NULL); + + app_registerKeybind(KEY_LEFTMETA , bind_passthrough, NULL); + app_registerKeybind(KEY_RIGHTMETA, bind_passthrough, NULL); + } +} diff --git a/client/src/keybind.h b/client/src/keybind.h new file mode 100644 index 00000000..c7eb9a3c --- /dev/null +++ b/client/src/keybind.h @@ -0,0 +1,25 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2021 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 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 General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _H_LG_KEYBIND_ +#define _H_LG_KEYBIND_ + +void keybind_register(void); + +#endif diff --git a/client/src/main.c b/client/src/main.c index c20dfb37..d529e044 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -1,6 +1,6 @@ /* Looking Glass - KVM FrameRelay (KVMFR) Client -Copyright (C) 2017-2019 Geoffrey McRae +Copyright (C) 2017-2021 Geoffrey McRae https://looking-glass.hostfission.com This program is free software; you can redistribute it and/or modify it under @@ -50,22 +50,19 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "core.h" #include "app.h" -#include "util.h" +#include "keybind.h" #include "clipboard.h" #include "ll.h" -#include "kb.h" // forwards static int cursorThread(void * unused); static int renderThread(void * unused); -static int frameThread (void * unused); static LGEvent *e_startup = NULL; static LGEvent *e_frame = NULL; static LGThread *t_spice = NULL; static LGThread *t_render = NULL; static LGThread *t_cursor = NULL; -static LGThread *t_frame = NULL; static SDL_Cursor *cursor = NULL; struct AppState g_state; @@ -175,8 +172,7 @@ static int renderThread(void * unused) if (t_cursor) lgJoinThread(t_cursor, NULL); - if (t_frame) - lgJoinThread(t_frame, NULL); + core_stopFrameThread(); g_state.lgr->deinitialize(g_state.lgrData); g_state.lgr = NULL; @@ -325,7 +321,7 @@ static int cursorThread(void * unused) return 0; } -static int frameThread(void * unused) +int main_frameThread(void * unused) { struct DMAFrameInfo { @@ -590,7 +586,7 @@ int eventFilter(void * userdata, SDL_Event * event) return 0; } -void int_handler(int sig) +void intHandler(int sig) { switch(sig) { @@ -611,7 +607,7 @@ void int_handler(int sig) } } -static bool try_renderer(const int index, const LG_RendererParams lgrParams, Uint32 * sdlFlags) +static bool tryRenderer(const int index, const LG_RendererParams lgrParams, Uint32 * sdlFlags) { const LG_Renderer *r = LG_Renderers[index]; @@ -637,143 +633,6 @@ static bool try_renderer(const int index, const LG_RendererParams lgrParams, Uin return true; } -static void keybind_fullscreen(int sc, void * opaque) -{ - SDL_SetWindowFullscreen(g_state.window, g_params.fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP); - g_params.fullscreen = !g_params.fullscreen; -} - -static void keybind_video(int sc, void * opaque) -{ - g_state.stopVideo = !g_state.stopVideo; - app_alert( - LG_ALERT_INFO, - g_state.stopVideo ? "Video Stream Disabled" : "Video Stream Enabled" - ); - - if (!g_state.stopVideo) - { - if (t_frame) - { - lgJoinThread(t_frame, NULL); - t_frame = NULL; - } - - if (!lgCreateThread("frameThread", frameThread, NULL, &t_frame)) - DEBUG_ERROR("frame create thread failed"); - } -} - -static void keybind_rotate(int sc, void * opaque) -{ - if (g_params.winRotate == LG_ROTATE_MAX-1) - g_params.winRotate = 0; - else - ++g_params.winRotate; - core_updatePositionInfo(); -} - -static void toggle_input(int sc, void * opaque) -{ - g_state.ignoreInput = !g_state.ignoreInput; - - if (g_state.ignoreInput) - core_setCursorInView(false); - else - g_state.ds->realignPointer(); - - app_alert( - LG_ALERT_INFO, - g_state.ignoreInput ? "Input Disabled" : "Input Enabled" - ); -} - -static void keybind_quit(int sc, void * opaque) -{ - g_state.state = APP_STATE_SHUTDOWN; -} - -static void mouse_sens_inc(int sc, void * opaque) -{ - char * msg; - if (g_cursor.sens < 9) - ++g_cursor.sens; - - alloc_sprintf(&msg, "Sensitivity: %s%d", g_cursor.sens > 0 ? "+" : "", g_cursor.sens); - app_alert( - LG_ALERT_INFO, - msg - ); - free(msg); -} - -static void mouse_sens_dec(int sc, void * opaque) -{ - char * msg; - - if (g_cursor.sens > -9) - --g_cursor.sens; - - alloc_sprintf(&msg, "Sensitivity: %s%d", g_cursor.sens > 0 ? "+" : "", g_cursor.sens); - app_alert( - LG_ALERT_INFO, - msg - ); - free(msg); -} - -static void keybind_ctrlAltFn(int sc, void * opaque) -{ - const uint32_t ctrl = xfree86_to_ps2[KEY_LEFTCTRL]; - const uint32_t alt = xfree86_to_ps2[KEY_LEFTALT ]; - const uint32_t fn = xfree86_to_ps2[sc]; - spice_key_down(ctrl); - spice_key_down(alt ); - spice_key_down(fn ); - - spice_key_up(ctrl); - spice_key_up(alt ); - spice_key_up(fn ); -} - -static void keybind_passthrough(int sc, void * opaque) -{ - sc = xfree86_to_ps2[sc]; - spice_key_down(sc); - spice_key_up (sc); -} - -static void register_key_binds(void) -{ - app_registerKeybind(KEY_F, keybind_fullscreen, NULL); - app_registerKeybind(KEY_V, keybind_video , NULL); - app_registerKeybind(KEY_R, keybind_rotate , NULL); - app_registerKeybind(KEY_Q, keybind_quit , NULL); - - if (g_params.useSpiceInput) - { - app_registerKeybind(KEY_I , toggle_input , NULL); - app_registerKeybind(KEY_INSERT, mouse_sens_inc , NULL); - app_registerKeybind(KEY_DELETE, mouse_sens_dec , NULL); - - app_registerKeybind(KEY_F1 , keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F2 , keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F3 , keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F4 , keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F5 , keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F6 , keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F7 , keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F8 , keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F9 , keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F10, keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F11, keybind_ctrlAltFn, NULL); - app_registerKeybind(KEY_F12, keybind_ctrlAltFn, NULL); - - app_registerKeybind(KEY_LEFTMETA , keybind_passthrough, NULL); - app_registerKeybind(KEY_RIGHTMETA, keybind_passthrough, NULL); - } -} - static void initSDLCursor(void) { const uint8_t data[4] = {0xf, 0x9, 0x9, 0xf}; @@ -849,8 +708,8 @@ static int lg_run(void) // override SDL's SIGINIT handler so that we can tell the difference between // SIGINT and the user sending a close event, such as ALT+F4 - signal(SIGINT , int_handler); - signal(SIGTERM, int_handler); + signal(SIGINT , intHandler); + signal(SIGTERM, intHandler); // try map the shared memory if (!ivshmemOpen(&g_state.shm)) @@ -900,7 +759,7 @@ static int lg_run(void) { DEBUG_INFO("Trying forced renderer"); sdlFlags = 0; - if (!try_renderer(g_params.forceRendererIndex, lgrParams, &sdlFlags)) + if (!tryRenderer(g_params.forceRendererIndex, lgrParams, &sdlFlags)) { DEBUG_ERROR("Forced renderer failed to iniailize"); return -1; @@ -913,7 +772,7 @@ static int lg_run(void) for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i) { sdlFlags = 0; - if (try_renderer(i, lgrParams, &sdlFlags)) + if (tryRenderer(i, lgrParams, &sdlFlags)) { g_state.lgr = LG_Renderers[i]; break; @@ -994,7 +853,7 @@ static int lg_run(void) g_state.frameTime = 1000000000ULL / (unsigned long long)g_params.fpsMin; } - register_key_binds(); + keybind_register(); initSDLCursor(); @@ -1136,11 +995,8 @@ restart: return 1; } - if (!lgCreateThread("frameThread", frameThread, NULL, &t_frame)) - { - DEBUG_ERROR("frame create thread failed"); + if (!core_startFrameThread()) return -1; - } while(g_state.state == APP_STATE_RUNNING) { @@ -1156,9 +1012,10 @@ restart: { lgSignalEvent(e_startup); lgSignalEvent(e_frame); - lgJoinThread(t_frame , NULL); + + core_stopFrameThread(); + lgJoinThread(t_cursor, NULL); - t_frame = NULL; t_cursor = NULL; lgInit(); diff --git a/client/src/main.h b/client/src/main.h index 3c6d27c1..145a9d05 100644 --- a/client/src/main.h +++ b/client/src/main.h @@ -25,6 +25,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "dynamic/displayservers.h" #include "dynamic/renderers.h" +#include "common/thread.h" #include "common/types.h" #include "common/ivshmem.h" @@ -81,6 +82,7 @@ struct AppState PLGMPClientQueue frameQueue; PLGMPClientQueue pointerQueue; + LGThread * frameThread; bool formatValid; atomic_uint_least64_t frameTime; uint64_t lastFrameTime; @@ -241,3 +243,5 @@ struct CursorState extern struct AppState g_state; extern struct CursorState g_cursor; extern struct AppParams g_params; + +int main_frameThread(void * unused);