FreeRDP
Loading...
Searching...
No Matches
SDL3/sdl_touch.cpp
1
20#include <freerdp/config.h>
21
22#include "sdl_touch.hpp"
23#include "sdl_context.hpp"
24#include "sdl_prefs.hpp"
25
26#include <winpr/wtypes.h>
27#include <winpr/assert.h>
28
29#include <freerdp/freerdp.h>
30#include <freerdp/gdi/gdi.h>
31
32#include <SDL3/SDL.h>
33
34[[nodiscard]] static bool send_mouse_wheel(SdlContext* sdl, UINT16 flags, INT32 avalue)
35{
36 WINPR_ASSERT(sdl);
37 if (avalue < 0)
38 {
39 flags |= PTR_FLAGS_WHEEL_NEGATIVE;
40 avalue = -avalue;
41 }
42
43 while (avalue > 0)
44 {
45 const UINT16 cval = (avalue > 0xFF) ? 0xFF : static_cast<UINT16>(avalue);
46 UINT16 cflags = flags | cval;
47 /* Convert negative values to 9bit twos complement */
48 if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
49 cflags = (flags & 0xFF00) | (0x100 - cval);
50 if (!freerdp_client_send_wheel_event(sdl->common(), cflags))
51 return FALSE;
52
53 avalue -= cval;
54 }
55 return TRUE;
56}
57
58[[nodiscard]] static UINT32 sdl_scale_pressure(const float pressure)
59{
60 const float val = pressure * 0x400; /* [MS-RDPEI] 2.2.3.3.1.1 RDPINPUT_TOUCH_CONTACT */
61 if (val < 0.0f)
62 return 0;
63 if (val > 0x400)
64 return 0x400;
65 return static_cast<UINT32>(val);
66}
67
68bool SdlTouch::touchUp(SdlContext* sdl, const SDL_TouchFingerEvent& ev)
69{
70 WINPR_ASSERT(sdl);
71
72 return freerdp_client_handle_touch(sdl->common(), FREERDP_TOUCH_UP | FREERDP_TOUCH_HAS_PRESSURE,
73 static_cast<INT32>(ev.fingerID),
74 sdl_scale_pressure(ev.pressure), static_cast<Sint32>(ev.x),
75 static_cast<Sint32>(ev.y));
76}
77
78bool SdlTouch::touchCancel(SdlContext* sdl, const SDL_TouchFingerEvent& ev)
79{
80 WINPR_ASSERT(sdl);
81
82 return freerdp_client_handle_touch(
83 sdl->common(), FREERDP_TOUCH_CANCEL | FREERDP_TOUCH_HAS_PRESSURE,
84 static_cast<INT32>(ev.fingerID), sdl_scale_pressure(ev.pressure), static_cast<Sint32>(ev.x),
85 static_cast<Sint32>(ev.y));
86}
87
88bool SdlTouch::touchDown(SdlContext* sdl, const SDL_TouchFingerEvent& ev)
89{
90 WINPR_ASSERT(sdl);
91
92 return freerdp_client_handle_touch(
93 sdl->common(), FREERDP_TOUCH_DOWN | FREERDP_TOUCH_HAS_PRESSURE,
94 static_cast<INT32>(ev.fingerID), sdl_scale_pressure(ev.pressure), static_cast<Sint32>(ev.x),
95 static_cast<Sint32>(ev.y));
96}
97
98bool SdlTouch::touchMotion(SdlContext* sdl, const SDL_TouchFingerEvent& ev)
99{
100 WINPR_ASSERT(sdl);
101
102 return freerdp_client_handle_touch(
103 sdl->common(), FREERDP_TOUCH_MOTION | FREERDP_TOUCH_HAS_PRESSURE,
104 static_cast<INT32>(ev.fingerID), sdl_scale_pressure(ev.pressure), static_cast<Sint32>(ev.x),
105 static_cast<Sint32>(ev.y));
106}
107
108bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_MouseMotionEvent& ev)
109{
110 WINPR_ASSERT(sdl);
111
112 if (!sdl->getInputChannelContext().mouse_focus(ev.windowID))
113 return FALSE;
114
115 const BOOL relative =
116 freerdp_client_use_relative_mouse_events(sdl->common()) && !sdl->hasCursor();
117 auto x = static_cast<INT32>(relative ? ev.xrel : ev.x);
118 auto y = static_cast<INT32>(relative ? ev.yrel : ev.y);
119 return freerdp_client_send_button_event(sdl->common(), relative, PTR_FLAGS_MOVE, x, y);
120}
121
122bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_MouseWheelEvent& ev)
123{
124 WINPR_ASSERT(sdl);
125
126 const bool flipped = (ev.direction == SDL_MOUSEWHEEL_FLIPPED) &&
127 !SdlPref::instance()->get_bool("UseLocalMouseScrollDirection");
128 const auto x = static_cast<INT32>(ev.x * (flipped ? -1.0f : 1.0f) * 120.0f);
129 const auto y = static_cast<INT32>(ev.y * (flipped ? -1.0f : 1.0f) * 120.0f);
130
131 /* [MS-RDPBCGR] 2.2.8.1.1.3.1.1.3 Pointer Event: a wheel rotation event carries no flags
132 * besides PTR_FLAGS_WHEEL_NEGATIVE and the rotation itself, so the two axes cannot share
133 * one event. Keep the flags apart, the horizontal rotation would otherwise be applied to
134 * the vertical axis. */
135 if (y != 0)
136 {
137 if (!send_mouse_wheel(sdl, PTR_FLAGS_WHEEL, y))
138 return false;
139 }
140
141 if (x != 0)
142 {
143 if (!send_mouse_wheel(sdl, PTR_FLAGS_HWHEEL, x))
144 return false;
145 }
146 return TRUE;
147}
148
149bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_MouseButtonEvent& ev)
150{
151 UINT16 flags = 0;
152 UINT16 xflags = 0;
153
154 WINPR_ASSERT(sdl);
155
156 if (ev.type == SDL_EVENT_MOUSE_BUTTON_DOWN)
157 {
158 flags |= PTR_FLAGS_DOWN;
159 xflags |= PTR_XFLAGS_DOWN;
160 }
161
162 switch (ev.button)
163 {
164 case 1:
165 flags |= PTR_FLAGS_BUTTON1;
166 break;
167 case 2:
168 flags |= PTR_FLAGS_BUTTON3;
169 break;
170 case 3:
171 flags |= PTR_FLAGS_BUTTON2;
172 break;
173 case 4:
174 xflags |= PTR_XFLAGS_BUTTON1;
175 break;
176 case 5:
177 xflags |= PTR_XFLAGS_BUTTON2;
178 break;
179 default:
180 break;
181 }
182
183 const BOOL relative =
184 freerdp_client_use_relative_mouse_events(sdl->common()) && !sdl->hasCursor();
185 auto x = static_cast<INT32>(relative ? 0 : ev.x);
186 auto y = static_cast<INT32>(relative ? 0 : ev.y);
187
188 if ((flags & (~PTR_FLAGS_DOWN)) != 0)
189 return freerdp_client_send_button_event(sdl->common(), relative, flags, x, y);
190 else if ((xflags & (~PTR_XFLAGS_DOWN)) != 0)
191 return freerdp_client_send_extended_button_event(sdl->common(), relative, xflags, x, y);
192 else
193 return TRUE;
194}
195
196bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_TouchFingerEvent& ev)
197{
198 switch (ev.type)
199 {
200 case SDL_EVENT_FINGER_CANCELED:
201 return SdlTouch::touchCancel(sdl, ev);
202 case SDL_EVENT_FINGER_UP:
203 return SdlTouch::touchUp(sdl, ev);
204 case SDL_EVENT_FINGER_DOWN:
205 return SdlTouch::touchDown(sdl, ev);
206 case SDL_EVENT_FINGER_MOTION:
207 return SdlTouch::touchMotion(sdl, ev);
208 default:
209 return false;
210 }
211}