19#include <winpr/assert.h>
20#include <freerdp/config.h>
22#include <freerdp/log.h>
25#define TAG SERVER_TAG("shadow.input")
28#define KEY_INDEX_EXTENDED 0x100
29#define KEY_INDEX_EXTENDED1 0x200
30#define KEY_INDEX_COUNT 0x400
33static size_t shadow_input_key_index(UINT16 flags, UINT8 code)
36 if (flags & KBD_FLAGS_EXTENDED)
37 index |= KEY_INDEX_EXTENDED;
38 if (flags & KBD_FLAGS_EXTENDED1)
39 index |= KEY_INDEX_EXTENDED1;
44static BOOL shadow_input_key_is_down(
const rdpShadowClient* client,
size_t index)
47 WINPR_ASSERT(index < KEY_INDEX_COUNT);
48 return (client->keysDown[index / 8] & (1u << (index % 8))) != 0;
56static void shadow_input_key_mark(rdpShadowClient* client,
size_t index, BOOL down)
59 WINPR_ASSERT(index < KEY_INDEX_COUNT);
60 rdpShadowServer* server = client->server;
63 const BYTE bit = (BYTE)(1u << (index % 8));
65 EnterCriticalSection(&server->lock);
66 if (down && !shadow_input_key_is_down(client, index))
68 client->keysDown[index / 8] |= bit;
69 server->keysHeld[index]++;
71 else if (!down && shadow_input_key_is_down(client, index))
73 client->keysDown[index / 8] &= (BYTE)~bit;
74 WINPR_ASSERT(server->keysHeld[index] > 0);
75 server->keysHeld[index]--;
77 LeaveCriticalSection(&server->lock);
83static BOOL shadow_input_key_release(rdpShadowClient* client,
size_t index)
86 rdpShadowServer* server = client->server;
89 EnterCriticalSection(&server->lock);
90 shadow_input_key_mark(client, index, FALSE);
91 const BOOL held = server->keysHeld[index] > 0;
92 LeaveCriticalSection(&server->lock);
96BOOL shadow_input_release_keys(rdpShadowClient* client)
99 WINPR_ASSERT(client->server);
100 rdpShadowSubsystem* subsystem = client->server->subsystem;
101 WINPR_ASSERT(subsystem);
104 for (
size_t index = 0; index < KEY_INDEX_COUNT; index++)
106 if (!shadow_input_key_is_down(client, index))
109 if (shadow_input_key_release(client, index))
112 UINT16 flags = KBD_FLAGS_RELEASE;
113 if (index & KEY_INDEX_EXTENDED)
114 flags |= KBD_FLAGS_EXTENDED;
115 if (index & KEY_INDEX_EXTENDED1)
116 flags |= KBD_FLAGS_EXTENDED1;
117 const UINT8 code = (UINT8)(index & 0xFF);
119 WLog_DBG(TAG,
"releasing key 0x%02" PRIx8
" flags=0x%04" PRIx16
" the client left down",
122 if (!IFCALLRESULT(TRUE, subsystem->KeyboardEvent, subsystem, client, flags, code))
124 WLog_WARN(TAG,
"releasing key 0x%02" PRIx8
" flags=0x%04" PRIx16
" failed", code,
133static BOOL shadow_input_synchronize_event(rdpInput* input, UINT32 flags)
136 rdpShadowClient* client = (rdpShadowClient*)input->context;
137 WINPR_ASSERT(client);
138 WINPR_ASSERT(client->server);
139 rdpShadowSubsystem* subsystem = client->server->subsystem;
140 WINPR_ASSERT(subsystem);
142 WLog_DBG(TAG,
"[%s] flags=0x%04" PRIx16, client->mayInteract ?
"use" :
"discard", flags);
143 if (!client->mayInteract)
148 const BOOL released = shadow_input_release_keys(client);
149 const BOOL synced = IFCALLRESULT(TRUE, subsystem->SynchronizeEvent, subsystem, client, flags);
150 return released && synced;
154static BOOL shadow_input_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
157 rdpShadowClient* client = (rdpShadowClient*)input->context;
158 WINPR_ASSERT(client);
159 WINPR_ASSERT(client->server);
160 rdpShadowSubsystem* subsystem = client->server->subsystem;
161 WINPR_ASSERT(subsystem);
163 WLog_DBG(TAG,
"[%s] flags=0x%04" PRIx16, client->mayInteract ?
"use" :
"discard", flags);
164 if (!client->mayInteract)
167 const BOOL rc = IFCALLRESULT(TRUE, subsystem->KeyboardEvent, subsystem, client, flags, code);
169 shadow_input_key_mark(client, shadow_input_key_index(flags, code),
170 (flags & KBD_FLAGS_RELEASE) == 0);
175static BOOL shadow_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
178 rdpShadowClient* client = (rdpShadowClient*)input->context;
179 WINPR_ASSERT(client);
180 WINPR_ASSERT(client->server);
181 rdpShadowSubsystem* subsystem = client->server->subsystem;
182 WINPR_ASSERT(subsystem);
184 WLog_DBG(TAG,
"[%s] flags=0x%04" PRIx16, client->mayInteract ?
"use" :
"discard", flags);
185 if (!client->mayInteract)
188 return IFCALLRESULT(TRUE, subsystem->UnicodeKeyboardEvent, subsystem, client, flags, code);
192static BOOL shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
195 rdpShadowClient* client = (rdpShadowClient*)input->context;
196 WINPR_ASSERT(client);
197 WINPR_ASSERT(client->server);
198 rdpShadowSubsystem* subsystem = client->server->subsystem;
199 WINPR_ASSERT(subsystem);
201 if (client->server->shareSubRect)
203 x += client->server->subRect.left;
204 y += client->server->subRect.top;
207 if ((flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE)) == 0)
209 client->pointerX = x;
210 client->pointerY = y;
212 if ((client->pointerX == subsystem->pointerX) && (client->pointerY == subsystem->pointerY))
214 flags &= ~PTR_FLAGS_MOVE;
216 if (!(flags & (PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3)))
221 WLog_DBG(TAG,
"[%s] flags=0x%04" PRIx16
", x=%" PRIu16
", y=%" PRIu16,
222 client->mayInteract ?
"use" :
"discard", flags, x, y);
223 if (!client->mayInteract)
226 return IFCALLRESULT(TRUE, subsystem->MouseEvent, subsystem, client, flags, x, y);
230static BOOL shadow_input_rel_mouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta)
234 rdpShadowClient* client = (rdpShadowClient*)input->context;
235 WINPR_ASSERT(client);
236 WINPR_ASSERT(client->server);
238 rdpShadowSubsystem* subsystem = client->server->subsystem;
239 WINPR_ASSERT(subsystem);
241 WLog_DBG(TAG,
"[%s] flags=0x%04" PRIx16
", x=%" PRId16
", y=%" PRId16,
242 client->mayInteract ?
"use" :
"discard", flags, xDelta, yDelta);
243 const uint16_t mask = PTR_FLAGS_MOVE | PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 |
244 PTR_FLAGS_BUTTON3 | PTR_XFLAGS_BUTTON1 | PTR_XFLAGS_BUTTON2;
245 if ((flags & mask) != 0)
247 WLog_WARN(TAG,
"Unknown flags 0x%04x", WINPR_CXX_COMPAT_CAST(
unsigned, flags & ~mask));
249 if (!client->mayInteract)
252 return IFCALLRESULT(TRUE, subsystem->RelMouseEvent, subsystem, client, flags, xDelta, yDelta);
256static BOOL shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
259 rdpShadowClient* client = (rdpShadowClient*)input->context;
260 WINPR_ASSERT(client);
261 WINPR_ASSERT(client->server);
262 rdpShadowSubsystem* subsystem = client->server->subsystem;
263 WINPR_ASSERT(subsystem);
265 if (client->server->shareSubRect)
267 x += client->server->subRect.left;
268 y += client->server->subRect.top;
271 client->pointerX = x;
272 client->pointerY = y;
274 WLog_DBG(TAG,
"[%s] flags=0x%04" PRIx16
", x=%" PRIu16
", y=%" PRIu16,
275 client->mayInteract ?
"use" :
"discard", flags, x, y);
276 if (!client->mayInteract)
279 return IFCALLRESULT(TRUE, subsystem->ExtendedMouseEvent, subsystem, client, flags, x, y);
282void shadow_input_register_callbacks(rdpInput* input)
285 input->SynchronizeEvent = shadow_input_synchronize_event;
286 input->KeyboardEvent = shadow_input_keyboard_event;
287 input->UnicodeKeyboardEvent = shadow_input_unicode_keyboard_event;
288 input->MouseEvent = shadow_input_mouse_event;
289 input->ExtendedMouseEvent = shadow_input_extended_mouse_event;
290 input->RelMouseEvent = shadow_input_rel_mouse_event;