added SDL2 client

This commit is contained in:
Armin Novak 2022-12-30 11:25:28 +01:00 committed by akallabeth
parent 82ba9ede9c
commit 070353bf90
24 changed files with 3425 additions and 16 deletions

View File

@ -28,6 +28,10 @@ if(FREERDP_VENDOR AND WITH_CLIENT)
endif()
endif()
if(WITH_CLIENT_SDL)
add_subdirectory(SDL)
endif()
if(WITH_X11)
add_subdirectory(X11)
endif()

50
client/SDL/CMakeLists.txt Normal file
View File

@ -0,0 +1,50 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP SDL Client
#
# Copyright 2022 Armin Novak <anovak@thincast.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(MODULE_NAME "sdl-client")
set(MODULE_PREFIX "FREERDP_CLIENT_X11_CONTROL")
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
message("xxxxxxxxxxxxx ${SDL2_INCLUDE_DIRS}")
set(SRCS
sdl_utils.c
sdl_utils.h
sdl_kbd.c
sdl_kbd.h
sdl_touch.c
sdl_touch.h
sdl_pointer.c
sdl_pointer.h
sdl_disp.c
sdl_disp.h
sdl_monitor.c
sdl_monitor.h
sdl_freerdp.h
sdl_freerdp.c
sdl_channels.h
sdl_channels.c)
set(LIBS
${SDL2_LIBRARIES}
freerdp-client)
add_executable(${MODULE_NAME} ${SRCS})
set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "sdl-freerdp")
target_link_libraries(${MODULE_NAME} PRIVATE ${LIBS})
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/SDL")
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client)

79
client/SDL/sdl_channels.c Normal file
View File

@ -0,0 +1,79 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Client Channels
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <winpr/assert.h>
#include <freerdp/client/rail.h>
#include <freerdp/client/cliprdr.h>
#include <freerdp/client/disp.h>
#include "sdl_channels.h"
#include "sdl_freerdp.h"
#include "sdl_disp.h"
void sdl_OnChannelConnectedEventHandler(void* context, const ChannelConnectedEventArgs* e)
{
sdlContext* sdl = (sdlContext*)context;
WINPR_ASSERT(sdl);
WINPR_ASSERT(e);
if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
{
}
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
{
CliprdrClientContext* clip = (CliprdrClientContext*)e->pInterface;
WINPR_ASSERT(clip);
clip->custom = context;
}
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
{
sdl_disp_init(sdl->disp, (DispClientContext*)e->pInterface);
}
else
freerdp_client_OnChannelConnectedEventHandler(context, e);
}
void sdl_OnChannelDisconnectedEventHandler(void* context, const ChannelDisconnectedEventArgs* e)
{
sdlContext* sdl = (sdlContext*)context;
WINPR_ASSERT(sdl);
WINPR_ASSERT(e);
// TODO: Set resizeable depending on disp channel and /dynamic-resolution
if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
{
}
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
{
CliprdrClientContext* clip = (CliprdrClientContext*)e->pInterface;
WINPR_ASSERT(clip);
clip->custom = NULL;
}
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
{
sdl_disp_uninit(sdl->disp, (DispClientContext*)e->pInterface);
}
else
freerdp_client_OnChannelDisconnectedEventHandler(context, e);
}

32
client/SDL/sdl_channels.h Normal file
View File

@ -0,0 +1,32 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Client Channels
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_SDL_CHANNELS_H
#define FREERDP_CLIENT_SDL_CHANNELS_H
#include <freerdp/freerdp.h>
#include <freerdp/client/channels.h>
int sdl_on_channel_connected(freerdp* instance, const char* name, void* pInterface);
int sdl_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface);
void sdl_OnChannelConnectedEventHandler(void* context, const ChannelConnectedEventArgs* e);
void sdl_OnChannelDisconnectedEventHandler(void* context, const ChannelDisconnectedEventArgs* e);
#endif /* FREERDP_CLIENT_SDL_CHANNELS_H */

536
client/SDL/sdl_disp.c Normal file
View File

@ -0,0 +1,536 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Display Control Channel
*
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/sysinfo.h>
#include <winpr/assert.h>
#include <freerdp/gdi/gdi.h>
#include <SDL.h>
#include "sdl_disp.h"
#include "sdl_kbd.h"
#include <freerdp/log.h>
#define TAG CLIENT_TAG("sdl.disp")
#define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */
struct s_sdlDispContext
{
sdlContext* sdl;
DispClientContext* disp;
int eventBase, errorBase;
int lastSentWidth, lastSentHeight;
UINT64 lastSentDate;
int targetWidth, targetHeight;
BOOL activated;
BOOL waitingResize;
BOOL fullscreen;
UINT16 lastSentDesktopOrientation;
UINT32 lastSentDesktopScaleFactor;
UINT32 lastSentDeviceScaleFactor;
};
static UINT sdl_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors,
size_t nmonitors);
static BOOL sdl_disp_settings_changed(sdlDispContext* sdlDisp)
{
rdpSettings* settings;
WINPR_ASSERT(sdlDisp);
WINPR_ASSERT(sdlDisp->sdl);
settings = sdlDisp->sdl->common.context.settings;
WINPR_ASSERT(settings);
if (sdlDisp->lastSentWidth != sdlDisp->targetWidth)
return TRUE;
if (sdlDisp->lastSentHeight != sdlDisp->targetHeight)
return TRUE;
if (sdlDisp->lastSentDesktopOrientation != settings->DesktopOrientation)
return TRUE;
if (sdlDisp->lastSentDesktopScaleFactor != settings->DesktopScaleFactor)
return TRUE;
if (sdlDisp->lastSentDeviceScaleFactor != settings->DeviceScaleFactor)
return TRUE;
/* TODFO
if (sdlDisp->fullscreen != sdlDisp->sdl->fullscreen)
return TRUE;
*/
return FALSE;
}
static BOOL sdl_update_last_sent(sdlDispContext* sdlDisp)
{
rdpSettings* settings;
WINPR_ASSERT(sdlDisp);
WINPR_ASSERT(sdlDisp->sdl);
settings = sdlDisp->sdl->common.context.settings;
WINPR_ASSERT(settings);
sdlDisp->lastSentWidth = sdlDisp->targetWidth;
sdlDisp->lastSentHeight = sdlDisp->targetHeight;
sdlDisp->lastSentDesktopOrientation = settings->DesktopOrientation;
sdlDisp->lastSentDesktopScaleFactor = settings->DesktopScaleFactor;
sdlDisp->lastSentDeviceScaleFactor = settings->DeviceScaleFactor;
// TODO sdlDisp->fullscreen = sdlDisp->sdl->fullscreen;
return TRUE;
}
static BOOL sdl_disp_sendResize(sdlDispContext* sdlDisp)
{
DISPLAY_CONTROL_MONITOR_LAYOUT layout;
sdlContext* sdl;
rdpSettings* settings;
if (!sdlDisp || !sdlDisp->sdl)
return FALSE;
sdl = sdlDisp->sdl;
settings = sdl->common.context.settings;
if (!settings)
return FALSE;
if (!sdlDisp->activated || !sdlDisp->disp)
return TRUE;
if (GetTickCount64() - sdlDisp->lastSentDate < RESIZE_MIN_DELAY)
return TRUE;
sdlDisp->lastSentDate = GetTickCount64();
if (!sdl_disp_settings_changed(sdlDisp))
return TRUE;
/* TODO: Multimonitor support for wayland
if (sdl->fullscreen && (settings->MonitorCount > 0))
{
if (sdl_disp_sendLayout(sdlDisp->disp, settings->MonitorDefArray,
settings->MonitorCount) != CHANNEL_RC_OK)
return FALSE;
}
else
*/
{
sdlDisp->waitingResize = TRUE;
layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
layout.Top = layout.Left = 0;
layout.Width = sdlDisp->targetWidth;
layout.Height = sdlDisp->targetHeight;
layout.Orientation = settings->DesktopOrientation;
layout.DesktopScaleFactor = settings->DesktopScaleFactor;
layout.DeviceScaleFactor = settings->DeviceScaleFactor;
layout.PhysicalWidth = sdlDisp->targetWidth;
layout.PhysicalHeight = sdlDisp->targetHeight;
if (IFCALLRESULT(CHANNEL_RC_OK, sdlDisp->disp->SendMonitorLayout, sdlDisp->disp, 1,
&layout) != CHANNEL_RC_OK)
return FALSE;
}
return sdl_update_last_sent(sdlDisp);
}
static BOOL sdl_disp_set_window_resizable(sdlDispContext* sdlDisp)
{
WINPR_ASSERT(sdlDisp);
update_resizeable(sdlDisp->sdl, TRUE);
return TRUE;
}
static BOOL sdl_disp_check_context(void* context, sdlContext** ppsdl, sdlDispContext** ppsdlDisp,
rdpSettings** ppSettings)
{
sdlContext* sdl;
if (!context)
return FALSE;
sdl = (sdlContext*)context;
if (!(sdl->disp))
return FALSE;
if (!sdl->common.context.settings)
return FALSE;
*ppsdl = sdl;
*ppsdlDisp = sdl->disp;
*ppSettings = sdl->common.context.settings;
return TRUE;
}
static void sdl_disp_OnActivated(void* context, const ActivatedEventArgs* e)
{
sdlContext* sdl;
sdlDispContext* sdlDisp;
rdpSettings* settings;
if (!sdl_disp_check_context(context, &sdl, &sdlDisp, &settings))
return;
sdlDisp->waitingResize = FALSE;
if (sdlDisp->activated && !settings->Fullscreen)
{
sdl_disp_set_window_resizable(sdlDisp);
if (e->firstActivation)
return;
sdl_disp_sendResize(sdlDisp);
}
}
static void sdl_disp_OnGraphicsReset(void* context, const GraphicsResetEventArgs* e)
{
sdlContext* sdl;
sdlDispContext* sdlDisp;
rdpSettings* settings;
WINPR_UNUSED(e);
if (!sdl_disp_check_context(context, &sdl, &sdlDisp, &settings))
return;
sdlDisp->waitingResize = FALSE;
if (sdlDisp->activated && !settings->Fullscreen)
{
sdl_disp_set_window_resizable(sdlDisp);
sdl_disp_sendResize(sdlDisp);
}
}
static void sdl_disp_OnTimer(void* context, const TimerEventArgs* e)
{
sdlContext* sdl;
sdlDispContext* sdlDisp;
rdpSettings* settings;
WINPR_UNUSED(e);
if (!sdl_disp_check_context(context, &sdl, &sdlDisp, &settings))
return;
if (!sdlDisp->activated || settings->Fullscreen)
return;
sdl_disp_sendResize(sdlDisp);
}
sdlDispContext* sdl_disp_new(sdlContext* sdl)
{
sdlDispContext* ret;
wPubSub* pubSub;
rdpSettings* settings;
if (!sdl || !sdl->common.context.settings || !sdl->common.context.pubSub)
return NULL;
settings = sdl->common.context.settings;
pubSub = sdl->common.context.pubSub;
ret = calloc(1, sizeof(sdlDispContext));
if (!ret)
return NULL;
ret->sdl = sdl;
ret->lastSentWidth = ret->targetWidth = settings->DesktopWidth;
ret->lastSentHeight = ret->targetHeight = settings->DesktopHeight;
PubSub_SubscribeActivated(pubSub, sdl_disp_OnActivated);
PubSub_SubscribeGraphicsReset(pubSub, sdl_disp_OnGraphicsReset);
PubSub_SubscribeTimer(pubSub, sdl_disp_OnTimer);
return ret;
}
void sdl_disp_free(sdlDispContext* disp)
{
if (!disp)
return;
if (disp->sdl)
{
wPubSub* pubSub = disp->sdl->common.context.pubSub;
PubSub_UnsubscribeActivated(pubSub, sdl_disp_OnActivated);
PubSub_UnsubscribeGraphicsReset(pubSub, sdl_disp_OnGraphicsReset);
PubSub_UnsubscribeTimer(pubSub, sdl_disp_OnTimer);
}
free(disp);
}
static UINT sdl_disp_sendLayout(DispClientContext* disp, const rdpMonitor* monitors,
size_t nmonitors)
{
UINT ret = CHANNEL_RC_OK;
DISPLAY_CONTROL_MONITOR_LAYOUT* layouts;
size_t i;
sdlDispContext* sdlDisp;
rdpSettings* settings;
WINPR_ASSERT(disp);
WINPR_ASSERT(monitors);
WINPR_ASSERT(nmonitors > 0);
sdlDisp = (sdlDispContext*)disp->custom;
WINPR_ASSERT(sdlDisp);
WINPR_ASSERT(sdlDisp->sdl);
settings = sdlDisp->sdl->common.context.settings;
WINPR_ASSERT(settings);
layouts = calloc(nmonitors, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
if (!layouts)
return CHANNEL_RC_NO_MEMORY;
for (i = 0; i < nmonitors; i++)
{
const rdpMonitor* monitor = &monitors[i];
DISPLAY_CONTROL_MONITOR_LAYOUT* layout = &layouts[i];
layout->Flags = (monitor->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
layout->Left = monitor->x;
layout->Top = monitor->y;
layout->Width = monitor->width;
layout->Height = monitor->height;
layout->Orientation = ORIENTATION_LANDSCAPE;
layout->PhysicalWidth = monitor->attributes.physicalWidth;
layout->PhysicalHeight = monitor->attributes.physicalHeight;
switch (monitor->attributes.orientation)
{
case 90:
layout->Orientation = ORIENTATION_PORTRAIT;
break;
case 180:
layout->Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
break;
case 270:
layout->Orientation = ORIENTATION_PORTRAIT_FLIPPED;
break;
case 0:
default:
/* MS-RDPEDISP - 2.2.2.2.1:
* Orientation (4 bytes): A 32-bit unsigned integer that specifies the
* orientation of the monitor in degrees. Valid values are 0, 90, 180
* or 270
*
* So we default to ORIENTATION_LANDSCAPE
*/
layout->Orientation = ORIENTATION_LANDSCAPE;
break;
}
layout->DesktopScaleFactor = settings->DesktopScaleFactor;
layout->DeviceScaleFactor = settings->DeviceScaleFactor;
}
ret = IFCALLRESULT(CHANNEL_RC_OK, disp->SendMonitorLayout, disp, nmonitors, layouts);
free(layouts);
return ret;
}
#if SDL_VERSION_ATLEAST(2, 0, 10)
BOOL sdl_disp_handle_display_event(sdlDispContext* disp, const SDL_DisplayEvent* ev)
{
WINPR_ASSERT(ev);
if (!disp)
return FALSE;
sdlContext* sdl = disp->sdl;
WINPR_ASSERT(sdl);
switch (ev->event)
{
#if SDL_VERSION_ATLEAST(2, 0, 14)
case SDL_DISPLAYEVENT_CONNECTED:
SDL_Log("A new display with id %d was connected", ev->display);
return TRUE;
case SDL_DISPLAYEVENT_DISCONNECTED:
SDL_Log("The display with id %d was disconnected", ev->display);
return TRUE;
#endif
case SDL_DISPLAYEVENT_ORIENTATION:
SDL_Log("The orientation of display with id %d was changed", ev->display);
return TRUE;
default:
return TRUE;
}
}
#endif
#if !SDL_VERSION_ATLEAST(2, 0, 16)
static BOOL sdl_grab(sdlContext* sdl, Uint32 windowID, SDL_bool enable)
{
SDL_Window* window = SDL_GetWindowFromID(windowID);
if (!window)
return FALSE;
sdl->grab_mouse = enable;
SDL_SetWindowGrab(window, enable);
return TRUE;
}
#endif
BOOL sdl_grab_keyboard(sdlContext* sdl, Uint32 windowID, SDL_bool enable)
{
SDL_Window* window = SDL_GetWindowFromID(windowID);
if (!window)
return FALSE;
#if SDL_VERSION_ATLEAST(2, 0, 16)
sdl->grab_kbd = enable;
SDL_SetWindowKeyboardGrab(window, enable);
return TRUE;
#else
WLog_WARN(TAG, "Keyboard grabbing not supported by SDL2 < 2.0.16");
return FALSE;
#endif
}
BOOL sdl_grab_mouse(sdlContext* sdl, Uint32 windowID, SDL_bool enable)
{
SDL_Window* window = SDL_GetWindowFromID(windowID);
if (!window)
return FALSE;
#if SDL_VERSION_ATLEAST(2, 0, 16)
sdl->grab_mouse = enable;
SDL_SetWindowMouseGrab(window, enable);
return TRUE;
#else
return sdl_grab(sdl, windowID, enable);
#endif
}
BOOL sdl_disp_handle_window_event(sdlDispContext* disp, const SDL_WindowEvent* ev)
{
WINPR_ASSERT(ev);
if (!disp)
return FALSE;
sdlContext* sdl = disp->sdl;
WINPR_ASSERT(sdl);
switch (ev->event)
{
case SDL_WINDOWEVENT_HIDDEN:
case SDL_WINDOWEVENT_MINIMIZED:
gdi_send_suppress_output(sdl->common.context.gdi, TRUE);
return TRUE;
case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_SHOWN:
case SDL_WINDOWEVENT_MAXIMIZED:
case SDL_WINDOWEVENT_RESTORED:
gdi_send_suppress_output(sdl->common.context.gdi, FALSE);
return TRUE;
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
disp->targetWidth = ev->data1;
disp->targetHeight = ev->data2;
return sdl_disp_sendResize(disp);
case SDL_WINDOWEVENT_LEAVE:
sdl_grab_keyboard(sdl, ev->windowID, SDL_FALSE);
return TRUE;
case SDL_WINDOWEVENT_ENTER:
sdl_grab_keyboard(sdl, ev->windowID, SDL_TRUE);
return sdl_keyboard_focus_in(&sdl->common.context);
case SDL_WINDOWEVENT_FOCUS_GAINED:
case SDL_WINDOWEVENT_TAKE_FOCUS:
return sdl_keyboard_focus_in(&sdl->common.context);
default:
return TRUE;
}
}
static UINT sdl_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
{
/* we're called only if dynamic resolution update is activated */
sdlDispContext* sdlDisp;
rdpSettings* settings;
WINPR_ASSERT(disp);
sdlDisp = (sdlDispContext*)disp->custom;
WINPR_ASSERT(sdlDisp);
WINPR_ASSERT(sdlDisp->sdl);
settings = sdlDisp->sdl->common.context.settings;
WINPR_ASSERT(settings);
WLog_DBG(TAG,
"DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32 " MaxMonitorAreaFactorA: %" PRIu32
" MaxMonitorAreaFactorB: %" PRIu32 "",
maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
sdlDisp->activated = TRUE;
if (settings->Fullscreen)
return CHANNEL_RC_OK;
WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable");
return sdl_disp_set_window_resizable(sdlDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
}
BOOL sdl_disp_init(sdlDispContext* sdlDisp, DispClientContext* disp)
{
rdpSettings* settings;
if (!sdlDisp || !sdlDisp->sdl || !disp)
return FALSE;
settings = sdlDisp->sdl->common.context.settings;
if (!settings)
return FALSE;
sdlDisp->disp = disp;
disp->custom = (void*)sdlDisp;
if (settings->DynamicResolutionUpdate)
{
disp->DisplayControlCaps = sdl_DisplayControlCaps;
}
update_resizeable(sdlDisp->sdl, TRUE);
return TRUE;
}
BOOL sdl_disp_uninit(sdlDispContext* sdlDisp, DispClientContext* disp)
{
if (!sdlDisp || !disp)
return FALSE;
sdlDisp->disp = NULL;
update_resizeable(sdlDisp->sdl, FALSE);
return TRUE;
}

42
client/SDL/sdl_disp.h Normal file
View File

@ -0,0 +1,42 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Display Control Channel
*
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_SDL_DISP_H
#define FREERDP_CLIENT_SDL_DISP_H
#include <freerdp/types.h>
#include <freerdp/client/disp.h>
#include "sdl_freerdp.h"
BOOL sdl_disp_init(sdlDispContext* xfDisp, DispClientContext* disp);
BOOL sdl_disp_uninit(sdlDispContext* xfDisp, DispClientContext* disp);
sdlDispContext* sdl_disp_new(sdlContext* sdl);
void sdl_disp_free(sdlDispContext* disp);
#if SDL_VERSION_ATLEAST(2, 0, 10)
BOOL sdl_disp_handle_display_event(sdlDispContext* disp, const SDL_DisplayEvent* ev);
#endif
BOOL sdl_disp_handle_window_event(sdlDispContext* disp, const SDL_WindowEvent* ev);
BOOL sdl_grab_keyboard(sdlContext* sdl, Uint32 windowID, SDL_bool enable);
BOOL sdl_grab_mouse(sdlContext* sdl, Uint32 windowID, SDL_bool enable);
#endif /* FREERDP_CLIENT_SDL_DISP_H */

1085
client/SDL/sdl_freerdp.c Normal file

File diff suppressed because it is too large Load Diff

65
client/SDL/sdl_freerdp.h Normal file
View File

@ -0,0 +1,65 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Client
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_SDL_H
#define FREERDP_CLIENT_SDL_H
#include <freerdp/freerdp.h>
#include <freerdp/client/rdpei.h>
#include <freerdp/client/rail.h>
#include <freerdp/client/cliprdr.h>
#include <freerdp/client/rdpgfx.h>
#include <SDL.h>
#include <SDL_video.h>
typedef struct s_sdlDispContext sdlDispContext;
typedef struct
{
SDL_Window* window;
int offset_x;
int offset_y;
} sdl_window_t;
typedef struct
{
rdpClientContext common;
/* SDL */
BOOL fullscreen;
BOOL resizeable;
BOOL grab_mouse;
BOOL grab_kbd;
BOOL highDpi;
size_t windowCount;
sdl_window_t windows[16];
HANDLE thread;
SDL_Surface* primary;
sdlDispContext* disp;
Uint32 sdl_pixel_format;
} sdlContext;
void update_resizeable(sdlContext* sdl, BOOL enable);
void update_fullscreen(sdlContext* sdl, BOOL enter);
#endif /* FREERDP_CLIENT_SDL_H */

463
client/SDL/sdl_kbd.c Normal file
View File

@ -0,0 +1,463 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP SDL keyboard helper
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sdl_kbd.h"
#include "sdl_disp.h"
#include "sdl_freerdp.h"
#include <freerdp/scancode.h>
#include <freerdp/log.h>
#define TAG CLIENT_TAG("SDL.kbd")
typedef struct
{
Uint32 sdl;
const char* sdl_name;
UINT32 rdp;
const char* rdp_name;
} scancode_entry_t;
#define STR(x) #x
#define ENTRY(x, y) \
{ \
x, STR(x), y, #y \
}
static const scancode_entry_t map[] = {
ENTRY(SDL_SCANCODE_UNKNOWN, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_A, RDP_SCANCODE_KEY_A),
ENTRY(SDL_SCANCODE_B, RDP_SCANCODE_KEY_B),
ENTRY(SDL_SCANCODE_C, RDP_SCANCODE_KEY_C),
ENTRY(SDL_SCANCODE_D, RDP_SCANCODE_KEY_D),
ENTRY(SDL_SCANCODE_E, RDP_SCANCODE_KEY_E),
ENTRY(SDL_SCANCODE_F, RDP_SCANCODE_KEY_F),
ENTRY(SDL_SCANCODE_G, RDP_SCANCODE_KEY_G),
ENTRY(SDL_SCANCODE_H, RDP_SCANCODE_KEY_H),
ENTRY(SDL_SCANCODE_I, RDP_SCANCODE_KEY_I),
ENTRY(SDL_SCANCODE_J, RDP_SCANCODE_KEY_J),
ENTRY(SDL_SCANCODE_K, RDP_SCANCODE_KEY_K),
ENTRY(SDL_SCANCODE_L, RDP_SCANCODE_KEY_L),
ENTRY(SDL_SCANCODE_M, RDP_SCANCODE_KEY_M),
ENTRY(SDL_SCANCODE_N, RDP_SCANCODE_KEY_N),
ENTRY(SDL_SCANCODE_O, RDP_SCANCODE_KEY_O),
ENTRY(SDL_SCANCODE_P, RDP_SCANCODE_KEY_P),
ENTRY(SDL_SCANCODE_Q, RDP_SCANCODE_KEY_Q),
ENTRY(SDL_SCANCODE_R, RDP_SCANCODE_KEY_R),
ENTRY(SDL_SCANCODE_S, RDP_SCANCODE_KEY_S),
ENTRY(SDL_SCANCODE_T, RDP_SCANCODE_KEY_T),
ENTRY(SDL_SCANCODE_U, RDP_SCANCODE_KEY_U),
ENTRY(SDL_SCANCODE_V, RDP_SCANCODE_KEY_V),
ENTRY(SDL_SCANCODE_W, RDP_SCANCODE_KEY_W),
ENTRY(SDL_SCANCODE_X, RDP_SCANCODE_KEY_X),
ENTRY(SDL_SCANCODE_Y, RDP_SCANCODE_KEY_Y),
ENTRY(SDL_SCANCODE_Z, RDP_SCANCODE_KEY_Z),
ENTRY(SDL_SCANCODE_1, RDP_SCANCODE_KEY_1),
ENTRY(SDL_SCANCODE_2, RDP_SCANCODE_KEY_2),
ENTRY(SDL_SCANCODE_3, RDP_SCANCODE_KEY_3),
ENTRY(SDL_SCANCODE_4, RDP_SCANCODE_KEY_4),
ENTRY(SDL_SCANCODE_5, RDP_SCANCODE_KEY_5),
ENTRY(SDL_SCANCODE_6, RDP_SCANCODE_KEY_6),
ENTRY(SDL_SCANCODE_7, RDP_SCANCODE_KEY_7),
ENTRY(SDL_SCANCODE_8, RDP_SCANCODE_KEY_8),
ENTRY(SDL_SCANCODE_9, RDP_SCANCODE_KEY_9),
ENTRY(SDL_SCANCODE_0, RDP_SCANCODE_KEY_0),
ENTRY(SDL_SCANCODE_RETURN, RDP_SCANCODE_RETURN),
ENTRY(SDL_SCANCODE_ESCAPE, RDP_SCANCODE_ESCAPE),
ENTRY(SDL_SCANCODE_BACKSPACE, RDP_SCANCODE_BACKSPACE),
ENTRY(SDL_SCANCODE_TAB, RDP_SCANCODE_TAB),
ENTRY(SDL_SCANCODE_SPACE, RDP_SCANCODE_SPACE),
ENTRY(SDL_SCANCODE_MINUS, RDP_SCANCODE_OEM_MINUS),
ENTRY(SDL_SCANCODE_CAPSLOCK, RDP_SCANCODE_CAPSLOCK),
ENTRY(SDL_SCANCODE_F1, RDP_SCANCODE_F1),
ENTRY(SDL_SCANCODE_F2, RDP_SCANCODE_F2),
ENTRY(SDL_SCANCODE_F3, RDP_SCANCODE_F3),
ENTRY(SDL_SCANCODE_F4, RDP_SCANCODE_F4),
ENTRY(SDL_SCANCODE_F5, RDP_SCANCODE_F5),
ENTRY(SDL_SCANCODE_F6, RDP_SCANCODE_F6),
ENTRY(SDL_SCANCODE_F7, RDP_SCANCODE_F7),
ENTRY(SDL_SCANCODE_F8, RDP_SCANCODE_F8),
ENTRY(SDL_SCANCODE_F9, RDP_SCANCODE_F9),
ENTRY(SDL_SCANCODE_F10, RDP_SCANCODE_F10),
ENTRY(SDL_SCANCODE_F11, RDP_SCANCODE_F11),
ENTRY(SDL_SCANCODE_F12, RDP_SCANCODE_F12),
ENTRY(SDL_SCANCODE_F13, RDP_SCANCODE_F13),
ENTRY(SDL_SCANCODE_F14, RDP_SCANCODE_F14),
ENTRY(SDL_SCANCODE_F15, RDP_SCANCODE_F15),
ENTRY(SDL_SCANCODE_F16, RDP_SCANCODE_F16),
ENTRY(SDL_SCANCODE_F17, RDP_SCANCODE_F17),
ENTRY(SDL_SCANCODE_F18, RDP_SCANCODE_F18),
ENTRY(SDL_SCANCODE_F19, RDP_SCANCODE_F19),
ENTRY(SDL_SCANCODE_F20, RDP_SCANCODE_F20),
ENTRY(SDL_SCANCODE_F21, RDP_SCANCODE_F21),
ENTRY(SDL_SCANCODE_F22, RDP_SCANCODE_F22),
ENTRY(SDL_SCANCODE_F23, RDP_SCANCODE_F23),
ENTRY(SDL_SCANCODE_F24, RDP_SCANCODE_F24),
ENTRY(SDL_SCANCODE_NUMLOCKCLEAR, RDP_SCANCODE_NUMLOCK),
ENTRY(SDL_SCANCODE_KP_DIVIDE, RDP_SCANCODE_DIVIDE),
ENTRY(SDL_SCANCODE_KP_MULTIPLY, RDP_SCANCODE_MULTIPLY),
ENTRY(SDL_SCANCODE_KP_MINUS, RDP_SCANCODE_OEM_MINUS),
ENTRY(SDL_SCANCODE_KP_PLUS, RDP_SCANCODE_OEM_PLUS),
ENTRY(SDL_SCANCODE_KP_ENTER, RDP_SCANCODE_RETURN_KP),
ENTRY(SDL_SCANCODE_KP_1, RDP_SCANCODE_NUMPAD1),
ENTRY(SDL_SCANCODE_KP_2, RDP_SCANCODE_NUMPAD2),
ENTRY(SDL_SCANCODE_KP_3, RDP_SCANCODE_NUMPAD3),
ENTRY(SDL_SCANCODE_KP_4, RDP_SCANCODE_NUMPAD4),
ENTRY(SDL_SCANCODE_KP_5, RDP_SCANCODE_NUMPAD5),
ENTRY(SDL_SCANCODE_KP_6, RDP_SCANCODE_NUMPAD6),
ENTRY(SDL_SCANCODE_KP_7, RDP_SCANCODE_NUMPAD7),
ENTRY(SDL_SCANCODE_KP_8, RDP_SCANCODE_NUMPAD8),
ENTRY(SDL_SCANCODE_KP_9, RDP_SCANCODE_NUMPAD9),
ENTRY(SDL_SCANCODE_KP_0, RDP_SCANCODE_NUMPAD0),
ENTRY(SDL_SCANCODE_KP_PERIOD, RDP_SCANCODE_OEM_PERIOD),
ENTRY(SDL_SCANCODE_LCTRL, RDP_SCANCODE_LCONTROL),
ENTRY(SDL_SCANCODE_LSHIFT, RDP_SCANCODE_LSHIFT),
ENTRY(SDL_SCANCODE_LALT, RDP_SCANCODE_LMENU),
ENTRY(SDL_SCANCODE_LGUI, RDP_SCANCODE_LWIN),
ENTRY(SDL_SCANCODE_RCTRL, RDP_SCANCODE_RCONTROL),
ENTRY(SDL_SCANCODE_RSHIFT, RDP_SCANCODE_RSHIFT),
ENTRY(SDL_SCANCODE_RALT, RDP_SCANCODE_RMENU),
ENTRY(SDL_SCANCODE_RGUI, RDP_SCANCODE_RWIN),
ENTRY(SDL_SCANCODE_MODE, RDP_SCANCODE_APPS),
ENTRY(SDL_SCANCODE_MUTE, RDP_SCANCODE_VOLUME_MUTE),
ENTRY(SDL_SCANCODE_VOLUMEUP, RDP_SCANCODE_VOLUME_UP),
ENTRY(SDL_SCANCODE_VOLUMEDOWN, RDP_SCANCODE_VOLUME_DOWN),
ENTRY(SDL_SCANCODE_GRAVE, RDP_SCANCODE_OEM_3),
ENTRY(SDL_SCANCODE_COMMA, RDP_SCANCODE_OEM_COMMA),
ENTRY(SDL_SCANCODE_PERIOD, RDP_SCANCODE_OEM_PERIOD),
ENTRY(SDL_SCANCODE_SLASH, RDP_SCANCODE_OEM_2),
ENTRY(SDL_SCANCODE_BACKSLASH, RDP_SCANCODE_OEM_5),
ENTRY(SDL_SCANCODE_SCROLLLOCK, RDP_SCANCODE_SCROLLLOCK),
ENTRY(SDL_SCANCODE_INSERT, RDP_SCANCODE_INSERT),
ENTRY(SDL_SCANCODE_PRINTSCREEN, RDP_SCANCODE_PRINTSCREEN),
ENTRY(SDL_SCANCODE_HOME, RDP_SCANCODE_HOME),
ENTRY(SDL_SCANCODE_DELETE, RDP_SCANCODE_DELETE),
ENTRY(SDL_SCANCODE_RIGHT, RDP_SCANCODE_RIGHT),
ENTRY(SDL_SCANCODE_LEFT, RDP_SCANCODE_LEFT),
ENTRY(SDL_SCANCODE_DOWN, RDP_SCANCODE_DOWN),
ENTRY(SDL_SCANCODE_UP, RDP_SCANCODE_UP),
ENTRY(SDL_SCANCODE_SEMICOLON, RDP_SCANCODE_OEM_1),
ENTRY(SDL_SCANCODE_PAUSE, RDP_SCANCODE_PAUSE),
ENTRY(SDL_SCANCODE_PAGEUP, RDP_SCANCODE_PRIOR),
ENTRY(SDL_SCANCODE_END, RDP_SCANCODE_END),
ENTRY(SDL_SCANCODE_PAGEDOWN, RDP_SCANCODE_NEXT),
ENTRY(SDL_SCANCODE_AUDIONEXT, RDP_SCANCODE_MEDIA_NEXT_TRACK),
ENTRY(SDL_SCANCODE_AUDIOPREV, RDP_SCANCODE_MEDIA_PREV_TRACK),
ENTRY(SDL_SCANCODE_AUDIOSTOP, RDP_SCANCODE_MEDIA_STOP),
ENTRY(SDL_SCANCODE_AUDIOPLAY, RDP_SCANCODE_MEDIA_PLAY_PAUSE),
ENTRY(SDL_SCANCODE_AUDIOMUTE, RDP_SCANCODE_VOLUME_MUTE),
ENTRY(SDL_SCANCODE_MEDIASELECT, RDP_SCANCODE_LAUNCH_MEDIA_SELECT),
ENTRY(SDL_SCANCODE_MAIL, RDP_SCANCODE_LAUNCH_MAIL),
ENTRY(SDL_SCANCODE_APP1, RDP_SCANCODE_LAUNCH_APP1),
ENTRY(SDL_SCANCODE_APP2, RDP_SCANCODE_LAUNCH_APP2),
ENTRY(SDL_SCANCODE_SYSREQ, RDP_SCANCODE_SYSREQ),
ENTRY(SDL_SCANCODE_WWW, RDP_SCANCODE_BROWSER_HOME),
ENTRY(SDL_SCANCODE_LEFTBRACKET, RDP_SCANCODE_OEM_4),
ENTRY(SDL_SCANCODE_RIGHTBRACKET, RDP_SCANCODE_OEM_6),
ENTRY(SDL_SCANCODE_APOSTROPHE, RDP_SCANCODE_OEM_7),
ENTRY(SDL_SCANCODE_NONUSBACKSLASH, RDP_SCANCODE_OEM_102),
ENTRY(SDL_SCANCODE_SLEEP, RDP_SCANCODE_SLEEP),
ENTRY(SDL_SCANCODE_EQUALS, VK_OEM_8),
ENTRY(SDL_SCANCODE_KP_COMMA, RDP_SCANCODE_DECIMAL),
ENTRY(SDL_SCANCODE_FIND, RDP_SCANCODE_BROWSER_SEARCH),
ENTRY(SDL_SCANCODE_RETURN2, RDP_SCANCODE_RETURN_KP),
ENTRY(SDL_SCANCODE_AC_SEARCH, RDP_SCANCODE_BROWSER_SEARCH),
ENTRY(SDL_SCANCODE_AC_HOME, RDP_SCANCODE_BROWSER_HOME),
ENTRY(SDL_SCANCODE_AC_BACK, RDP_SCANCODE_BROWSER_BACK),
ENTRY(SDL_SCANCODE_AC_FORWARD, RDP_SCANCODE_BROWSER_FORWARD),
ENTRY(SDL_SCANCODE_AC_STOP, RDP_SCANCODE_BROWSER_STOP),
#if 1 // TODO: unmapped
ENTRY(SDL_SCANCODE_NONUSHASH, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_APPLICATION, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_POWER, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_EQUALS, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_EXECUTE, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_HELP, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_MENU, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_SELECT, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_STOP, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_AGAIN, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_UNDO, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_CUT, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_COPY, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_PASTE, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_EQUALSAS400, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_INTERNATIONAL1, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_INTERNATIONAL2, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_INTERNATIONAL3, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_INTERNATIONAL4, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_INTERNATIONAL5, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_INTERNATIONAL6, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_INTERNATIONAL7, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_INTERNATIONAL8, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_INTERNATIONAL9, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_LANG1, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_LANG2, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_LANG3, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_LANG4, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_LANG5, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_LANG6, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_LANG7, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_LANG8, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_LANG9, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_ALTERASE, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_CANCEL, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_CLEAR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_PRIOR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_SEPARATOR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_OUT, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_OPER, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_CLEARAGAIN, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_CRSEL, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_EXSEL, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_00, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_000, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_THOUSANDSSEPARATOR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_DECIMALSEPARATOR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_CURRENCYUNIT, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_CURRENCYSUBUNIT, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_LEFTPAREN, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_RIGHTPAREN, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_LEFTBRACE, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_RIGHTBRACE, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_TAB, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_BACKSPACE, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_A, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_B, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_C, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_D, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_E, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_F, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_XOR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_POWER, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_PERCENT, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_LESS, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_GREATER, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_AMPERSAND, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_DBLAMPERSAND, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_VERTICALBAR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_DBLVERTICALBAR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_COLON, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_HASH, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_SPACE, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_AT, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_EXCLAM, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_MEMSTORE, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_MEMRECALL, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_MEMCLEAR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_MEMADD, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_MEMSUBTRACT, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_MEMMULTIPLY, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_MEMDIVIDE, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_PLUSMINUS, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_CLEAR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_CLEARENTRY, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_BINARY, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_OCTAL, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_DECIMAL, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KP_HEXADECIMAL, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_CALCULATOR, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_COMPUTER, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_AC_REFRESH, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_AC_BOOKMARKS, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_BRIGHTNESSDOWN, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_BRIGHTNESSUP, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_DISPLAYSWITCH, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KBDILLUMTOGGLE, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KBDILLUMDOWN, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_KBDILLUMUP, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_EJECT, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_AUDIOREWIND, RDP_SCANCODE_UNKNOWN),
ENTRY(SDL_SCANCODE_AUDIOFASTFORWARD, RDP_SCANCODE_UNKNOWN)
#endif
};
static UINT32 sdl_get_kbd_flags(void)
{
UINT32 flags = 0;
SDL_Keymod mod = SDL_GetModState();
if ((mod & KMOD_NUM) != 0)
flags |= KBD_SYNC_NUM_LOCK;
if ((mod & KMOD_CAPS) != 0)
flags |= KBD_SYNC_CAPS_LOCK;
#if SDL_VERSION_ATLEAST(2, 0, 18)
if ((mod & KMOD_SCROLL) != 0)
flags |= KBD_SYNC_SCROLL_LOCK;
#endif
// TODO: KBD_SYNC_KANA_LOCK
return flags;
}
BOOL sdl_sync_kbd_state(rdpContext* context)
{
const UINT32 syncFlags = sdl_get_kbd_flags();
WINPR_ASSERT(context);
return freerdp_input_send_synchronize_event(context->input, syncFlags);
}
BOOL sdl_keyboard_focus_in(rdpContext* context)
{
rdpInput* input;
UINT32 syncFlags;
WINPR_ASSERT(context);
input = context->input;
WINPR_ASSERT(input);
syncFlags = sdl_get_kbd_flags();
freerdp_input_send_focus_in_event(input, syncFlags);
/* finish with a mouse pointer position like mstsc.exe if required */
#if 0
if (xfc->remote_app)
return;
if (XQueryPointer(xfc->display, xfc->window->handle, &w, &w, &d, &d, &x, &y, &state))
{
if ((x >= 0) && (x < xfc->window->width) && (y >= 0) && (y < xfc->window->height))
{
xf_event_adjust_coordinates(xfc, &x, &y);
freerdp_client_send_button_event(&xfc->common, FALSE, PTR_FLAGS_MOVE, x, y);
}
}
#endif
return TRUE;
}
/* This function is called to update the keyboard indocator LED */
BOOL sdl_keyboard_set_indicators(rdpContext* context, UINT16 led_flags)
{
WINPR_UNUSED(context);
SDL_Keymod state = KMOD_NONE;
if ((led_flags & KBD_SYNC_NUM_LOCK) != 0)
state |= KMOD_NUM;
if ((led_flags & KBD_SYNC_CAPS_LOCK) != 0)
state |= KMOD_CAPS;
#if SDL_VERSION_ATLEAST(2, 0, 18)
if ((led_flags & KBD_SYNC_SCROLL_LOCK) != 0)
state |= KMOD_SCROLL;
#endif
// TODO: KBD_SYNC_KANA_LOCK
SDL_SetModState(state);
return TRUE;
}
/* This function is called to set the IME state */
BOOL sdl_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
UINT32 imeConvMode)
{
if (!context)
return FALSE;
WLog_WARN(TAG,
"KeyboardSetImeStatus(unitId=%04" PRIx16 ", imeState=%08" PRIx32
", imeConvMode=%08" PRIx32 ") ignored",
imeId, imeState, imeConvMode);
return TRUE;
}
static const char* sdl_scancode_name(Uint32 scancode)
{
for (size_t x = 0; x < ARRAYSIZE(map); x++)
{
const scancode_entry_t* cur = &map[x];
if (cur->sdl == scancode)
return cur->sdl_name;
}
return "SDL_SCANCODE_UNKNOWN";
}
static const char* sdl_rdp_scancode_name(UINT32 scancode)
{
for (size_t x = 0; x < ARRAYSIZE(map); x++)
{
const scancode_entry_t* cur = &map[x];
if (cur->rdp == scancode)
return cur->rdp_name;
}
return "RDP_SCANCODE_UNKNOWN";
}
static UINT32 sdl_scancode_to_rdp(Uint32 scancode)
{
UINT32 rdp = RDP_SCANCODE_UNKNOWN;
for (size_t x = 0; x < ARRAYSIZE(map); x++)
{
const scancode_entry_t* cur = &map[x];
if (cur->sdl == scancode)
{
rdp = cur->rdp;
break;
}
}
WLog_INFO(TAG, "got %s [%s] -> [%s]", SDL_GetScancodeName(scancode),
sdl_scancode_name(scancode), sdl_rdp_scancode_name(rdp));
return rdp;
}
BOOL sdl_handle_keyboard_event(sdlContext* sdl, const SDL_KeyboardEvent* ev)
{
WINPR_ASSERT(sdl);
WINPR_ASSERT(ev);
const UINT32 rdp_scancode = sdl_scancode_to_rdp(ev->keysym.scancode);
const SDL_Keymod mods = SDL_GetModState();
const SDL_Keymod mask = KMOD_RSHIFT;
if ((mods & mask) == mask)
{
switch (ev->keysym.scancode)
{
case SDL_SCANCODE_RETURN:
if (ev->type == SDL_KEYDOWN)
{
update_fullscreen(sdl, !sdl->fullscreen);
}
return TRUE;
case SDL_SCANCODE_R:
if (ev->type == SDL_KEYDOWN)
{
update_resizeable(sdl, !sdl->resizeable);
}
return TRUE;
case SDL_SCANCODE_G:
if (ev->type == SDL_KEYDOWN)
{
sdl_grab_keyboard(sdl, ev->windowID, !sdl->grab_kbd);
}
return TRUE;
default:
break;
}
}
return freerdp_input_send_keyboard_event_ex(sdl->common.context.input, ev->type == SDL_KEYDOWN,
ev->repeat, rdp_scancode);
}

38
client/SDL/sdl_kbd.h Normal file
View File

@ -0,0 +1,38 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Client keyboard helper
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_SDL_KBD_H
#define FREERDP_CLIENT_SDL_KBD_H
#include <winpr/wtypes.h>
#include <freerdp/freerdp.h>
#include <SDL.h>
#include "sdl_freerdp.h"
BOOL sdl_sync_kbd_state(rdpContext* context);
BOOL sdl_keyboard_focus_in(rdpContext* context);
BOOL sdl_keyboard_set_indicators(rdpContext* context, UINT16 led_flags);
BOOL sdl_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
UINT32 imeConvMode);
BOOL sdl_handle_keyboard_event(sdlContext* sdl, const SDL_KeyboardEvent* ev);
#endif /* FREERDP_CLIENT_SDL_KBD_H */

312
client/SDL/sdl_monitor.c Normal file
View File

@ -0,0 +1,312 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* X11 Monitor Handling
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2017 David Fort <contact@hardening-consulting.com>
* Copyright 2018 Kai Harms <kharms@rangee.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <SDL.h>
#include <winpr/assert.h>
#include <winpr/crt.h>
#include <freerdp/log.h>
#define TAG CLIENT_TAG("sdl")
#include "sdl_monitor.h"
typedef struct
{
RECTANGLE_16 area;
RECTANGLE_16 workarea;
BOOL primary;
} MONITOR_INFO;
typedef struct
{
int nmonitors;
RECTANGLE_16 area;
RECTANGLE_16 workarea;
MONITOR_INFO* monitors;
} VIRTUAL_SCREEN;
/* See MSDN Section on Multiple Display Monitors: http://msdn.microsoft.com/en-us/library/dd145071
*/
int sdl_list_monitors(sdlContext* sdl)
{
SDL_Init(SDL_INIT_VIDEO);
const int nmonitors = SDL_GetNumVideoDisplays();
for (int i = 0; i < nmonitors; i++)
{
SDL_Rect rect = { 0 };
const int brc = SDL_GetDisplayBounds(i, &rect);
const char* name = SDL_GetDisplayName(i);
if (brc != 0)
continue;
printf(" %s [%d] [%s] %dx%d\t+%d+%d\n", (i == 0) ? "*" : " ", i, name, rect.w, rect.h,
rect.x, rect.y);
}
SDL_Quit();
return 0;
}
static BOOL sdl_is_monitor_id_active(sdlContext* sdl, UINT32 id)
{
UINT32 index;
const rdpSettings* settings;
WINPR_ASSERT(sdl);
settings = sdl->common.context.settings;
WINPR_ASSERT(settings);
if (!settings->NumMonitorIds)
return TRUE;
for (index = 0; index < settings->NumMonitorIds; index++)
{
if (settings->MonitorIds[index] == id)
return TRUE;
}
return FALSE;
}
static BOOL sdl_apply_max_size(sdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
{
WINPR_ASSERT(sdl);
WINPR_ASSERT(pMaxWidth);
WINPR_ASSERT(pMaxHeight);
rdpSettings* settings = sdl->common.context.settings;
WINPR_ASSERT(settings);
*pMaxWidth = 0;
*pMaxHeight = 0;
for (size_t x = 0; x < settings->MonitorCount; x++)
{
const rdpMonitor* monitor = &settings->MonitorDefArray[x];
if (settings->Fullscreen)
{
*pMaxWidth = monitor->width;
*pMaxHeight = monitor->height;
}
else if (settings->Workarea)
{
SDL_Rect rect = { 0 };
SDL_GetDisplayUsableBounds(monitor->orig_screen, &rect);
*pMaxWidth = rect.w;
*pMaxHeight = rect.h;
}
else if (settings->PercentScreen)
{
SDL_Rect rect = { 0 };
SDL_GetDisplayUsableBounds(monitor->orig_screen, &rect);
*pMaxWidth = rect.w;
*pMaxHeight = rect.h;
if (settings->PercentScreenUseWidth)
*pMaxWidth = (rect.w * settings->PercentScreen) / 100;
if (settings->PercentScreenUseHeight)
*pMaxHeight = (rect.h * settings->PercentScreen) / 100;
}
else if (settings->DesktopWidth && settings->DesktopHeight)
{
*pMaxWidth = settings->DesktopWidth;
*pMaxHeight = settings->DesktopHeight;
}
}
return TRUE;
}
#if SDL_VERSION_ATLEAST(2, 0, 10)
static UINT32 sdl_orientaion_to_rdp(SDL_DisplayOrientation orientation)
{
switch (orientation)
{
case SDL_ORIENTATION_LANDSCAPE:
return ORIENTATION_LANDSCAPE;
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
return ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED;
case SDL_ORIENTATION_PORTRAIT_FLIPPED:
return ORIENTATION_PORTRAIT_FLIPPED;
case SDL_ORIENTATION_PORTRAIT:
default:
return ORIENTATION_PORTRAIT;
}
}
#endif
static BOOL sdl_apply_display_properties(sdlContext* sdl)
{
WINPR_ASSERT(sdl);
rdpSettings* settings = sdl->common.context.settings;
WINPR_ASSERT(settings);
const UINT32 numIds = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds);
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorDefArray, NULL, numIds))
return FALSE;
if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount, numIds))
return FALSE;
for (UINT32 x = 0; x < numIds; x++)
{
const UINT32* id = freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, x);
WINPR_ASSERT(id);
float hdpi;
float vdpi;
SDL_Rect rect = { 0 };
SDL_GetDisplayBounds(*id, &rect);
SDL_GetDisplayDPI(*id, NULL, &hdpi, &vdpi);
if (sdl->highDpi)
{
// HighDPI is problematic with SDL: We can only get native resolution by creating a
// window. Work around this by checking the supported resolutions (and keep maximum)
// Also scale the DPI
const SDL_Rect scaleRect = rect;
for (int i = 0; i < SDL_GetNumDisplayModes(*id); i++)
{
SDL_DisplayMode mode = { 0 };
SDL_GetDisplayMode(x, i, &mode);
if (mode.w > rect.w)
{
rect.w = mode.w;
rect.h = mode.h;
}
else if (mode.w == rect.w)
{
if (mode.h > rect.h)
{
rect.w = mode.w;
rect.h = mode.h;
}
}
}
const float dw = rect.w / scaleRect.w;
const float dh = rect.h / scaleRect.h;
hdpi /= dw;
vdpi /= dh;
}
#if SDL_VERSION_ATLEAST(2, 0, 10)
const SDL_DisplayOrientation orientation = SDL_GetDisplayOrientation(*id);
const UINT32 rdp_orientation = sdl_orientaion_to_rdp(orientation);
#else
const UINT32 rdp_orientation = ORIENTATION_LANDSCAPE;
#endif
rdpMonitor* monitor =
freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x);
WINPR_ASSERT(monitor);
monitor->orig_screen = x;
monitor->x = rect.x;
monitor->y = rect.y;
monitor->width = rect.w;
monitor->height = rect.h;
monitor->is_primary = (rect.x == 0) && (rect.y == 0);
monitor->attributes.desktopScaleFactor = 100;
monitor->attributes.deviceScaleFactor = 100;
monitor->attributes.orientation = rdp_orientation;
monitor->attributes.physicalWidth = rect.w / hdpi;
monitor->attributes.physicalHeight = rect.h / vdpi;
}
return TRUE;
}
static BOOL sdl_detect_single_window(sdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
{
WINPR_ASSERT(sdl);
WINPR_ASSERT(pMaxWidth);
WINPR_ASSERT(pMaxHeight);
rdpSettings* settings = sdl->common.context.settings;
WINPR_ASSERT(settings);
if ((!settings->UseMultimon && !settings->SpanMonitors) ||
(settings->Workarea && !settings->RemoteApplicationMode))
{
/* If no monitors were specified on the command-line then set the current monitor as active
*/
if (!settings->NumMonitorIds)
{
const size_t id =
(sdl->windowCount > 0) ? SDL_GetWindowDisplayIndex(sdl->windows[0].window) : 0;
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, &id, 1))
return FALSE;
}
else
{
/* Always sets number of monitors from command-line to just 1.
* If the monitor is invalid then we will default back to current monitor
* later as a fallback. So, there is no need to validate command-line entry here.
*/
settings->NumMonitorIds = 1;
}
// TODO: Fill monitor struct
if (!sdl_apply_display_properties(sdl))
return FALSE;
return sdl_apply_max_size(sdl, pMaxWidth, pMaxHeight);
}
return TRUE;
}
BOOL sdl_detect_monitors(sdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
{
WINPR_ASSERT(sdl);
WINPR_ASSERT(pMaxWidth);
WINPR_ASSERT(pMaxHeight);
rdpSettings* settings = sdl->common.context.settings;
WINPR_ASSERT(settings);
const int numDisplays = SDL_GetNumVideoDisplays();
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, NULL, numDisplays))
return FALSE;
for (size_t x = 0; x < numDisplays; x++)
{
if (!freerdp_settings_set_pointer_array(settings, FreeRDP_MonitorIds, x, &x))
return FALSE;
}
if (!sdl_apply_display_properties(sdl))
return FALSE;
return sdl_detect_single_window(sdl, pMaxWidth, pMaxHeight);
}

31
client/SDL/sdl_monitor.h Normal file
View File

@ -0,0 +1,31 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Monitor Handling
*
* Copyright 2023 Armin Novak <anovak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_SDL_MONITOR_H
#define FREERDP_CLIENT_SDL_MONITOR_H
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
#include "sdl_freerdp.h"
int sdl_list_monitors(sdlContext* sdl);
BOOL sdl_detect_monitors(sdlContext* sdl, UINT32* pWidth, UINT32* pHeight);
#endif /* FREERDP_CLIENT_SDL_MONITOR_H */

198
client/SDL/sdl_pointer.c Normal file
View File

@ -0,0 +1,198 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Wayland Mouse Pointer
*
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <freerdp/gdi/gdi.h>
#include "sdl_pointer.h"
#include "sdl_freerdp.h"
#include "sdl_touch.h"
#include <SDL_mouse.h>
#define TAG CLIENT_TAG("SDL.pointer")
typedef struct
{
rdpPointer pointer;
SDL_Cursor* cursor;
SDL_Surface* image;
size_t size;
void* data;
} sdlPointer;
static BOOL sdl_Pointer_New(rdpContext* context, rdpPointer* pointer)
{
sdlPointer* ptr = (sdlPointer*)pointer;
WINPR_ASSERT(context);
if (!ptr)
return FALSE;
rdpGdi* gdi = context->gdi;
WINPR_ASSERT(gdi);
ptr->size = pointer->width * pointer->height * 4ULL;
ptr->data = winpr_aligned_malloc(ptr->size, 16);
if (!ptr->data)
return FALSE;
if (!freerdp_image_copy_from_pointer_data(
ptr->data, gdi->dstFormat, 0, 0, 0, pointer->width, pointer->height,
pointer->xorMaskData, pointer->lengthXorMask, pointer->andMaskData,
pointer->lengthAndMask, pointer->xorBpp, &context->gdi->palette))
{
winpr_aligned_free(ptr->data);
return FALSE;
}
return TRUE;
}
static void sdl_Pointer_Clear(sdlPointer* ptr)
{
WINPR_ASSERT(ptr);
SDL_FreeCursor(ptr->cursor);
SDL_FreeSurface(ptr->image);
ptr->cursor = NULL;
ptr->image = NULL;
}
static void sdl_Pointer_Free(rdpContext* context, rdpPointer* pointer)
{
sdlPointer* ptr = (sdlPointer*)pointer;
WINPR_UNUSED(context);
if (ptr)
{
sdl_Pointer_Clear(ptr);
winpr_aligned_free(ptr->data);
ptr->data = NULL;
}
}
static BOOL sdl_Pointer_SetDefault(rdpContext* context)
{
WINPR_UNUSED(context);
SDL_Cursor* def = SDL_GetDefaultCursor();
SDL_SetCursor(def);
SDL_ShowCursor(SDL_ENABLE);
return TRUE;
}
static BOOL sdl_Pointer_Set(rdpContext* context, rdpPointer* pointer)
{
sdlContext* sdl = (sdlContext*)context;
sdlPointer* ptr = (sdlPointer*)pointer;
INT32 w, h, x, y, sw, sh;
WINPR_ASSERT(sdl);
WINPR_ASSERT(ptr);
rdpGdi* gdi = context->gdi;
WINPR_ASSERT(gdi);
x = (INT32)pointer->xPos;
y = (INT32)pointer->yPos;
sw = w = (INT32)pointer->width;
sh = h = (INT32)pointer->height;
SDL_Window* window = SDL_GetMouseFocus();
if (!window)
return sdl_Pointer_SetDefault(context);
const Uint32 id = SDL_GetWindowID(window);
if (!sdl_scale_coordinates(sdl, id, &x, &y, FALSE, FALSE) ||
!sdl_scale_coordinates(sdl, id, &sw, &sh, FALSE, FALSE))
return FALSE;
sdl_Pointer_Clear(ptr);
const DWORD bpp = FreeRDPGetBitsPerPixel(gdi->dstFormat);
ptr->image = SDL_CreateRGBSurfaceWithFormat(0, sw, sh, (int)bpp, sdl->sdl_pixel_format);
if (!ptr->image)
return FALSE;
SDL_LockSurface(ptr->image);
const BOOL rc =
freerdp_image_scale(ptr->image->pixels, gdi->dstFormat, ptr->image->pitch, 0, 0,
ptr->image->w, ptr->image->h, ptr->data, gdi->dstFormat, 0, 0, 0, w, h);
SDL_UnlockSurface(ptr->image);
if (!rc)
return FALSE;
ptr->cursor = SDL_CreateColorCursor(ptr->image, x, y);
if (!ptr->cursor)
return FALSE;
SDL_SetCursor(ptr->cursor);
SDL_ShowCursor(SDL_ENABLE);
return TRUE;
}
static BOOL sdl_Pointer_SetNull(rdpContext* context)
{
WINPR_UNUSED(context);
SDL_ShowCursor(SDL_DISABLE);
return TRUE;
}
static BOOL sdl_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
{
sdlContext* sdl = (sdlContext*)context;
WINPR_ASSERT(sdl);
SDL_Window* window = SDL_GetMouseFocus();
if (!window)
return TRUE;
const Uint32 id = SDL_GetWindowID(window);
INT32 sx = (INT32)x;
INT32 sy = (INT32)y;
if (!sdl_scale_coordinates(sdl, id, &sx, &sy, FALSE, FALSE))
return FALSE;
SDL_WarpMouseInWindow(window, sx, sy);
return TRUE;
}
BOOL sdl_register_pointer(rdpGraphics* graphics)
{
rdpPointer* pointer = NULL;
if (!(pointer = (rdpPointer*)calloc(1, sizeof(rdpPointer))))
return FALSE;
pointer->size = sizeof(sdlPointer);
pointer->New = sdl_Pointer_New;
pointer->Free = sdl_Pointer_Free;
pointer->Set = sdl_Pointer_Set;
pointer->SetNull = sdl_Pointer_SetNull;
pointer->SetDefault = sdl_Pointer_SetDefault;
pointer->SetPosition = sdl_Pointer_SetPosition;
graphics_register_pointer(graphics, pointer);
free(pointer);
return TRUE;
}

27
client/SDL/sdl_pointer.h Normal file
View File

@ -0,0 +1,27 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Mouse Pointer
*
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_SDL_POINTER_H
#define FREERDP_CLIENT_SDL_POINTER_H
#include <freerdp/graphics.h>
BOOL sdl_register_pointer(rdpGraphics* graphics);
#endif /* FREERDP_CLIENT_SDL_POINTER_H */

280
client/SDL/sdl_touch.c Normal file
View File

@ -0,0 +1,280 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP SDL touch/mouse input
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include "sdl_touch.h"
#include "sdl_freerdp.h"
#include <winpr/wtypes.h>
#include <winpr/assert.h>
#include <freerdp/freerdp.h>
#include <freerdp/gdi/gdi.h>
#include <SDL.h>
#define TAG CLIENT_TAG("SDL.touch")
BOOL sdl_scale_coordinates(sdlContext* sdl, Uint32 windowId, INT32* px, INT32* py,
BOOL fromLocalToRDP, BOOL applyOffset)
{
rdpGdi* gdi;
double sx = 1.0;
double sy = 1.0;
if (!sdl || !px || !py || !sdl->common.context.gdi)
return FALSE;
WINPR_ASSERT(sdl->common.context.gdi);
WINPR_ASSERT(sdl->common.context.settings);
gdi = sdl->common.context.gdi;
// TODO: Make this multimonitor ready!
// TODO: Need to find the primary monitor, get the scale
// TODO: Need to find the destination monitor, get the scale
// TODO: All intermediate monitors, get the scale
int offset_x = 0;
int offset_y = 0;
for (size_t x = 0; x < sdl->windowCount; x++)
{
int w, h;
const sdl_window_t* window = &sdl->windows[x];
const Uint32 id = SDL_GetWindowID(window->window);
if (id != windowId)
{
continue;
}
SDL_GetWindowSize(window->window, &w, &h);
sx = w / (double)gdi->width;
sy = h / (double)gdi->height;
offset_x = window->offset_x;
offset_y = window->offset_y;
break;
}
if (sdl->common.context.settings->SmartSizing)
{
if (!fromLocalToRDP)
{
*px = (INT32)(*px * sx);
*py = (INT32)(*py * sy);
}
else
{
*px = (INT32)(*px / sx);
*py = (INT32)(*py / sy);
}
}
else if (applyOffset)
{
*px -= offset_x;
*py -= offset_y;
}
return TRUE;
}
static BOOL sdl_get_touch_scaled(sdlContext* sdl, const SDL_TouchFingerEvent* ev, INT32* px,
INT32* py, BOOL local)
{
Uint32 windowID;
WINPR_ASSERT(sdl);
WINPR_ASSERT(ev);
WINPR_ASSERT(px);
WINPR_ASSERT(py);
#if SDL_VERSION_ATLEAST(2, 0, 12)
SDL_Window* window = SDL_GetWindowFromID(ev->windowID);
#else
SDL_Window* window = SDL_GetMouseFocus();
#endif
if (!window)
return FALSE;
windowID = SDL_GetWindowID(window);
SDL_Surface* surface = SDL_GetWindowSurface(window);
if (!surface)
return FALSE;
// TODO: Add the offset of the surface in the global coordinates
*px = (INT32)(ev->x * (float)surface->w);
*py = (INT32)(ev->y * (float)surface->h);
return sdl_scale_coordinates(sdl, windowID, px, py, local, TRUE);
}
static BOOL send_mouse_wheel(sdlContext* sdl, UINT16 flags, INT32 avalue)
{
WINPR_ASSERT(sdl);
if (avalue < 0)
{
flags |= PTR_FLAGS_WHEEL_NEGATIVE;
avalue = -avalue;
}
while (avalue > 0)
{
const UINT16 cval = (avalue > 0xFF) ? 0xFF : (UINT16)avalue;
UINT16 cflags = flags | cval;
/* Convert negative values to 9bit twos complement */
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
cflags = (flags & 0xFF00) | (0x100 - cval);
if (!freerdp_client_send_wheel_event(&sdl->common, cflags))
return FALSE;
avalue -= cval;
}
return TRUE;
}
static UINT32 sdl_scale_pressure(const float pressure)
{
const float val = pressure * 0x400; /* [MS-RDPEI] 2.2.3.3.1.1 RDPINPUT_TOUCH_CONTACT */
if (val < 0.0f)
return 0;
if (val > 0x400)
return 0x400;
return (UINT32)val;
}
BOOL sdl_handle_touch_up(sdlContext* sdl, const SDL_TouchFingerEvent* ev)
{
WINPR_ASSERT(sdl);
WINPR_ASSERT(ev);
INT32 x, y;
if (!sdl_get_touch_scaled(sdl, ev, &x, &y, TRUE))
return FALSE;
return freerdp_client_handle_touch(&sdl->common, FREERDP_TOUCH_UP | FREERDP_TOUCH_HAS_PRESSURE,
(INT32)ev->fingerId, sdl_scale_pressure(ev->pressure), x, y);
}
BOOL sdl_handle_touch_down(sdlContext* sdl, const SDL_TouchFingerEvent* ev)
{
WINPR_ASSERT(sdl);
WINPR_ASSERT(ev);
INT32 x, y;
if (!sdl_get_touch_scaled(sdl, ev, &x, &y, TRUE))
return FALSE;
return freerdp_client_handle_touch(&sdl->common,
FREERDP_TOUCH_DOWN | FREERDP_TOUCH_HAS_PRESSURE,
(INT32)ev->fingerId, sdl_scale_pressure(ev->pressure), x, y);
}
BOOL sdl_handle_touch_motion(sdlContext* sdl, const SDL_TouchFingerEvent* ev)
{
WINPR_ASSERT(sdl);
WINPR_ASSERT(ev);
INT32 x, y;
if (!sdl_get_touch_scaled(sdl, ev, &x, &y, TRUE))
return FALSE;
return freerdp_client_handle_touch(&sdl->common,
FREERDP_TOUCH_MOTION | FREERDP_TOUCH_HAS_PRESSURE,
(INT32)ev->fingerId, sdl_scale_pressure(ev->pressure), x, y);
}
BOOL sdl_handle_mouse_motion(sdlContext* sdl, const SDL_MouseMotionEvent* ev)
{
WINPR_ASSERT(sdl);
WINPR_ASSERT(ev);
const BOOL relative =
freerdp_settings_get_bool(sdl->common.context.settings, FreeRDP_MouseUseRelativeMove);
INT32 x = relative ? ev->xrel : ev->x;
INT32 y = relative ? ev->yrel : ev->y;
sdl_scale_coordinates(sdl, ev->windowID, &x, &y, TRUE, TRUE);
return freerdp_client_send_button_event(&sdl->common, relative, PTR_FLAGS_MOVE, x, y);
}
BOOL sdl_handle_mouse_wheel(sdlContext* sdl, const SDL_MouseWheelEvent* ev)
{
WINPR_ASSERT(sdl);
WINPR_ASSERT(ev);
const BOOL flipped = (ev->direction == SDL_MOUSEWHEEL_FLIPPED);
const INT32 x = ev->x * (flipped ? -1 : 1);
const INT32 y = ev->y * (flipped ? -1 : 1);
UINT16 flags = 0;
if (y != 0)
{
flags |= PTR_FLAGS_WHEEL;
send_mouse_wheel(sdl, flags, y);
}
if (x != 0)
{
flags |= PTR_FLAGS_HWHEEL;
send_mouse_wheel(sdl, flags, x);
}
return TRUE;
}
BOOL sdl_handle_mouse_button(sdlContext* sdl, const SDL_MouseButtonEvent* ev)
{
UINT16 flags = 0;
UINT16 xflags = 0;
WINPR_ASSERT(sdl);
WINPR_ASSERT(ev);
if (ev->state == SDL_PRESSED)
{
flags |= PTR_FLAGS_DOWN;
xflags |= PTR_XFLAGS_DOWN;
}
switch (ev->button)
{
case 1:
flags |= PTR_FLAGS_BUTTON1;
break;
case 2:
flags |= PTR_FLAGS_BUTTON3;
break;
case 3:
flags |= PTR_FLAGS_BUTTON2;
break;
case 4:
xflags |= PTR_XFLAGS_BUTTON1;
break;
case 5:
xflags |= PTR_XFLAGS_BUTTON2;
break;
default:
break;
}
INT32 x = ev->x;
INT32 y = ev->y;
sdl_scale_coordinates(sdl, ev->windowID, &x, &y, TRUE, TRUE);
if ((flags & (~PTR_FLAGS_DOWN)) != 0)
return freerdp_client_send_button_event(&sdl->common, FALSE, flags, x, y);
else if ((xflags & (~PTR_XFLAGS_DOWN)) != 0)
return freerdp_client_send_extended_button_event(&sdl->common, FALSE, xflags, x, y);
else
return FALSE;
}

36
client/SDL/sdl_touch.h Normal file
View File

@ -0,0 +1,36 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* FreeRDP SDL touch/mouse input
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_SDL_TOUCH_H
#define FREERDP_CLIENT_SDL_TOUCH_H
#include "sdl_freerdp.h"
BOOL sdl_scale_coordinates(sdlContext* sdl, Uint32 windowId, INT32* px, INT32* py,
BOOL fromLocalToRDP, BOOL applyOffset);
BOOL sdl_handle_mouse_motion(sdlContext* sdl, const SDL_MouseMotionEvent* ev);
BOOL sdl_handle_mouse_wheel(sdlContext* sdl, const SDL_MouseWheelEvent* ev);
BOOL sdl_handle_mouse_button(sdlContext* sdl, const SDL_MouseButtonEvent* ev);
BOOL sdl_handle_touch_down(sdlContext* sdl, const SDL_TouchFingerEvent* ev);
BOOL sdl_handle_touch_up(sdlContext* sdl, const SDL_TouchFingerEvent* ev);
BOOL sdl_handle_touch_motion(sdlContext* sdl, const SDL_TouchFingerEvent* ev);
#endif /* FREERDP_CLIENT_SDL_TOUCH_H */

101
client/SDL/sdl_utils.c Normal file
View File

@ -0,0 +1,101 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Client
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <assert.h>
#include "sdl_utils.h"
#include <SDL.h>
const char* sdl_event_type_str(Uint32 type)
{
#define STR(x) #x
#define EV_CASE_STR(x) \
case x: \
return STR(x)
switch (type)
{
EV_CASE_STR(SDL_FIRSTEVENT);
EV_CASE_STR(SDL_QUIT);
EV_CASE_STR(SDL_APP_TERMINATING);
EV_CASE_STR(SDL_APP_LOWMEMORY);
EV_CASE_STR(SDL_APP_WILLENTERBACKGROUND);
EV_CASE_STR(SDL_APP_DIDENTERBACKGROUND);
EV_CASE_STR(SDL_APP_WILLENTERFOREGROUND);
EV_CASE_STR(SDL_APP_DIDENTERFOREGROUND);
#if SDL_VERSION_ATLEAST(2, 0, 10)
EV_CASE_STR(SDL_DISPLAYEVENT);
#endif
EV_CASE_STR(SDL_WINDOWEVENT);
EV_CASE_STR(SDL_SYSWMEVENT);
EV_CASE_STR(SDL_KEYDOWN);
EV_CASE_STR(SDL_KEYUP);
EV_CASE_STR(SDL_TEXTEDITING);
EV_CASE_STR(SDL_TEXTINPUT);
EV_CASE_STR(SDL_KEYMAPCHANGED);
EV_CASE_STR(SDL_MOUSEMOTION);
EV_CASE_STR(SDL_MOUSEBUTTONDOWN);
EV_CASE_STR(SDL_MOUSEBUTTONUP);
EV_CASE_STR(SDL_MOUSEWHEEL);
EV_CASE_STR(SDL_JOYAXISMOTION);
EV_CASE_STR(SDL_JOYBALLMOTION);
EV_CASE_STR(SDL_JOYHATMOTION);
EV_CASE_STR(SDL_JOYBUTTONDOWN);
EV_CASE_STR(SDL_JOYBUTTONUP);
EV_CASE_STR(SDL_JOYDEVICEADDED);
EV_CASE_STR(SDL_JOYDEVICEREMOVED);
EV_CASE_STR(SDL_CONTROLLERAXISMOTION);
EV_CASE_STR(SDL_CONTROLLERBUTTONDOWN);
EV_CASE_STR(SDL_CONTROLLERBUTTONUP);
EV_CASE_STR(SDL_CONTROLLERDEVICEADDED);
EV_CASE_STR(SDL_CONTROLLERDEVICEREMOVED);
EV_CASE_STR(SDL_CONTROLLERDEVICEREMAPPED);
#if SDL_VERSION_ATLEAST(2, 0, 14)
EV_CASE_STR(SDL_LOCALECHANGED);
EV_CASE_STR(SDL_CONTROLLERTOUCHPADDOWN);
EV_CASE_STR(SDL_CONTROLLERTOUCHPADMOTION);
EV_CASE_STR(SDL_CONTROLLERTOUCHPADUP);
EV_CASE_STR(SDL_CONTROLLERSENSORUPDATE);
#endif
EV_CASE_STR(SDL_FINGERDOWN);
EV_CASE_STR(SDL_FINGERUP);
EV_CASE_STR(SDL_FINGERMOTION);
EV_CASE_STR(SDL_DOLLARGESTURE);
EV_CASE_STR(SDL_DOLLARRECORD);
EV_CASE_STR(SDL_MULTIGESTURE);
EV_CASE_STR(SDL_CLIPBOARDUPDATE);
EV_CASE_STR(SDL_DROPFILE);
EV_CASE_STR(SDL_DROPTEXT);
EV_CASE_STR(SDL_DROPBEGIN);
EV_CASE_STR(SDL_DROPCOMPLETE);
EV_CASE_STR(SDL_AUDIODEVICEADDED);
EV_CASE_STR(SDL_AUDIODEVICEREMOVED);
#if SDL_VERSION_ATLEAST(2, 0, 9)
EV_CASE_STR(SDL_SENSORUPDATE);
#endif
EV_CASE_STR(SDL_RENDER_TARGETS_RESET);
EV_CASE_STR(SDL_RENDER_DEVICE_RESET);
EV_CASE_STR(SDL_USEREVENT);
EV_CASE_STR(SDL_LASTEVENT);
default:
return "SDL_UNKNOWNEVENT";
}
#undef EV_CASE_STR
#undef STR
}

28
client/SDL/sdl_utils.h Normal file
View File

@ -0,0 +1,28 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Client
*
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CLIENT_SDL_UTILS_H
#define FREERDP_CLIENT_SDL_UTILS_H
#include <stdbool.h>
#include <SDL.h>
const char* sdl_event_type_str(Uint32 type);
#endif /* FREERDP_CLIENT_SDL_UTILS_H */

View File

@ -410,7 +410,7 @@ BOOL wlf_handle_touch_up(freerdp* instance, const UwacTouchUp* ev)
if (!scale_signed_coordinates(instance->context, &x, &y, TRUE))
return FALSE;
return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_UP, ev->id,0, x, y);
return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_UP, ev->id, 0, x, y);
}
BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev)
@ -429,7 +429,7 @@ BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev)
if (!scale_signed_coordinates(instance->context, &x, &y, TRUE))
return FALSE;
return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_DOWN, ev->id, 0,x, y);
return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_DOWN, ev->id, 0, x, y);
}
BOOL wlf_handle_touch_motion(freerdp* instance, const UwacTouchMotion* ev)
@ -448,5 +448,5 @@ BOOL wlf_handle_touch_motion(freerdp* instance, const UwacTouchMotion* ev)
if (!scale_signed_coordinates(instance->context, &x, &y, TRUE))
return FALSE;
return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_MOTION,0, ev->id, x, y);
return freerdp_client_handle_touch(&wlf->common, FREERDP_TOUCH_MOTION, 0, ev->id, x, y);
}

View File

@ -609,13 +609,13 @@ static int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtyp
switch (evtype)
{
case XI_TouchBegin:
freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_DOWN, touchId, x, y);
freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_DOWN, touchId, 0, x, y);
break;
case XI_TouchUpdate:
freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_MOTION, touchId, x, y);
freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_MOTION, touchId, 0, x, y);
break;
case XI_TouchEnd:
freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_UP, touchId, x, y);
freerdp_client_handle_touch(&xfc->common, FREERDP_TOUCH_UP, touchId, 0, x, y);
break;
default:
break;

View File

@ -1421,9 +1421,9 @@ static BOOL freerdp_handle_touch_down(rdpClientContext* cctx, const FreeRDP_Touc
flags |= PTR_FLAGS_MOVE;
flags |= PTR_FLAGS_BUTTON1;
WINPR_ASSERT(contact->x <= UINT16_MAX);
WINPR_ASSERT(contact->y <= UINT16_MAX);
return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
WINPR_ASSERT(contact->x <= UINT16_MAX);
WINPR_ASSERT(contact->y <= UINT16_MAX);
return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
}
else
{
@ -1465,9 +1465,9 @@ static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx, const FreeRDP_To
UINT16 flags = 0;
flags |= PTR_FLAGS_MOVE;
WINPR_ASSERT(contact->x <= UINT16_MAX);
WINPR_ASSERT(contact->y <= UINT16_MAX);
return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
WINPR_ASSERT(contact->x <= UINT16_MAX);
WINPR_ASSERT(contact->y <= UINT16_MAX);
return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
}
else
{
@ -1509,12 +1509,12 @@ static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, IN
if (contact->id == touchId)
{
*ppcontact = contact;
*ppcontact = contact;
contact->flags = flags;
contact->pressure = pressure;
contact->x = x;
contact->y = y;
contact->y = y;
return TRUE;
}
}

View File

@ -69,6 +69,7 @@ option(WITH_SAMPLE "Build sample code" OFF)
option(WITH_CLIENT_COMMON "Build client common library" ON)
CMAKE_DEPENDENT_OPTION(WITH_CLIENT "Build client binaries" ON "WITH_CLIENT_COMMON" OFF)
CMAKE_DEPENDENT_OPTION(WITH_CLIENT_SDL "[experimental] Build SDL client " ON "WITH_CLIENT" OFF)
option(WITH_SERVER "Build server binaries" OFF)

View File

@ -85,8 +85,8 @@ extern "C"
{
ALIGN64 INT32 id;
ALIGN64 UINT32 count;
ALIGN64 INT32 x;
ALIGN64 INT32 y;
ALIGN64 INT32 x;
ALIGN64 INT32 y;
ALIGN64 UINT32 flags;
ALIGN64 UINT32 pressure;
} FreeRDP_TouchContact;

View File

@ -65,5 +65,6 @@ enum RDP_CODEC_ID
#define OSMINORTYPE_WINDOWS_RT 0x0009
/* As of 2022-03-29 the following does not exist officially in [MS-RDPBCGR] */
#define OSMINORTYPE_NATIVE_WAYLAND (0xFFFF - 1)
#define OSMINORTYPE_NATIVE_SDL (0xFFFF - 2)
#endif /* FREERDP_CONSTANTS_H */