/src/FreeRDP/channels/ainput/client/ainput_main.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * FreeRDP: A Remote Desktop Protocol Implementation |
3 | | * Advanced Input Virtual Channel Extension |
4 | | * |
5 | | * Copyright 2022 Armin Novak <anovak@thincast.com> |
6 | | * Copyright 2022 Thincast Technologies GmbH |
7 | | * |
8 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
9 | | * you may not use this file except in compliance with the License. |
10 | | * You may obtain a copy of the License at |
11 | | * |
12 | | * http://www.apache.org/licenses/LICENSE-2.0 |
13 | | * |
14 | | * Unless required by applicable law or agreed to in writing, software |
15 | | * distributed under the License is distributed on an "AS IS" BASIS, |
16 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
17 | | * See the License for the specific language governing permissions and |
18 | | * limitations under the License. |
19 | | */ |
20 | | |
21 | | #include <freerdp/config.h> |
22 | | |
23 | | #include <stdio.h> |
24 | | #include <stdlib.h> |
25 | | |
26 | | #include <winpr/crt.h> |
27 | | #include <winpr/assert.h> |
28 | | #include <winpr/stream.h> |
29 | | #include <winpr/sysinfo.h> |
30 | | |
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> |
36 | | |
37 | | #include "../common/ainput_common.h" |
38 | | |
39 | 0 | #define TAG CHANNELS_TAG("ainput.client") |
40 | | |
41 | | typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN; |
42 | | struct AINPUT_PLUGIN_ |
43 | | { |
44 | | GENERIC_DYNVC_PLUGIN base; |
45 | | AInputClientContext* context; |
46 | | UINT32 MajorVersion; |
47 | | UINT32 MinorVersion; |
48 | | }; |
49 | | |
50 | | /** |
51 | | * Function description |
52 | | * |
53 | | * @return 0 on success, otherwise a Win32 error code |
54 | | */ |
55 | | static UINT ainput_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) |
56 | 0 | { |
57 | 0 | UINT16 type = 0; |
58 | 0 | AINPUT_PLUGIN* ainput = NULL; |
59 | 0 | GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback; |
60 | |
|
61 | 0 | WINPR_ASSERT(callback); |
62 | 0 | WINPR_ASSERT(data); |
63 | | |
64 | 0 | ainput = (AINPUT_PLUGIN*)callback->plugin; |
65 | 0 | WINPR_ASSERT(ainput); |
66 | | |
67 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, data, 2)) |
68 | 0 | return ERROR_NO_DATA; |
69 | 0 | Stream_Read_UINT16(data, type); |
70 | 0 | switch (type) |
71 | 0 | { |
72 | 0 | case MSG_AINPUT_VERSION: |
73 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, data, 8)) |
74 | 0 | return ERROR_NO_DATA; |
75 | 0 | Stream_Read_UINT32(data, ainput->MajorVersion); |
76 | 0 | Stream_Read_UINT32(data, ainput->MinorVersion); |
77 | 0 | break; |
78 | 0 | default: |
79 | 0 | WLog_WARN(TAG, "Received unsupported message type 0x%04" PRIx16, type); |
80 | 0 | break; |
81 | 0 | } |
82 | | |
83 | 0 | return CHANNEL_RC_OK; |
84 | 0 | } |
85 | | |
86 | | static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, INT32 x, INT32 y) |
87 | 0 | { |
88 | 0 | AINPUT_PLUGIN* ainput = NULL; |
89 | 0 | GENERIC_CHANNEL_CALLBACK* callback = NULL; |
90 | 0 | BYTE buffer[32] = { 0 }; |
91 | 0 | UINT64 time = 0; |
92 | 0 | wStream sbuffer = { 0 }; |
93 | 0 | wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); |
94 | |
|
95 | 0 | WINPR_ASSERT(s); |
96 | 0 | WINPR_ASSERT(context); |
97 | | |
98 | 0 | time = GetTickCount64(); |
99 | 0 | ainput = (AINPUT_PLUGIN*)context->handle; |
100 | 0 | WINPR_ASSERT(ainput); |
101 | | |
102 | 0 | if (ainput->MajorVersion != AINPUT_VERSION_MAJOR) |
103 | 0 | { |
104 | 0 | WLog_WARN(TAG, "Unsupported channel version %" PRIu32 ".%" PRIu32 ", aborting.", |
105 | 0 | ainput->MajorVersion, ainput->MinorVersion); |
106 | 0 | return CHANNEL_RC_UNSUPPORTED_VERSION; |
107 | 0 | } |
108 | 0 | callback = ainput->base.listener_callback->channel_callback; |
109 | 0 | WINPR_ASSERT(callback); |
110 | | |
111 | 0 | { |
112 | 0 | char ebuffer[128] = { 0 }; |
113 | 0 | WLog_VRB(TAG, "sending timestamp=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32, time, |
114 | 0 | ainput_flags_to_string(flags, ebuffer, sizeof(ebuffer)), x, y); |
115 | 0 | } |
116 | | |
117 | | /* Message type */ |
118 | 0 | Stream_Write_UINT16(s, MSG_AINPUT_MOUSE); |
119 | | |
120 | | /* Event data */ |
121 | 0 | Stream_Write_UINT64(s, time); |
122 | 0 | Stream_Write_UINT64(s, flags); |
123 | 0 | Stream_Write_INT32(s, x); |
124 | 0 | Stream_Write_INT32(s, y); |
125 | 0 | Stream_SealLength(s); |
126 | | |
127 | | /* ainput back what we have received. AINPUT does not have any message IDs. */ |
128 | 0 | WINPR_ASSERT(callback->channel); |
129 | 0 | WINPR_ASSERT(callback->channel->Write); |
130 | 0 | return callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s), |
131 | 0 | NULL); |
132 | 0 | } |
133 | | |
134 | | /** |
135 | | * Function description |
136 | | * |
137 | | * @return 0 on success, otherwise a Win32 error code |
138 | | */ |
139 | | static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback) |
140 | 0 | { |
141 | 0 | GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback; |
142 | |
|
143 | 0 | free(callback); |
144 | |
|
145 | 0 | return CHANNEL_RC_OK; |
146 | 0 | } |
147 | | |
148 | | static UINT init_plugin_cb(GENERIC_DYNVC_PLUGIN* base, WINPR_ATTR_UNUSED rdpContext* rcontext, |
149 | | WINPR_ATTR_UNUSED rdpSettings* settings) |
150 | 0 | { |
151 | 0 | AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)base; |
152 | 0 | AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext)); |
153 | 0 | if (!context) |
154 | 0 | return CHANNEL_RC_NO_MEMORY; |
155 | | |
156 | 0 | context->handle = (void*)base; |
157 | 0 | context->AInputSendInputEvent = ainput_send_input_event; |
158 | |
|
159 | 0 | ainput->context = context; |
160 | 0 | ainput->base.iface.pInterface = context; |
161 | 0 | return CHANNEL_RC_OK; |
162 | 0 | } |
163 | | |
164 | | static void terminate_plugin_cb(GENERIC_DYNVC_PLUGIN* base) |
165 | 0 | { |
166 | 0 | AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)base; |
167 | 0 | free(ainput->context); |
168 | 0 | } |
169 | | |
170 | | static const IWTSVirtualChannelCallback ainput_functions = { ainput_on_data_received, |
171 | | NULL, /* Open */ |
172 | | ainput_on_close, NULL }; |
173 | | |
174 | | /** |
175 | | * Function description |
176 | | * |
177 | | * @return 0 on success, otherwise a Win32 error code |
178 | | */ |
179 | | FREERDP_ENTRY_POINT(UINT VCAPITYPE ainput_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)) |
180 | 0 | { |
181 | 0 | return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, AINPUT_DVC_CHANNEL_NAME, |
182 | 0 | sizeof(AINPUT_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK), |
183 | 0 | &ainput_functions, init_plugin_cb, terminate_plugin_cb); |
184 | 0 | } |