[client/common] restructure project in prep for full SDL removal

This commit is contained in:
Geoffrey McRae 2021-01-25 19:58:36 +11:00
parent 6f1c19b3b0
commit bf583290a4
42 changed files with 1668 additions and 1822 deletions

View File

@ -99,11 +99,14 @@ link_libraries(
set(SOURCES set(SOURCES
${CMAKE_BINARY_DIR}/version.c ${CMAKE_BINARY_DIR}/version.c
src/main.c src/main.c
src/core.c
src/app.c src/app.c
src/config.c src/config.c
src/lg-renderer.c src/lg-renderer.c
src/ll.c src/ll.c
src/utils.c src/util.c
src/clipboard.c
src/kb.c
) )
add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common" ) add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common" )

View File

@ -128,12 +128,12 @@ static bool sdlEventFilter(SDL_Event * event)
switch(event->window.event) switch(event->window.event)
{ {
case SDL_WINDOWEVENT_ENTER: case SDL_WINDOWEVENT_ENTER:
app_handleWindowEnter(); app_handleEnterEvent(true);
return true; return true;
case SDL_WINDOWEVENT_LEAVE: case SDL_WINDOWEVENT_LEAVE:
sdl.exiting = false; sdl.exiting = false;
app_handleWindowLeave(); app_handleEnterEvent(false);
return true; return true;
case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_GAINED:

View File

@ -372,7 +372,7 @@ static bool x11EventFilter(SDL_Event * event)
XIEnterEvent *xie = cookie->data; XIEnterEvent *xie = cookie->data;
app_updateCursorPos(xie->event_x, xie->event_y); app_updateCursorPos(xie->event_x, xie->event_y);
app_handleWindowEnter(); app_handleEnterEvent(true);
x11.entered = true; x11.entered = true;
return true; return true;
} }
@ -384,7 +384,7 @@ static bool x11EventFilter(SDL_Event * event)
XILeaveEvent *xie = cookie->data; XILeaveEvent *xie = cookie->data;
app_updateCursorPos(xie->event_x, xie->event_y); app_updateCursorPos(xie->event_x, xie->event_y);
app_handleWindowLeave(); app_handleEnterEvent(false);
x11.entered = false; x11.entered = false;
return true; return true;
} }

View File

@ -21,7 +21,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "interface/displayserver.h" #include "interface/displayserver.h"
SDL_Window * app_getWindow(void); SDL_Window * app_getWindow(void);
bool app_getProp(LG_DSProperty prop, void * ret); bool app_getProp(LG_DSProperty prop, void * ret);
@ -39,8 +38,7 @@ void app_handleButtonPress(int button);
void app_handleButtonRelease(int button); void app_handleButtonRelease(int button);
void app_handleKeyPress(int scancode); void app_handleKeyPress(int scancode);
void app_handleKeyRelease(int scancode); void app_handleKeyRelease(int scancode);
void app_handleWindowEnter(void); void app_handleEnterEvent(bool entered);
void app_handleWindowLeave(void);
void app_handleFocusEvent(bool focused); void app_handleFocusEvent(bool focused);
void app_handleCloseEvent(void); void app_handleCloseEvent(void);

View File

@ -105,10 +105,10 @@ struct LG_DisplayServerOps
void (*uninhibitIdle)(); void (*uninhibitIdle)();
/* clipboard support */ /* clipboard support */
bool (* cbInit)(void); bool (*cbInit)(void);
void (* cbNotice)(LG_ClipboardData type); void (*cbNotice)(LG_ClipboardData type);
void (* cbRelease)(void); void (*cbRelease)(void);
void (* cbRequest)(LG_ClipboardData type); void (*cbRequest)(LG_ClipboardData type);
}; };
#endif #endif

37
client/include/util.h Normal file
View File

@ -0,0 +1,37 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
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_UTIL_
#define _H_LG_UTIL_
#include <stdlib.h>
#include <stdbool.h>
#include "common/types.h"
// reads the specified file into a new buffer
// the callee must free the buffer
bool util_fileGetContents(const char * filename, char ** buffer, size_t * length);
void util_cursorToInt(double ex, double ey, int *x, int *y);
bool util_guestCurToLocal(struct DoublePoint *local);
void util_localCurToGuest(struct DoublePoint *guest);
void util_rotatePoint(struct DoublePoint *point);
bool util_isValidCursorLocation(int x, int y);
#endif

View File

@ -24,7 +24,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common/sysinfo.h" #include "common/sysinfo.h"
#include "common/time.h" #include "common/time.h"
#include "common/locking.h" #include "common/locking.h"
#include "utils.h" #include "util.h"
#include "dynamic/fonts.h" #include "dynamic/fonts.h"
#include <SDL2/SDL_syswm.h> #include <SDL2/SDL_syswm.h>

View File

@ -19,7 +19,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "fps.h" #include "fps.h"
#include "common/debug.h" #include "common/debug.h"
#include "utils.h"
#include "texture.h" #include "texture.h"
#include "shader.h" #include "shader.h"

View File

@ -22,7 +22,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "texture.h" #include "texture.h"
#include "common/debug.h" #include "common/debug.h"
#include "utils.h"
#include "ll.h" #include "ll.h"
#include <stdlib.h> #include <stdlib.h>

View File

@ -19,7 +19,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "shader.h" #include "shader.h"
#include "common/debug.h" #include "common/debug.h"
#include "utils.h" #include "util.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -63,7 +63,7 @@ bool egl_shader_load(EGL_Shader * this, const char * vertex_file, const char * f
char * vertex_code, * fragment_code; char * vertex_code, * fragment_code;
size_t vertex_size, fragment_size; size_t vertex_size, fragment_size;
if (!file_get_contents(vertex_file, &vertex_code, &vertex_size)) if (!util_fileGetContents(vertex_file, &vertex_code, &vertex_size))
{ {
DEBUG_ERROR("Failed to read vertex shader"); DEBUG_ERROR("Failed to read vertex shader");
return false; return false;
@ -71,7 +71,7 @@ bool egl_shader_load(EGL_Shader * this, const char * vertex_file, const char * f
DEBUG_INFO("Loaded vertex shader: %s", vertex_file); DEBUG_INFO("Loaded vertex shader: %s", vertex_file);
if (!file_get_contents(fragment_file, &fragment_code, &fragment_size)) if (!util_fileGetContents(fragment_file, &fragment_code, &fragment_size))
{ {
DEBUG_ERROR("Failed to read fragment shader"); DEBUG_ERROR("Failed to read fragment shader");
free(vertex_code); free(vertex_code);

View File

@ -19,7 +19,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "splash.h" #include "splash.h"
#include "common/debug.h" #include "common/debug.h"
#include "utils.h"
#include "draw.h" #include "draw.h"
#include "texture.h" #include "texture.h"

View File

@ -21,7 +21,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common/debug.h" #include "common/debug.h"
#include "common/framebuffer.h" #include "common/framebuffer.h"
#include "dynprocs.h" #include "dynprocs.h"
#include "utils.h"
#include "egldebug.h" #include "egldebug.h"
#include <stdlib.h> #include <stdlib.h>

View File

@ -17,13 +17,22 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "app.h"
#include "main.h" #include "main.h"
#include "core.h"
#include "util.h"
#include "clipboard.h"
#include "ll.h"
#include "kb.h"
#include "common/debug.h" #include "common/debug.h"
#include <stdarg.h> #include <stdarg.h>
void app_alert(LG_MsgAlert type, const char * fmt, ...) void app_alert(LG_MsgAlert type, const char * fmt, ...)
{ {
if (!g_state.lgr || !params.showAlerts) if (!g_state.lgr || !g_params.showAlerts)
return; return;
va_list args; va_list args;
@ -73,3 +82,529 @@ void app_release_keybind(KeybindHandle * handle)
free(*handle); free(*handle);
*handle = NULL; *handle = NULL;
} }
bool app_getProp(LG_DSProperty prop, void * ret)
{
return g_state.ds->getProp(prop, ret);
}
SDL_Window * app_getWindow(void)
{
return g_state.window;
}
bool app_inputEnabled(void)
{
return g_params.useSpiceInput && !g_state.ignoreInput &&
((g_cursor.grab && g_params.captureInputOnly) || !g_params.captureInputOnly);
}
bool app_cursorInWindow(void)
{
return g_cursor.inWindow;
}
bool app_cursorIsGrabbed(void)
{
return g_cursor.grab;
}
bool app_cursorWantsRaw(void)
{
return g_params.rawMouse;
}
void app_updateCursorPos(double x, double y)
{
g_cursor.pos.x = x;
g_cursor.pos.y = y;
g_cursor.valid = true;
}
void app_handleFocusEvent(bool focused)
{
g_state.focused = focused;
if (!app_inputEnabled())
return;
if (!focused)
{
core_setGrabQuiet(false);
core_setCursorInView(false);
}
g_cursor.realign = true;
g_state.ds->realignPointer();
}
void app_handleEnterEvent(bool entered)
{
if (entered)
{
g_cursor.inWindow = true;
if (!app_inputEnabled())
return;
g_cursor.realign = true;
}
else
{
g_cursor.inWindow = false;
core_setCursorInView(false);
if (!app_inputEnabled())
return;
if (!g_params.alwaysShowCursor)
g_cursor.draw = false;
g_cursor.redraw = true;
}
}
void app_clipboardRelease(void)
{
if (!g_params.clipboardToVM)
return;
spice_clipboard_release();
}
void app_clipboardNotify(const LG_ClipboardData type, size_t size)
{
if (!g_params.clipboardToVM)
return;
if (type == LG_CLIPBOARD_DATA_NONE)
{
spice_clipboard_release();
return;
}
g_state.cbType = cb_lgTypeToSpiceType(type);
g_state.cbChunked = size > 0;
g_state.cbXfer = size;
spice_clipboard_grab(g_state.cbType);
if (size)
spice_clipboard_data_start(g_state.cbType, size);
}
void app_clipboardData(const LG_ClipboardData type, uint8_t * data, size_t size)
{
if (!g_params.clipboardToVM)
return;
if (g_state.cbChunked && size > g_state.cbXfer)
{
DEBUG_ERROR("refusing to send more then cbXfer bytes for chunked xfer");
size = g_state.cbXfer;
}
if (!g_state.cbChunked)
spice_clipboard_data_start(g_state.cbType, size);
spice_clipboard_data(g_state.cbType, data, (uint32_t)size);
g_state.cbXfer -= size;
}
void app_clipboardRequest(const LG_ClipboardReplyFn replyFn, void * opaque)
{
if (!g_params.clipboardToLocal)
return;
struct CBRequest * cbr = (struct CBRequest *)malloc(sizeof(struct CBRequest));
cbr->type = g_state.cbType;
cbr->replyFn = replyFn;
cbr->opaque = opaque;
ll_push(g_state.cbRequestList, cbr);
spice_clipboard_request(g_state.cbType);
}
void spiceClipboardNotice(const SpiceDataType type)
{
if (!g_params.clipboardToLocal)
return;
if (!g_state.cbAvailable)
return;
g_state.cbType = type;
g_state.ds->cbNotice(cb_spiceTypeToLGType(type));
}
void app_handleMouseGrabbed(double ex, double ey)
{
if (!app_inputEnabled())
return;
int x, y;
if (g_params.rawMouse && !g_cursor.useScale)
{
/* raw unscaled input are always round numbers */
x = floor(ex);
y = floor(ey);
}
else
{
/* apply sensitivity */
ex = (ex / 10.0) * (g_cursor.sens + 10);
ey = (ey / 10.0) * (g_cursor.sens + 10);
util_cursorToInt(ex, ey, &x, &y);
}
if (x == 0 && y == 0)
return;
if (!spice_mouse_motion(x, y))
DEBUG_ERROR("failed to send mouse motion message");
}
void app_handleButtonPress(int button)
{
if (!app_inputEnabled() || !g_cursor.inView)
return;
g_cursor.buttons |= (1U << button);
if (!spice_mouse_press(button))
DEBUG_ERROR("SDL_MOUSEBUTTONDOWN: failed to send message");
}
void app_handleButtonRelease(int button)
{
if (!app_inputEnabled())
return;
g_cursor.buttons &= ~(1U << button);
if (!spice_mouse_release(button))
DEBUG_ERROR("SDL_MOUSEBUTTONUP: failed to send message");
}
void app_handleKeyPress(int sc)
{
if (sc == g_params.escapeKey && !g_state.escapeActive)
{
g_state.escapeActive = true;
g_state.escapeAction = -1;
return;
}
if (g_state.escapeActive)
{
g_state.escapeAction = sc;
return;
}
if (!app_inputEnabled())
return;
if (g_params.ignoreWindowsKeys && (sc == KEY_LEFTMETA || sc == KEY_RIGHTMETA))
return;
if (!g_state.keyDown[sc])
{
uint32_t ps2 = xfree86_to_ps2[sc];
if (!ps2)
return;
if (spice_key_down(ps2))
g_state.keyDown[sc] = true;
else
{
DEBUG_ERROR("SDL_KEYDOWN: failed to send message");
return;
}
}
}
void app_handleKeyRelease(int sc)
{
if (g_state.escapeActive)
{
if (g_state.escapeAction == -1)
{
if (g_params.useSpiceInput)
core_setGrab(!g_cursor.grab);
}
else
{
KeybindHandle handle = g_state.bindings[sc];
if (handle)
{
handle->callback(sc, handle->opaque);
return;
}
}
if (sc == g_params.escapeKey)
g_state.escapeActive = false;
}
if (!app_inputEnabled())
return;
// avoid sending key up events when we didn't send a down
if (!g_state.keyDown[sc])
return;
if (g_params.ignoreWindowsKeys && (sc == KEY_LEFTMETA || sc == KEY_RIGHTMETA))
return;
uint32_t ps2 = xfree86_to_ps2[sc];
if (!ps2)
return;
if (spice_key_up(ps2))
g_state.keyDown[sc] = false;
else
{
DEBUG_ERROR("SDL_KEYUP: failed to send message");
return;
}
}
void app_handleMouseNormal(double ex, double ey)
{
// prevent cursor handling outside of capture if the position is not known
if (!g_cursor.guest.valid)
return;
if (!app_inputEnabled())
return;
/* scale the movement to the guest */
if (g_cursor.useScale && g_params.scaleMouseInput)
{
ex *= g_cursor.scale.x / g_cursor.dpiScale;
ey *= g_cursor.scale.y / g_cursor.dpiScale;
}
bool testExit = true;
if (!g_cursor.inView)
{
const bool inView =
g_cursor.pos.x >= g_state.dstRect.x &&
g_cursor.pos.x < g_state.dstRect.x + g_state.dstRect.w &&
g_cursor.pos.y >= g_state.dstRect.y &&
g_cursor.pos.y < g_state.dstRect.y + g_state.dstRect.h;
core_setCursorInView(inView);
if (inView)
g_cursor.realign = true;
}
/* nothing to do if we are outside the viewport */
if (!g_cursor.inView)
return;
/*
* do not pass mouse events to the guest if we do not have focus, this must be
* done after the inView test has been performed so that when focus is gained
* we know if we should be drawing the cursor.
*/
if (!g_state.focused)
return;
/* if we have been instructed to realign */
if (g_cursor.realign)
{
g_cursor.realign = false;
struct DoublePoint guest;
util_localCurToGuest(&guest);
/* add the difference to the offset */
ex += guest.x - (g_cursor.guest.x + g_cursor.guest.hx);
ey += guest.y - (g_cursor.guest.y + g_cursor.guest.hy);
/* don't test for an exit as we just entered, we can get into a enter/exit
* loop otherwise */
testExit = false;
}
/* if we are in "autoCapture" and the delta was large don't test for exit */
if (g_params.autoCapture &&
(fabs(ex) > 100.0 / g_cursor.scale.x || fabs(ey) > 100.0 / g_cursor.scale.y))
testExit = false;
/* if any buttons are held we should not allow exit to happen */
if (g_cursor.buttons)
testExit = false;
if (testExit)
{
/* translate the move to the guests orientation */
struct DoublePoint move = {.x = ex, .y = ey};
util_rotatePoint(&move);
/* translate the guests position to our coordinate space */
struct DoublePoint local;
util_guestCurToLocal(&local);
/* check if the move would push the cursor outside the guest's viewport */
if (
local.x + move.x < g_state.dstRect.x ||
local.y + move.y < g_state.dstRect.y ||
local.x + move.x >= g_state.dstRect.x + g_state.dstRect.w ||
local.y + move.y >= g_state.dstRect.y + g_state.dstRect.h)
{
local.x += move.x;
local.y += move.y;
const int tx = (local.x <= 0.0) ? floor(local.x) : ceil(local.x);
const int ty = (local.y <= 0.0) ? floor(local.y) : ceil(local.y);
if (util_isValidCursorLocation(
g_state.windowPos.x + g_state.border.x + tx,
g_state.windowPos.y + g_state.border.y + ty))
{
core_setCursorInView(false);
/* preempt the window leave flag if the warp will leave our window */
if (tx < 0 || ty < 0 || tx > g_state.windowW || ty > g_state.windowH)
g_cursor.inWindow = false;
/* ungrab the pointer and move the local cursor to the exit point */
g_state.ds->ungrabPointer();
core_warpPointer(tx, ty, true);
return;
}
}
}
int x, y;
util_cursorToInt(ex, ey, &x, &y);
if (x == 0 && y == 0)
return;
if (g_params.autoCapture)
{
g_cursor.delta.x += x;
g_cursor.delta.y += y;
if (fabs(g_cursor.delta.x) > 50.0 || fabs(g_cursor.delta.y) > 50.0)
{
g_cursor.delta.x = 0;
g_cursor.delta.y = 0;
core_warpPointer(g_state.windowCX, g_state.windowCY, false);
}
g_cursor.guest.x = g_state.srcSize.x / 2;
g_cursor.guest.y = g_state.srcSize.y / 2;
}
else
{
/* assume the mouse will move to the location we attempt to move it to so we
* avoid warp out of window issues. The cursorThread will correct this if
* wrong after the movement has ocurred on the guest */
g_cursor.guest.x += x;
g_cursor.guest.y += y;
}
if (!spice_mouse_motion(x, y))
DEBUG_ERROR("failed to send mouse motion message");
}
// On some display servers normal cursor logic does not work due to the lack of
// cursor warp support. Instead, we attempt a best-effort emulation which works
// with a 1:1 mouse movement patch applied in the guest. For anything fancy, use
// capture mode.
void app_handleMouseBasic()
{
/* do not pass mouse events to the guest if we do not have focus */
if (!g_state.focused)
return;
if (!app_inputEnabled())
return;
const bool inView =
g_cursor.pos.x >= g_state.dstRect.x &&
g_cursor.pos.x < g_state.dstRect.x + g_state.dstRect.w &&
g_cursor.pos.y >= g_state.dstRect.y &&
g_cursor.pos.y < g_state.dstRect.y + g_state.dstRect.h;
core_setCursorInView(inView);
if (g_cursor.guest.dpiScale == 0)
return;
double px = g_cursor.pos.x;
double py = g_cursor.pos.y;
if (px < g_state.dstRect.x)
px = g_state.dstRect.x;
else if (px > g_state.dstRect.x + g_state.dstRect.w)
px = g_state.dstRect.x + g_state.dstRect.w;
if (py < g_state.dstRect.y)
py = g_state.dstRect.y;
else if (py > g_state.dstRect.y + g_state.dstRect.h)
py = g_state.dstRect.y + g_state.dstRect.h;
/* translate the guests position to our coordinate space */
struct DoublePoint local;
util_guestCurToLocal(&local);
int x = (int) round((px - local.x) / g_cursor.dpiScale);
int y = (int) round((py - local.y) / g_cursor.dpiScale);
if (!x && !y)
return;
g_cursor.guest.x += x;
g_cursor.guest.y += y;
if (!spice_mouse_motion(x, y))
DEBUG_ERROR("failed to send mouse motion message");
}
void app_updateWindowPos(int x, int y)
{
g_state.windowPos.x = x;
g_state.windowPos.y = y;
}
void app_handleResizeEvent(int w, int h)
{
SDL_GetWindowBordersSize(g_state.window,
&g_state.border.y,
&g_state.border.x,
&g_state.border.h,
&g_state.border.w
);
/* don't do anything else if the window dimensions have not changed */
if (g_state.windowW == w && g_state.windowH == h)
return;
g_state.windowW = w;
g_state.windowH = h;
g_state.windowCX = w / 2;
g_state.windowCY = h / 2;
core_updatePositionInfo();
if (app_inputEnabled())
{
/* if the window is moved/resized causing a loss of focus while grabbed, it
* makes it impossible to re-focus the window, so we quietly re-enter
* capture if we were already in it */
if (g_cursor.grab)
{
core_setGrabQuiet(false);
core_setGrabQuiet(true);
}
core_alignToGuest();
}
}
void app_handleCloseEvent(void)
{
if (!g_params.ignoreQuit || !g_cursor.inView)
g_state.state = APP_STATE_SHUTDOWN;
}

116
client/src/clipboard.c Normal file
View File

@ -0,0 +1,116 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
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 "clipboard.h"
#include "main.h"
#include "ll.h"
#include "common/debug.h"
LG_ClipboardData cb_spiceTypeToLGType(const SpiceDataType type)
{
switch(type)
{
case SPICE_DATA_TEXT: return LG_CLIPBOARD_DATA_TEXT; break;
case SPICE_DATA_PNG : return LG_CLIPBOARD_DATA_PNG ; break;
case SPICE_DATA_BMP : return LG_CLIPBOARD_DATA_BMP ; break;
case SPICE_DATA_TIFF: return LG_CLIPBOARD_DATA_TIFF; break;
case SPICE_DATA_JPEG: return LG_CLIPBOARD_DATA_JPEG; break;
default:
DEBUG_ERROR("invalid spice data type");
return LG_CLIPBOARD_DATA_NONE;
}
}
SpiceDataType cb_lgTypeToSpiceType(const LG_ClipboardData type)
{
switch(type)
{
case LG_CLIPBOARD_DATA_TEXT: return SPICE_DATA_TEXT; break;
case LG_CLIPBOARD_DATA_PNG : return SPICE_DATA_PNG ; break;
case LG_CLIPBOARD_DATA_BMP : return SPICE_DATA_BMP ; break;
case LG_CLIPBOARD_DATA_TIFF: return SPICE_DATA_TIFF; break;
case LG_CLIPBOARD_DATA_JPEG: return SPICE_DATA_JPEG; break;
default:
DEBUG_ERROR("invalid clipboard data type");
return SPICE_DATA_NONE;
}
}
void cb_spiceNotice(const SpiceDataType type)
{
if (!g_params.clipboardToLocal)
return;
if (!g_state.cbAvailable)
return;
g_state.cbType = type;
g_state.ds->cbNotice(cb_spiceTypeToLGType(type));
}
void cb_spiceData(const SpiceDataType type, uint8_t * buffer, uint32_t size)
{
if (!g_params.clipboardToLocal)
return;
if (type == SPICE_DATA_TEXT)
{
// dos2unix
uint8_t * p = buffer;
uint32_t newSize = size;
for(uint32_t i = 0; i < size; ++i)
{
uint8_t c = buffer[i];
if (c == '\r')
{
--newSize;
continue;
}
*p++ = c;
}
size = newSize;
}
struct CBRequest * cbr;
if (ll_shift(g_state.cbRequestList, (void **)&cbr))
{
cbr->replyFn(cbr->opaque, cb_spiceTypeToLGType(type), buffer, size);
free(cbr);
}
}
void cb_spiceRelease(void)
{
if (!g_params.clipboardToLocal)
return;
if (g_state.cbAvailable)
g_state.ds->cbRelease();
}
void cb_spiceRequest(const SpiceDataType type)
{
if (!g_params.clipboardToVM)
return;
if (g_state.cbAvailable)
g_state.ds->cbRequest(cb_spiceTypeToLGType(type));
}

View File

@ -1,6 +1,6 @@
/* /*
Looking Glass - KVM FrameRelay (KVMFR) Client Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -17,17 +17,13 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#pragma once #include "spice/spice.h"
#include "interface/decoder.h" #include "interface/displayserver.h"
extern const LG_Decoder LGD_NULL; LG_ClipboardData cb_spiceTypeToLGType(const SpiceDataType type);
extern const LG_Decoder LGD_YUV420; SpiceDataType cb_lgTypeToSpiceType(const LG_ClipboardData type);
const LG_Decoder * LG_Decoders[] = void cb_spiceNotice(const SpiceDataType type);
{ void cb_spiceData(const SpiceDataType type, uint8_t * buffer, uint32_t size);
&LGD_NULL, void cb_spiceRelease(void);
&LGD_YUV420, void cb_spiceRequest(const SpiceDataType type);
NULL // end of array sentinal
};
#define LG_DECODER_COUNT ((sizeof(LG_Decoders) / sizeof(LG_Decoder *)) - 1)

View File

@ -411,9 +411,9 @@ static struct Option options[] =
void config_init(void) void config_init(void)
{ {
params.center = true; g_params.center = true;
params.w = 1024; g_params.w = 1024;
params.h = 768; g_params.h = 768;
option_register(options); option_register(options);
} }
@ -468,72 +468,72 @@ bool config_load(int argc, char * argv[])
} }
// setup the application params for the basic types // setup the application params for the basic types
params.cursorPollInterval = option_get_int ("app", "cursorPollInterval"); g_params.cursorPollInterval = option_get_int ("app", "cursorPollInterval");
params.framePollInterval = option_get_int ("app", "framePollInterval" ); g_params.framePollInterval = option_get_int ("app", "framePollInterval" );
params.allowDMA = option_get_bool ("app", "allowDMA" ); g_params.allowDMA = option_get_bool ("app", "allowDMA" );
params.windowTitle = option_get_string("win", "title" ); g_params.windowTitle = option_get_string("win", "title" );
params.autoResize = option_get_bool ("win", "autoResize" ); g_params.autoResize = option_get_bool ("win", "autoResize" );
params.allowResize = option_get_bool ("win", "allowResize" ); g_params.allowResize = option_get_bool ("win", "allowResize" );
params.keepAspect = option_get_bool ("win", "keepAspect" ); g_params.keepAspect = option_get_bool ("win", "keepAspect" );
params.forceAspect = option_get_bool ("win", "forceAspect" ); g_params.forceAspect = option_get_bool ("win", "forceAspect" );
params.dontUpscale = option_get_bool ("win", "dontUpscale" ); g_params.dontUpscale = option_get_bool ("win", "dontUpscale" );
params.borderless = option_get_bool ("win", "borderless" ); g_params.borderless = option_get_bool ("win", "borderless" );
params.fullscreen = option_get_bool ("win", "fullScreen" ); g_params.fullscreen = option_get_bool ("win", "fullScreen" );
params.maximize = option_get_bool ("win", "maximize" ); g_params.maximize = option_get_bool ("win", "maximize" );
params.fpsMin = option_get_int ("win", "fpsMin" ); g_params.fpsMin = option_get_int ("win", "fpsMin" );
params.showFPS = option_get_bool ("win", "showFPS" ); g_params.showFPS = option_get_bool ("win", "showFPS" );
params.ignoreQuit = option_get_bool ("win", "ignoreQuit" ); g_params.ignoreQuit = option_get_bool ("win", "ignoreQuit" );
params.noScreensaver = option_get_bool ("win", "noScreensaver"); g_params.noScreensaver = option_get_bool ("win", "noScreensaver");
params.showAlerts = option_get_bool ("win", "alerts" ); g_params.showAlerts = option_get_bool ("win", "alerts" );
params.quickSplash = option_get_bool ("win", "quickSplash" ); g_params.quickSplash = option_get_bool ("win", "quickSplash" );
switch(option_get_int("win", "rotate")) switch(option_get_int("win", "rotate"))
{ {
case 0 : params.winRotate = LG_ROTATE_0 ; break; case 0 : g_params.winRotate = LG_ROTATE_0 ; break;
case 90 : params.winRotate = LG_ROTATE_90 ; break; case 90 : g_params.winRotate = LG_ROTATE_90 ; break;
case 180: params.winRotate = LG_ROTATE_180; break; case 180: g_params.winRotate = LG_ROTATE_180; break;
case 270: params.winRotate = LG_ROTATE_270; break; case 270: g_params.winRotate = LG_ROTATE_270; break;
} }
params.grabKeyboard = option_get_bool("input", "grabKeyboard" ); g_params.grabKeyboard = option_get_bool("input", "grabKeyboard" );
params.grabKeyboardOnFocus = option_get_bool("input", "grabKeyboardOnFocus"); g_params.grabKeyboardOnFocus = option_get_bool("input", "grabKeyboardOnFocus");
params.escapeKey = option_get_int ("input", "escapeKey" ); g_params.escapeKey = option_get_int ("input", "escapeKey" );
params.ignoreWindowsKeys = option_get_bool("input", "ignoreWindowsKeys" ); g_params.ignoreWindowsKeys = option_get_bool("input", "ignoreWindowsKeys" );
params.hideMouse = option_get_bool("input", "hideCursor" ); g_params.hideMouse = option_get_bool("input", "hideCursor" );
params.mouseSens = option_get_int ("input", "mouseSens" ); g_params.mouseSens = option_get_int ("input", "mouseSens" );
params.mouseSmoothing = option_get_bool("input", "mouseSmoothing" ); g_params.mouseSmoothing = option_get_bool("input", "mouseSmoothing" );
params.rawMouse = option_get_bool("input", "rawMouse" ); g_params.rawMouse = option_get_bool("input", "rawMouse" );
params.mouseRedraw = option_get_bool("input", "mouseRedraw" ); g_params.mouseRedraw = option_get_bool("input", "mouseRedraw" );
params.autoCapture = option_get_bool("input", "autoCapture" ); g_params.autoCapture = option_get_bool("input", "autoCapture" );
params.captureInputOnly = option_get_bool("input", "captureOnly" ); g_params.captureInputOnly = option_get_bool("input", "captureOnly" );
params.minimizeOnFocusLoss = option_get_bool("win", "minimizeOnFocusLoss"); g_params.minimizeOnFocusLoss = option_get_bool("win", "minimizeOnFocusLoss");
if (option_get_bool("spice", "enable")) if (option_get_bool("spice", "enable"))
{ {
params.spiceHost = option_get_string("spice", "host"); g_params.spiceHost = option_get_string("spice", "host");
params.spicePort = option_get_int ("spice", "port"); g_params.spicePort = option_get_int ("spice", "port");
params.useSpiceInput = option_get_bool("spice", "input" ); g_params.useSpiceInput = option_get_bool("spice", "input" );
params.useSpiceClipboard = option_get_bool("spice", "clipboard"); g_params.useSpiceClipboard = option_get_bool("spice", "clipboard");
if (params.useSpiceClipboard) if (g_params.useSpiceClipboard)
{ {
params.clipboardToVM = option_get_bool("spice", "clipboardToVM" ); g_params.clipboardToVM = option_get_bool("spice", "clipboardToVM" );
params.clipboardToLocal = option_get_bool("spice", "clipboardToLocal"); g_params.clipboardToLocal = option_get_bool("spice", "clipboardToLocal");
if (!params.clipboardToVM && !params.clipboardToLocal) if (!g_params.clipboardToVM && !g_params.clipboardToLocal)
params.useSpiceClipboard = false; g_params.useSpiceClipboard = false;
} }
params.scaleMouseInput = option_get_bool("spice", "scaleCursor"); g_params.scaleMouseInput = option_get_bool("spice", "scaleCursor");
params.captureOnStart = option_get_bool("spice", "captureOnStart"); g_params.captureOnStart = option_get_bool("spice", "captureOnStart");
params.alwaysShowCursor = option_get_bool("spice", "alwaysShowCursor"); g_params.alwaysShowCursor = option_get_bool("spice", "alwaysShowCursor");
} }
//FIXME, this should be using linux keycodes //FIXME, this should be using linux keycodes
params.escapeKey = sdl_to_xfree86[params.escapeKey]; g_params.escapeKey = sdl_to_xfree86[g_params.escapeKey];
return true; return true;
} }
@ -574,15 +574,15 @@ static bool optRendererParse(struct Option * opt, const char * str)
if (strcasecmp(str, "auto") == 0) if (strcasecmp(str, "auto") == 0)
{ {
params.forceRenderer = false; g_params.forceRenderer = false;
return true; return true;
} }
for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i) for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i)
if (strcasecmp(str, LG_Renderers[i]->get_name()) == 0) if (strcasecmp(str, LG_Renderers[i]->get_name()) == 0)
{ {
params.forceRenderer = true; g_params.forceRenderer = true;
params.forceRendererIndex = i; g_params.forceRendererIndex = i;
return true; return true;
} }
@ -602,13 +602,13 @@ static StringList optRendererValues(struct Option * opt)
static char * optRendererToString(struct Option * opt) static char * optRendererToString(struct Option * opt)
{ {
if (!params.forceRenderer) if (!g_params.forceRenderer)
return strdup("auto"); return strdup("auto");
if (params.forceRendererIndex >= LG_RENDERER_COUNT) if (g_params.forceRendererIndex >= LG_RENDERER_COUNT)
return NULL; return NULL;
return strdup(LG_Renderers[params.forceRendererIndex]->get_name()); return strdup(LG_Renderers[g_params.forceRendererIndex]->get_name());
} }
static bool optPosParse(struct Option * opt, const char * str) static bool optPosParse(struct Option * opt, const char * str)
@ -618,13 +618,13 @@ static bool optPosParse(struct Option * opt, const char * str)
if (strcmp(str, "center") == 0) if (strcmp(str, "center") == 0)
{ {
params.center = true; g_params.center = true;
return true; return true;
} }
if (sscanf(str, "%dx%d", &params.x, &params.y) == 2) if (sscanf(str, "%dx%d", &g_params.x, &g_params.y) == 2)
{ {
params.center = false; g_params.center = false;
return true; return true;
} }
@ -641,12 +641,12 @@ static StringList optPosValues(struct Option * opt)
static char * optPosToString(struct Option * opt) static char * optPosToString(struct Option * opt)
{ {
if (params.center) if (g_params.center)
return strdup("center"); return strdup("center");
int len = snprintf(NULL, 0, "%dx%d", params.x, params.y); int len = snprintf(NULL, 0, "%dx%d", g_params.x, g_params.y);
char * str = malloc(len + 1); char * str = malloc(len + 1);
sprintf(str, "%dx%d", params.x, params.y); sprintf(str, "%dx%d", g_params.x, g_params.y);
return str; return str;
} }
@ -656,9 +656,9 @@ static bool optSizeParse(struct Option * opt, const char * str)
if (!str) if (!str)
return false; return false;
if (sscanf(str, "%dx%d", &params.w, &params.h) == 2) if (sscanf(str, "%dx%d", &g_params.w, &g_params.h) == 2)
{ {
if (params.w < 1 || params.h < 1) if (g_params.w < 1 || g_params.h < 1)
return false; return false;
return true; return true;
} }
@ -675,9 +675,9 @@ static StringList optSizeValues(struct Option * opt)
static char * optSizeToString(struct Option * opt) static char * optSizeToString(struct Option * opt)
{ {
int len = snprintf(NULL, 0, "%dx%d", params.w, params.h); int len = snprintf(NULL, 0, "%dx%d", g_params.w, g_params.h);
char * str = malloc(len + 1); char * str = malloc(len + 1);
sprintf(str, "%dx%d", params.w, params.h); sprintf(str, "%dx%d", g_params.w, g_params.h);
return str; return str;
} }

262
client/src/core.c Normal file
View File

@ -0,0 +1,262 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
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 "core.h"
#include "main.h"
#include "app.h"
#include "util.h"
#include "common/time.h"
#include <assert.h>
#define RESIZE_TIMEOUT (10 * 1000) // 10ms
void core_setCursorInView(bool enable)
{
// if the state has not changed, don't do anything else
if (g_cursor.inView == enable)
return;
if (enable && !g_state.focused)
return;
// do not allow the view to become active if any mouse buttons are being held,
// this fixes issues with meta window resizing.
if (enable && g_cursor.buttons)
return;
g_cursor.inView = enable;
g_cursor.draw = (g_params.alwaysShowCursor || g_params.captureInputOnly)
? true : enable;
g_cursor.redraw = true;
/* if the display server does not support warp, then we can not operate in
* always relative mode and we should not grab the pointer */
bool warpSupport = true;
app_getProp(LG_DS_WARP_SUPPORT, &warpSupport);
g_cursor.warpState = enable ? WARP_STATE_ON : WARP_STATE_OFF;
if (enable)
{
if (g_params.hideMouse)
SDL_ShowCursor(SDL_DISABLE);
if (warpSupport && !g_params.captureInputOnly)
g_state.ds->grabPointer();
}
else
{
if (g_params.hideMouse)
SDL_ShowCursor(SDL_ENABLE);
if (warpSupport)
g_state.ds->ungrabPointer();
g_state.ds->ungrabKeyboard();
}
g_cursor.warpState = WARP_STATE_ON;
}
void core_setGrab(bool enable)
{
core_setGrabQuiet(enable);
app_alert(
g_cursor.grab ? LG_ALERT_SUCCESS : LG_ALERT_WARNING,
g_cursor.grab ? "Capture Enabled" : "Capture Disabled"
);
}
void core_setGrabQuiet(bool enable)
{
/* we always do this so that at init the cursor is in the right state */
if (g_params.captureInputOnly && g_params.hideMouse)
SDL_ShowCursor(enable ? SDL_DISABLE : SDL_ENABLE);
if (g_cursor.grab == enable)
return;
g_cursor.grab = enable;
g_cursor.acc.x = 0.0;
g_cursor.acc.y = 0.0;
/* if the display server does not support warp we need to ungrab the pointer
* here instead of in the move handler */
bool warpSupport = true;
app_getProp(LG_DS_WARP_SUPPORT, &warpSupport);
if (enable)
{
core_setCursorInView(true);
g_state.ignoreInput = false;
if (g_params.grabKeyboard)
g_state.ds->grabKeyboard();
g_state.ds->grabPointer();
}
else
{
if (g_params.grabKeyboard)
{
if (!g_params.grabKeyboardOnFocus ||
!g_state.focused || g_params.captureInputOnly)
g_state.ds->ungrabKeyboard();
}
if (!warpSupport || g_params.captureInputOnly || !g_state.formatValid)
g_state.ds->ungrabPointer();
// if exiting capture when input on capture only, we want to show the cursor
if (g_params.captureInputOnly || !g_params.hideMouse)
core_alignToGuest();
}
}
bool core_warpPointer(int x, int y, bool exiting)
{
if (!g_cursor.inWindow && !exiting)
return false;
if (g_cursor.warpState == WARP_STATE_OFF)
return false;
if (exiting)
g_cursor.warpState = WARP_STATE_OFF;
if (g_cursor.pos.x == x && g_cursor.pos.y == y)
return true;
g_state.ds->warpPointer(x, y, exiting);
return true;
}
void core_updatePositionInfo(void)
{
if (!g_state.haveSrcSize)
goto done;
float srcW;
float srcH;
switch(g_params.winRotate)
{
case LG_ROTATE_0:
case LG_ROTATE_180:
srcW = g_state.srcSize.x;
srcH = g_state.srcSize.y;
break;
case LG_ROTATE_90:
case LG_ROTATE_270:
srcW = g_state.srcSize.y;
srcH = g_state.srcSize.x;
break;
default:
assert(!"unreachable");
}
if (g_params.keepAspect)
{
const float srcAspect = srcH / srcW;
const float wndAspect = (float)g_state.windowH / (float)g_state.windowW;
bool force = true;
if (g_params.dontUpscale &&
srcW <= g_state.windowW &&
srcH <= g_state.windowH)
{
force = false;
g_state.dstRect.w = srcW;
g_state.dstRect.h = srcH;
g_state.dstRect.x = g_state.windowCX - srcW / 2;
g_state.dstRect.y = g_state.windowCY - srcH / 2;
}
else
if ((int)(wndAspect * 1000) == (int)(srcAspect * 1000))
{
force = false;
g_state.dstRect.w = g_state.windowW;
g_state.dstRect.h = g_state.windowH;
g_state.dstRect.x = 0;
g_state.dstRect.y = 0;
}
else
if (wndAspect < srcAspect)
{
g_state.dstRect.w = (float)g_state.windowH / srcAspect;
g_state.dstRect.h = g_state.windowH;
g_state.dstRect.x = (g_state.windowW >> 1) - (g_state.dstRect.w >> 1);
g_state.dstRect.y = 0;
}
else
{
g_state.dstRect.w = g_state.windowW;
g_state.dstRect.h = (float)g_state.windowW * srcAspect;
g_state.dstRect.x = 0;
g_state.dstRect.y = (g_state.windowH >> 1) - (g_state.dstRect.h >> 1);
}
if (force && g_params.forceAspect)
{
g_state.resizeTimeout = microtime() + RESIZE_TIMEOUT;
g_state.resizeDone = false;
}
}
else
{
g_state.dstRect.x = 0;
g_state.dstRect.y = 0;
g_state.dstRect.w = g_state.windowW;
g_state.dstRect.h = g_state.windowH;
}
g_state.dstRect.valid = true;
g_cursor.useScale = (
srcH != g_state.dstRect.h ||
srcW != g_state.dstRect.w ||
g_cursor.guest.dpiScale != 100);
g_cursor.scale.x = (float)srcW / (float)g_state.dstRect.w;
g_cursor.scale.y = (float)srcH / (float)g_state.dstRect.h;
g_cursor.dpiScale = g_cursor.guest.dpiScale / 100.0f;
if (!g_state.posInfoValid)
{
g_state.posInfoValid = true;
g_state.ds->realignPointer();
}
done:
atomic_fetch_add(&g_state.lgrResize, 1);
}
void core_alignToGuest(void)
{
if (!g_cursor.guest.valid || !g_state.focused)
return;
struct DoublePoint local;
if (util_guestCurToLocal(&local))
if (core_warpPointer(round(local.x), round(local.y), false))
core_setCursorInView(true);
}

View File

@ -1,6 +1,6 @@
/* /*
Looking Glass - KVM FrameRelay (KVMFR) Client Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -17,11 +17,16 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#pragma once #ifndef _H_LG_CORE_
#define _H_LG_CORE_
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
// reads the specified file into a new buffer void core_setCursorInView(bool enable);
// the callee must free the buffer void core_setGrab(bool enable);
bool file_get_contents(const char * filename, char ** buffer, size_t * length); void core_setGrabQuiet(bool enable);
bool core_warpPointer(int x, int y, bool exiting);
void core_updatePositionInfo(void);
void core_alignToGuest(void);
#endif

148
client/src/kb.c Normal file
View File

@ -0,0 +1,148 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
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_KB_
#define _H_LG_KB_
#include "kb.h"
const uint32_t xfree86_to_ps2[KEY_MAX] =
{
[KEY_RESERVED] /* = USB 0 */ = 0x000000,
[KEY_ESC] /* = USB 41 */ = 0x000001,
[KEY_1] /* = USB 30 */ = 0x000002,
[KEY_2] /* = USB 31 */ = 0x000003,
[KEY_3] /* = USB 32 */ = 0x000004,
[KEY_4] /* = USB 33 */ = 0x000005,
[KEY_5] /* = USB 34 */ = 0x000006,
[KEY_6] /* = USB 35 */ = 0x000007,
[KEY_7] /* = USB 36 */ = 0x000008,
[KEY_8] /* = USB 37 */ = 0x000009,
[KEY_9] /* = USB 38 */ = 0x00000A,
[KEY_0] /* = USB 39 */ = 0x00000B,
[KEY_MINUS] /* = USB 45 */ = 0x00000C,
[KEY_EQUAL] /* = USB 46 */ = 0x00000D,
[KEY_BACKSPACE] /* = USB 42 */ = 0x00000E,
[KEY_TAB] /* = USB 43 */ = 0x00000F,
[KEY_Q] /* = USB 20 */ = 0x000010,
[KEY_W] /* = USB 26 */ = 0x000011,
[KEY_E] /* = USB 8 */ = 0x000012,
[KEY_R] /* = USB 21 */ = 0x000013,
[KEY_T] /* = USB 23 */ = 0x000014,
[KEY_Y] /* = USB 28 */ = 0x000015,
[KEY_U] /* = USB 24 */ = 0x000016,
[KEY_I] /* = USB 12 */ = 0x000017,
[KEY_O] /* = USB 18 */ = 0x000018,
[KEY_P] /* = USB 19 */ = 0x000019,
[KEY_LEFTBRACE] /* = USB 47 */ = 0x00001A,
[KEY_RIGHTBRACE] /* = USB 48 */ = 0x00001B,
[KEY_ENTER] /* = USB 40 */ = 0x00001C,
[KEY_LEFTCTRL] /* = USB 224 */ = 0x00001D,
[KEY_A] /* = USB 4 */ = 0x00001E,
[KEY_S] /* = USB 22 */ = 0x00001F,
[KEY_D] /* = USB 7 */ = 0x000020,
[KEY_F] /* = USB 9 */ = 0x000021,
[KEY_G] /* = USB 10 */ = 0x000022,
[KEY_H] /* = USB 11 */ = 0x000023,
[KEY_J] /* = USB 13 */ = 0x000024,
[KEY_K] /* = USB 14 */ = 0x000025,
[KEY_L] /* = USB 15 */ = 0x000026,
[KEY_SEMICOLON] /* = USB 51 */ = 0x000027,
[KEY_APOSTROPHE] /* = USB 52 */ = 0x000028,
[KEY_GRAVE] /* = USB 53 */ = 0x000029,
[KEY_LEFTSHIFT] /* = USB 225 */ = 0x00002A,
[KEY_BACKSLASH] /* = USB 49 */ = 0x00002B,
[KEY_Z] /* = USB 29 */ = 0x00002C,
[KEY_X] /* = USB 27 */ = 0x00002D,
[KEY_C] /* = USB 6 */ = 0x00002E,
[KEY_V] /* = USB 25 */ = 0x00002F,
[KEY_B] /* = USB 5 */ = 0x000030,
[KEY_N] /* = USB 17 */ = 0x000031,
[KEY_M] /* = USB 16 */ = 0x000032,
[KEY_COMMA] /* = USB 54 */ = 0x000033,
[KEY_DOT] /* = USB 55 */ = 0x000034,
[KEY_SLASH] /* = USB 56 */ = 0x000035,
[KEY_RIGHTSHIFT] /* = USB 229 */ = 0x000036,
[KEY_KPASTERISK] /* = USB 85 */ = 0x000037,
[KEY_LEFTALT] /* = USB 226 */ = 0x000038,
[KEY_SPACE] /* = USB 44 */ = 0x000039,
[KEY_CAPSLOCK] /* = USB 57 */ = 0x00003A,
[KEY_F1] /* = USB 58 */ = 0x00003B,
[KEY_F2] /* = USB 59 */ = 0x00003C,
[KEY_F3] /* = USB 60 */ = 0x00003D,
[KEY_F4] /* = USB 61 */ = 0x00003E,
[KEY_F5] /* = USB 62 */ = 0x00003F,
[KEY_F6] /* = USB 63 */ = 0x000040,
[KEY_F7] /* = USB 64 */ = 0x000041,
[KEY_F8] /* = USB 65 */ = 0x000042,
[KEY_F9] /* = USB 66 */ = 0x000043,
[KEY_F10] /* = USB 67 */ = 0x000044,
[KEY_NUMLOCK] /* = USB 83 */ = 0x000045,
[KEY_SCROLLLOCK] /* = USB 71 */ = 0x000046,
[KEY_KP7] /* = USB 95 */ = 0x000047,
[KEY_KP8] /* = USB 96 */ = 0x000048,
[KEY_KP9] /* = USB 97 */ = 0x000049,
[KEY_KPMINUS] /* = USB 86 */ = 0x00004A,
[KEY_KP4] /* = USB 92 */ = 0x00004B,
[KEY_KP5] /* = USB 93 */ = 0x00004C,
[KEY_KP6] /* = USB 94 */ = 0x00004D,
[KEY_KPPLUS] /* = USB 87 */ = 0x00004E,
[KEY_KP1] /* = USB 89 */ = 0x00004F,
[KEY_KP2] /* = USB 90 */ = 0x000050,
[KEY_KP3] /* = USB 91 */ = 0x000051,
[KEY_KP0] /* = USB 98 */ = 0x000052,
[KEY_KPDOT] /* = USB 99 */ = 0x000053,
[KEY_102ND] /* = USB 100 */ = 0x000056,
[KEY_F11] /* = USB 68 */ = 0x000057,
[KEY_F12] /* = USB 69 */ = 0x000058,
[KEY_RO] /* = USB 135 */ = 0x000073,
[KEY_HENKAN] /* = USB 138 */ = 0x000079,
[KEY_KATAKANAHIRAGANA] /* = USB 136 */ = 0x000070,
[KEY_MUHENKAN] /* = USB 139 */ = 0x00007B,
[KEY_KPENTER] /* = USB 88 */ = 0x00E01C,
[KEY_RIGHTCTRL] /* = USB 228 */ = 0x00E01D,
[KEY_KPSLASH] /* = USB 84 */ = 0x00E035,
[KEY_SYSRQ] /* = USB 70 */ = 0x00E037,
[KEY_RIGHTALT] /* = USB 230 */ = 0x00E038,
[KEY_HOME] /* = USB 74 */ = 0x00E047,
[KEY_UP] /* = USB 82 */ = 0x00E048,
[KEY_PAGEUP] /* = USB 75 */ = 0x00E049,
[KEY_LEFT] /* = USB 80 */ = 0x00E04B,
[KEY_RIGHT] /* = USB 79 */ = 0x00E04D,
[KEY_END] /* = USB 77 */ = 0x00E04F,
[KEY_DOWN] /* = USB 81 */ = 0x00E050,
[KEY_PAGEDOWN] /* = USB 78 */ = 0x00E051,
[KEY_INSERT] /* = USB 73 */ = 0x00E052,
[KEY_DELETE] /* = USB 76 */ = 0x00E053,
[KEY_KPEQUAL] /* = USB 103 */ = 0x000059,
[KEY_PAUSE] /* = USB 72 */ = 0x00E046,
[KEY_KPCOMMA] /* = USB 133 */ = 0x00007E,
[KEY_HANGEUL] /* = USB 144 */ = 0x0000F2,
[KEY_HANJA] /* = USB 145 */ = 0x0000F1,
[KEY_YEN] /* = USB 137 */ = 0x00007D,
[KEY_LEFTMETA] /* = USB 227 */ = 0x00E05B,
[KEY_RIGHTMETA] /* = USB 231 */ = 0x00E05C,
[KEY_COMPOSE] /* = USB 101 */ = 0x00E05D,
[KEY_F13] /* = USB 104 */ = 0x00005D,
[KEY_F14] /* = USB 105 */ = 0x00005E,
[KEY_F15] /* = USB 106 */ = 0x00005F,
[KEY_PRINT] /* = USB 70 */ = 0x00E037,
};
#endif

View File

@ -1,6 +1,6 @@
/* /*
Looking Glass - KVM FrameRelay (KVMFR) Client Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -18,126 +18,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/input.h> #include <linux/input.h>
#include <stdint.h>
const uint32_t xfree86_to_ps2[KEY_MAX] = extern const uint32_t xfree86_to_ps2[KEY_MAX];
{
[KEY_RESERVED] /* = USB 0 */ = 0x000000,
[KEY_ESC] /* = USB 41 */ = 0x000001,
[KEY_1] /* = USB 30 */ = 0x000002,
[KEY_2] /* = USB 31 */ = 0x000003,
[KEY_3] /* = USB 32 */ = 0x000004,
[KEY_4] /* = USB 33 */ = 0x000005,
[KEY_5] /* = USB 34 */ = 0x000006,
[KEY_6] /* = USB 35 */ = 0x000007,
[KEY_7] /* = USB 36 */ = 0x000008,
[KEY_8] /* = USB 37 */ = 0x000009,
[KEY_9] /* = USB 38 */ = 0x00000A,
[KEY_0] /* = USB 39 */ = 0x00000B,
[KEY_MINUS] /* = USB 45 */ = 0x00000C,
[KEY_EQUAL] /* = USB 46 */ = 0x00000D,
[KEY_BACKSPACE] /* = USB 42 */ = 0x00000E,
[KEY_TAB] /* = USB 43 */ = 0x00000F,
[KEY_Q] /* = USB 20 */ = 0x000010,
[KEY_W] /* = USB 26 */ = 0x000011,
[KEY_E] /* = USB 8 */ = 0x000012,
[KEY_R] /* = USB 21 */ = 0x000013,
[KEY_T] /* = USB 23 */ = 0x000014,
[KEY_Y] /* = USB 28 */ = 0x000015,
[KEY_U] /* = USB 24 */ = 0x000016,
[KEY_I] /* = USB 12 */ = 0x000017,
[KEY_O] /* = USB 18 */ = 0x000018,
[KEY_P] /* = USB 19 */ = 0x000019,
[KEY_LEFTBRACE] /* = USB 47 */ = 0x00001A,
[KEY_RIGHTBRACE] /* = USB 48 */ = 0x00001B,
[KEY_ENTER] /* = USB 40 */ = 0x00001C,
[KEY_LEFTCTRL] /* = USB 224 */ = 0x00001D,
[KEY_A] /* = USB 4 */ = 0x00001E,
[KEY_S] /* = USB 22 */ = 0x00001F,
[KEY_D] /* = USB 7 */ = 0x000020,
[KEY_F] /* = USB 9 */ = 0x000021,
[KEY_G] /* = USB 10 */ = 0x000022,
[KEY_H] /* = USB 11 */ = 0x000023,
[KEY_J] /* = USB 13 */ = 0x000024,
[KEY_K] /* = USB 14 */ = 0x000025,
[KEY_L] /* = USB 15 */ = 0x000026,
[KEY_SEMICOLON] /* = USB 51 */ = 0x000027,
[KEY_APOSTROPHE] /* = USB 52 */ = 0x000028,
[KEY_GRAVE] /* = USB 53 */ = 0x000029,
[KEY_LEFTSHIFT] /* = USB 225 */ = 0x00002A,
[KEY_BACKSLASH] /* = USB 49 */ = 0x00002B,
[KEY_Z] /* = USB 29 */ = 0x00002C,
[KEY_X] /* = USB 27 */ = 0x00002D,
[KEY_C] /* = USB 6 */ = 0x00002E,
[KEY_V] /* = USB 25 */ = 0x00002F,
[KEY_B] /* = USB 5 */ = 0x000030,
[KEY_N] /* = USB 17 */ = 0x000031,
[KEY_M] /* = USB 16 */ = 0x000032,
[KEY_COMMA] /* = USB 54 */ = 0x000033,
[KEY_DOT] /* = USB 55 */ = 0x000034,
[KEY_SLASH] /* = USB 56 */ = 0x000035,
[KEY_RIGHTSHIFT] /* = USB 229 */ = 0x000036,
[KEY_KPASTERISK] /* = USB 85 */ = 0x000037,
[KEY_LEFTALT] /* = USB 226 */ = 0x000038,
[KEY_SPACE] /* = USB 44 */ = 0x000039,
[KEY_CAPSLOCK] /* = USB 57 */ = 0x00003A,
[KEY_F1] /* = USB 58 */ = 0x00003B,
[KEY_F2] /* = USB 59 */ = 0x00003C,
[KEY_F3] /* = USB 60 */ = 0x00003D,
[KEY_F4] /* = USB 61 */ = 0x00003E,
[KEY_F5] /* = USB 62 */ = 0x00003F,
[KEY_F6] /* = USB 63 */ = 0x000040,
[KEY_F7] /* = USB 64 */ = 0x000041,
[KEY_F8] /* = USB 65 */ = 0x000042,
[KEY_F9] /* = USB 66 */ = 0x000043,
[KEY_F10] /* = USB 67 */ = 0x000044,
[KEY_NUMLOCK] /* = USB 83 */ = 0x000045,
[KEY_SCROLLLOCK] /* = USB 71 */ = 0x000046,
[KEY_KP7] /* = USB 95 */ = 0x000047,
[KEY_KP8] /* = USB 96 */ = 0x000048,
[KEY_KP9] /* = USB 97 */ = 0x000049,
[KEY_KPMINUS] /* = USB 86 */ = 0x00004A,
[KEY_KP4] /* = USB 92 */ = 0x00004B,
[KEY_KP5] /* = USB 93 */ = 0x00004C,
[KEY_KP6] /* = USB 94 */ = 0x00004D,
[KEY_KPPLUS] /* = USB 87 */ = 0x00004E,
[KEY_KP1] /* = USB 89 */ = 0x00004F,
[KEY_KP2] /* = USB 90 */ = 0x000050,
[KEY_KP3] /* = USB 91 */ = 0x000051,
[KEY_KP0] /* = USB 98 */ = 0x000052,
[KEY_KPDOT] /* = USB 99 */ = 0x000053,
[KEY_102ND] /* = USB 100 */ = 0x000056,
[KEY_F11] /* = USB 68 */ = 0x000057,
[KEY_F12] /* = USB 69 */ = 0x000058,
[KEY_RO] /* = USB 135 */ = 0x000073,
[KEY_HENKAN] /* = USB 138 */ = 0x000079,
[KEY_KATAKANAHIRAGANA] /* = USB 136 */ = 0x000070,
[KEY_MUHENKAN] /* = USB 139 */ = 0x00007B,
[KEY_KPENTER] /* = USB 88 */ = 0x00E01C,
[KEY_RIGHTCTRL] /* = USB 228 */ = 0x00E01D,
[KEY_KPSLASH] /* = USB 84 */ = 0x00E035,
[KEY_SYSRQ] /* = USB 70 */ = 0x00E037,
[KEY_RIGHTALT] /* = USB 230 */ = 0x00E038,
[KEY_HOME] /* = USB 74 */ = 0x00E047,
[KEY_UP] /* = USB 82 */ = 0x00E048,
[KEY_PAGEUP] /* = USB 75 */ = 0x00E049,
[KEY_LEFT] /* = USB 80 */ = 0x00E04B,
[KEY_RIGHT] /* = USB 79 */ = 0x00E04D,
[KEY_END] /* = USB 77 */ = 0x00E04F,
[KEY_DOWN] /* = USB 81 */ = 0x00E050,
[KEY_PAGEDOWN] /* = USB 78 */ = 0x00E051,
[KEY_INSERT] /* = USB 73 */ = 0x00E052,
[KEY_DELETE] /* = USB 76 */ = 0x00E053,
[KEY_KPEQUAL] /* = USB 103 */ = 0x000059,
[KEY_PAUSE] /* = USB 72 */ = 0x00E046,
[KEY_KPCOMMA] /* = USB 133 */ = 0x00007E,
[KEY_HANGEUL] /* = USB 144 */ = 0x0000F2,
[KEY_HANJA] /* = USB 145 */ = 0x0000F1,
[KEY_YEN] /* = USB 137 */ = 0x00007D,
[KEY_LEFTMETA] /* = USB 227 */ = 0x00E05B,
[KEY_RIGHTMETA] /* = USB 231 */ = 0x00E05C,
[KEY_COMPOSE] /* = USB 101 */ = 0x00E05D,
[KEY_F13] /* = USB 104 */ = 0x00005D,
[KEY_F14] /* = USB 105 */ = 0x00005E,
[KEY_F15] /* = USB 106 */ = 0x00005F,
[KEY_PRINT] /* = USB 70 */ = 0x00E037,
};

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/* /*
Looking Glass - KVM FrameRelay (KVMFR) Client Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -25,6 +25,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "interface/app.h" #include "interface/app.h"
#include "dynamic/displayservers.h" #include "dynamic/displayservers.h"
#include "dynamic/renderers.h" #include "dynamic/renderers.h"
#include "common/types.h"
#include "common/ivshmem.h" #include "common/ivshmem.h"
#include "spice/spice.h" #include "spice/spice.h"
@ -192,11 +194,6 @@ struct CursorInfo
uint32_t dpiScale; uint32_t dpiScale;
}; };
struct DoublePoint
{
double x, y;
};
struct CursorState struct CursorState
{ {
/* cursor is in grab mode */ /* cursor is in grab mode */
@ -253,4 +250,5 @@ struct CursorState
// forwards // forwards
extern struct AppState g_state; extern struct AppState g_state;
extern struct AppParams params; extern struct CursorState g_cursor;
extern struct AppParams g_params;

222
client/src/util.c Normal file
View File

@ -0,0 +1,222 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
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 "util.h"
#include "main.h"
#include "common/debug.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
bool util_fileGetContents(const char * filename, char ** buffer, size_t * length)
{
FILE * fh = fopen(filename, "r");
if (!fh)
{
DEBUG_ERROR("Failed to open the file: %s", filename);
return false;
}
if (fseek(fh, 0, SEEK_END) != 0)
{
DEBUG_ERROR("Failed to seek");
fclose(fh);
return false;
}
long fsize = ftell(fh);
if (fseek(fh, 0, SEEK_SET) != 0)
{
DEBUG_ERROR("Failed to seek");
fclose(fh);
return false;
}
*buffer = malloc(fsize + 1);
if (!*buffer)
{
DEBUG_ERROR("Failed to allocate buffer of %lu bytes", fsize + 1);
fclose(fh);
return false;
}
if (fread(*buffer, 1, fsize, fh) != fsize)
{
DEBUG_ERROR("Failed to read the entire file");
fclose(fh);
free(*buffer);
return false;
}
fclose(fh);
buffer[fsize] = 0;
*length = fsize;
return true;
}
void util_cursorToInt(double ex, double ey, int *x, int *y)
{
/* only smooth if enabled and not using raw mode */
if (g_params.mouseSmoothing && !(g_cursor.grab && g_params.rawMouse))
{
static struct DoublePoint last = { 0 };
/* only apply smoothing to small deltas */
if (fabs(ex - last.x) < 5.0 && fabs(ey - last.y) < 5.0)
{
ex = last.x = (last.x + ex) / 2.0;
ey = last.y = (last.y + ey) / 2.0;
}
else
{
last.x = ex;
last.y = ey;
}
}
/* convert to int accumulating the fractional error */
ex += g_cursor.acc.x;
ey += g_cursor.acc.y;
g_cursor.acc.x = modf(ex, &ex);
g_cursor.acc.y = modf(ey, &ey);
*x = (int)ex;
*y = (int)ey;
}
bool util_guestCurToLocal(struct DoublePoint *local)
{
if (!g_cursor.guest.valid || !g_state.posInfoValid)
return false;
const struct DoublePoint point =
{
.x = g_cursor.guest.x + g_cursor.guest.hx,
.y = g_cursor.guest.y + g_cursor.guest.hy
};
switch((g_state.rotate + g_params.winRotate) % LG_ROTATE_MAX)
{
case LG_ROTATE_0:
local->x = (point.x / g_cursor.scale.x) + g_state.dstRect.x;
local->y = (point.y / g_cursor.scale.y) + g_state.dstRect.y;;
break;
case LG_ROTATE_90:
local->x = (g_state.dstRect.x + g_state.dstRect.w) -
point.y / g_cursor.scale.y;
local->y = (point.x / g_cursor.scale.x) + g_state.dstRect.y;
break;
case LG_ROTATE_180:
local->x = (g_state.dstRect.x + g_state.dstRect.w) -
point.x / g_cursor.scale.x;
local->y = (g_state.dstRect.y + g_state.dstRect.h) -
point.y / g_cursor.scale.y;
break;
case LG_ROTATE_270:
local->x = (point.y / g_cursor.scale.y) + g_state.dstRect.x;
local->y = (g_state.dstRect.y + g_state.dstRect.h) -
point.x / g_cursor.scale.x;
break;
}
return true;
}
void util_localCurToGuest(struct DoublePoint *guest)
{
const struct DoublePoint point =
g_cursor.pos;
switch((g_state.rotate + g_params.winRotate) % LG_ROTATE_MAX)
{
case LG_ROTATE_0:
guest->x = (point.x - g_state.dstRect.x) * g_cursor.scale.x;
guest->y = (point.y - g_state.dstRect.y) * g_cursor.scale.y;
break;
case LG_ROTATE_90:
guest->x = (point.y - g_state.dstRect.y) * g_cursor.scale.y;
guest->y = (g_state.dstRect.w - point.x + g_state.dstRect.x)
* g_cursor.scale.x;
break;
case LG_ROTATE_180:
guest->x = (g_state.dstRect.w - point.x + g_state.dstRect.x)
* g_cursor.scale.x;
guest->y = (g_state.dstRect.h - point.y + g_state.dstRect.y)
* g_cursor.scale.y;
break;
case LG_ROTATE_270:
guest->x = (g_state.dstRect.h - point.y + g_state.dstRect.y)
* g_cursor.scale.y;
guest->y = (point.x - g_state.dstRect.x) * g_cursor.scale.x;
break;
default:
assert(!"unreachable");
}
}
void util_rotatePoint(struct DoublePoint *point)
{
double temp;
switch((g_state.rotate + g_params.winRotate) % LG_ROTATE_MAX)
{
case LG_ROTATE_0:
break;
case LG_ROTATE_90:
temp = point->x;
point->x = point->y;
point->y = -temp;
break;
case LG_ROTATE_180:
point->x = -point->x;
point->y = -point->y;
break;
case LG_ROTATE_270:
temp = point->x;
point->x = -point->y;
point->y = temp;
break;
}
}
bool util_isValidCursorLocation(int x, int y)
{
const int displays = SDL_GetNumVideoDisplays();
for(int i = 0; i < displays; ++i)
{
SDL_Rect r;
SDL_GetDisplayBounds(i, &r);
if ((x >= r.x && x < r.x + r.w) &&
(y >= r.y && y < r.y + r.h))
return true;
}
return false;
}

View File

@ -1,70 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
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 "utils.h"
#include "common/debug.h"
#include <stdlib.h>
#include <stdio.h>
bool file_get_contents(const char * filename, char ** buffer, size_t * length)
{
FILE * fh = fopen(filename, "r");
if (!fh)
{
DEBUG_ERROR("Failed to open the file: %s", filename);
return false;
}
if (fseek(fh, 0, SEEK_END) != 0)
{
DEBUG_ERROR("Failed to seek");
fclose(fh);
return false;
}
long fsize = ftell(fh);
if (fseek(fh, 0, SEEK_SET) != 0)
{
DEBUG_ERROR("Failed to seek");
fclose(fh);
return false;
}
*buffer = malloc(fsize + 1);
if (!*buffer)
{
DEBUG_ERROR("Failed to allocate buffer of %lu bytes", fsize + 1);
fclose(fh);
return false;
}
if (fread(*buffer, 1, fsize, fh) != fsize)
{
DEBUG_ERROR("Failed to read the entire file");
fclose(fh);
free(*buffer);
return false;
}
fclose(fh);
buffer[fsize] = 0;
*length = fsize;
return true;
}

View File

@ -1,6 +1,6 @@
/* /*
Looking Glass - KVM FrameRelay (KVMFR) Looking Glass - KVM FrameRelay (KVMFR)
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -16,9 +16,17 @@ 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef _H_LG_COMMON_KVMFR_
#define _H_LG_COMMON_KVMFR_
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include "types.h"
#define KVMFR_MAGIC "KVMFR---"
#define KVMFR_VERSION 8
#define LGMP_Q_POINTER 1 #define LGMP_Q_POINTER 1
#define LGMP_Q_FRAME 2 #define LGMP_Q_FRAME 2
@ -26,47 +34,15 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#define LGMP_Q_FRAME_LEN 2 #define LGMP_Q_FRAME_LEN 2
#define LGMP_Q_POINTER_LEN 20 #define LGMP_Q_POINTER_LEN 20
typedef enum FrameType
{
FRAME_TYPE_INVALID ,
FRAME_TYPE_BGRA , // BGRA interleaved: B,G,R,A 32bpp
FRAME_TYPE_RGBA , // RGBA interleaved: R,G,B,A 32bpp
FRAME_TYPE_RGBA10 , // RGBA interleaved: R,G,B,A 10,10,10,2 bpp
FRAME_TYPE_RGBA16F , // RGBA interleaved: R,G,B,A 16,16,16,16 bpp float
FRAME_TYPE_MAX , // sentinel value
}
FrameType;
typedef enum FrameRotation
{
FRAME_ROT_0,
FRAME_ROT_90,
FRAME_ROT_180,
FRAME_ROT_270
}
FrameRotation;
extern const char * FrameTypeStr[FRAME_TYPE_MAX];
enum enum
{ {
CURSOR_FLAG_POSITION = 0x1, CURSOR_FLAG_POSITION = 0x1,
CURSOR_FLAG_VISIBLE = 0x2, CURSOR_FLAG_VISIBLE = 0x2,
CURSOR_FLAG_SHAPE = 0x4 CURSOR_FLAG_SHAPE = 0x4
}; };
typedef uint32_t KVMFRCursorFlags; typedef uint32_t KVMFRCursorFlags;
typedef enum CursorType
{
CURSOR_TYPE_COLOR ,
CURSOR_TYPE_MONOCHROME ,
CURSOR_TYPE_MASKED_COLOR
}
CursorType;
#define KVMFR_MAGIC "KVMFR---"
#define KVMFR_VERSION 8
typedef struct KVMFR typedef struct KVMFR
{ {
char magic[8]; char magic[8];
@ -99,3 +75,5 @@ typedef struct KVMFRFrame
uint32_t mouseScalePercent; // movement scale factor of the mouse (relates to DPI of display, 100 = no scale) uint32_t mouseScalePercent; // movement scale factor of the mouse (relates to DPI of display, 100 = no scale)
} }
KVMFRFrame; KVMFRFrame;
#endif

View File

@ -1,6 +1,6 @@
/* /*
KVMGFX Client - A KVM Client for VGA Passthrough KVMGFX Client - A KVM Client for VGA Passthrough
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -17,7 +17,12 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef _H_LG_COMMON_CRASH_
#define _H_LG_COMMON_CRASH_
#include <stdbool.h> #include <stdbool.h>
bool installCrashHandler(const char * exe); bool installCrashHandler(const char * exe);
void cleanupCrashHandler(void); void cleanupCrashHandler(void);
#endif

View File

@ -17,6 +17,9 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef _H_LG_COMMON_DEBUG_
#define _H_LG_COMMON_DEBUG_
#ifndef __STDC_FORMAT_MACROS #ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS
#endif #endif
@ -82,3 +85,5 @@ void printBacktrace(void);
#else #else
#define DEBUG_PROTO(fmt, ...) do {} while(0) #define DEBUG_PROTO(fmt, ...) do {} while(0)
#endif #endif
#endif

View File

@ -17,9 +17,14 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef _H_LG_COMMON_DPI_
#define _H_LG_COMMON_DPI_
#include <windows.h> #include <windows.h>
// At 100% scaling, Windows reports 96 DPI. // At 100% scaling, Windows reports 96 DPI.
#define DPI_100_PERCENT 96 #define DPI_100_PERCENT 96
UINT monitor_dpi(HMONITOR hMonitor); UINT monitor_dpi(HMONITOR hMonitor);
#endif

View File

@ -1,6 +1,6 @@
/* /*
Looking Glass - KVM FrameRelay (KVMFR) Client Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2020 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -17,7 +17,8 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#pragma once #ifndef _H_LG_COMMON_EVENT_
#define _H_LG_COMMON_EVENT_
#include <stdbool.h> #include <stdbool.h>
#include <time.h> #include <time.h>
@ -40,3 +41,5 @@ LGEvent * lgWrapEvent(void * handle);
// Posix specific, not implmented/possible in windows // Posix specific, not implmented/possible in windows
bool lgWaitEventAbs(LGEvent * handle, struct timespec * ts); bool lgWaitEventAbs(LGEvent * handle, struct timespec * ts);
bool lgWaitEventNS (LGEvent * handle, unsigned int timeout); bool lgWaitEventNS (LGEvent * handle, unsigned int timeout);
#endif

View File

@ -1,6 +1,6 @@
/* /*
KVMGFX Client - A KVM Client for VGA Passthrough KVMGFX Client - A KVM Client for VGA Passthrough
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -17,7 +17,8 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#pragma once #ifndef _H_LG_COMMON_FRAMEBUFFER_
#define _H_LG_COMMON_FRAMEBUFFER_
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
@ -58,3 +59,5 @@ void framebuffer_prepare(FrameBuffer * frame);
* Write data from the src buffer into the KVMFRFrame * Write data from the src buffer into the KVMFRFrame
*/ */
bool framebuffer_write(FrameBuffer * frame, const void * src, size_t size); bool framebuffer_write(FrameBuffer * frame, const void * src, size_t size);
#endif

View File

@ -1,6 +1,6 @@
/* /*
Looking Glass - KVM FrameRelay (KVMFR) Client Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2020 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -17,7 +17,8 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#pragma once #ifndef _H_LG_COMMON_IVSHMEM_
#define _H_LG_COMMON_IVSHMEM_
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -41,3 +42,5 @@ void ivshmemFree(struct IVSHMEM * dev);
/* Linux KVMFR support only for now (VM->VM) */ /* Linux KVMFR support only for now (VM->VM) */
bool ivshmemHasDMA (struct IVSHMEM * dev); bool ivshmemHasDMA (struct IVSHMEM * dev);
int ivshmemGetDMABuf(struct IVSHMEM * dev, uint64_t offset, uint64_t size); int ivshmemGetDMABuf(struct IVSHMEM * dev, uint64_t offset, uint64_t size);
#endif

View File

@ -1,6 +1,6 @@
/* /*
Looking Glass - KVM FrameRelay (KVMFR) Client Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -16,7 +16,9 @@ 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#pragma once
#ifndef _H_LG_COMMON_LOCKING_
#define _H_LG_COMMON_LOCKING_
#include "time.h" #include "time.h"
@ -38,3 +40,5 @@ typedef atomic_flag LG_Lock;
LG_LOCK(lock) \ LG_LOCK(lock) \
x \ x \
LG_UNLOCK(lock) LG_UNLOCK(lock)
#endif

View File

@ -1,135 +0,0 @@
/*
KVMGFX Client - A KVM Client for VGA Passthrough
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
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
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <tmmintrin.h>
#include <immintrin.h>
#include "debug.h"
#if defined(NATIVE_MEMCPY)
#define memcpySSE memcpy
#elif defined(_MSC_VER)
extern "C" void * memcpySSE(void *dst, const void * src, size_t length);
#elif (defined(__GNUC__) || defined(__GNUG__)) && defined(__i386__)
inline static void * memcpySSE(void *dst, const void * src, size_t length)
{
if (length == 0 || dst == src)
return;
// copies under 1MB are faster with the inlined memcpy
// tell the dev to use that instead
if (length < 1048576)
{
static bool smallBufferWarn = false;
if (!smallBufferWarn)
{
DEBUG_WARN("Do not use memcpySSE for copies under 1MB in size!");
smallBufferWarn = true;
}
memcpy(dst, src, length);
return;
}
const void * end = dst + (length & ~0x7F);
const size_t off = (7 - ((length & 0x7F) >> 4)) * 9;
__asm__ __volatile__ (
"cmp %[dst],%[end] \n\t"
"je Remain_%= \n\t"
// perform SIMD block copy
"loop_%=: \n\t"
"movaps 0x00(%[src]),%%xmm0 \n\t"
"movaps 0x10(%[src]),%%xmm1 \n\t"
"movaps 0x20(%[src]),%%xmm2 \n\t"
"movaps 0x30(%[src]),%%xmm3 \n\t"
"movaps 0x40(%[src]),%%xmm4 \n\t"
"movaps 0x50(%[src]),%%xmm5 \n\t"
"movaps 0x60(%[src]),%%xmm6 \n\t"
"movaps 0x70(%[src]),%%xmm7 \n\t"
"movntdq %%xmm0 ,0x00(%[dst]) \n\t"
"movntdq %%xmm1 ,0x10(%[dst]) \n\t"
"movntdq %%xmm2 ,0x20(%[dst]) \n\t"
"movntdq %%xmm3 ,0x30(%[dst]) \n\t"
"movntdq %%xmm4 ,0x40(%[dst]) \n\t"
"movntdq %%xmm5 ,0x50(%[dst]) \n\t"
"movntdq %%xmm6 ,0x60(%[dst]) \n\t"
"movntdq %%xmm7 ,0x70(%[dst]) \n\t"
"add $0x80,%[dst] \n\t"
"add $0x80,%[src] \n\t"
"cmp %[dst],%[end] \n\t"
"jne loop_%= \n\t"
"Remain_%=: \n\t"
// copy any remaining 16 byte blocks
"call GetPC_%=\n\t"
"Offset_%=:\n\t"
"add $(BlockTable_%= - Offset_%=), %%eax \n\t"
"add %[off],%%eax \n\t"
"jmp *%%eax \n\t"
"GetPC_%=:\n\t"
"mov (%%esp), %%eax \n\t"
"ret \n\t"
"BlockTable_%=:\n\t"
"movaps 0x60(%[src]),%%xmm6 \n\t"
"movntdq %%xmm6 ,0x60(%[dst]) \n\t"
"movaps 0x50(%[src]),%%xmm5 \n\t"
"movntdq %%xmm5 ,0x50(%[dst]) \n\t"
"movaps 0x40(%[src]),%%xmm4 \n\t"
"movntdq %%xmm4 ,0x40(%[dst]) \n\t"
"movaps 0x30(%[src]),%%xmm3 \n\t"
"movntdq %%xmm3 ,0x30(%[dst]) \n\t"
"movaps 0x20(%[src]),%%xmm2 \n\t"
"movntdq %%xmm2 ,0x20(%[dst]) \n\t"
"movaps 0x10(%[src]),%%xmm1 \n\t"
"movntdq %%xmm1 ,0x10(%[dst]) \n\t"
"movaps 0x00(%[src]),%%xmm0 \n\t"
"movntdq %%xmm0 ,0x00(%[dst]) \n\t"
"nop\n\t"
"nop\n\t"
: [dst]"+r" (dst),
[src]"+r" (src)
: [off]"r" (off),
[end]"r" (end)
: "eax",
"xmm0",
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm5",
"xmm6",
"xmm7",
"memory"
);
//copy any remaining bytes
memcpy(dst, src, length & 0xF);
}
#else
#define memcpySSE memcpy
#endif

View File

@ -17,6 +17,9 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef _H_COMMON_OPTION_
#define _H_COMMON_OPTION_
#include <stdbool.h> #include <stdbool.h>
#include "common/stringlist.h" #include "common/stringlist.h"
@ -53,7 +56,7 @@ struct Option
char * (*toString )(struct Option * opt); char * (*toString )(struct Option * opt);
StringList (*getValues)(struct Option * opt); StringList (*getValues)(struct Option * opt);
void (*printHelp)(); void (*printHelp)(void);
// internal use only // internal use only
bool failed_set; bool failed_set;
@ -75,10 +78,12 @@ bool option_parse(int argc, char * argv[]);
bool option_load(const char * filename); bool option_load(const char * filename);
// called by the main application to validate the option values // called by the main application to validate the option values
bool option_validate(); bool option_validate(void);
// print out the options, help, and their current values // print out the options, help, and their current values
void option_print(); void option_print(void);
// final cleanup // final cleanup
void option_free(); void option_free(void);
#endif

View File

@ -17,6 +17,9 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef _H_LG_COMMON_STRINGLIST_
#define _H_LG_COMMON_STRINGLIST_
#include <stdbool.h> #include <stdbool.h>
typedef struct StringList * StringList; typedef struct StringList * StringList;
@ -26,3 +29,5 @@ void stringlist_free (StringList * sl);
int stringlist_push (StringList sl, char * str); int stringlist_push (StringList sl, char * str);
unsigned int stringlist_count(StringList sl); unsigned int stringlist_count(StringList sl);
char * stringlist_at (StringList sl, unsigned int index); char * stringlist_at (StringList sl, unsigned int index);
#endif

View File

@ -1,6 +1,6 @@
/* /*
KVMGFX Client - A KVM Client for VGA Passthrough KVMGFX Client - A KVM Client for VGA Passthrough
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -17,6 +17,11 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef _H_LG_COMMON_STRINGUTILS
#define _H_LG_COMMON_STRINGUTILS
// sprintf but with buffer allocation // sprintf but with buffer allocation
int alloc_sprintf(char ** str, const char * format, ...) int alloc_sprintf(char ** str, const char * format, ...)
__attribute__ ((format (printf, 2, 3))); __attribute__ ((format (printf, 2, 3)));
#endif

View File

@ -1,6 +1,6 @@
/* /*
KVMGFX Client - A KVM Client for VGA Passthrough KVMGFX Client - A KVM Client for VGA Passthrough
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -17,5 +17,10 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef _H_LG_COMMON_SYSUTILS
#define _H_LG_COMMON_SYSUTILS
// returns the page size // returns the page size
long sysinfo_getPageSize(); long sysinfo_getPageSize();
#endif

View File

@ -1,6 +1,6 @@
/* /*
Looking Glass - KVM FrameRelay (KVMFR) Client Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2020 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -17,12 +17,16 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#pragma once #ifndef _H_LG_COMMON_THREAD_
#define _H_LG_COMMON_THREAD_
#include <stdbool.h> #include <stdbool.h>
typedef struct LGThread LGThread; typedef struct LGThread LGThread;
typedef int (*LGThreadFunction)(void * opaque); typedef int (*LGThreadFunction)(void * opaque);
bool lgCreateThread(const char * name, LGThreadFunction function, void * opaque, LGThread ** handle); bool lgCreateThread(const char * name, LGThreadFunction function, void * opaque,
LGThread ** handle);
bool lgJoinThread (LGThread * handle, int * resultCode); bool lgJoinThread (LGThread * handle, int * resultCode);
#endif

View File

@ -0,0 +1,58 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
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 _LG_TYPES_H_
#define _LG_TYPES_H_
struct DoublePoint
{
double x, y;
};
typedef enum FrameType
{
FRAME_TYPE_INVALID ,
FRAME_TYPE_BGRA , // BGRA interleaved: B,G,R,A 32bpp
FRAME_TYPE_RGBA , // RGBA interleaved: R,G,B,A 32bpp
FRAME_TYPE_RGBA10 , // RGBA interleaved: R,G,B,A 10,10,10,2 bpp
FRAME_TYPE_RGBA16F , // RGBA interleaved: R,G,B,A 16,16,16,16 bpp float
FRAME_TYPE_MAX , // sentinel value
}
FrameType;
typedef enum FrameRotation
{
FRAME_ROT_0,
FRAME_ROT_90,
FRAME_ROT_180,
FRAME_ROT_270
}
FrameRotation;
extern const char * FrameTypeStr[FRAME_TYPE_MAX];
typedef enum CursorType
{
CURSOR_TYPE_COLOR ,
CURSOR_TYPE_MONOCHROME ,
CURSOR_TYPE_MASKED_COLOR
}
CursorType;
#endif

View File

@ -1 +1,25 @@
/*
KVMGFX Client - A KVM Client for VGA Passthrough
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
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_COMMON_VERSION_
#define _H_LG_COMMON_VERSION_
extern char * BUILD_VERSION; extern char * BUILD_VERSION;
#endif

View File

@ -1,6 +1,6 @@
/* /*
Looking Glass - KVM FrameRelay (KVMFR) Client Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2020 Geoffrey McRae <geoff@hostfission.com> Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -17,7 +17,8 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#pragma once #ifndef _H_LG_COMMON_WINDEBUG_
#define _H_LG_COMMON_WINDEBUG_
#include "debug.h" #include "debug.h"
#include <windows.h> #include <windows.h>
@ -36,3 +37,5 @@ bool IsWindows8();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif

View File

@ -1,237 +0,0 @@
.code
memcpySSE proc
; dst = rcx
; src = rdx
; len = r8
mov rax, rcx
test r8, r8
jz @Exit
cmp rcx, rdx
je @Exit
sub rsp, 8 + 2*16 + 4*8
movdqa oword ptr [rsp + 4*8 + 00 ], xmm6
movdqa oword ptr [rsp + 4*8 + 16 ], xmm7
; void * end = dst + (length & ~0x7F);
; end = r10
mov r9 , r8
and r9 , 0FFFFFFFFFFFFFF80h
jz @RemainingBlocks
mov r10, rcx
add r10, r9
@FullLoop:
movaps xmm0 , xmmword ptr [rdx + 000h]
movaps xmm1 , xmmword ptr [rdx + 010h]
movaps xmm2 , xmmword ptr [rdx + 020h]
movaps xmm3 , xmmword ptr [rdx + 030h]
movaps xmm4 , xmmword ptr [rdx + 040h]
movaps xmm5 , xmmword ptr [rdx + 050h]
movaps xmm6 , xmmword ptr [rdx + 060h]
movaps xmm7 , xmmword ptr [rdx + 070h]
movntdq xmmword ptr [rcx + 000h], xmm0
movntdq xmmword ptr [rcx + 010h], xmm1
movntdq xmmword ptr [rcx + 020h], xmm2
movntdq xmmword ptr [rcx + 030h], xmm3
movntdq xmmword ptr [rcx + 040h], xmm4
movntdq xmmword ptr [rcx + 050h], xmm5
movntdq xmmword ptr [rcx + 060h], xmm6
movntdq xmmword ptr [rcx + 070h], xmm7
add rdx, 080h
add rcx, 080h
cmp rcx, r10
jne @FullLoop
@RemainingBlocks:
; size_t rem = (length & 0x7F) >> 4);
; rem = r11
mov r11, r8
and r11, 07Fh
jz @RestoreExit
shr r11, 4
jz @FinalBytes
mov r10, 7
sub r10, r11
imul r10, 9
lea r9 , @FinalBlocks
add r9 , r10
jmp r9
@RestoreExit:
movdqa xmm6 , oword ptr [rsp + 4*8 + 00]
movdqa xmm7 , oword ptr [rsp + 4*8 + 16]
add rsp, 8 + 2*16 + 4*8
@Exit:
ret
@FinalBlocks:
movaps xmm6 , xmmword ptr [rdx + 060h]
movntdq xmmword ptr [rcx + 060h], xmm6
movaps xmm5 , xmmword ptr [rdx + 050h]
movntdq xmmword ptr [rcx + 050h], xmm5
movaps xmm4 , xmmword ptr [rdx + 040h]
movntdq xmmword ptr [rcx + 040h], xmm4
movaps xmm3 , xmmword ptr [rdx + 030h]
movntdq xmmword ptr [rcx + 030h], xmm3
movaps xmm2 , xmmword ptr [rdx + 020h]
movntdq xmmword ptr [rcx + 020h], xmm2
movaps xmm1 , xmmword ptr [rdx + 010h]
movntdq xmmword ptr [rcx + 010h], xmm1
movaps xmm0 , xmmword ptr [rdx + 000h]
movntdq xmmword ptr [rcx + 000h], xmm0
movdqa xmm6 , oword ptr [rsp + 4*8 + 00]
movdqa xmm7 , oword ptr [rsp + 4*8 + 16]
add rsp, 8 + 2*16 + 4*8
sfence
shl r11, 4
add rdx, r11
add rcx, r11
@FinalBytes:
and r8, 0Fh
jz @Exit
imul r8, 5
lea r9, @FinalBytesTable
add r9, r8
jmp r9
@FinalBytesTable:
jmp @Copy1
jmp @Copy2
jmp @Copy3
jmp @Copy4
jmp @Copy5
jmp @Copy6
jmp @Copy7
jmp @Copy8
jmp @Copy9
jmp @Copy10
jmp @Copy11
jmp @Copy12
jmp @Copy13
jmp @Copy14
jmp @Copy15
db 128 DUP(0CCh)
; fall through - 1 byte
@Copy1:
mov al, byte ptr [rdx]
mov byte ptr [rcx], al
ret
@Copy2:
mov r10w, word ptr [rdx]
mov word ptr [rcx], r10w
ret
@Copy3:
mov r10w, word ptr [rdx]
mov word ptr [rcx], r10w
mov r11b, byte ptr [rdx + 02h]
mov byte ptr [rcx + 02h], r11b
ret
@Copy4:
mov r9d, dword ptr [rdx]
mov dword ptr [rcx], r9d
ret
@Copy5:
mov r9d, dword ptr [rdx ]
mov r11b , byte ptr [rdx + 04h]
mov dword ptr [rcx ], r9d
mov byte ptr [rcx + 04h], r11b
ret
@Copy6:
mov r9d , dword ptr [rdx ]
mov r10w, word ptr [rdx + 04h]
mov dword ptr [rcx ], r9d
mov word ptr [rcx + 04h], r10w
ret
@Copy7:
mov r9d , dword ptr [rdx ]
mov r10w, word ptr [rdx + 04h]
mov r11b, byte ptr [rdx + 06h]
mov dword ptr [rcx ], r9d
mov word ptr [rcx + 04h], r10w
mov byte ptr [rcx + 06h], r11b
ret
@Copy8:
mov r8, qword ptr [rdx]
mov qword ptr [rcx], r8
ret
@Copy9:
mov r8 , qword ptr [rdx ]
mov r11b, byte ptr [rdx + 08h]
mov qword ptr [rcx ], r8
mov byte ptr [rcx + 08h], r11b
ret
@Copy10:
mov r8 , qword ptr [rdx ]
mov r10w, word ptr [rdx + 08h]
mov qword ptr [rcx ], r8
mov word ptr [rcx + 08h], r10w
ret
@Copy11:
mov r8 , qword ptr [rdx ]
mov r10w, word ptr [rdx + 08h]
mov r11b, byte ptr [rdx + 0Ah]
mov qword ptr [rcx ], r8
mov word ptr [rcx + 08h], r10w
mov byte ptr [rcx + 0Ah], r11b
ret
@Copy12:
mov r8 , qword ptr [rdx ]
mov r9d, dword ptr [rdx + 08h]
mov qword ptr [rcx ], r8
mov dword ptr [rcx + 08h], r9d
ret
@Copy13:
mov r8 , qword ptr [rdx ]
mov r9d , dword ptr [rdx + 08h]
mov r11b, byte ptr [rdx + 0Ch]
mov qword ptr [rcx ], r8
mov dword ptr [rcx + 08h], r9d
mov byte ptr [rcx + 0Ch], r11b
ret
@Copy14:
mov r8 , qword ptr [rdx ]
mov r9d , dword ptr [rdx + 08h]
mov r10w, word ptr [rdx + 0Ch]
mov qword ptr [rcx ], r8
mov dword ptr [rcx + 08h], r9d
mov word ptr [rcx + 0Ch], r10w
ret
; copy 15
@Copy15:
mov r8 , qword ptr [rdx + 00h]
mov r9d , dword ptr [rdx + 08h]
mov r10w, word ptr [rdx + 0Ch]
mov r11b, byte ptr [rdx + 0Eh]
mov qword ptr [rcx + 00h], r8
mov dword ptr [rcx + 08h], r9d
mov word ptr [rcx + 0Ch], r10w
mov byte ptr [rcx + 0Eh], r11b
ret
memcpySSE endp
end