21#include <freerdp/config.h>
27#include <winpr/assert.h>
28#include <winpr/stream.h>
29#include <winpr/sysinfo.h>
31#include "ainput_main.h"
32#include <freerdp/channels/log.h>
33#include <freerdp/client/channels.h>
34#include <freerdp/client/ainput.h>
35#include <freerdp/channels/ainput.h>
37#include "../common/ainput_common.h"
39#define TAG CHANNELS_TAG("ainput.client")
41typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN;
45 AInputClientContext* context;
56static UINT ainput_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
59 AINPUT_PLUGIN* ainput = NULL;
62 WINPR_ASSERT(callback);
65 ainput = (AINPUT_PLUGIN*)callback->plugin;
68 if (!Stream_CheckAndLogRequiredLength(TAG, data, 2))
70 Stream_Read_UINT16(data, type);
73 case MSG_AINPUT_VERSION:
74 if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
76 Stream_Read_UINT32(data, ainput->MajorVersion);
77 Stream_Read_UINT32(data, ainput->MinorVersion);
80 WLog_WARN(TAG,
"Received unsupported message type 0x%04" PRIx16, type);
87static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, INT32 x, INT32 y)
89 BYTE buffer[32] = { 0 };
91 wStream* s = Stream_StaticInit(&sbuffer, buffer,
sizeof(buffer));
94 WINPR_ASSERT(context);
96 const UINT64 time = GetTickCount64();
97 AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)context->handle;
100 if (ainput->MajorVersion != AINPUT_VERSION_MAJOR)
102 WLog_WARN(TAG,
"Unsupported channel version %" PRIu32
".%" PRIu32
", aborting.",
103 ainput->MajorVersion, ainput->MinorVersion);
104 return CHANNEL_RC_UNSUPPORTED_VERSION;
108 char ebuffer[128] = { 0 };
109 WLog_VRB(TAG,
"sending timestamp=0x%08" PRIx64
", flags=%s, %" PRId32
"x%" PRId32, time,
110 ainput_flags_to_string(flags, ebuffer,
sizeof(ebuffer)), x, y);
114 Stream_Write_UINT16(s, MSG_AINPUT_MOUSE);
117 Stream_Write_UINT64(s, time);
118 Stream_Write_UINT64(s, flags);
119 Stream_Write_INT32(s, x);
120 Stream_Write_INT32(s, y);
121 Stream_SealLength(s);
124 EnterCriticalSection(&ainput->lock);
126 WINPR_ASSERT(callback);
127 WINPR_ASSERT(callback->channel);
128 WINPR_ASSERT(callback->channel->Write);
129 const UINT rc = callback->channel->Write(callback->channel, (ULONG)Stream_Length(s),
130 Stream_Buffer(s), NULL);
131 LeaveCriticalSection(&ainput->lock);
140static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback)
146 AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)callback->plugin;
147 WINPR_ASSERT(ainput);
150 EnterCriticalSection(&ainput->lock);
152 LeaveCriticalSection(&ainput->lock);
154 return CHANNEL_RC_OK;
158 WINPR_ATTR_UNUSED rdpSettings* settings)
160 AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)base;
161 AInputClientContext* context = (AInputClientContext*)calloc(1,
sizeof(AInputClientContext));
163 return CHANNEL_RC_NO_MEMORY;
165 context->handle = (
void*)base;
166 context->AInputSendInputEvent = ainput_send_input_event;
168 InitializeCriticalSection(&ainput->lock);
170 EnterCriticalSection(&ainput->lock);
171 ainput->context = context;
172 ainput->base.iface.pInterface = context;
173 LeaveCriticalSection(&ainput->lock);
174 return CHANNEL_RC_OK;
179 AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)base;
180 WINPR_ASSERT(ainput);
182 DeleteCriticalSection(&ainput->lock);
183 free(ainput->context);
186static const IWTSVirtualChannelCallback ainput_functions = { ainput_on_data_received,
188 ainput_on_close, NULL };
195FREERDP_ENTRY_POINT(UINT VCAPITYPE ainput_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
197 return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, AINPUT_DVC_CHANNEL_NAME,
199 &ainput_functions, init_plugin_cb, terminate_plugin_cb);