20#include <winpr/cast.h>
22#include <freerdp/config.h>
30#include <freerdp/client.h>
32#include <freerdp/freerdp.h>
33#include <freerdp/addin.h>
34#include <freerdp/assistance.h>
35#include <freerdp/client/file.h>
36#include <freerdp/utils/passphrase.h>
37#include <freerdp/client/cmdline.h>
38#include <freerdp/client/channels.h>
39#include <freerdp/utils/smartcardlogon.h>
41#if defined(CHANNEL_AINPUT_CLIENT)
42#include <freerdp/client/ainput.h>
43#include <freerdp/channels/ainput.h>
46#if defined(CHANNEL_VIDEO_CLIENT)
47#include <freerdp/client/video.h>
48#include <freerdp/channels/video.h>
51#if defined(CHANNEL_RDPGFX_CLIENT)
52#include <freerdp/client/rdpgfx.h>
53#include <freerdp/channels/rdpgfx.h>
54#include <freerdp/gdi/gfx.h>
57#if defined(CHANNEL_GEOMETRY_CLIENT)
58#include <freerdp/client/geometry.h>
59#include <freerdp/channels/geometry.h>
62#if defined(CHANNEL_GEOMETRY_CLIENT) || defined(CHANNEL_VIDEO_CLIENT)
63#include <freerdp/gdi/video.h>
67#include <freerdp/utils/http.h>
68#include <freerdp/utils/aad.h>
71#include <freerdp/log.h>
72#define TAG CLIENT_TAG("common")
74static void set_default_callbacks(freerdp* instance)
76 WINPR_ASSERT(instance);
77 instance->AuthenticateEx = client_cli_authenticate_ex;
78 instance->ChooseSmartcard = client_cli_choose_smartcard;
79 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
80 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
81 instance->PresentGatewayMessage = client_cli_present_gateway_message;
82 instance->LogonErrorInfo = client_cli_logon_error_info;
83 instance->GetAccessToken = client_cli_get_access_token;
84 instance->RetryDialog = client_common_retry_dialog;
87static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
89 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
91 WINPR_ASSERT(instance);
92 WINPR_ASSERT(context);
94 instance->LoadChannels = freerdp_client_load_channels;
95 set_default_callbacks(instance);
97 pEntryPoints = instance->pClientEntryPoints;
98 WINPR_ASSERT(pEntryPoints);
99 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
102static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
104 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
106 WINPR_ASSERT(instance);
107 WINPR_ASSERT(context);
109 pEntryPoints = instance->pClientEntryPoints;
110 WINPR_ASSERT(pEntryPoints);
111 IFCALL(pEntryPoints->ClientFree, instance, context);
116rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
118 freerdp* instance = NULL;
119 rdpContext* context = NULL;
124 IFCALL(pEntryPoints->GlobalInit);
125 instance = freerdp_new();
130 instance->ContextSize = pEntryPoints->ContextSize;
131 instance->ContextNew = freerdp_client_common_new;
132 instance->ContextFree = freerdp_client_common_free;
133 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
135 if (!instance->pClientEntryPoints)
138 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
140 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
143 context = instance->context;
144 context->instance = instance;
146#if defined(WITH_CHANNELS)
147 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
154 free(instance->pClientEntryPoints);
156 freerdp_free(instance);
160void freerdp_client_context_free(rdpContext* context)
162 freerdp* instance = NULL;
167 instance = context->instance;
171 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
172 freerdp_context_free(instance);
175 IFCALL(pEntryPoints->GlobalUninit);
177 free(instance->pClientEntryPoints);
178 freerdp_free(instance);
182int freerdp_client_start(rdpContext* context)
184 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
186 if (!context || !context->instance || !context->instance->pClientEntryPoints)
187 return ERROR_BAD_ARGUMENTS;
190 set_default_callbacks(context->instance);
192 pEntryPoints = context->instance->pClientEntryPoints;
193 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
196int freerdp_client_stop(rdpContext* context)
198 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
200 if (!context || !context->instance || !context->instance->pClientEntryPoints)
201 return ERROR_BAD_ARGUMENTS;
203 pEntryPoints = context->instance->pClientEntryPoints;
204 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
207freerdp* freerdp_client_get_instance(rdpContext* context)
209 if (!context || !context->instance)
212 return context->instance;
215HANDLE freerdp_client_get_thread(rdpContext* context)
220 return ((rdpClientContext*)context)->thread;
223static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
248 settings, FreeRDP_GatewayPassword,
288int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
292 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown, NULL,
296int freerdp_client_settings_parse_command_line_ex(
298 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
308 status = freerdp_client_settings_parse_command_line_arguments_ex(
309 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
316 if (!freerdp_client_settings_post_process(settings))
319 const char* name = argv[0];
320 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
321 freerdp_get_build_config());
325int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
327 rdpFile* file = NULL;
329 file = freerdp_client_rdp_file_new();
334 if (!freerdp_client_parse_rdp_file(file, filename))
337 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
342 freerdp_client_rdp_file_free(file);
346int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
349 rdpFile* file = NULL;
351 file = freerdp_client_rdp_file_new();
356 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
357 freerdp_client_populate_settings_from_rdp_file(file, settings))
362 freerdp_client_rdp_file_free(file);
366int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
369 rdpFile* file = NULL;
371 file = freerdp_client_rdp_file_new();
376 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
379 if (!freerdp_client_write_rdp_file(file, filename, unicode))
384 freerdp_client_rdp_file_free(file);
388int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
392 char* filename = NULL;
393 char* password = NULL;
394 rdpAssistanceFile* file = NULL;
396 if (!settings || !argv || (argc < 2))
401 for (
int x = 2; x < argc; x++)
403 const char* key = strstr(argv[x],
"assistance:");
406 password = strchr(key,
':') + 1;
409 file = freerdp_assistance_file_new();
414 status = freerdp_assistance_parse_file(file, filename, password);
419 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
424 freerdp_assistance_file_free(file);
441static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
442 char** password,
char** domain)
444 static const size_t password_size = 512;
445 const char* auth[] = {
"Username: ",
"Domain: ",
"Password: " };
446 const char* authPin[] = {
"Username: ",
"Domain: ",
"Smartcard-Pin: " };
447 const char* gw[] = {
"GatewayUsername: ",
"GatewayDomain: ",
"GatewayPassword: " };
448 const char** prompt = NULL;
449 BOOL pinOnly = FALSE;
451 WINPR_ASSERT(instance);
452 WINPR_ASSERT(instance->context);
453 WINPR_ASSERT(instance->context->settings);
457 case AUTH_SMARTCARD_PIN:
475 if (!username || !password || !domain)
478 if (!*username && !pinOnly)
480 size_t username_size = 0;
481 printf(
"%s", prompt[0]);
482 (void)fflush(stdout);
484 if (freerdp_interruptible_get_line(instance->context, username, &username_size, stdin) < 0)
486 char ebuffer[256] = { 0 };
487 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
488 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
494 *username = StrSep(username,
"\r");
495 *username = StrSep(username,
"\n");
499 if (!*domain && !pinOnly)
501 size_t domain_size = 0;
502 printf(
"%s", prompt[1]);
503 (void)fflush(stdout);
505 if (freerdp_interruptible_get_line(instance->context, domain, &domain_size, stdin) < 0)
507 char ebuffer[256] = { 0 };
508 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
509 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
515 *domain = StrSep(domain,
"\r");
516 *domain = StrSep(domain,
"\n");
522 *password = calloc(password_size,
sizeof(
char));
527 const BOOL fromStdin =
529 if (freerdp_passphrase_read(instance->context, prompt[2], *password, password_size,
545BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
546 rdp_auth_reason reason)
548 WINPR_ASSERT(instance);
549 WINPR_ASSERT(username);
550 WINPR_ASSERT(password);
551 WINPR_ASSERT(domain);
560 case AUTH_SMARTCARD_PIN:
561 if ((*username) && (*password))
572 return client_cli_authenticate_raw(instance, reason, username, password, domain);
575BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
576 DWORD count, DWORD* choice, BOOL gateway)
578 unsigned long answer = 0;
581 printf(
"Multiple smartcards are available for use:\n");
582 for (DWORD i = 0; i < count; i++)
585 char* reader = ConvertWCharToUtf8Alloc(cert->reader, NULL);
586 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, NULL);
589 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
590 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
591 cert->issuer, cert->upn);
594 free(container_name);
599 char input[10] = { 0 };
601 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
602 gateway ?
"gateway authentication" :
"logon", count - 1);
603 (void)fflush(stdout);
604 if (!fgets(input, 10, stdin))
606 WLog_ERR(TAG,
"could not read from stdin");
610 answer = strtoul(input, &p, 10);
611 if ((*p ==
'\n' && p != input) && answer < count)
613 *choice = (UINT32)answer;
619#if defined(WITH_FREERDP_DEPRECATED)
620BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
624 WLog_INFO(TAG,
"Authentication via smartcard");
628 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
631BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
633 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
637static DWORD client_cli_accept_certificate(freerdp* instance)
641 WINPR_ASSERT(instance);
642 WINPR_ASSERT(instance->context);
644 const rdpSettings* settings = instance->context->settings;
645 WINPR_ASSERT(settings);
653 printf(
"Do you trust the above certificate? (Y/T/N) ");
654 (void)fflush(stdout);
655 answer = freerdp_interruptible_getc(instance->context, stdin);
657 if ((answer == EOF) || feof(stdin))
659 printf(
"\nError: Could not read answer from stdin.\n");
667 answer = freerdp_interruptible_getc(instance->context, stdin);
674 answer = freerdp_interruptible_getc(instance->context, stdin);
681 answer = freerdp_interruptible_getc(instance->context, stdin);
707#if defined(WITH_FREERDP_DEPRECATED)
708DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
709 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
711 WINPR_UNUSED(common_name);
712 WINPR_UNUSED(host_mismatch);
714 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
715 printf(
"Certificate details:\n");
716 printf(
"\tSubject: %s\n", subject);
717 printf(
"\tIssuer: %s\n", issuer);
718 printf(
"\tThumbprint: %s\n", fingerprint);
719 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
720 "the CA certificate in your certificate store, or the certificate has expired.\n"
721 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
722 return client_cli_accept_certificate(instance);
726static char* client_cli_pem_cert(
const char* pem)
728 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
732 char* fp = freerdp_certificate_get_fingerprint(cert);
733 char* start = freerdp_certificate_get_validity(cert, TRUE);
734 char* end = freerdp_certificate_get_validity(cert, FALSE);
735 freerdp_certificate_free(cert);
739 winpr_asprintf(&str, &slen,
742 "\tThumbprint: %s\n",
765DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
766 const char* common_name,
const char* subject,
767 const char* issuer,
const char* fingerprint, DWORD flags)
769 const char* type =
"RDP-Server";
771 WINPR_ASSERT(instance);
772 WINPR_ASSERT(instance->context);
773 WINPR_ASSERT(instance->context->settings);
775 if (flags & VERIFY_CERT_FLAG_GATEWAY)
776 type =
"RDP-Gateway";
778 if (flags & VERIFY_CERT_FLAG_REDIRECT)
779 type =
"RDP-Redirect";
781 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
782 printf(
"\tCommon Name: %s\n", common_name);
783 printf(
"\tSubject: %s\n", subject);
784 printf(
"\tIssuer: %s\n", issuer);
788 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
790 char* str = client_cli_pem_cert(fingerprint);
795 printf(
"\tThumbprint: %s\n", fingerprint);
797 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
798 "the CA certificate in your certificate store, or the certificate has expired.\n"
799 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
800 return client_cli_accept_certificate(instance);
818#if defined(WITH_FREERDP_DEPRECATED)
819DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
820 const char* subject,
const char* issuer,
821 const char* fingerprint,
const char* old_subject,
822 const char* old_issuer,
const char* old_fingerprint)
824 WINPR_UNUSED(common_name);
826 printf(
"WARNING: This callback is deprecated, migrate to "
827 "client_cli_verify_changed_certificate_ex\n");
828 printf(
"!!! Certificate has changed !!!\n");
830 printf(
"New Certificate details:\n");
831 printf(
"\tSubject: %s\n", subject);
832 printf(
"\tIssuer: %s\n", issuer);
833 printf(
"\tThumbprint: %s\n", fingerprint);
835 printf(
"Old Certificate details:\n");
836 printf(
"\tSubject: %s\n", old_subject);
837 printf(
"\tIssuer: %s\n", old_issuer);
838 printf(
"\tThumbprint: %s\n", old_fingerprint);
840 printf(
"The above X.509 certificate does not match the certificate used for previous "
842 "This may indicate that the certificate has been tampered with.\n"
843 "Please contact the administrator of the RDP server and clarify.\n");
844 return client_cli_accept_certificate(instance);
867DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
868 const char* common_name,
const char* subject,
869 const char* issuer,
const char* fingerprint,
870 const char* old_subject,
const char* old_issuer,
871 const char* old_fingerprint, DWORD flags)
873 const char* type =
"RDP-Server";
875 WINPR_ASSERT(instance);
876 WINPR_ASSERT(instance->context);
877 WINPR_ASSERT(instance->context->settings);
879 if (flags & VERIFY_CERT_FLAG_GATEWAY)
880 type =
"RDP-Gateway";
882 if (flags & VERIFY_CERT_FLAG_REDIRECT)
883 type =
"RDP-Redirect";
885 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
887 printf(
"New Certificate details:\n");
888 printf(
"\tCommon Name: %s\n", common_name);
889 printf(
"\tSubject: %s\n", subject);
890 printf(
"\tIssuer: %s\n", issuer);
894 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
896 char* str = client_cli_pem_cert(fingerprint);
901 printf(
"\tThumbprint: %s\n", fingerprint);
903 printf(
"Old Certificate details:\n");
904 printf(
"\tSubject: %s\n", old_subject);
905 printf(
"\tIssuer: %s\n", old_issuer);
909 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
911 char* str = client_cli_pem_cert(old_fingerprint);
916 printf(
"\tThumbprint: %s\n", old_fingerprint);
918 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
920 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
921 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
922 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
923 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
926 printf(
"The above X.509 certificate does not match the certificate used for previous "
928 "This may indicate that the certificate has been tampered with.\n"
929 "Please contact the administrator of the RDP server and clarify.\n");
930 return client_cli_accept_certificate(instance);
933BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
934 BOOL isConsentMandatory,
size_t length,
935 const WCHAR* message)
938 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
940 WINPR_ASSERT(instance);
941 WINPR_ASSERT(instance->context);
942 WINPR_ASSERT(instance->context->settings);
944 if (!isDisplayMandatory && !isConsentMandatory)
947 printf(
"%s:\n", msgType);
949 printf(
"%.*S\n", (
int)length, message);
952 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR), NULL);
955 printf(
"Failed to convert message!\n");
963 while (isConsentMandatory)
965 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
966 (void)fflush(stdout);
967 answer = freerdp_interruptible_getc(instance->context, stdin);
969 if ((answer == EOF) || feof(stdin))
971 printf(
"\nError: Could not read answer from stdin.\n");
979 answer = freerdp_interruptible_getc(instance->context, stdin);
986 (void)freerdp_interruptible_getc(instance->context, stdin);
999static char* extract_authorization_code(
char* url)
1003 for (
char* p = strchr(url,
'?'); p++ != NULL; p = strchr(p,
'&'))
1005 if (strncmp(p,
"code=", 5) != 0)
1011 end = strchr(p,
'&');
1021#if defined(WITH_AAD)
1022static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1023 const char* req_cnf,
char** token)
1025 WINPR_ASSERT(instance);
1026 WINPR_ASSERT(instance->context);
1030 char* token_request = NULL;
1031 char* redirect_uri = NULL;
1032 size_t redirec_uri_len = 0;
1034 WINPR_ASSERT(scope);
1035 WINPR_ASSERT(req_cnf);
1036 WINPR_ASSERT(token);
1041 const char* client_id =
1046 winpr_asprintf(&redirect_uri, &redirec_uri_len,
1047 "ms-appx-web%%3a%%2f%%2fMicrosoft.AAD.BrokerPlugin%%2f%s", client_id);
1051 const char* ep = freerdp_utils_aad_get_wellknown_string(instance->context,
1052 AAD_WELLKNOWN_authorization_endpoint);
1053 printf(
"Browse to: %s?client_id=%s&response_type="
1054 "code&scope=%s&redirect_uri=%s"
1056 ep, client_id, scope, redirect_uri);
1057 printf(
"Paste redirect URL here: \n");
1059 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1062 char* code = extract_authorization_code(url);
1066 if (winpr_asprintf(&token_request, &size,
1067 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%"
1069 code, client_id, scope, redirect_uri, req_cnf) <= 0)
1072 rc = client_common_get_access_token(instance, token_request, token);
1076 free(token_request);
1078 return rc && (*token != NULL);
1081static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1083 WINPR_ASSERT(instance);
1084 WINPR_ASSERT(instance->context);
1088 char* token_request = NULL;
1089 char* redirect_uri = NULL;
1090 size_t redirec_uri_len = 0;
1091 const char* scope =
"https%3A%2F%2Fwww.wvd.microsoft.com%2F.default";
1093 WINPR_ASSERT(token);
1099 const char* client_id =
1102 FreeRDP_GatewayAzureActiveDirectory);
1103 const BOOL useTenant =
1105 const char* tenantid =
"common";
1109 if (!base || !tenantid || !client_id)
1112 winpr_asprintf(&redirect_uri, &redirec_uri_len,
1113 "https%%3A%%2F%%2F%s%%2F%s%%2Foauth2%%2Fnativeclient", base, tenantid);
1117 const char* ep = freerdp_utils_aad_get_wellknown_string(instance->context,
1118 AAD_WELLKNOWN_authorization_endpoint);
1119 printf(
"Browse to: %s?client_id=%s&response_type="
1120 "code&scope=%s&redirect_uri=%s"
1122 ep, client_id, scope, redirect_uri);
1123 printf(
"Paste redirect URL here: \n");
1125 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1128 char* code = extract_authorization_code(url);
1133 &token_request, &size,
1134 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s", code,
1135 client_id, scope, redirect_uri) <= 0)
1138 rc = client_common_get_access_token(instance, token_request, token);
1142 free(token_request);
1144 return rc && (*token != NULL);
1148BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1151 WINPR_ASSERT(instance);
1152 WINPR_ASSERT(token);
1154#if !defined(WITH_AAD)
1155 WLog_ERR(TAG,
"Build does not support AAD authentication");
1160 case ACCESS_TOKEN_TYPE_AAD:
1165 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1172 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1176 va_start(ap, count);
1177 const char* scope = va_arg(ap,
const char*);
1178 const char* req_cnf = va_arg(ap,
const char*);
1179 const BOOL rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1183 case ACCESS_TOKEN_TYPE_AVD:
1186 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1189 return client_cli_get_avd_access_token(instance, token);
1191 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%" PRIuz
"], aborting", tokenType);
1197BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1200 WINPR_ASSERT(request);
1201 WINPR_ASSERT(token);
1205 BYTE* response = NULL;
1206 size_t response_length = 0;
1208 wLog* log = WLog_Get(TAG);
1210 const char* token_ep =
1211 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1212 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1214 WLog_ERR(TAG,
"access token request failed");
1218 if (resp_code != HTTP_STATUS_OK)
1220 char buffer[64] = { 0 };
1222 WLog_Print(log, WLOG_ERROR,
1223 "Server unwilling to provide access token; returned status code %s",
1224 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1225 if (response_length > 0)
1226 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1230 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1242SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1245 WINPR_UNUSED(instance);
1246 WINPR_ASSERT(instance->context);
1247 WINPR_UNUSED(userarg);
1248 WINPR_ASSERT(instance);
1251 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1253 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1259 if (strcmp(what,
"arm-transport") == 0)
1260 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1263 const rdpSettings* settings = instance->context->settings;
1267 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1276 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1277 "tech support for help if this keeps happening.",
1282 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1283 what, current, max, delay);
1284 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1287BOOL client_auto_reconnect(freerdp* instance)
1289 return client_auto_reconnect_ex(instance, NULL);
1292BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1296 UINT32 numRetries = 0;
1297 rdpSettings* settings = NULL;
1302 WINPR_ASSERT(instance->context);
1304 settings = instance->context->settings;
1305 WINPR_ASSERT(settings);
1307 const UINT32 maxRetries =
1311 error = freerdp_error_info(instance);
1314 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1316 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1317 freerdp_get_error_info_string(error));
1319 case ERRINFO_SUCCESS:
1321 WLog_INFO(TAG,
"Network disconnect!");
1333 switch (freerdp_get_last_error(instance->context))
1335 case FREERDP_ERROR_CONNECT_CANCELLED:
1336 WLog_WARN(TAG,
"Connection aborted by user");
1346 if ((maxRetries > 0) && (numRetries++ >= maxRetries))
1352 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1354 IFCALL(instance->RetryDialog, instance,
"connection", numRetries, NULL);
1356 if (freerdp_reconnect(instance))
1359 switch (freerdp_get_last_error(instance->context))
1361 case FREERDP_ERROR_CONNECT_CANCELLED:
1362 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1367 for (UINT32 x = 0; x < 50; x++)
1369 if (!IFCALLRESULT(TRUE, window_events, instance))
1376 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1380int freerdp_client_common_stop(rdpContext* context)
1382 rdpClientContext* cctx = (rdpClientContext*)context;
1385 freerdp_abort_connect_context(&cctx->context);
1389 (void)WaitForSingleObject(cctx->thread, INFINITE);
1390 (void)CloseHandle(cctx->thread);
1391 cctx->thread = NULL;
1397#if defined(CHANNEL_ENCOMSP_CLIENT)
1398BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1400 rdpClientContext* cctx = NULL;
1406 cctx = (rdpClientContext*)encomsp->custom;
1408 state = cctx->controlToggle;
1409 cctx->controlToggle = !cctx->controlToggle;
1410 return freerdp_client_encomsp_set_control(encomsp, state);
1413BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1420 pdu.ParticipantId = encomsp->participantId;
1421 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1424 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1426 encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1432client_encomsp_participant_created(EncomspClientContext* context,
1435 rdpClientContext* cctx = NULL;
1436 rdpSettings* settings = NULL;
1439 if (!context || !context->custom || !participantCreated)
1440 return ERROR_INVALID_PARAMETER;
1442 cctx = (rdpClientContext*)context->custom;
1445 settings = cctx->context.settings;
1446 WINPR_ASSERT(settings);
1448 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1449 context->participantId = participantCreated->ParticipantId;
1452 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1453 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1455 if (!freerdp_client_encomsp_set_control(context, TRUE))
1456 return ERROR_INTERNAL_ERROR;
1462 return ERROR_INTERNAL_ERROR;
1465 return CHANNEL_RC_OK;
1468static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1470 cctx->encomsp = encomsp;
1471 encomsp->custom = (
void*)cctx;
1472 encomsp->ParticipantCreated = client_encomsp_participant_created;
1475static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1479 encomsp->custom = NULL;
1480 encomsp->ParticipantCreated = NULL;
1484 cctx->encomsp = NULL;
1488void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1489 const ChannelConnectedEventArgs* e)
1491 rdpClientContext* cctx = (rdpClientContext*)context;
1499#if defined(CHANNEL_AINPUT_CLIENT)
1500 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1501 cctx->ainput = (AInputClientContext*)e->pInterface;
1503#if defined(CHANNEL_RDPEI_CLIENT)
1504 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1506 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1509#if defined(CHANNEL_RDPGFX_CLIENT)
1510 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1512 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1515#if defined(CHANNEL_GEOMETRY_CLIENT)
1516 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1518 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1521#if defined(CHANNEL_VIDEO_CLIENT)
1522 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1524 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1526 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1528 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1531#if defined(CHANNEL_ENCOMSP_CLIENT)
1532 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1534 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1539void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1540 const ChannelDisconnectedEventArgs* e)
1542 rdpClientContext* cctx = (rdpClientContext*)context;
1550#if defined(CHANNEL_AINPUT_CLIENT)
1551 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1552 cctx->ainput = NULL;
1554#if defined(CHANNEL_RDPEI_CLIENT)
1555 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1560#if defined(CHANNEL_RDPGFX_CLIENT)
1561 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1563 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1566#if defined(CHANNEL_GEOMETRY_CLIENT)
1567 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1569 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1572#if defined(CHANNEL_VIDEO_CLIENT)
1573 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1575 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1577 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1579 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1582#if defined(CHANNEL_ENCOMSP_CLIENT)
1583 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1585 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1590BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1592 BOOL handled = FALSE;
1596#if defined(CHANNEL_AINPUT_CLIENT)
1603 INT32 value = mflags & 0xFF;
1605 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1606 value = -1 * (0x100 - value);
1612 if (mflags & PTR_FLAGS_WHEEL)
1614 flags |= AINPUT_FLAGS_WHEEL;
1618 if (mflags & PTR_FLAGS_HWHEEL)
1620 flags |= AINPUT_FLAGS_WHEEL;
1624 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1625 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1626 if (rc == CHANNEL_RC_OK)
1632 freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1637#if defined(CHANNEL_AINPUT_CLIENT)
1638static INLINE BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1643 WINPR_ASSERT(cctx->ainput);
1644 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1646 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1648 return rc == CHANNEL_RC_OK;
1652BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1655 BOOL handled = FALSE;
1659 const BOOL haveRelative =
1661 if (relative && haveRelative)
1663 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1664 WINPR_ASSERTING_INT_CAST(int16_t, x),
1665 WINPR_ASSERTING_INT_CAST(int16_t, y));
1668#if defined(CHANNEL_AINPUT_CLIENT)
1673 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1674 flags |= AINPUT_FLAGS_HAVE_REL;
1677 flags |= AINPUT_FLAGS_REL;
1679 if (mflags & PTR_FLAGS_DOWN)
1680 flags |= AINPUT_FLAGS_DOWN;
1681 if (mflags & PTR_FLAGS_BUTTON1)
1682 flags |= AINPUT_FLAGS_BUTTON1;
1683 if (mflags & PTR_FLAGS_BUTTON2)
1684 flags |= AINPUT_FLAGS_BUTTON2;
1685 if (mflags & PTR_FLAGS_BUTTON3)
1686 flags |= AINPUT_FLAGS_BUTTON3;
1687 if (mflags & PTR_FLAGS_MOVE)
1688 flags |= AINPUT_FLAGS_MOVE;
1689 handled = ainput_send_diff_event(cctx, flags, x, y);
1699 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1706 freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1707 (UINT16)cctx->lastY);
1712BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1715 BOOL handled = FALSE;
1718 const BOOL haveRelative =
1720 if (relative && haveRelative)
1722 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1723 WINPR_ASSERTING_INT_CAST(int16_t, x),
1724 WINPR_ASSERTING_INT_CAST(int16_t, y));
1727#if defined(CHANNEL_AINPUT_CLIENT)
1733 flags |= AINPUT_FLAGS_REL;
1734 if (mflags & PTR_XFLAGS_DOWN)
1735 flags |= AINPUT_FLAGS_DOWN;
1736 if (mflags & PTR_XFLAGS_BUTTON1)
1737 flags |= AINPUT_XFLAGS_BUTTON1;
1738 if (mflags & PTR_XFLAGS_BUTTON2)
1739 flags |= AINPUT_XFLAGS_BUTTON2;
1741 handled = ainput_send_diff_event(cctx, flags, x, y);
1751 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1758 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1759 (UINT16)cctx->lastY);
1765static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1768 WINPR_ASSERT(contact);
1770#if defined(CHANNEL_RDPEI_CLIENT)
1771 RdpeiClientContext* rdpei = cctx->rdpei;
1776 flags |= PTR_FLAGS_BUTTON1;
1778 WINPR_ASSERT(contact->x <= UINT16_MAX);
1779 WINPR_ASSERT(contact->y <= UINT16_MAX);
1780 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1786 if (rdpei->TouchRawEvent)
1788 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1789 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1790 ? CONTACT_DATA_PRESSURE_PRESENT
1793 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1794 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1795 RDPINPUT_CONTACT_FLAG_INCONTACT,
1796 contactFlags, contact->pressure);
1797 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1798 contactFlags, contact->pressure);
1802 WINPR_ASSERT(rdpei->TouchEnd);
1803 rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1807 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1808 "-DWITH_CHANNELS=ON");
1814static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1817 WINPR_ASSERT(contact);
1819#if defined(CHANNEL_RDPEI_CLIENT)
1820 RdpeiClientContext* rdpei = cctx->rdpei;
1826 flags |= PTR_FLAGS_DOWN;
1827 flags |= PTR_FLAGS_MOVE;
1828 flags |= PTR_FLAGS_BUTTON1;
1830 WINPR_ASSERT(contact->x <= UINT16_MAX);
1831 WINPR_ASSERT(contact->y <= UINT16_MAX);
1832 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1838 if (rdpei->TouchRawEvent)
1840 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1841 RDPINPUT_CONTACT_FLAG_INCONTACT;
1842 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1843 ? CONTACT_DATA_PRESSURE_PRESENT
1845 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1846 contactFlags, contact->pressure);
1850 WINPR_ASSERT(rdpei->TouchBegin);
1851 rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1855 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1856 "-DWITH_CHANNELS=ON");
1862static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1865 WINPR_ASSERT(contact);
1867#if defined(CHANNEL_RDPEI_CLIENT)
1868 RdpeiClientContext* rdpei = cctx->rdpei;
1873 flags |= PTR_FLAGS_MOVE;
1875 WINPR_ASSERT(contact->x <= UINT16_MAX);
1876 WINPR_ASSERT(contact->y <= UINT16_MAX);
1877 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1883 if (rdpei->TouchRawEvent)
1885 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1886 RDPINPUT_CONTACT_FLAG_INCONTACT;
1887 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1888 ? CONTACT_DATA_PRESSURE_PRESENT
1890 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1891 contactFlags, contact->pressure);
1895 WINPR_ASSERT(rdpei->TouchUpdate);
1896 rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
1900 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1901 "-DWITH_CHANNELS=ON");
1907static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
1908 UINT32 pressure, INT32 x, INT32 y,
1912 WINPR_ASSERT(pcontact);
1914 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
1918 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
1919 if (newcontact || (contact->id == touchId))
1921 contact->id = touchId;
1922 contact->flags = flags;
1923 contact->pressure = pressure;
1927 *pcontact = *contact;
1929 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
1942BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
1943 UINT32 pressure, INT32 x, INT32 y)
1945 const UINT32 mask = FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION;
1950 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
1953 switch (flags & mask)
1955 case FREERDP_TOUCH_DOWN:
1956 return freerdp_handle_touch_down(cctx, &contact);
1957 case FREERDP_TOUCH_UP:
1958 return freerdp_handle_touch_up(cctx, &contact);
1959 case FREERDP_TOUCH_MOTION:
1960 return freerdp_handle_touch_motion(cctx, &contact);
1962 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %d, ignoring", flags);
1967BOOL freerdp_client_load_channels(freerdp* instance)
1969 WINPR_ASSERT(instance);
1970 WINPR_ASSERT(instance->context);
1972 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
1974 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
1980int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
1982 const char* str_data = freerdp_get_logon_error_info_data(data);
1983 const char* str_type = freerdp_get_logon_error_info_type(type);
1985 if (!instance || !instance->context)
1988 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
1992static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
1997 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2000 if (deviceid == pen->deviceid)
2010static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2013 static const INT32 null_deviceid = 0;
2016 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2017 if (freerdp_client_is_pen(cctx, deviceid))
2019 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2030 pen->deviceid = deviceid;
2031 pen->max_pressure = pressure;
2034 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2038 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2042BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2044 if ((flags & FREERDP_PEN_REGISTER) != 0)
2048 va_start(args, deviceid);
2049 double pressure = va_arg(args,
double);
2051 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2057 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2061 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2063 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2065 RdpeiClientContext* rdpei = cctx->rdpei;
2066 WINPR_ASSERT(rdpei);
2068 UINT32 normalizedpressure = 1024;
2071 UINT16 rotation = 0;
2075 va_start(args, deviceid);
2077 x = va_arg(args, INT32);
2078 y = va_arg(args, INT32);
2079 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2081 const double pressure = va_arg(args,
double);
2082 const double np = (pressure * 1024.0) / pen->max_pressure;
2083 normalizedpressure = (UINT32)lround(np);
2084 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2085 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2087 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2089 const unsigned arg = va_arg(args,
unsigned);
2090 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2091 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2093 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2095 const int arg = va_arg(args,
int);
2096 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2097 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2099 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2101 const int arg = va_arg(args,
int);
2102 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2103 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2107 if ((flags & FREERDP_PEN_PRESS) != 0)
2111 flags = FREERDP_PEN_MOTION |
2112 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2113 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2114 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2116 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2118 if (!pen->pressed ||
2119 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2120 flags = FREERDP_PEN_MOTION |
2121 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2123 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2126 flags |= pen->flags;
2127 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2128 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2129 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2130 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2134 if ((flags & FREERDP_PEN_PRESS) != 0)
2136 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2137 pen->hovering = FALSE;
2138 pen->pressed = TRUE;
2140 WINPR_ASSERT(rdpei->PenBegin);
2141 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2142 normalizedpressure, rotation, tiltX, tiltY);
2143 return rc == CHANNEL_RC_OK;
2145 else if ((flags & FREERDP_PEN_MOTION) != 0)
2147 UINT rc = ERROR_INTERNAL_ERROR;
2150 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2153 WINPR_ASSERT(rdpei->PenUpdate);
2154 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2155 rotation, tiltX, tiltY);
2157 else if (pen->hovering)
2159 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2161 WINPR_ASSERT(rdpei->PenHoverUpdate);
2162 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2163 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2167 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2168 pen->hovering = TRUE;
2170 WINPR_ASSERT(rdpei->PenHoverBegin);
2171 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2172 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2174 return rc == CHANNEL_RC_OK;
2176 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2178 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2179 pen->pressed = FALSE;
2180 pen->hovering = TRUE;
2182 WINPR_ASSERT(rdpei->PenUpdate);
2183 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2184 normalizedpressure, rotation, tiltX, tiltY);
2185 if (rc != CHANNEL_RC_OK)
2187 WINPR_ASSERT(rdpei->PenEnd);
2188 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2189 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2190 return re == CHANNEL_RC_OK;
2193 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2197BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2201 RdpeiClientContext* rdpei = cctx->rdpei;
2206 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2211 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2212 pen->hovering = FALSE;
2213 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2219BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2226 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2229 if (pen->deviceid == deviceid)
2236BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* ccontext)
2238 WINPR_ASSERT(ccontext);
2240 const rdpSettings* settings = ccontext->context.settings;
2243 BOOL ainput = FALSE;
2244#if defined(CHANNEL_AINPUT_CLIENT)
2245 ainput = ccontext->ainput != NULL;
2248 return useRelative && (haveRelative || ainput);
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.