/** * FreeRDP: A Remote Desktop Protocol Implementation * FreeRDP SDL touch/mouse input * * 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 "sdl_touch.hpp" #include "sdl_context.hpp" #include #include #include #include #include [[nodiscard]] 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 : static_cast(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; } [[nodiscard]] 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 static_cast(val); } bool SdlTouch::touchUp(SdlContext* sdl, const SDL_TouchFingerEvent& ev) { WINPR_ASSERT(sdl); return freerdp_client_handle_touch(sdl->common(), FREERDP_TOUCH_UP | FREERDP_TOUCH_HAS_PRESSURE, static_cast(ev.fingerID), sdl_scale_pressure(ev.pressure), static_cast(ev.x), static_cast(ev.y)); } bool SdlTouch::touchCancel(SdlContext* sdl, const SDL_TouchFingerEvent& ev) { WINPR_ASSERT(sdl); return freerdp_client_handle_touch( sdl->common(), FREERDP_TOUCH_CANCEL | FREERDP_TOUCH_HAS_PRESSURE, static_cast(ev.fingerID), sdl_scale_pressure(ev.pressure), static_cast(ev.x), static_cast(ev.y)); } bool SdlTouch::touchDown(SdlContext* sdl, const SDL_TouchFingerEvent& ev) { WINPR_ASSERT(sdl); return freerdp_client_handle_touch( sdl->common(), FREERDP_TOUCH_DOWN | FREERDP_TOUCH_HAS_PRESSURE, static_cast(ev.fingerID), sdl_scale_pressure(ev.pressure), static_cast(ev.x), static_cast(ev.y)); } bool SdlTouch::touchMotion(SdlContext* sdl, const SDL_TouchFingerEvent& ev) { WINPR_ASSERT(sdl); return freerdp_client_handle_touch( sdl->common(), FREERDP_TOUCH_MOTION | FREERDP_TOUCH_HAS_PRESSURE, static_cast(ev.fingerID), sdl_scale_pressure(ev.pressure), static_cast(ev.x), static_cast(ev.y)); } bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_MouseMotionEvent& ev) { WINPR_ASSERT(sdl); if (!sdl->getInputChannelContext().mouse_focus(ev.windowID)) return FALSE; const BOOL relative = freerdp_client_use_relative_mouse_events(sdl->common()) && !sdl->hasCursor(); auto x = static_cast(relative ? ev.xrel : ev.x); auto y = static_cast(relative ? ev.yrel : ev.y); return freerdp_client_send_button_event(sdl->common(), relative, PTR_FLAGS_MOVE, x, y); } bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_MouseWheelEvent& ev) { WINPR_ASSERT(sdl); const BOOL flipped = (ev.direction == SDL_MOUSEWHEEL_FLIPPED); const auto x = static_cast(ev.x * (flipped ? -1.0f : 1.0f) * 120.0f); const auto y = static_cast(ev.y * (flipped ? -1.0f : 1.0f) * 120.0f); UINT16 flags = 0; if (y != 0) { flags |= PTR_FLAGS_WHEEL; if (!send_mouse_wheel(sdl, flags, y)) return false; } if (x != 0) { flags |= PTR_FLAGS_HWHEEL; if (!send_mouse_wheel(sdl, flags, x)) return false; } return TRUE; } bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_MouseButtonEvent& ev) { UINT16 flags = 0; UINT16 xflags = 0; WINPR_ASSERT(sdl); if (ev.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { 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; } const BOOL relative = freerdp_client_use_relative_mouse_events(sdl->common()) && !sdl->hasCursor(); auto x = static_cast(relative ? 0 : ev.x); auto y = static_cast(relative ? 0 : ev.y); if ((flags & (~PTR_FLAGS_DOWN)) != 0) return freerdp_client_send_button_event(sdl->common(), relative, flags, x, y); else if ((xflags & (~PTR_XFLAGS_DOWN)) != 0) return freerdp_client_send_extended_button_event(sdl->common(), relative, xflags, x, y); else return FALSE; } bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_TouchFingerEvent& ev) { switch (ev.type) { case SDL_EVENT_FINGER_CANCELED: return SdlTouch::touchCancel(sdl, ev); case SDL_EVENT_FINGER_UP: return SdlTouch::touchUp(sdl, ev); case SDL_EVENT_FINGER_DOWN: return SdlTouch::touchDown(sdl, ev); case SDL_EVENT_FINGER_MOTION: return SdlTouch::touchMotion(sdl, ev); default: return false; } }