mirror of
https://github.com/FreeRDP/FreeRDP.git
synced 2025-06-03 00:00:20 +00:00
added SDL2 client
This commit is contained in:
parent
82ba9ede9c
commit
070353bf90
@ -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
50
client/SDL/CMakeLists.txt
Normal 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
79
client/SDL/sdl_channels.c
Normal 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
32
client/SDL/sdl_channels.h
Normal 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
536
client/SDL/sdl_disp.c
Normal 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
42
client/SDL/sdl_disp.h
Normal 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
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
65
client/SDL/sdl_freerdp.h
Normal 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
463
client/SDL/sdl_kbd.c
Normal 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
38
client/SDL/sdl_kbd.h
Normal 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
312
client/SDL/sdl_monitor.c
Normal 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
31
client/SDL/sdl_monitor.h
Normal 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
198
client/SDL/sdl_pointer.c
Normal 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
27
client/SDL/sdl_pointer.h
Normal 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
280
client/SDL/sdl_touch.c
Normal 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
36
client/SDL/sdl_touch.h
Normal 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
101
client/SDL/sdl_utils.c
Normal 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
28
client/SDL/sdl_utils.h
Normal 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 */
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user