/** * FreeRDP: A Remote Desktop Protocol Implementation * SDL Client * * Copyright 2022 Armin Novak * * 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 #include #include #include #include "sdl_utils.hpp" #include "sdl_freerdp.hpp" #include #include #define STR(x) #x #define EV_CASE_STR(x) \ case x: \ return STR(x) const char* sdl_event_type_str(Uint32 type) { switch (type) { EV_CASE_STR(SDL_EVENT_FIRST); EV_CASE_STR(SDL_EVENT_QUIT); EV_CASE_STR(SDL_EVENT_TERMINATING); EV_CASE_STR(SDL_EVENT_LOW_MEMORY); EV_CASE_STR(SDL_EVENT_WILL_ENTER_BACKGROUND); EV_CASE_STR(SDL_EVENT_DID_ENTER_BACKGROUND); EV_CASE_STR(SDL_EVENT_WILL_ENTER_FOREGROUND); EV_CASE_STR(SDL_EVENT_DID_ENTER_FOREGROUND); EV_CASE_STR(SDL_EVENT_LOCALE_CHANGED); EV_CASE_STR(SDL_EVENT_SYSTEM_THEME_CHANGED); EV_CASE_STR(SDL_EVENT_DISPLAY_ORIENTATION); EV_CASE_STR(SDL_EVENT_DISPLAY_ADDED); EV_CASE_STR(SDL_EVENT_DISPLAY_REMOVED); EV_CASE_STR(SDL_EVENT_DISPLAY_MOVED); EV_CASE_STR(SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED); EV_CASE_STR(SDL_EVENT_WINDOW_SHOWN); EV_CASE_STR(SDL_EVENT_WINDOW_HIDDEN); EV_CASE_STR(SDL_EVENT_WINDOW_EXPOSED); EV_CASE_STR(SDL_EVENT_WINDOW_MOVED); EV_CASE_STR(SDL_EVENT_WINDOW_RESIZED); EV_CASE_STR(SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED); EV_CASE_STR(SDL_EVENT_WINDOW_MINIMIZED); EV_CASE_STR(SDL_EVENT_WINDOW_MAXIMIZED); EV_CASE_STR(SDL_EVENT_WINDOW_RESTORED); EV_CASE_STR(SDL_EVENT_WINDOW_MOUSE_ENTER); EV_CASE_STR(SDL_EVENT_WINDOW_MOUSE_LEAVE); EV_CASE_STR(SDL_EVENT_WINDOW_FOCUS_GAINED); EV_CASE_STR(SDL_EVENT_WINDOW_FOCUS_LOST); EV_CASE_STR(SDL_EVENT_WINDOW_CLOSE_REQUESTED); EV_CASE_STR(SDL_EVENT_WINDOW_HIT_TEST); EV_CASE_STR(SDL_EVENT_WINDOW_ICCPROF_CHANGED); EV_CASE_STR(SDL_EVENT_WINDOW_DISPLAY_CHANGED); EV_CASE_STR(SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED); EV_CASE_STR(SDL_EVENT_WINDOW_OCCLUDED); EV_CASE_STR(SDL_EVENT_WINDOW_ENTER_FULLSCREEN); EV_CASE_STR(SDL_EVENT_WINDOW_LEAVE_FULLSCREEN); EV_CASE_STR(SDL_EVENT_WINDOW_DESTROYED); EV_CASE_STR(SDL_EVENT_KEY_DOWN); EV_CASE_STR(SDL_EVENT_KEY_UP); EV_CASE_STR(SDL_EVENT_TEXT_EDITING); EV_CASE_STR(SDL_EVENT_TEXT_INPUT); EV_CASE_STR(SDL_EVENT_KEYMAP_CHANGED); EV_CASE_STR(SDL_EVENT_KEYBOARD_ADDED); EV_CASE_STR(SDL_EVENT_KEYBOARD_REMOVED); EV_CASE_STR(SDL_EVENT_MOUSE_MOTION); EV_CASE_STR(SDL_EVENT_MOUSE_BUTTON_DOWN); EV_CASE_STR(SDL_EVENT_MOUSE_BUTTON_UP); EV_CASE_STR(SDL_EVENT_MOUSE_WHEEL); EV_CASE_STR(SDL_EVENT_MOUSE_ADDED); EV_CASE_STR(SDL_EVENT_MOUSE_REMOVED); EV_CASE_STR(SDL_EVENT_JOYSTICK_AXIS_MOTION); EV_CASE_STR(SDL_EVENT_JOYSTICK_BALL_MOTION); EV_CASE_STR(SDL_EVENT_JOYSTICK_HAT_MOTION); EV_CASE_STR(SDL_EVENT_JOYSTICK_BUTTON_DOWN); EV_CASE_STR(SDL_EVENT_JOYSTICK_BUTTON_UP); EV_CASE_STR(SDL_EVENT_JOYSTICK_ADDED); EV_CASE_STR(SDL_EVENT_JOYSTICK_REMOVED); EV_CASE_STR(SDL_EVENT_JOYSTICK_BATTERY_UPDATED); EV_CASE_STR(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE); EV_CASE_STR(SDL_EVENT_GAMEPAD_AXIS_MOTION); EV_CASE_STR(SDL_EVENT_GAMEPAD_BUTTON_DOWN); EV_CASE_STR(SDL_EVENT_GAMEPAD_BUTTON_UP); EV_CASE_STR(SDL_EVENT_GAMEPAD_ADDED); EV_CASE_STR(SDL_EVENT_GAMEPAD_REMOVED); EV_CASE_STR(SDL_EVENT_GAMEPAD_REMAPPED); EV_CASE_STR(SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN); EV_CASE_STR(SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION); EV_CASE_STR(SDL_EVENT_GAMEPAD_TOUCHPAD_UP); EV_CASE_STR(SDL_EVENT_GAMEPAD_SENSOR_UPDATE); EV_CASE_STR(SDL_EVENT_GAMEPAD_UPDATE_COMPLETE); EV_CASE_STR(SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED); EV_CASE_STR(SDL_EVENT_FINGER_DOWN); EV_CASE_STR(SDL_EVENT_FINGER_UP); EV_CASE_STR(SDL_EVENT_FINGER_MOTION); EV_CASE_STR(SDL_EVENT_CLIPBOARD_UPDATE); EV_CASE_STR(SDL_EVENT_DROP_FILE); EV_CASE_STR(SDL_EVENT_DROP_TEXT); EV_CASE_STR(SDL_EVENT_DROP_BEGIN); EV_CASE_STR(SDL_EVENT_DROP_COMPLETE); EV_CASE_STR(SDL_EVENT_DROP_POSITION); EV_CASE_STR(SDL_EVENT_AUDIO_DEVICE_ADDED); EV_CASE_STR(SDL_EVENT_AUDIO_DEVICE_REMOVED); EV_CASE_STR(SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED); EV_CASE_STR(SDL_EVENT_SENSOR_UPDATE); EV_CASE_STR(SDL_EVENT_PEN_DOWN); EV_CASE_STR(SDL_EVENT_PEN_UP); EV_CASE_STR(SDL_EVENT_PEN_MOTION); EV_CASE_STR(SDL_EVENT_PEN_BUTTON_DOWN); EV_CASE_STR(SDL_EVENT_PEN_BUTTON_UP); EV_CASE_STR(SDL_EVENT_CAMERA_DEVICE_ADDED); EV_CASE_STR(SDL_EVENT_CAMERA_DEVICE_REMOVED); EV_CASE_STR(SDL_EVENT_CAMERA_DEVICE_APPROVED); EV_CASE_STR(SDL_EVENT_CAMERA_DEVICE_DENIED); EV_CASE_STR(SDL_EVENT_RENDER_TARGETS_RESET); EV_CASE_STR(SDL_EVENT_RENDER_DEVICE_RESET); EV_CASE_STR(SDL_EVENT_POLL_SENTINEL); EV_CASE_STR(SDL_EVENT_USER); EV_CASE_STR(SDL_EVENT_USER_CERT_DIALOG); EV_CASE_STR(SDL_EVENT_USER_CERT_RESULT); EV_CASE_STR(SDL_EVENT_USER_SHOW_DIALOG); EV_CASE_STR(SDL_EVENT_USER_SHOW_RESULT); EV_CASE_STR(SDL_EVENT_USER_AUTH_DIALOG); EV_CASE_STR(SDL_EVENT_USER_AUTH_RESULT); EV_CASE_STR(SDL_EVENT_USER_SCARD_DIALOG); EV_CASE_STR(SDL_EVENT_USER_RETRY_DIALOG); EV_CASE_STR(SDL_EVENT_USER_SCARD_RESULT); EV_CASE_STR(SDL_EVENT_USER_UPDATE); EV_CASE_STR(SDL_EVENT_USER_CREATE_WINDOWS); EV_CASE_STR(SDL_EVENT_USER_WINDOW_RESIZEABLE); EV_CASE_STR(SDL_EVENT_USER_WINDOW_FULLSCREEN); EV_CASE_STR(SDL_EVENT_USER_WINDOW_MINIMIZE); EV_CASE_STR(SDL_EVENT_USER_POINTER_NULL); EV_CASE_STR(SDL_EVENT_USER_POINTER_DEFAULT); EV_CASE_STR(SDL_EVENT_USER_POINTER_POSITION); EV_CASE_STR(SDL_EVENT_USER_POINTER_SET); EV_CASE_STR(SDL_EVENT_USER_QUIT); EV_CASE_STR(SDL_EVENT_LAST); default: return "SDL_UNKNOWNEVENT"; } } const char* sdl_error_string(Sint32 res) { if (res == 0) return nullptr; return SDL_GetError(); } BOOL sdl_log_error_ex(Sint32 res, wLog* log, const char* what, const char* file, size_t line, const char* fkt) { const char* msg = sdl_error_string(res); WINPR_UNUSED(file); if (!msg) return FALSE; WLog_Print(log, WLOG_ERROR, "[%s:%" PRIuz "][%s]: %s", fkt, line, what, msg); return TRUE; } bool sdl_push_user_event(Uint32 type, ...) { SDL_Event ev = {}; SDL_UserEvent* event = &ev.user; va_list ap = {}; va_start(ap, type); event->type = type; switch (type) { case SDL_EVENT_USER_AUTH_RESULT: { auto arg = reinterpret_cast(ev.padding); arg->user = va_arg(ap, char*); arg->domain = va_arg(ap, char*); arg->password = va_arg(ap, char*); arg->result = va_arg(ap, Sint32); } break; case SDL_EVENT_USER_AUTH_DIALOG: { auto arg = reinterpret_cast(ev.padding); arg->title = va_arg(ap, char*); arg->user = va_arg(ap, char*); arg->domain = va_arg(ap, char*); arg->password = va_arg(ap, char*); arg->result = va_arg(ap, Sint32); } break; case SDL_EVENT_USER_SCARD_DIALOG: { event->data1 = va_arg(ap, char*); event->data2 = va_arg(ap, char**); event->code = va_arg(ap, Sint32); } break; case SDL_EVENT_USER_RETRY_DIALOG: event->code = va_arg(ap, Sint32); break; case SDL_EVENT_USER_SCARD_RESULT: case SDL_EVENT_USER_SHOW_RESULT: case SDL_EVENT_USER_CERT_RESULT: event->code = va_arg(ap, Sint32); break; case SDL_EVENT_USER_SHOW_DIALOG: event->data1 = va_arg(ap, char*); event->data2 = va_arg(ap, char*); event->code = va_arg(ap, Sint32); break; case SDL_EVENT_USER_CERT_DIALOG: event->data1 = va_arg(ap, char*); event->data2 = va_arg(ap, char*); break; case SDL_EVENT_USER_UPDATE: event->data1 = va_arg(ap, void*); break; case SDL_EVENT_USER_POINTER_POSITION: event->data1 = reinterpret_cast(static_cast(va_arg(ap, UINT32))); event->data2 = reinterpret_cast(static_cast(va_arg(ap, UINT32))); break; case SDL_EVENT_USER_POINTER_SET: event->data1 = va_arg(ap, void*); event->data2 = va_arg(ap, void*); break; case SDL_EVENT_USER_CREATE_WINDOWS: event->data1 = va_arg(ap, void*); break; case SDL_EVENT_USER_WINDOW_FULLSCREEN: case SDL_EVENT_USER_WINDOW_RESIZEABLE: event->data1 = va_arg(ap, void*); event->code = va_arg(ap, int); break; case SDL_EVENT_USER_WINDOW_MINIMIZE: case SDL_EVENT_USER_QUIT: case SDL_EVENT_USER_POINTER_NULL: case SDL_EVENT_USER_POINTER_DEFAULT: case SDL_EVENT_CLIPBOARD_UPDATE: break; default: va_end(ap); SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "[%s] unsupported type %u", __func__, type); return false; } va_end(ap); return SDL_PushEvent(&ev) == 1; } bool sdl_push_quit() { SDL_Event ev = {}; ev.type = SDL_EVENT_QUIT; SDL_PushEvent(&ev); return true; } std::string sdl_window_event_str(Uint32 ev) { if ((ev >= SDL_EVENT_WINDOW_FIRST) && (ev <= SDL_EVENT_WINDOW_LAST)) return sdl_event_type_str(ev); return "SDL_EVENT_WINDOW_UNKNOWN"; } UINT32 sdl::utils::orientaion_to_rdp(SDL_DisplayOrientation orientation) { switch (orientation) { case SDL_ORIENTATION_LANDSCAPE: return ORIENTATION_LANDSCAPE; case SDL_ORIENTATION_LANDSCAPE_FLIPPED: return ORIENTATION_LANDSCAPE_FLIPPED; case SDL_ORIENTATION_PORTRAIT_FLIPPED: return ORIENTATION_PORTRAIT_FLIPPED; case SDL_ORIENTATION_PORTRAIT: default: return ORIENTATION_PORTRAIT; } } std::string sdl::utils::sdl_orientation_to_str(SDL_DisplayOrientation orientation) { switch (orientation) { case SDL_ORIENTATION_LANDSCAPE: return "SDL_ORIENTATION_LANDSCAPE"; case SDL_ORIENTATION_LANDSCAPE_FLIPPED: return "SDL_ORIENTATION_LANDSCAPE_FLIPPED"; case SDL_ORIENTATION_PORTRAIT_FLIPPED: return "SDL_ORIENTATION_PORTRAIT_FLIPPED"; case SDL_ORIENTATION_PORTRAIT: return "SDL_ORIENTATION_PORTRAIT"; default: return "SDL_ORIENTATION_UNKNOWN"; } } std::string sdl::utils::rdp_orientation_to_str(uint32_t orientation) { switch (orientation) { case ORIENTATION_LANDSCAPE: return "ORIENTATION_LANDSCAPE"; case ORIENTATION_LANDSCAPE_FLIPPED: return "ORIENTATION_LANDSCAPE_FLIPPED"; case ORIENTATION_PORTRAIT_FLIPPED: return "ORIENTATION_PORTRAIT_FLIPPED"; case ORIENTATION_PORTRAIT: return "ORIENTATION_PORTRAIT"; default: { std::stringstream ss; ss << "ORIENTATION_UNKNOWN_" << std::hex << std::setfill('0') << std::setw(8) << orientation; return ss.str(); } } } std::string sdl::utils::generate_uuid_v4() { static std::random_device rd; static std::mt19937 gen(rd()); static std::uniform_int_distribution<> dis(0, 255); std::stringstream ss; ss << std::hex << std::setfill('0') << std::setw(2); for (int i = 0; i < 4; i++) { ss << dis(gen); } ss << "-"; for (int i = 0; i < 2; i++) { ss << dis(gen); } ss << "-"; for (int i = 0; i < 2; i++) { ss << dis(gen); } ss << "-"; for (int i = 0; i < 2; i++) { ss << dis(gen); } ss << "-"; for (int i = 0; i < 6; i++) { ss << dis(gen); } return ss.str(); }